From 8df4d8aff07323b7ff62fbde8f661a597d7925ed Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 17 Jul 2018 22:47:50 +0100 Subject: [PATCH 1/1] Update leaflet to 1.3.2 --- Vendorfile | 6 +- vendor/assets/leaflet/leaflet.js | 1224 ++++++++++++++++-------------- 2 files changed, 639 insertions(+), 591 deletions(-) diff --git a/Vendorfile b/Vendorfile index 8ca4342d7..c25b8a616 100644 --- a/Vendorfile +++ b/Vendorfile @@ -11,13 +11,13 @@ folder 'vendor/assets' do end folder 'leaflet' do - file 'leaflet.js', 'https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js' - file 'leaflet.css', 'https://unpkg.com/leaflet@1.3.1/dist/leaflet.css' + file 'leaflet.js', 'https://unpkg.com/leaflet@1.3.2/dist/leaflet-src.js' + file 'leaflet.css', 'https://unpkg.com/leaflet@1.3.2/dist/leaflet.css' [ 'layers.png', 'layers-2x.png', 'marker-icon.png', 'marker-icon-2x.png', 'marker-shadow.png' ].each do |image| - file "images/#{image}", "https://unpkg.com/leaflet@1.3.1/dist/images/#{image}" + file "images/#{image}", "https://unpkg.com/leaflet@1.3.2/dist/images/#{image}" end from 'git://github.com/aratcliffe/Leaflet.contextmenu.git', :tag => 'v1.5.0' do diff --git a/vendor/assets/leaflet/leaflet.js b/vendor/assets/leaflet/leaflet.js index 63f6fb790..c5f0ee52f 100644 --- a/vendor/assets/leaflet/leaflet.js +++ b/vendor/assets/leaflet/leaflet.js @@ -1,6 +1,6 @@ /* @preserve - * Leaflet 1.3.1, a JS library for interactive maps. http://leafletjs.com - * (c) 2010-2017 Vladimir Agafonkin, (c) 2010-2011 CloudMade + * Leaflet 1.3.2, a JS library for interactive maps. http://leafletjs.com + * (c) 2010-2018 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ (function (global, factory) { @@ -9,7 +9,7 @@ (factory((global.L = {}))); }(this, (function (exports) { 'use strict'; -var version = "1.3.1"; +var version = "1.3.2"; /* * @namespace Util @@ -1360,7 +1360,7 @@ function toLatLngBounds(a, b) { * map.panTo(L.latLng(50, 30)); * ``` * - * Note that `LatLng` does not inherit from Leafet's `Class` object, + * Note that `LatLng` does not inherit from Leaflet's `Class` object, * which means new classes can't inherit from it, and new methods * can't be added to it with the `include` function. */ @@ -1922,7 +1922,7 @@ var mobileOpera = mobile && opera; var mobileGecko = mobile && gecko; // @property retina: Boolean -// `true` for browsers on a high-resolution "retina" screen. +// `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%. var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1; @@ -2207,671 +2207,698 @@ function removeDoubleTapListener(obj, id) { } /* - * @namespace DomEvent - * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally. + * @namespace DomUtil + * + * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) + * tree, used by Leaflet internally. + * + * Most functions expecting or returning a `HTMLElement` also work for + * SVG elements. The only difference is that classes refer to CSS classes + * in HTML and SVG classes in SVG. */ -// Inspired by John Resig, Dean Edwards and YUI addEvent implementations. - -// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this -// Adds a listener function (`fn`) to a particular DOM event type of the -// element `el`. You can optionally specify the context of the listener -// (object the `this` keyword will point to). You can also pass several -// space-separated types (e.g. `'click dblclick'`). - -// @alternative -// @function on(el: HTMLElement, eventMap: Object, context?: Object): this -// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` -function on(obj, types, fn, context) { - if (typeof types === 'object') { - for (var type in types) { - addOne(obj, type, types[type], fn); - } - } else { - types = splitWords(types); +// @property TRANSFORM: String +// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit). +var TRANSFORM = testProp( + ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); - for (var i = 0, len = types.length; i < len; i++) { - addOne(obj, types[i], fn, context); - } - } +// webkitTransition comes first because some browser versions that drop vendor prefix don't do +// the same for the transitionend event, in particular the Android 4.1 stock browser - return this; -} +// @property TRANSITION: String +// Vendor-prefixed transition style name. +var TRANSITION = testProp( + ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); -var eventsKey = '_leaflet_events'; +// @property TRANSITION_END: String +// Vendor-prefixed transitionend event name. +var TRANSITION_END = + TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend'; -// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this -// Removes a previously added listener function. -// Note that if you passed a custom context to on, you must pass the same -// context to `off` in order to remove the listener. -// @alternative -// @function off(el: HTMLElement, eventMap: Object, context?: Object): this -// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` -function off(obj, types, fn, context) { +// @function get(id: String|HTMLElement): HTMLElement +// Returns an element given its DOM id, or returns the element itself +// if it was passed directly. +function get(id) { + return typeof id === 'string' ? document.getElementById(id) : id; +} - if (typeof types === 'object') { - for (var type in types) { - removeOne(obj, type, types[type], fn); - } - } else if (types) { - types = splitWords(types); +// @function getStyle(el: HTMLElement, styleAttrib: String): String +// Returns the value for a certain style attribute on an element, +// including computed values or values set through CSS. +function getStyle(el, style) { + var value = el.style[style] || (el.currentStyle && el.currentStyle[style]); - for (var i = 0, len = types.length; i < len; i++) { - removeOne(obj, types[i], fn, context); - } - } else { - for (var j in obj[eventsKey]) { - removeOne(obj, j, obj[eventsKey][j]); - } - delete obj[eventsKey]; + if ((!value || value === 'auto') && document.defaultView) { + var css = document.defaultView.getComputedStyle(el, null); + value = css ? css[style] : null; } - - return this; + return value === 'auto' ? null : value; } -function addOne(obj, type, fn, context) { - var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''); - - if (obj[eventsKey] && obj[eventsKey][id]) { return this; } - - var handler = function (e) { - return fn.call(context || obj, e || window.event); - }; +// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement +// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element. +function create$1(tagName, className, container) { + var el = document.createElement(tagName); + el.className = className || ''; - var originalHandler = handler; + if (container) { + container.appendChild(el); + } + return el; +} - if (pointer && type.indexOf('touch') === 0) { - // Needs DomEvent.Pointer.js - addPointerListener(obj, type, handler, id); +// @function remove(el: HTMLElement) +// Removes `el` from its parent element +function remove(el) { + var parent = el.parentNode; + if (parent) { + parent.removeChild(el); + } +} - } else if (touch && (type === 'dblclick') && addDoubleTapListener && - !(pointer && chrome)) { - // Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener - // See #5180 - addDoubleTapListener(obj, handler, id); +// @function empty(el: HTMLElement) +// Removes all of `el`'s children elements from `el` +function empty(el) { + while (el.firstChild) { + el.removeChild(el.firstChild); + } +} - } else if ('addEventListener' in obj) { +// @function toFront(el: HTMLElement) +// Makes `el` the last child of its parent, so it renders in front of the other children. +function toFront(el) { + var parent = el.parentNode; + if (parent.lastChild !== el) { + parent.appendChild(el); + } +} - if (type === 'mousewheel') { - obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false); +// @function toBack(el: HTMLElement) +// Makes `el` the first child of its parent, so it renders behind the other children. +function toBack(el) { + var parent = el.parentNode; + if (parent.firstChild !== el) { + parent.insertBefore(el, parent.firstChild); + } +} - } else if ((type === 'mouseenter') || (type === 'mouseleave')) { - handler = function (e) { - e = e || window.event; - if (isExternalTarget(obj, e)) { - originalHandler(e); - } - }; - obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false); +// @function hasClass(el: HTMLElement, name: String): Boolean +// Returns `true` if the element's class attribute contains `name`. +function hasClass(el, name) { + if (el.classList !== undefined) { + return el.classList.contains(name); + } + var className = getClass(el); + return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); +} - } else { - if (type === 'click' && android) { - handler = function (e) { - filterClick(e, originalHandler); - }; - } - obj.addEventListener(type, handler, false); +// @function addClass(el: HTMLElement, name: String) +// Adds `name` to the element's class attribute. +function addClass(el, name) { + if (el.classList !== undefined) { + var classes = splitWords(name); + for (var i = 0, len = classes.length; i < len; i++) { + el.classList.add(classes[i]); } - - } else if ('attachEvent' in obj) { - obj.attachEvent('on' + type, handler); + } else if (!hasClass(el, name)) { + var className = getClass(el); + setClass(el, (className ? className + ' ' : '') + name); } - - obj[eventsKey] = obj[eventsKey] || {}; - obj[eventsKey][id] = handler; } -function removeOne(obj, type, fn, context) { - - var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''), - handler = obj[eventsKey] && obj[eventsKey][id]; +// @function removeClass(el: HTMLElement, name: String) +// Removes `name` from the element's class attribute. +function removeClass(el, name) { + if (el.classList !== undefined) { + el.classList.remove(name); + } else { + setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' '))); + } +} - if (!handler) { return this; } +// @function setClass(el: HTMLElement, name: String) +// Sets the element's class. +function setClass(el, name) { + if (el.className.baseVal === undefined) { + el.className = name; + } else { + // in case of SVG element + el.className.baseVal = name; + } +} - if (pointer && type.indexOf('touch') === 0) { - removePointerListener(obj, type, id); +// @function getClass(el: HTMLElement): String +// Returns the element's class. +function getClass(el) { + return el.className.baseVal === undefined ? el.className : el.className.baseVal; +} - } else if (touch && (type === 'dblclick') && removeDoubleTapListener && - !(pointer && chrome)) { - removeDoubleTapListener(obj, id); +// @function setOpacity(el: HTMLElement, opacity: Number) +// Set the opacity of an element (including old IE support). +// `opacity` must be a number from `0` to `1`. +function setOpacity(el, value) { + if ('opacity' in el.style) { + el.style.opacity = value; + } else if ('filter' in el.style) { + _setOpacityIE(el, value); + } +} - } else if ('removeEventListener' in obj) { +function _setOpacityIE(el, value) { + var filter = false, + filterName = 'DXImageTransform.Microsoft.Alpha'; - if (type === 'mousewheel') { - obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false); + // filters collection throws an error if we try to retrieve a filter that doesn't exist + try { + filter = el.filters.item(filterName); + } catch (e) { + // don't set opacity to 1 if we haven't already set an opacity, + // it isn't needed and breaks transparent pngs. + if (value === 1) { return; } + } - } else { - obj.removeEventListener( - type === 'mouseenter' ? 'mouseover' : - type === 'mouseleave' ? 'mouseout' : type, handler, false); - } + value = Math.round(value * 100); - } else if ('detachEvent' in obj) { - obj.detachEvent('on' + type, handler); + if (filter) { + filter.Enabled = (value !== 100); + filter.Opacity = value; + } else { + el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; } - - obj[eventsKey][id] = null; } -// @function stopPropagation(ev: DOMEvent): this -// Stop the given event from propagation to parent elements. Used inside the listener functions: -// ```js -// L.DomEvent.on(div, 'click', function (ev) { -// L.DomEvent.stopPropagation(ev); -// }); -// ``` -function stopPropagation(e) { +// @function testProp(props: String[]): String|false +// Goes through the array of style names and returns the first name +// that is a valid style name for an element. If no such name is found, +// it returns false. Useful for vendor-prefixed styles like `transform`. +function testProp(props) { + var style = document.documentElement.style; - if (e.stopPropagation) { - e.stopPropagation(); - } else if (e.originalEvent) { // In case of Leaflet event. - e.originalEvent._stopped = true; - } else { - e.cancelBubble = true; + for (var i = 0; i < props.length; i++) { + if (props[i] in style) { + return props[i]; + } } - skipped(e); - - return this; + return false; } -// @function disableScrollPropagation(el: HTMLElement): this -// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants). -function disableScrollPropagation(el) { - addOne(el, 'mousewheel', stopPropagation); - return this; -} +// @function setTransform(el: HTMLElement, offset: Point, scale?: Number) +// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels +// and optionally scaled by `scale`. Does not have an effect if the +// browser doesn't support 3D CSS transforms. +function setTransform(el, offset, scale) { + var pos = offset || new Point(0, 0); -// @function disableClickPropagation(el: HTMLElement): this -// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`, -// `'mousedown'` and `'touchstart'` events (plus browser variants). -function disableClickPropagation(el) { - on(el, 'mousedown touchstart dblclick', stopPropagation); - addOne(el, 'click', fakeStop); - return this; + el.style[TRANSFORM] = + (ie3d ? + 'translate(' + pos.x + 'px,' + pos.y + 'px)' : + 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') + + (scale ? ' scale(' + scale + ')' : ''); } -// @function preventDefault(ev: DOMEvent): this -// Prevents the default action of the DOM Event `ev` from happening (such as -// following a link in the href of the a element, or doing a POST request -// with page reload when a `
` is submitted). -// Use it inside listener functions. -function preventDefault(e) { - if (e.preventDefault) { - e.preventDefault(); +// @function setPosition(el: HTMLElement, position: Point) +// Sets the position of `el` to coordinates specified by `position`, +// using CSS translate or top/left positioning depending on the browser +// (used by Leaflet internally to position its layers). +function setPosition(el, point) { + + /*eslint-disable */ + el._leaflet_pos = point; + /* eslint-enable */ + + if (any3d) { + setTransform(el, point); } else { - e.returnValue = false; + el.style.left = point.x + 'px'; + el.style.top = point.y + 'px'; } - return this; } -// @function stop(ev: DOMEvent): this -// Does `stopPropagation` and `preventDefault` at the same time. -function stop(e) { - preventDefault(e); - stopPropagation(e); - return this; +// @function getPosition(el: HTMLElement): Point +// Returns the coordinates of an element previously positioned with setPosition. +function getPosition(el) { + // this method is only used for elements previously positioned using setPosition, + // so it's safe to cache the position for performance + + return el._leaflet_pos || new Point(0, 0); } -// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point -// Gets normalized mouse position from a DOM event relative to the -// `container` or to the whole page if not specified. -function getMousePosition(e, container) { - if (!container) { - return new Point(e.clientX, e.clientY); - } +// @function disableTextSelection() +// Prevents the user from generating `selectstart` DOM events, usually generated +// when the user drags the mouse through a page with text. Used internally +// by Leaflet to override the behaviour of any click-and-drag interaction on +// the map. Affects drag interactions on the whole document. - var rect = container.getBoundingClientRect(); +// @function enableTextSelection() +// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection). +var disableTextSelection; +var enableTextSelection; +var _userSelect; +if ('onselectstart' in document) { + disableTextSelection = function () { + on(window, 'selectstart', preventDefault); + }; + enableTextSelection = function () { + off(window, 'selectstart', preventDefault); + }; +} else { + var userSelectProperty = testProp( + ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); - var scaleX = rect.width / container.offsetWidth || 1; - var scaleY = rect.height / container.offsetHeight || 1; - return new Point( - e.clientX / scaleX - rect.left - container.clientLeft, - e.clientY / scaleY - rect.top - container.clientTop); + disableTextSelection = function () { + if (userSelectProperty) { + var style = document.documentElement.style; + _userSelect = style[userSelectProperty]; + style[userSelectProperty] = 'none'; + } + }; + enableTextSelection = function () { + if (userSelectProperty) { + document.documentElement.style[userSelectProperty] = _userSelect; + _userSelect = undefined; + } + }; } -// Chrome on Win scrolls double the pixels as in other platforms (see #4538), -// and Firefox scrolls device pixels, not CSS pixels -var wheelPxFactor = - (win && chrome) ? 2 * window.devicePixelRatio : - gecko ? window.devicePixelRatio : 1; +// @function disableImageDrag() +// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but +// for `dragstart` DOM events, usually generated when the user drags an image. +function disableImageDrag() { + on(window, 'dragstart', preventDefault); +} -// @function getWheelDelta(ev: DOMEvent): Number -// Gets normalized wheel delta from a mousewheel DOM event, in vertical -// pixels scrolled (negative if scrolling down). -// Events from pointing devices without precise scrolling are mapped to -// a best guess of 60 pixels. -function getWheelDelta(e) { - return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta - (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels - (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines - (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages - (e.deltaX || e.deltaZ) ? 0 : // Skip horizontal/depth wheel events - e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels - (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines - e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages - 0; +// @function enableImageDrag() +// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection). +function enableImageDrag() { + off(window, 'dragstart', preventDefault); } -var skipEvents = {}; +var _outlineElement; +var _outlineStyle; +// @function preventOutline(el: HTMLElement) +// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline) +// of the element `el` invisible. Used internally by Leaflet to prevent +// focusable elements from displaying an outline when the user performs a +// drag interaction on them. +function preventOutline(element) { + while (element.tabIndex === -1) { + element = element.parentNode; + } + if (!element.style) { return; } + restoreOutline(); + _outlineElement = element; + _outlineStyle = element.style.outline; + element.style.outline = 'none'; + on(window, 'keydown', restoreOutline); +} -function fakeStop(e) { - // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e) - skipEvents[e.type] = true; +// @function restoreOutline() +// Cancels the effects of a previous [`L.DomUtil.preventOutline`](). +function restoreOutline() { + if (!_outlineElement) { return; } + _outlineElement.style.outline = _outlineStyle; + _outlineElement = undefined; + _outlineStyle = undefined; + off(window, 'keydown', restoreOutline); } -function skipped(e) { - var events = skipEvents[e.type]; - // reset when checking, as it's only used in map container and propagates outside of the map - skipEvents[e.type] = false; - return events; +// @function getSizedParentNode(el: HTMLElement): HTMLElement +// Finds the closest parent node which size (width and height) is not null. +function getSizedParentNode(element) { + do { + element = element.parentNode; + } while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body); + return element; } -// check if element really left/entered the event target (for mouseenter/mouseleave) -function isExternalTarget(el, e) { +// @function getScale(el: HTMLElement): Object +// Computes the CSS scale currently applied on the element. +// Returns an object with `x` and `y` members as horizontal and vertical scales respectively, +// and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). +function getScale(element) { + var rect = element.getBoundingClientRect(); // Read-only in old browsers. - var related = e.relatedTarget; + return { + x: rect.width / element.offsetWidth || 1, + y: rect.height / element.offsetHeight || 1, + boundingClientRect: rect + }; +} - if (!related) { return true; } - try { - while (related && (related !== el)) { - related = related.parentNode; - } - } catch (err) { - return false; - } - return (related !== el); -} +var DomUtil = (Object.freeze || Object)({ + TRANSFORM: TRANSFORM, + TRANSITION: TRANSITION, + TRANSITION_END: TRANSITION_END, + get: get, + getStyle: getStyle, + create: create$1, + remove: remove, + empty: empty, + toFront: toFront, + toBack: toBack, + hasClass: hasClass, + addClass: addClass, + removeClass: removeClass, + setClass: setClass, + getClass: getClass, + setOpacity: setOpacity, + testProp: testProp, + setTransform: setTransform, + setPosition: setPosition, + getPosition: getPosition, + disableTextSelection: disableTextSelection, + enableTextSelection: enableTextSelection, + disableImageDrag: disableImageDrag, + enableImageDrag: enableImageDrag, + preventOutline: preventOutline, + restoreOutline: restoreOutline, + getSizedParentNode: getSizedParentNode, + getScale: getScale +}); -var lastClick; +/* + * @namespace DomEvent + * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally. + */ -// this is a horrible workaround for a bug in Android where a single touch triggers two click events -function filterClick(e, handler) { - var timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)), - elapsed = lastClick && (timeStamp - lastClick); +// Inspired by John Resig, Dean Edwards and YUI addEvent implementations. - // are they closer together than 500ms yet more than 100ms? - // Android typically triggers them ~300ms apart while multiple listeners - // on the same event should be triggered far faster; - // or check if click is simulated on the element, and if it is, reject any non-simulated events +// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this +// Adds a listener function (`fn`) to a particular DOM event type of the +// element `el`. You can optionally specify the context of the listener +// (object the `this` keyword will point to). You can also pass several +// space-separated types (e.g. `'click dblclick'`). - if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) { - stop(e); - return; +// @alternative +// @function on(el: HTMLElement, eventMap: Object, context?: Object): this +// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` +function on(obj, types, fn, context) { + + if (typeof types === 'object') { + for (var type in types) { + addOne(obj, type, types[type], fn); + } + } else { + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + addOne(obj, types[i], fn, context); + } } - lastClick = timeStamp; - handler(e); + return this; } +var eventsKey = '_leaflet_events'; + +// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this +// Removes a previously added listener function. +// Note that if you passed a custom context to on, you must pass the same +// context to `off` in order to remove the listener. +// @alternative +// @function off(el: HTMLElement, eventMap: Object, context?: Object): this +// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` +function off(obj, types, fn, context) { + if (typeof types === 'object') { + for (var type in types) { + removeOne(obj, type, types[type], fn); + } + } else if (types) { + types = splitWords(types); -var DomEvent = (Object.freeze || Object)({ - on: on, - off: off, - stopPropagation: stopPropagation, - disableScrollPropagation: disableScrollPropagation, - disableClickPropagation: disableClickPropagation, - preventDefault: preventDefault, - stop: stop, - getMousePosition: getMousePosition, - getWheelDelta: getWheelDelta, - fakeStop: fakeStop, - skipped: skipped, - isExternalTarget: isExternalTarget, - addListener: on, - removeListener: off -}); + for (var i = 0, len = types.length; i < len; i++) { + removeOne(obj, types[i], fn, context); + } + } else { + for (var j in obj[eventsKey]) { + removeOne(obj, j, obj[eventsKey][j]); + } + delete obj[eventsKey]; + } -/* - * @namespace DomUtil - * - * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) - * tree, used by Leaflet internally. - * - * Most functions expecting or returning a `HTMLElement` also work for - * SVG elements. The only difference is that classes refer to CSS classes - * in HTML and SVG classes in SVG. - */ + return this; +} +function addOne(obj, type, fn, context) { + var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''); -// @property TRANSFORM: String -// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit). -var TRANSFORM = testProp( - ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); + if (obj[eventsKey] && obj[eventsKey][id]) { return this; } -// webkitTransition comes first because some browser versions that drop vendor prefix don't do -// the same for the transitionend event, in particular the Android 4.1 stock browser + var handler = function (e) { + return fn.call(context || obj, e || window.event); + }; -// @property TRANSITION: String -// Vendor-prefixed transition style name. -var TRANSITION = testProp( - ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); + var originalHandler = handler; -// @property TRANSITION_END: String -// Vendor-prefixed transitionend event name. -var TRANSITION_END = - TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend'; + if (pointer && type.indexOf('touch') === 0) { + // Needs DomEvent.Pointer.js + addPointerListener(obj, type, handler, id); + } else if (touch && (type === 'dblclick') && addDoubleTapListener && + !(pointer && chrome)) { + // Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener + // See #5180 + addDoubleTapListener(obj, handler, id); -// @function get(id: String|HTMLElement): HTMLElement -// Returns an element given its DOM id, or returns the element itself -// if it was passed directly. -function get(id) { - return typeof id === 'string' ? document.getElementById(id) : id; -} + } else if ('addEventListener' in obj) { -// @function getStyle(el: HTMLElement, styleAttrib: String): String -// Returns the value for a certain style attribute on an element, -// including computed values or values set through CSS. -function getStyle(el, style) { - var value = el.style[style] || (el.currentStyle && el.currentStyle[style]); + if (type === 'mousewheel') { + obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false); - if ((!value || value === 'auto') && document.defaultView) { - var css = document.defaultView.getComputedStyle(el, null); - value = css ? css[style] : null; - } - return value === 'auto' ? null : value; -} + } else if ((type === 'mouseenter') || (type === 'mouseleave')) { + handler = function (e) { + e = e || window.event; + if (isExternalTarget(obj, e)) { + originalHandler(e); + } + }; + obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false); -// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement -// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element. -function create$1(tagName, className, container) { - var el = document.createElement(tagName); - el.className = className || ''; + } else { + if (type === 'click' && android) { + handler = function (e) { + filterClick(e, originalHandler); + }; + } + obj.addEventListener(type, handler, false); + } - if (container) { - container.appendChild(el); + } else if ('attachEvent' in obj) { + obj.attachEvent('on' + type, handler); } - return el; -} -// @function remove(el: HTMLElement) -// Removes `el` from its parent element -function remove(el) { - var parent = el.parentNode; - if (parent) { - parent.removeChild(el); - } + obj[eventsKey] = obj[eventsKey] || {}; + obj[eventsKey][id] = handler; } -// @function empty(el: HTMLElement) -// Removes all of `el`'s children elements from `el` -function empty(el) { - while (el.firstChild) { - el.removeChild(el.firstChild); - } -} +function removeOne(obj, type, fn, context) { -// @function toFront(el: HTMLElement) -// Makes `el` the last child of its parent, so it renders in front of the other children. -function toFront(el) { - var parent = el.parentNode; - if (parent.lastChild !== el) { - parent.appendChild(el); - } -} + var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''), + handler = obj[eventsKey] && obj[eventsKey][id]; -// @function toBack(el: HTMLElement) -// Makes `el` the first child of its parent, so it renders behind the other children. -function toBack(el) { - var parent = el.parentNode; - if (parent.firstChild !== el) { - parent.insertBefore(el, parent.firstChild); - } -} + if (!handler) { return this; } -// @function hasClass(el: HTMLElement, name: String): Boolean -// Returns `true` if the element's class attribute contains `name`. -function hasClass(el, name) { - if (el.classList !== undefined) { - return el.classList.contains(name); - } - var className = getClass(el); - return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); -} + if (pointer && type.indexOf('touch') === 0) { + removePointerListener(obj, type, id); -// @function addClass(el: HTMLElement, name: String) -// Adds `name` to the element's class attribute. -function addClass(el, name) { - if (el.classList !== undefined) { - var classes = splitWords(name); - for (var i = 0, len = classes.length; i < len; i++) { - el.classList.add(classes[i]); + } else if (touch && (type === 'dblclick') && removeDoubleTapListener && + !(pointer && chrome)) { + removeDoubleTapListener(obj, id); + + } else if ('removeEventListener' in obj) { + + if (type === 'mousewheel') { + obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false); + + } else { + obj.removeEventListener( + type === 'mouseenter' ? 'mouseover' : + type === 'mouseleave' ? 'mouseout' : type, handler, false); } - } else if (!hasClass(el, name)) { - var className = getClass(el); - setClass(el, (className ? className + ' ' : '') + name); + + } else if ('detachEvent' in obj) { + obj.detachEvent('on' + type, handler); } + + obj[eventsKey][id] = null; } -// @function removeClass(el: HTMLElement, name: String) -// Removes `name` from the element's class attribute. -function removeClass(el, name) { - if (el.classList !== undefined) { - el.classList.remove(name); +// @function stopPropagation(ev: DOMEvent): this +// Stop the given event from propagation to parent elements. Used inside the listener functions: +// ```js +// L.DomEvent.on(div, 'click', function (ev) { +// L.DomEvent.stopPropagation(ev); +// }); +// ``` +function stopPropagation(e) { + + if (e.stopPropagation) { + e.stopPropagation(); + } else if (e.originalEvent) { // In case of Leaflet event. + e.originalEvent._stopped = true; } else { - setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' '))); + e.cancelBubble = true; } + skipped(e); + + return this; } -// @function setClass(el: HTMLElement, name: String) -// Sets the element's class. -function setClass(el, name) { - if (el.className.baseVal === undefined) { - el.className = name; - } else { - // in case of SVG element - el.className.baseVal = name; - } +// @function disableScrollPropagation(el: HTMLElement): this +// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants). +function disableScrollPropagation(el) { + addOne(el, 'mousewheel', stopPropagation); + return this; } -// @function getClass(el: HTMLElement): String -// Returns the element's class. -function getClass(el) { - return el.className.baseVal === undefined ? el.className : el.className.baseVal; +// @function disableClickPropagation(el: HTMLElement): this +// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`, +// `'mousedown'` and `'touchstart'` events (plus browser variants). +function disableClickPropagation(el) { + on(el, 'mousedown touchstart dblclick', stopPropagation); + addOne(el, 'click', fakeStop); + return this; } -// @function setOpacity(el: HTMLElement, opacity: Number) -// Set the opacity of an element (including old IE support). -// `opacity` must be a number from `0` to `1`. -function setOpacity(el, value) { - if ('opacity' in el.style) { - el.style.opacity = value; - } else if ('filter' in el.style) { - _setOpacityIE(el, value); +// @function preventDefault(ev: DOMEvent): this +// Prevents the default action of the DOM Event `ev` from happening (such as +// following a link in the href of the a element, or doing a POST request +// with page reload when a `` is submitted). +// Use it inside listener functions. +function preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; } + return this; } -function _setOpacityIE(el, value) { - var filter = false, - filterName = 'DXImageTransform.Microsoft.Alpha'; +// @function stop(ev: DOMEvent): this +// Does `stopPropagation` and `preventDefault` at the same time. +function stop(e) { + preventDefault(e); + stopPropagation(e); + return this; +} - // filters collection throws an error if we try to retrieve a filter that doesn't exist - try { - filter = el.filters.item(filterName); - } catch (e) { - // don't set opacity to 1 if we haven't already set an opacity, - // it isn't needed and breaks transparent pngs. - if (value === 1) { return; } +// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point +// Gets normalized mouse position from a DOM event relative to the +// `container` (border excluded) or to the whole page if not specified. +function getMousePosition(e, container) { + if (!container) { + return new Point(e.clientX, e.clientY); } - value = Math.round(value * 100); + var scale = getScale(container), + offset = scale.boundingClientRect; // left and top values are in page scale (like the event clientX/Y) - if (filter) { - filter.Enabled = (value !== 100); - filter.Opacity = value; - } else { - el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; - } + return new Point( + // offset.left/top values are in page scale (like clientX/Y), + // whereas clientLeft/Top (border width) values are the original values (before CSS scale applies). + (e.clientX - offset.left) / scale.x - container.clientLeft, + (e.clientY - offset.top) / scale.y - container.clientTop + ); } -// @function testProp(props: String[]): String|false -// Goes through the array of style names and returns the first name -// that is a valid style name for an element. If no such name is found, -// it returns false. Useful for vendor-prefixed styles like `transform`. -function testProp(props) { - var style = document.documentElement.style; +// Chrome on Win scrolls double the pixels as in other platforms (see #4538), +// and Firefox scrolls device pixels, not CSS pixels +var wheelPxFactor = + (win && chrome) ? 2 * window.devicePixelRatio : + gecko ? window.devicePixelRatio : 1; - for (var i = 0; i < props.length; i++) { - if (props[i] in style) { - return props[i]; - } - } - return false; +// @function getWheelDelta(ev: DOMEvent): Number +// Gets normalized wheel delta from a mousewheel DOM event, in vertical +// pixels scrolled (negative if scrolling down). +// Events from pointing devices without precise scrolling are mapped to +// a best guess of 60 pixels. +function getWheelDelta(e) { + return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta + (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels + (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines + (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages + (e.deltaX || e.deltaZ) ? 0 : // Skip horizontal/depth wheel events + e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels + (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines + e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages + 0; } -// @function setTransform(el: HTMLElement, offset: Point, scale?: Number) -// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels -// and optionally scaled by `scale`. Does not have an effect if the -// browser doesn't support 3D CSS transforms. -function setTransform(el, offset, scale) { - var pos = offset || new Point(0, 0); +var skipEvents = {}; - el.style[TRANSFORM] = - (ie3d ? - 'translate(' + pos.x + 'px,' + pos.y + 'px)' : - 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') + - (scale ? ' scale(' + scale + ')' : ''); +function fakeStop(e) { + // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e) + skipEvents[e.type] = true; } -// @function setPosition(el: HTMLElement, position: Point) -// Sets the position of `el` to coordinates specified by `position`, -// using CSS translate or top/left positioning depending on the browser -// (used by Leaflet internally to position its layers). -function setPosition(el, point) { - - /*eslint-disable */ - el._leaflet_pos = point; - /* eslint-enable */ - - if (any3d) { - setTransform(el, point); - } else { - el.style.left = point.x + 'px'; - el.style.top = point.y + 'px'; - } +function skipped(e) { + var events = skipEvents[e.type]; + // reset when checking, as it's only used in map container and propagates outside of the map + skipEvents[e.type] = false; + return events; } -// @function getPosition(el: HTMLElement): Point -// Returns the coordinates of an element previously positioned with setPosition. -function getPosition(el) { - // this method is only used for elements previously positioned using setPosition, - // so it's safe to cache the position for performance - - return el._leaflet_pos || new Point(0, 0); -} +// check if element really left/entered the event target (for mouseenter/mouseleave) +function isExternalTarget(el, e) { -// @function disableTextSelection() -// Prevents the user from generating `selectstart` DOM events, usually generated -// when the user drags the mouse through a page with text. Used internally -// by Leaflet to override the behaviour of any click-and-drag interaction on -// the map. Affects drag interactions on the whole document. + var related = e.relatedTarget; -// @function enableTextSelection() -// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection). -var disableTextSelection; -var enableTextSelection; -var _userSelect; -if ('onselectstart' in document) { - disableTextSelection = function () { - on(window, 'selectstart', preventDefault); - }; - enableTextSelection = function () { - off(window, 'selectstart', preventDefault); - }; -} else { - var userSelectProperty = testProp( - ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); + if (!related) { return true; } - disableTextSelection = function () { - if (userSelectProperty) { - var style = document.documentElement.style; - _userSelect = style[userSelectProperty]; - style[userSelectProperty] = 'none'; - } - }; - enableTextSelection = function () { - if (userSelectProperty) { - document.documentElement.style[userSelectProperty] = _userSelect; - _userSelect = undefined; + try { + while (related && (related !== el)) { + related = related.parentNode; } - }; + } catch (err) { + return false; + } + return (related !== el); } -// @function disableImageDrag() -// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but -// for `dragstart` DOM events, usually generated when the user drags an image. -function disableImageDrag() { - on(window, 'dragstart', preventDefault); -} +var lastClick; -// @function enableImageDrag() -// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection). -function enableImageDrag() { - off(window, 'dragstart', preventDefault); -} +// this is a horrible workaround for a bug in Android where a single touch triggers two click events +function filterClick(e, handler) { + var timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)), + elapsed = lastClick && (timeStamp - lastClick); -var _outlineElement; -var _outlineStyle; -// @function preventOutline(el: HTMLElement) -// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline) -// of the element `el` invisible. Used internally by Leaflet to prevent -// focusable elements from displaying an outline when the user performs a -// drag interaction on them. -function preventOutline(element) { - while (element.tabIndex === -1) { - element = element.parentNode; + // are they closer together than 500ms yet more than 100ms? + // Android typically triggers them ~300ms apart while multiple listeners + // on the same event should be triggered far faster; + // or check if click is simulated on the element, and if it is, reject any non-simulated events + + if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) { + stop(e); + return; } - if (!element.style) { return; } - restoreOutline(); - _outlineElement = element; - _outlineStyle = element.style.outline; - element.style.outline = 'none'; - on(window, 'keydown', restoreOutline); -} + lastClick = timeStamp; -// @function restoreOutline() -// Cancels the effects of a previous [`L.DomUtil.preventOutline`](). -function restoreOutline() { - if (!_outlineElement) { return; } - _outlineElement.style.outline = _outlineStyle; - _outlineElement = undefined; - _outlineStyle = undefined; - off(window, 'keydown', restoreOutline); + handler(e); } -var DomUtil = (Object.freeze || Object)({ - TRANSFORM: TRANSFORM, - TRANSITION: TRANSITION, - TRANSITION_END: TRANSITION_END, - get: get, - getStyle: getStyle, - create: create$1, - remove: remove, - empty: empty, - toFront: toFront, - toBack: toBack, - hasClass: hasClass, - addClass: addClass, - removeClass: removeClass, - setClass: setClass, - getClass: getClass, - setOpacity: setOpacity, - testProp: testProp, - setTransform: setTransform, - setPosition: setPosition, - getPosition: getPosition, - disableTextSelection: disableTextSelection, - enableTextSelection: enableTextSelection, - disableImageDrag: disableImageDrag, - enableImageDrag: enableImageDrag, - preventOutline: preventOutline, - restoreOutline: restoreOutline + + +var DomEvent = (Object.freeze || Object)({ + on: on, + off: off, + stopPropagation: stopPropagation, + disableScrollPropagation: disableScrollPropagation, + disableClickPropagation: disableClickPropagation, + preventDefault: preventDefault, + stop: stop, + getMousePosition: getMousePosition, + getWheelDelta: getWheelDelta, + fakeStop: fakeStop, + skipped: skipped, + isExternalTarget: isExternalTarget, + addListener: on, + removeListener: off }); /* @@ -3616,7 +3643,7 @@ var Map = Evented.extend({ var lat = pos.coords.latitude, lng = pos.coords.longitude, latlng = new LatLng(lat, lng), - bounds = latlng.toBounds(pos.coords.accuracy), + bounds = latlng.toBounds(pos.coords.accuracy * 2), options = this._locateOptions; if (options.setView) { @@ -3692,6 +3719,10 @@ var Map = Evented.extend({ if (this._clearControlPos) { this._clearControlPos(); } + if (this._resizeRequest) { + cancelAnimFrame(this._resizeRequest); + this._resizeRequest = null; + } this._clearHandlers(); @@ -3776,7 +3807,7 @@ var Map = Evented.extend({ this.options.maxZoom; }, - // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean): Number + // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number // Returns the maximum zoom level on which the given bounds fit to the map // view in its entirety. If `inside` (optional) is set to `true`, the method // instead returns the minimum zoom level on which the map view fits into @@ -5777,10 +5808,14 @@ var Draggable = Evented.extend({ // Fired when a drag is about to start. this.fire('down'); - var first = e.touches ? e.touches[0] : e; + var first = e.touches ? e.touches[0] : e, + sizedParent = getSizedParentNode(this._element); this._startPoint = new Point(first.clientX, first.clientY); + // Cache the scale, so that we can continuously compensate for it during drag (_onMove). + this._parentScale = getScale(sizedParent); + on(document, MOVE[e.type], this._onMove, this); on(document, END[e.type], this._onUp, this); }, @@ -5799,12 +5834,17 @@ var Draggable = Evented.extend({ } var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), - newPoint = new Point(first.clientX, first.clientY), - offset = newPoint.subtract(this._startPoint); + offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint); if (!offset.x && !offset.y) { return; } if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; } + // We assume that the parent container's position, border and scale do not change for the duration of the drag. + // Therefore there is no need to account for the position and border (they are eliminated by the subtraction) + // and we can use the cached value for the scale. + offset.x /= this._parentScale.x; + offset.y /= this._parentScale.y; + preventDefault(e); if (!this._moved) { @@ -7173,7 +7213,7 @@ var MarkerDrag = Handler.extend({ map = marker._map, speed = this._marker.options.autoPanSpeed, padding = this._marker.options.autoPanPadding, - iconPos = L.DomUtil.getPosition(marker._icon), + iconPos = getPosition(marker._icon), bounds = map.getPixelBounds(), origin = map.getPixelOrigin(); @@ -7197,7 +7237,7 @@ var MarkerDrag = Handler.extend({ this._draggable._newPos._add(movement); this._draggable._startPos._add(movement); - L.DomUtil.setPosition(marker._icon, this._draggable._newPos); + setPosition(marker._icon, this._draggable._newPos); this._onDrag(e); this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e)); @@ -7229,7 +7269,7 @@ var MarkerDrag = Handler.extend({ _onDrag: function (e) { var marker = this._marker, shadow = marker._shadow, - iconPos = getPosition(marker._icon), + iconPos = getPosition(marker._icon), latlng = marker._map.layerPointToLatLng(iconPos); // update shadow position @@ -8050,7 +8090,7 @@ var Polyline = Path.extend({ return !this._latlngs.length; }, - // @method closestLayerPoint: Point + // @method closestLayerPoint(p: Point): Point // Returns the point closest to `p` on the Polyline. closestLayerPoint: function (p) { var minDistance = Infinity, @@ -8443,7 +8483,7 @@ var Polygon = Polyline.extend({ var inside = false, part, p1, p2, i, j, k, len, len2; - if (!this._pxBounds.contains(p)) { return false; } + if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; } // ray casting algorithm for detecting if point is in polygon for (i = 0, len = this._parts.length; i < len; i++) { @@ -8870,7 +8910,7 @@ LayerGroup.include({ // @namespace GeoJSON // @factory L.geoJSON(geojson?: Object, options?: GeoJSON options) // Creates a GeoJSON layer. Optionally accepts an object in -// [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map +// [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map // (you can alternatively add it later with `addData` method) and an `options` object. function geoJSON(geojson, options) { return new GeoJSON(geojson, options); @@ -8912,8 +8952,10 @@ var ImageOverlay = Layer.extend({ // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered. interactive: false, - // @option crossOrigin: Boolean = false - // If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data. + // @option crossOrigin: Boolean|String = false + // Whether the crossOrigin attribute will be added to the image. + // If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image 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 errorOverlayUrl: String = '' @@ -9069,8 +9111,8 @@ var ImageOverlay = Layer.extend({ img.onload = bind(this.fire, this, 'load'); img.onerror = bind(this._overlayOnError, this, 'error'); - if (this.options.crossOrigin) { - img.crossOrigin = ''; + if (this.options.crossOrigin || this.options.crossOrigin === '') { + img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin; } if (this.options.zIndex) { @@ -9151,7 +9193,7 @@ var imageOverlay = function (url, bounds, options) { * ```js * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm', * videoBounds = [[ 32, -130], [ 13, -100]]; - * L.VideoOverlay(videoUrl, videoBounds ).addTo(map); + * L.videoOverlay(videoUrl, videoBounds ).addTo(map); * ``` */ @@ -11252,7 +11294,7 @@ var GridLayer = Layer.extend({ }, _tileReady: function (coords, err, tile) { - if (!this._map) { return; } + if (!this._map || tile.getAttribute('src') === emptyImageUrl) { return; } if (err) { // @event tileerror: TileErrorEvent @@ -11348,7 +11390,7 @@ function gridLayer(options) { * @example * * ```js - * L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map); + * L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map); * ``` * * @section URL template @@ -11407,8 +11449,10 @@ var TileLayer = GridLayer.extend({ // 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 = false - // If true, all tiles will have their crossOrigin attribute set to ''. This is needed if you want to access tile pixel data. + // @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 }, @@ -11465,8 +11509,8 @@ var TileLayer = GridLayer.extend({ on(tile, 'load', bind(this._tileOnLoad, this, done, tile)); on(tile, 'error', bind(this._tileOnError, this, done, tile)); - if (this.options.crossOrigin) { - tile.crossOrigin = ''; + if (this.options.crossOrigin || this.options.crossOrigin === '') { + tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin; } /* @@ -11683,7 +11727,7 @@ var TileLayerWMS = TileLayer.extend({ bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ? [min.y, min.x, max.y, max.x] : [min.x, min.y, max.x, max.y]).join(','), - url = L.TileLayer.prototype.getTileUrl.call(this, coords); + url = TileLayer.prototype.getTileUrl.call(this, coords); return url + getParamString(this.wmsParams, url, this.options.uppercase) + (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox; @@ -11909,6 +11953,7 @@ var Canvas = Renderer.extend({ }, _destroyContainer: function () { + cancelAnimFrame(this._redrawRequest); delete this._ctx; remove(this._container); off(this._container); @@ -12001,9 +12046,11 @@ var Canvas = Renderer.extend({ this._drawFirst = next; } + delete this._drawnLayers[layer._leaflet_id]; + delete layer._order; - delete this._layers[L.stamp(layer)]; + delete this._layers[stamp(layer)]; this._requestRedraw(layer); }, @@ -12025,7 +12072,7 @@ var Canvas = Renderer.extend({ }, _updateDashArray: function (layer) { - if (layer.options.dashArray) { + if (typeof layer.options.dashArray === 'string') { var parts = layer.options.dashArray.split(','), dashArray = [], i; @@ -12033,6 +12080,8 @@ var Canvas = Renderer.extend({ dashArray.push(Number(parts[i])); } layer.options._dashArray = dashArray; + } else { + layer.options._dashArray = layer.options.dashArray; } }, @@ -12669,10 +12718,7 @@ Map.include({ var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer; if (!renderer) { - // @namespace Map; @option preferCanvas: Boolean = false - // Whether `Path`s should be rendered on a `Canvas` renderer. - // By default, all `Path`s are rendered in a `SVG` renderer. - renderer = this._renderer = (this.options.preferCanvas && canvas$1()) || svg$1(); + renderer = this._renderer = this._createRenderer(); } if (!this.hasLayer(renderer)) { @@ -12688,10 +12734,17 @@ Map.include({ var renderer = this._paneRenderers[name]; if (renderer === undefined) { - renderer = (SVG && svg$1({pane: name})) || (Canvas && canvas$1({pane: name})); + renderer = this._createRenderer({pane: name}); this._paneRenderers[name] = renderer; } return renderer; + }, + + _createRenderer: function (options) { + // @namespace Map; @option preferCanvas: Boolean = false + // Whether `Path`s should be rendered on a `Canvas` renderer. + // By default, all `Path`s are rendered in a `SVG` renderer. + return (this.options.preferCanvas && canvas$1(options)) || svg$1(options); } }); @@ -13326,20 +13379,18 @@ var Keyboard = Handler.extend({ offset; if (key in this._panKeys) { + if (!map._panAnim || !map._panAnim._inProgress) { + offset = this._panKeys[key]; + if (e.shiftKey) { + offset = toPoint(offset).multiplyBy(3); + } - if (map._panAnim && map._panAnim._inProgress) { return; } - - offset = this._panKeys[key]; - if (e.shiftKey) { - offset = toPoint(offset).multiplyBy(3); - } - - map.panBy(offset); + map.panBy(offset); - if (map.options.maxBounds) { - map.panInsideBounds(map.options.maxBounds); + if (map.options.maxBounds) { + map.panInsideBounds(map.options.maxBounds); + } } - } else if (key in this._zoomKeys) { map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]); @@ -13707,21 +13758,9 @@ Map.ScrollWheelZoom = ScrollWheelZoom; Map.Tap = Tap; Map.TouchZoom = TouchZoom; -// misc - -var oldL = window.L; -function noConflict() { - window.L = oldL; - return this; -} - -// Always export us to window global (see #2364) -window.L = exports; - Object.freeze = freeze; exports.version = version; -exports.noConflict = noConflict; exports.Control = Control; exports.control = control; exports.Browser = Browser; @@ -13798,5 +13837,14 @@ exports.rectangle = rectangle; exports.Map = Map; exports.map = createMap; +var oldL = window.L; +exports.noConflict = function() { + window.L = oldL; + return this; +} + +// Always export us to window global (see #2364) +window.L = exports; + }))); //# sourceMappingURL=leaflet-src.js.map -- 2.39.5