UNPKG

leaflet

Version:

JavaScript library for mobile-friendly interactive maps

321 lines (269 loc) 11.1 kB
/* * @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. */ L.DomUtil = { // @function get(id: String|HTMLElement): HTMLElement // Returns an element given its DOM id, or returns the element itself // if it was passed directly. get: function (id) { return typeof id === 'string' ? document.getElementById(id) : id; }, // @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. getStyle: function (el, style) { var value = el.style[style] || (el.currentStyle && el.currentStyle[style]); if ((!value || value === 'auto') && document.defaultView) { var css = document.defaultView.getComputedStyle(el, null); value = css ? css[style] : null; } return value === 'auto' ? null : value; }, // @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. create: function (tagName, className, container) { var el = document.createElement(tagName); el.className = className || ''; if (container) { container.appendChild(el); } return el; }, // @function remove(el: HTMLElement) // Removes `el` from its parent element remove: function (el) { var parent = el.parentNode; if (parent) { parent.removeChild(el); } }, // @function empty(el: HTMLElement) // Removes all of `el`'s children elements from `el` empty: function (el) { while (el.firstChild) { el.removeChild(el.firstChild); } }, // @function toFront(el: HTMLElement) // Makes `el` the last children of its parent, so it renders in front of the other children. toFront: function (el) { el.parentNode.appendChild(el); }, // @function toBack(el: HTMLElement) // Makes `el` the first children of its parent, so it renders back from the other children. toBack: function (el) { var parent = el.parentNode; parent.insertBefore(el, parent.firstChild); }, // @function hasClass(el: HTMLElement, name: String): Boolean // Returns `true` if the element's class attribute contains `name`. hasClass: function (el, name) { if (el.classList !== undefined) { return el.classList.contains(name); } var className = L.DomUtil.getClass(el); return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); }, // @function addClass(el: HTMLElement, name: String) // Adds `name` to the element's class attribute. addClass: function (el, name) { if (el.classList !== undefined) { var classes = L.Util.splitWords(name); for (var i = 0, len = classes.length; i < len; i++) { el.classList.add(classes[i]); } } else if (!L.DomUtil.hasClass(el, name)) { var className = L.DomUtil.getClass(el); L.DomUtil.setClass(el, (className ? className + ' ' : '') + name); } }, // @function removeClass(el: HTMLElement, name: String) // Removes `name` from the element's class attribute. removeClass: function (el, name) { if (el.classList !== undefined) { el.classList.remove(name); } else { L.DomUtil.setClass(el, L.Util.trim((' ' + L.DomUtil.getClass(el) + ' ').replace(' ' + name + ' ', ' '))); } }, // @function setClass(el: HTMLElement, name: String) // Sets the element's class. setClass: function (el, name) { if (el.className.baseVal === undefined) { el.className = name; } else { // in case of SVG element el.className.baseVal = name; } }, // @function getClass(el: HTMLElement): String // Returns the element's class. getClass: function (el) { return el.className.baseVal === undefined ? el.className : el.className.baseVal; }, // @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`. setOpacity: function (el, value) { if ('opacity' in el.style) { el.style.opacity = value; } else if ('filter' in el.style) { L.DomUtil._setOpacityIE(el, value); } }, _setOpacityIE: function (el, value) { var filter = false, filterName = 'DXImageTransform.Microsoft.Alpha'; // 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; } } value = Math.round(value * 100); if (filter) { filter.Enabled = (value !== 100); filter.Opacity = value; } else { el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; } }, // @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`. testProp: function (props) { var style = document.documentElement.style; for (var i = 0; i < props.length; i++) { if (props[i] in style) { return props[i]; } } return false; }, // @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. setTransform: function (el, offset, scale) { var pos = offset || new L.Point(0, 0); el.style[L.DomUtil.TRANSFORM] = (L.Browser.ie3d ? 'translate(' + pos.x + 'px,' + pos.y + 'px)' : 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') + (scale ? ' scale(' + scale + ')' : ''); }, // @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). setPosition: function (el, point) { // (HTMLElement, Point[, Boolean]) /*eslint-disable */ el._leaflet_pos = point; /*eslint-enable */ if (L.Browser.any3d) { L.DomUtil.setTransform(el, point); } else { el.style.left = point.x + 'px'; el.style.top = point.y + 'px'; } }, // @function getPosition(el: HTMLElement): Point // Returns the coordinates of an element previously positioned with setPosition. getPosition: function (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 L.Point(0, 0); } }; (function () { // prefix style property names // @property TRANSFORM: String // Vendor-prefixed fransform style name (e.g. `'webkitTransform'` for WebKit). L.DomUtil.TRANSFORM = L.DomUtil.testProp( ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); // 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 // @property TRANSITION: String // Vendor-prefixed transform style name. var transition = L.DomUtil.TRANSITION = L.DomUtil.testProp( ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); L.DomUtil.TRANSITION_END = transition === 'webkitTransition' || transition === 'OTransition' ? transition + 'End' : 'transitionend'; // @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. // @function enableTextSelection() // Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection). if ('onselectstart' in document) { L.DomUtil.disableTextSelection = function () { L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault); }; L.DomUtil.enableTextSelection = function () { L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault); }; } else { var userSelectProperty = L.DomUtil.testProp( ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); L.DomUtil.disableTextSelection = function () { if (userSelectProperty) { var style = document.documentElement.style; this._userSelect = style[userSelectProperty]; style[userSelectProperty] = 'none'; } }; L.DomUtil.enableTextSelection = function () { if (userSelectProperty) { document.documentElement.style[userSelectProperty] = this._userSelect; delete this._userSelect; } }; } // @function disableImageDrag() // As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but // for `dragstart` DOM events, usually generated when the user drags an image. L.DomUtil.disableImageDrag = function () { L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault); }; // @function enableImageDrag() // Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection). L.DomUtil.enableImageDrag = function () { L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault); }; // @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. L.DomUtil.preventOutline = function (element) { while (element.tabIndex === -1) { element = element.parentNode; } if (!element || !element.style) { return; } L.DomUtil.restoreOutline(); this._outlineElement = element; this._outlineStyle = element.style.outline; element.style.outline = 'none'; L.DomEvent.on(window, 'keydown', L.DomUtil.restoreOutline, this); }; // @function restoreOutline() // Cancels the effects of a previous [`L.DomUtil.preventOutline`](). L.DomUtil.restoreOutline = function () { if (!this._outlineElement) { return; } this._outlineElement.style.outline = this._outlineStyle; delete this._outlineElement; delete this._outlineStyle; L.DomEvent.off(window, 'keydown', L.DomUtil.restoreOutline, this); }; })();