<NME> TileLayer.js
<BEF> import {GridLayer} from './GridLayer';
import Browser from '../../core/Browser';
import * as Util from '../../core/Util';
import * as DomEvent from '../../dom/DomEvent';
import * as DomUtil from '../../dom/DomUtil';


/*
 * @class TileLayer
 * @inherits GridLayer
 * @aka L.TileLayer
 * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.
 *
 * @example
 *
 * ```js
 * L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'}).addTo(map);
 * ```
 *
 * @section URL template
 * @example
 *
 * A string of the following form:
 *
 * ```
 * 'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
 * ```
 *
 * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "&commat;2x" to the URL to load retina tiles.
 *
 * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
 *
 * ```
 * L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
 * ```
 */


export const TileLayer = GridLayer.extend({

	// @section
	// @aka TileLayer options
	options: {
		// @option minZoom: Number = 0
		// The minimum zoom level down to which this layer will be displayed (inclusive).
		minZoom: 0,

		// @option maxZoom: Number = 18
		// The maximum zoom level up to which this layer will be displayed (inclusive).
		maxZoom: 18,

		// @option subdomains: String|String[] = 'abc'
		// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.
		subdomains: 'abc',

		// @option errorTileUrl: String = ''
		// URL to the tile image to show in place of the tile that failed to load.
		errorTileUrl: '',

		// @option zoomOffset: Number = 0
		// The zoom number used in tile URLs will be offset with this value.
		zoomOffset: 0,

		// @option tms: Boolean = false
		// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
		tms: false,

		// @option zoomReverse: Boolean = false
		// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
		zoomReverse: false,

		// @option detectRetina: Boolean = false
		// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.
		detectRetina: false,

		// @option crossOrigin: Boolean|String = false
		// Whether the crossOrigin attribute will be added to the tiles.
		// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
		crossOrigin: false,

		// @option referrerPolicy: Boolean|String = false
		// Whether the referrerPolicy attribute will be added to the tiles.
		// If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.
		// This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer
		// (e.g. to validate an API token).
		// Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.
		referrerPolicy: false
	},

	initialize(url, options) {

		this._url = url;

		options = Util.setOptions(this, options);

		// detecting retina displays, adjusting tileSize and zoom levels
		if (options.detectRetina && Browser.retina && options.maxZoom > 0) {

			options.tileSize = Math.floor(options.tileSize / 2);

			if (!options.zoomReverse) {
				options.zoomOffset++;
				options.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);
			} else {
				options.zoomOffset--;
				options.minZoom = Math.min(options.maxZoom, options.minZoom + 1);
			}

			options.minZoom = Math.max(0, options.minZoom);
		} else if (!options.zoomReverse) {
			// make sure maxZoom is gte minZoom
			options.maxZoom = Math.max(options.minZoom, options.maxZoom);
		} else {
			// make sure minZoom is lte maxZoom
			options.minZoom = Math.min(options.maxZoom, options.minZoom);
		}

		if (typeof options.subdomains === 'string') {
			options.subdomains = options.subdomains.split('');
		}

		this.on('tileunload', this._onTileRemove);
	},

	// @method setUrl(url: String, noRedraw?: Boolean): this
	// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
	// If the URL does not change, the layer will not be redrawn unless
	// the noRedraw parameter is set to false.
	setUrl(url, noRedraw) {
		if (this._url === url && noRedraw === undefined) {
			noRedraw = true;
		}

		this._url = url;

		if (!noRedraw) {
			this.redraw();
		}
		return this;
	},

	// @method createTile(coords: Object, done?: Function): HTMLElement
	// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
	// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
	// callback is called when the tile has been loaded.
	createTile(coords, done) {
		const tile = document.createElement('img');

		DomEvent.on(tile, 'load', this._tileOnLoad.bind(this, done, tile));
		DomEvent.on(tile, 'error', this._tileOnError.bind(this, done, tile));

		if (this.options.crossOrigin || this.options.crossOrigin === '') {
			tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
		}

		// for this new option we follow the documented behavior
		// more closely by only setting the property when string
		if (typeof this.options.referrerPolicy === 'string') {
			tile.referrerPolicy = this.options.referrerPolicy;
		}

		// The alt attribute is set to the empty string,
		// allowing screen readers to ignore the decorative image tiles.
		// https://www.w3.org/WAI/tutorials/images/decorative/
		// https://www.w3.org/TR/html-aria/#el-img-empty-alt
	_setAutoZIndex: function (pane, compare) {

		var layers = pane.getElementsByClassName('leaflet-layer'),
		    edgeZIndex = -compare(Infinity, -Infinity), // -Ifinity for max, Infinity for min
		    zIndex, i, len;

		for (i = 0, len = layers.length; i < len; i++) {
	// @section Extension methods
	// @uninheritable
	// Layers extending `TileLayer` might reimplement the following method.
	// @method getTileUrl(coords: Object): String
	// Called only internally, returns the URL for a tile given its coordinates.
	// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
	getTileUrl(coords) {
		const data = {
			r: Browser.retina ? '@2x' : '',
			s: this._getSubdomain(coords),
			x: coords.x,
			y: coords.y,
			z: this._getZoomForUrl()
		};
		if (this._map && !this._map.options.crs.infinite) {
			const invertedY = this._globalTileRange.max.y - coords.y;
			if (this.options.tms) {
				data['y'] = invertedY;
			}
			data['-y'] = invertedY;
		}

		return Util.template(this._url, Util.extend(data, this.options));
	},

	_tileOnLoad(done, tile) {
		done(null, tile);
	},

	_tileOnError(done, tile, e) {
		const errorUrl = this.options.errorTileUrl;
		if (errorUrl && tile.getAttribute('src') !== errorUrl) {
			tile.src = errorUrl;
		}
		done(e, tile);
	},

	_onTileRemove(e) {
		e.tile.onload = null;
	},

	_getZoomForUrl() {
		let zoom = this._tileZoom;
		const maxZoom = this.options.maxZoom,
		      zoomReverse = this.options.zoomReverse,
		      zoomOffset = this.options.zoomOffset;

		if (zoomReverse) {
			zoom = maxZoom - zoom;
		}

		return zoom + zoomOffset;
	},

	_getSubdomain(tilePoint) {
		const index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
		return this.options.subdomains[index];
	},

	// stops loading all tiles in the background layer
	_abortLoading() {
		let i, tile;
		for (i in this._tiles) {
			if (this._tiles[i].coords.z !== this._tileZoom) {
				tile = this._tiles[i].el;

				tile.onload = Util.falseFn;
				tile.onerror = Util.falseFn;

				if (!tile.complete) {
					tile.src = Util.emptyImageUrl;
					const coords = this._tiles[i].coords;
					DomUtil.remove(tile);
					delete this._tiles[i];
					// @event tileabort: TileEvent
					// Fired when a tile was loading but is now not wanted.
					this.fire('tileabort', {
						tile,
						coords
					});
				}
			}
		}
	},

	_removeTile(key) {
		const tile = this._tiles[key];
		if (!tile) { return; }

		// Cancels any pending http requests associated with the tile
		tile.el.setAttribute('src', Util.emptyImageUrl);

		return GridLayer.prototype._removeTile.call(this, key);
	},

	_tileReady(coords, err, tile) {
		if (!this._map || (tile && tile.getAttribute('src') === Util.emptyImageUrl)) {
			return;
		}

		return GridLayer.prototype._tileReady.call(this, coords, err, tile);
	}
});


// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
// Instantiates a tile layer object given a `URL template` and optionally an options object.

export function tileLayer(url, options) {
	return new TileLayer(url, options);
}

<MSG> Merge branch 'master' of github.com:CloudMade/Leaflet

<DFF> @@ -167,7 +167,7 @@ L.TileLayer = L.Class.extend({
 	_setAutoZIndex: function (pane, compare) {
 
 		var layers = pane.getElementsByClassName('leaflet-layer'),
-		    edgeZIndex = -compare(Infinity, -Infinity), // -Ifinity for max, Infinity for min
+		    edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min
 		    zIndex, i, len;
 
 		for (i = 0, len = layers.length; i < len; i++) {

{'commit': 'diff --git a/README.md b/README.md\nindex d200f2db..e074ecb8 100644\n--- a/README.md\n+++ b/README.md\n@@ -1,6 +1,6 @@\n <img src="http://leafletjs.com/docs/images/logo.png" alt="Leaflet" />\r\n \r\n-Leaflet is a modern open-source JavaScript library for **mobile-friendly interactive maps**. It is developed by [Vladimir Agafonkin][] of [CloudMade][] with a team of dedicated [contributors][]. Weighing just about 27 KB of gzipped JS code, it has all the [features][] most devepers ever need for online maps.\r\n+Leaflet is a modern open-source JavaScript library for **mobile-friendly interactive maps**. It is developed by [Vladimir Agafonkin][] of [CloudMade][] with a team of dedicated [contributors][]. Weighing just about 27 KB of gzipped JS code, it has all the [features][] most developers ever need for online maps.\r\n \r\n Leaflet is designed with *simplicity*, *performance* and *usability* in mind. It works efficiently across all major desktop and mobile platforms out of the box, taking advantage of HTML5 and CSS3 on modern browsers while being accessible on older ones too. It can also be extended with many [plugins][], has a beautiful, easy to use and [well-documented][] API and a simple, readable [source code][] that is a joy to [contribute][] to.\r\n \r\ndiff --git a/spec/suites/dom/DomEventSpec.js b/spec/suites/dom/DomEventSpec.js\nindex 83d08541..511ff9c3 100644\n--- a/spec/suites/dom/DomEventSpec.js\n+++ b/spec/suites/dom/DomEventSpec.js\n@@ -63,7 +63,7 @@ describe(\'DomEvent\', function() {\n \t});\r\n \t\r\n \tdescribe(\'#removeListener\', function() {\r\n-\t\tit(\'should remove prevously added listener\', function() {\r\n+\t\tit(\'should remove previously added listener\', function() {\r\n \t\t\tvar listener = jasmine.createSpy(\'listener\');\r\n \t\t\t\r\n \t\t\tL.DomEvent.addListener(el, \'click\', listener);\r\ndiff --git a/spec/suites/geo/LatLngSpec.js b/spec/suites/geo/LatLngSpec.js\nindex ccf1706e..692f88a1 100644\n--- a/spec/suites/geo/LatLngSpec.js\n+++ b/spec/suites/geo/LatLngSpec.js\n@@ -18,7 +18,7 @@ describe(\'LatLng\', function() {\n \t\t\texpect(b).toEqual(-90);\r\n \t\t});\r\n \t\t\r\n-\t\tit("should clamp longtitude to lie between -180 and 180", function() {\r\n+\t\tit("should clamp longitude to lie between -180 and 180", function() {\r\n \t\t\tvar a = new L.LatLng(0, 190).lng;\r\n \t\t\texpect(a).toEqual(-170);\r\n \r\n@@ -44,7 +44,7 @@ describe(\'LatLng\', function() {\n \t\t\texpect(h).toEqual(180);\r\n \t });\r\n \t\t\r\n-\t\tit("should not clamp latitude and longtitude if unbounded flag set to true", function() {\r\n+\t\tit("should not clamp latitude and longitude if unbounded flag set to true", function() {\r\n \t\t\tvar a = new L.LatLng(150, 0, true).lat;\r\n \t\t\texpect(a).toEqual(150);\r\n \t\t\t\r\ndiff --git a/src/Leaflet.js b/src/Leaflet.js\nindex 1ef8a76d..27a7c082 100644\n--- a/src/Leaflet.js\n+++ b/src/Leaflet.js\n@@ -14,4 +14,4 @@ if (typeof exports !== undefined + \'\') {\n \twindow.L = L;\r\n }\r\n \r\n-L.version = \'0.4.4\';\r\n+L.version = \'0.5\';\r\ndiff --git a/src/dom/DomEvent.js b/src/dom/DomEvent.js\nindex 82649b0e..c495514f 100644\n--- a/src/dom/DomEvent.js\n+++ b/src/dom/DomEvent.js\n@@ -3,7 +3,7 @@\n  */\r\n \r\n L.DomEvent = {\r\n-\t/* inpired by John Resig, Dean Edwards and YUI addEvent implementations */\r\n+\t/* inspired by John Resig, Dean Edwards and YUI addEvent implementations */\r\n \taddListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object])\r\n \r\n \t\tvar id = L.stamp(fn),\r\ndiff --git a/src/dom/PosAnimation.js b/src/dom/PosAnimation.js\nindex 1afe7613..1c988766 100644\n--- a/src/dom/PosAnimation.js\n+++ b/src/dom/PosAnimation.js\n@@ -22,7 +22,7 @@ L.PosAnimation = L.Class.extend({\n \t\t// toggle reflow, Chrome flickers for some reason if you don\'t do this\n \t\tL.Util.falseFn(el.offsetWidth);\n \n-\t\t// there\'s no native way to track value updates of tranisitioned properties, so we imitate this\n+\t\t// there\'s no native way to track value updates of transitioned properties, so we imitate this\n \t\tthis._stepTimer = setInterval(L.bind(this.fire, this, \'step\'), 50);\n \t},\n \ndiff --git a/src/geo/LatLng.js b/src/geo/LatLng.js\nindex 2b6a92c1..17549c68 100644\n--- a/src/geo/LatLng.js\n+++ b/src/geo/LatLng.js\n@@ -1,5 +1,5 @@\n /*\r\n-\tCM.LatLng represents a geographical point with latitude and longtitude coordinates.\r\n+\tCM.LatLng represents a geographical point with latitude and longitude coordinates.\r\n */\r\n \r\n L.LatLng = function (rawLat, rawLng, noWrap) { // (Number, Number[, Boolean])\r\n@@ -12,7 +12,7 @@ L.LatLng = function (rawLat, rawLng, noWrap) { // (Number, Number[, Boolean])\n \r\n \tif (noWrap !== true) {\r\n \t\tlat = Math.max(Math.min(lat, 90), -90);\t\t\t\t\t// clamp latitude into -90..90\r\n-\t\tlng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180);\t// wrap longtitude into -180..180\r\n+\t\tlng = (lng + 180) % 360 + ((lng < -180 || lng === 180) ? 180 : -180);\t// wrap longitude into -180..180\r\n \t}\r\n \r\n \tthis.lat = lat;\r\ndiff --git a/src/geometry/PolyUtil.js b/src/geometry/PolyUtil.js\nindex 806fdcb9..dbce39df 100644\n--- a/src/geometry/PolyUtil.js\n+++ b/src/geometry/PolyUtil.js\n@@ -1,8 +1,8 @@\n /*\r\n- * L.PolyUtil contains utilify functions for polygons (clipping, etc.).\r\n+ * L.PolyUtil contains utility functions for polygons (clipping, etc.).\r\n  */\r\n \r\n-/*jshint bitwise:false */ // allow bitwise oprations here\r\n+/*jshint bitwise:false */ // allow bitwise operations here\r\n \r\n L.PolyUtil = {};\r\n \r\ndiff --git a/src/layer/tile/TileLayer.js b/src/layer/tile/TileLayer.js\nindex 8b9285c6..ab0ba41c 100644\n--- a/src/layer/tile/TileLayer.js\n+++ b/src/layer/tile/TileLayer.js\n@@ -167,7 +167,7 @@ L.TileLayer = L.Class.extend({\n \t_setAutoZIndex: function (pane, compare) {\r\n \r\n \t\tvar layers = pane.getElementsByClassName(\'leaflet-layer\'),\r\n-\t\t    edgeZIndex = -compare(Infinity, -Infinity), // -Ifinity for max, Infinity for min\r\n+\t\t    edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min\r\n \t\t    zIndex, i, len;\r\n \r\n \t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n', 'commit_subject': "Merge branch 'master' of github.com:CloudMade/Leaflet", 'repo_name': 'Leaflet/Leaflet', 'committer': {'name': 'Vladimir Agafonkin', 'email': 'af9b9b551d320013945f6a952e71e091983bc228@gmail.com', 'time_sec': '1352818122', 'tz_offset': '120', 'date': {'seconds': '1352818122'}}, 'commit_tree': 'e0fe1f36ba26755f5f02a9f5451e45265c2f5d51', 'commit_message': "Merge branch 'master' of github.com:CloudMade/Leaflet\n", 'language_name': 'HTML', 'license': 'bsd-2-clause', 'hunks': "@@ -167,7 +167,7 @@ L.TileLayer = L.Class.extend({\n \t_setAutoZIndex: function (pane, compare) {\r\n \r\n \t\tvar layers = pane.getElementsByClassName('leaflet-layer'),\r\n-\t\t    edgeZIndex = -compare(Infinity, -Infinity), // -Ifinity for max, Infinity for min\r\n+\t\t    edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min\r\n \t\t    zIndex, i, len;\r\n \r\n \t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n", 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/src/layer/tile/TileLayer.js', 'tgt_file': 'b/src/layer/tile/TileLayer.js', 'file_extension': '.js', 'before_file': 'import {GridLayer} from \'./GridLayer\';\nimport Browser from \'../../core/Browser\';\nimport * as Util from \'../../core/Util\';\nimport * as DomEvent from \'../../dom/DomEvent\';\nimport * as DomUtil from \'../../dom/DomUtil\';\n\n\n/*\n * @class TileLayer\n * @inherits GridLayer\n * @aka L.TileLayer\n * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.\n *\n * @example\n *\n * ```js\n * L.tileLayer(\'https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}\', {foo: \'bar\', attribution: \'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors\'}).addTo(map);\n * ```\n *\n * @section URL template\n * @example\n *\n * A string of the following form:\n *\n * ```\n * \'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png\'\n * ```\n *\n * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "&commat;2x" to the URL to load retina tiles.\n *\n * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:\n *\n * ```\n * L.tileLayer(\'https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png\', {foo: \'bar\'});\n * ```\n */\n\n\nexport const TileLayer = GridLayer.extend({\n\n\t// @section\n\t// @aka TileLayer options\n\toptions: {\n\t\t// @option minZoom: Number = 0\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\n\t\tminZoom: 0,\n\n\t\t// @option maxZoom: Number = 18\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\n\t\tmaxZoom: 18,\n\n\t\t// @option subdomains: String|String[] = \'abc\'\n\t\t// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.\n\t\tsubdomains: \'abc\',\n\n\t\t// @option errorTileUrl: String = \'\'\n\t\t// URL to the tile image to show in place of the tile that failed to load.\n\t\terrorTileUrl: \'\',\n\n\t\t// @option zoomOffset: Number = 0\n\t\t// The zoom number used in tile URLs will be offset with this value.\n\t\tzoomOffset: 0,\n\n\t\t// @option tms: Boolean = false\n\t\t// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).\n\t\ttms: false,\n\n\t\t// @option zoomReverse: Boolean = false\n\t\t// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)\n\t\tzoomReverse: false,\n\n\t\t// @option detectRetina: Boolean = false\n\t\t// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.\n\t\tdetectRetina: false,\n\n\t\t// @option crossOrigin: Boolean|String = false\n\t\t// Whether the crossOrigin attribute will be added to the tiles.\n\t\t// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\n\t\tcrossOrigin: false,\n\n\t\t// @option referrerPolicy: Boolean|String = false\n\t\t// Whether the referrerPolicy attribute will be added to the tiles.\n\t\t// If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.\n\t\t// This may be needed if your map\'s rendering context has a strict default but your tile provider expects a valid referrer\n\t\t// (e.g. to validate an API token).\n\t\t// Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.\n\t\treferrerPolicy: false\n\t},\n\n\tinitialize(url, options) {\n\n\t\tthis._url = url;\n\n\t\toptions = Util.setOptions(this, options);\n\n\t\t// detecting retina displays, adjusting tileSize and zoom levels\n\t\tif (options.detectRetina && Browser.retina && options.maxZoom > 0) {\n\n\t\t\toptions.tileSize = Math.floor(options.tileSize / 2);\n\n\t\t\tif (!options.zoomReverse) {\n\t\t\t\toptions.zoomOffset++;\n\t\t\t\toptions.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);\n\t\t\t} else {\n\t\t\t\toptions.zoomOffset--;\n\t\t\t\toptions.minZoom = Math.min(options.maxZoom, options.minZoom + 1);\n\t\t\t}\n\n\t\t\toptions.minZoom = Math.max(0, options.minZoom);\n\t\t} else if (!options.zoomReverse) {\n\t\t\t// make sure maxZoom is gte minZoom\n\t\t\toptions.maxZoom = Math.max(options.minZoom, options.maxZoom);\n\t\t} else {\n\t\t\t// make sure minZoom is lte maxZoom\n\t\t\toptions.minZoom = Math.min(options.maxZoom, options.minZoom);\n\t\t}\n\n\t\tif (typeof options.subdomains === \'string\') {\n\t\t\toptions.subdomains = options.subdomains.split(\'\');\n\t\t}\n\n\t\tthis.on(\'tileunload\', this._onTileRemove);\n\t},\n\n\t// @method setUrl(url: String, noRedraw?: Boolean): this\n\t// Updates the layer\'s URL template and redraws it (unless `noRedraw` is set to `true`).\n\t// If the URL does not change, the layer will not be redrawn unless\n\t// the noRedraw parameter is set to false.\n\tsetUrl(url, noRedraw) {\n\t\tif (this._url === url && noRedraw === undefined) {\n\t\t\tnoRedraw = true;\n\t\t}\n\n\t\tthis._url = url;\n\n\t\tif (!noRedraw) {\n\t\t\tthis.redraw();\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\n\t// Called only internally, overrides GridLayer\'s [`createTile()`](#gridlayer-createtile)\n\t// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`\n\t// callback is called when the tile has been loaded.\n\tcreateTile(coords, done) {\n\t\tconst tile = document.createElement(\'img\');\n\n\t\tDomEvent.on(tile, \'load\', this._tileOnLoad.bind(this, done, tile));\n\t\tDomEvent.on(tile, \'error\', this._tileOnError.bind(this, done, tile));\n\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === \'\') {\n\t\t\ttile.crossOrigin = this.options.crossOrigin === true ? \'\' : this.options.crossOrigin;\n\t\t}\n\n\t\t// for this new option we follow the documented behavior\n\t\t// more closely by only setting the property when string\n\t\tif (typeof this.options.referrerPolicy === \'string\') {\n\t\t\ttile.referrerPolicy = this.options.referrerPolicy;\n\t\t}\n\n\t\t// The alt attribute is set to the empty string,\n\t\t// allowing screen readers to ignore the decorative image tiles.\n\t\t// https://www.w3.org/WAI/tutorials/images/decorative/\n\t\t// https://www.w3.org/TR/html-aria/#el-img-empty-alt\n\t_setAutoZIndex: function (pane, compare) {\r\n\r\n\t\tvar layers = pane.getElementsByClassName(\'leaflet-layer\'),\r\n\t\t    edgeZIndex = -compare(Infinity, -Infinity), // -Ifinity for max, Infinity for min\r\n\t\t    zIndex, i, len;\r\n\r\n\t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n\t// @section Extension methods\n\t// @uninheritable\n\t// Layers extending `TileLayer` might reimplement the following method.\n\t// @method getTileUrl(coords: Object): String\n\t// Called only internally, returns the URL for a tile given its coordinates.\n\t// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.\n\tgetTileUrl(coords) {\n\t\tconst data = {\n\t\t\tr: Browser.retina ? \'@2x\' : \'\',\n\t\t\ts: this._getSubdomain(coords),\n\t\t\tx: coords.x,\n\t\t\ty: coords.y,\n\t\t\tz: this._getZoomForUrl()\n\t\t};\n\t\tif (this._map && !this._map.options.crs.infinite) {\n\t\t\tconst invertedY = this._globalTileRange.max.y - coords.y;\n\t\t\tif (this.options.tms) {\n\t\t\t\tdata[\'y\'] = invertedY;\n\t\t\t}\n\t\t\tdata[\'-y\'] = invertedY;\n\t\t}\n\n\t\treturn Util.template(this._url, Util.extend(data, this.options));\n\t},\n\n\t_tileOnLoad(done, tile) {\n\t\tdone(null, tile);\n\t},\n\n\t_tileOnError(done, tile, e) {\n\t\tconst errorUrl = this.options.errorTileUrl;\n\t\tif (errorUrl && tile.getAttribute(\'src\') !== errorUrl) {\n\t\t\ttile.src = errorUrl;\n\t\t}\n\t\tdone(e, tile);\n\t},\n\n\t_onTileRemove(e) {\n\t\te.tile.onload = null;\n\t},\n\n\t_getZoomForUrl() {\n\t\tlet zoom = this._tileZoom;\n\t\tconst maxZoom = this.options.maxZoom,\n\t\t      zoomReverse = this.options.zoomReverse,\n\t\t      zoomOffset = this.options.zoomOffset;\n\n\t\tif (zoomReverse) {\n\t\t\tzoom = maxZoom - zoom;\n\t\t}\n\n\t\treturn zoom + zoomOffset;\n\t},\n\n\t_getSubdomain(tilePoint) {\n\t\tconst index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;\n\t\treturn this.options.subdomains[index];\n\t},\n\n\t// stops loading all tiles in the background layer\n\t_abortLoading() {\n\t\tlet i, tile;\n\t\tfor (i in this._tiles) {\n\t\t\tif (this._tiles[i].coords.z !== this._tileZoom) {\n\t\t\t\ttile = this._tiles[i].el;\n\n\t\t\t\ttile.onload = Util.falseFn;\n\t\t\t\ttile.onerror = Util.falseFn;\n\n\t\t\t\tif (!tile.complete) {\n\t\t\t\t\ttile.src = Util.emptyImageUrl;\n\t\t\t\t\tconst coords = this._tiles[i].coords;\n\t\t\t\t\tDomUtil.remove(tile);\n\t\t\t\t\tdelete this._tiles[i];\n\t\t\t\t\t// @event tileabort: TileEvent\n\t\t\t\t\t// Fired when a tile was loading but is now not wanted.\n\t\t\t\t\tthis.fire(\'tileabort\', {\n\t\t\t\t\t\ttile,\n\t\t\t\t\t\tcoords\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_removeTile(key) {\n\t\tconst tile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\t// Cancels any pending http requests associated with the tile\n\t\ttile.el.setAttribute(\'src\', Util.emptyImageUrl);\n\n\t\treturn GridLayer.prototype._removeTile.call(this, key);\n\t},\n\n\t_tileReady(coords, err, tile) {\n\t\tif (!this._map || (tile && tile.getAttribute(\'src\') === Util.emptyImageUrl)) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn GridLayer.prototype._tileReady.call(this, coords, err, tile);\n\t}\n});\n\n\n// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)\n// Instantiates a tile layer object given a `URL template` and optionally an options object.\n\nexport function tileLayer(url, options) {\n\treturn new TileLayer(url, options);\n}\n', 'message': "Merge branch 'master' of github.com:CloudMade/Leaflet\n", 'author_name': 'Vladimir Agafonkin', 'lang': 'js'}