|
- import { IE11OrLess } from './BrowserInfo.js';
- import Sortable from './Sortable.js';
-
- const captureMode = {
- capture: false,
- passive: false
- };
-
- function on(el, event, fn) {
- el.addEventListener(event, fn, !IE11OrLess && captureMode);
- }
-
-
- function off(el, event, fn) {
- el.removeEventListener(event, fn, !IE11OrLess && captureMode);
- }
-
- function matches(/**HTMLElement*/el, /**String*/selector) {
- if (!selector) return;
-
- selector[0] === '>' && (selector = selector.substring(1));
-
- if (el) {
- try {
- if (el.matches) {
- return el.matches(selector);
- } else if (el.msMatchesSelector) {
- return el.msMatchesSelector(selector);
- } else if (el.webkitMatchesSelector) {
- return el.webkitMatchesSelector(selector);
- }
- } catch(_) {
- return false;
- }
- }
-
- return false;
- }
-
- function getParentOrHost(el) {
- return (el.host && el !== document && el.host.nodeType)
- ? el.host
- : el.parentNode;
- }
-
- function closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {
- if (el) {
- ctx = ctx || document;
-
- do {
- if (
- selector != null &&
- (
- selector[0] === '>' ?
- el.parentNode === ctx && matches(el, selector) :
- matches(el, selector)
- ) ||
- includeCTX && el === ctx
- ) {
- return el;
- }
-
- if (el === ctx) break;
- /* jshint boss:true */
- } while (el = getParentOrHost(el));
- }
-
- return null;
- }
-
- const R_SPACE = /\s+/g;
-
- function toggleClass(el, name, state) {
- if (el && name) {
- if (el.classList) {
- el.classList[state ? 'add' : 'remove'](name);
- }
- else {
- let className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
- el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
- }
- }
- }
-
-
- function css(el, prop, val) {
- let style = el && el.style;
-
- if (style) {
- if (val === void 0) {
- if (document.defaultView && document.defaultView.getComputedStyle) {
- val = document.defaultView.getComputedStyle(el, '');
- }
- else if (el.currentStyle) {
- val = el.currentStyle;
- }
-
- return prop === void 0 ? val : val[prop];
- }
- else {
- if (!(prop in style) && prop.indexOf('webkit') === -1) {
- prop = '-webkit-' + prop;
- }
-
- style[prop] = val + (typeof val === 'string' ? '' : 'px');
- }
- }
- }
-
- function matrix(el, selfOnly) {
- let appliedTransforms = '';
- if (typeof(el) === 'string') {
- appliedTransforms = el;
- } else {
- do {
- let transform = css(el, 'transform');
-
- if (transform && transform !== 'none') {
- appliedTransforms = transform + ' ' + appliedTransforms;
- }
- /* jshint boss:true */
- } while (!selfOnly && (el = el.parentNode));
- }
-
- const matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
- /*jshint -W056 */
- return matrixFn && (new matrixFn(appliedTransforms));
- }
-
-
- function find(ctx, tagName, iterator) {
- if (ctx) {
- let list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
-
- if (iterator) {
- for (; i < n; i++) {
- iterator(list[i], i);
- }
- }
-
- return list;
- }
-
- return [];
- }
-
-
-
- function getWindowScrollingElement() {
- let scrollingElement = document.scrollingElement;
-
- if (scrollingElement) {
- return scrollingElement
- } else {
- return document.documentElement
- }
- }
-
-
- /**
- * Returns the "bounding client rect" of given element
- * @param {HTMLElement} el The element whose boundingClientRect is wanted
- * @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container
- * @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr
- * @param {[Boolean]} undoScale Whether the container's scale() should be undone
- * @param {[HTMLElement]} container The parent the element will be placed in
- * @return {Object} The boundingClientRect of el, with specified adjustments
- */
- function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
- if (!el.getBoundingClientRect && el !== window) return;
-
- let elRect,
- top,
- left,
- bottom,
- right,
- height,
- width;
-
- if (el !== window && el !== getWindowScrollingElement()) {
- elRect = el.getBoundingClientRect();
- top = elRect.top;
- left = elRect.left;
- bottom = elRect.bottom;
- right = elRect.right;
- height = elRect.height;
- width = elRect.width;
- } else {
- top = 0;
- left = 0;
- bottom = window.innerHeight;
- right = window.innerWidth;
- height = window.innerHeight;
- width = window.innerWidth;
- }
-
- if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
- // Adjust for translate()
- container = container || el.parentNode;
-
- // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
- // Not needed on <= IE11
- if (!IE11OrLess) {
- do {
- if (
- container &&
- container.getBoundingClientRect &&
- (
- css(container, 'transform') !== 'none' ||
- relativeToNonStaticParent &&
- css(container, 'position') !== 'static'
- )
- ) {
- let containerRect = container.getBoundingClientRect();
-
- // Set relative to edges of padding box of container
- top -= containerRect.top + parseInt(css(container, 'border-top-width'));
- left -= containerRect.left + parseInt(css(container, 'border-left-width'));
- bottom = top + elRect.height;
- right = left + elRect.width;
-
- break;
- }
- /* jshint boss:true */
- } while (container = container.parentNode);
- }
- }
-
- if (undoScale && el !== window) {
- // Adjust for scale()
- let elMatrix = matrix(container || el),
- scaleX = elMatrix && elMatrix.a,
- scaleY = elMatrix && elMatrix.d;
-
- if (elMatrix) {
- top /= scaleY;
- left /= scaleX;
-
- width /= scaleX;
- height /= scaleY;
-
- bottom = top + height;
- right = left + width;
- }
- }
-
- return {
- top: top,
- left: left,
- bottom: bottom,
- right: right,
- width: width,
- height: height
- };
- }
-
- /**
- * Checks if a side of an element is scrolled past a side of its parents
- * @param {HTMLElement} el The element who's side being scrolled out of view is in question
- * @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom')
- * @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom')
- * @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element
- */
- function isScrolledPast(el, elSide, parentSide) {
- let parent = getParentAutoScrollElement(el, true),
- elSideVal = getRect(el)[elSide];
-
- /* jshint boss:true */
- while (parent) {
- let parentSideVal = getRect(parent)[parentSide],
- visible;
-
- if (parentSide === 'top' || parentSide === 'left') {
- visible = elSideVal >= parentSideVal;
- } else {
- visible = elSideVal <= parentSideVal;
- }
-
- if (!visible) return parent;
-
- if (parent === getWindowScrollingElement()) break;
-
- parent = getParentAutoScrollElement(parent, false);
- }
-
- return false;
- }
-
-
-
- /**
- * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
- * and non-draggable elements
- * @param {HTMLElement} el The parent element
- * @param {Number} childNum The index of the child
- * @param {Object} options Parent Sortable's options
- * @return {HTMLElement} The child at index childNum, or null if not found
- */
- function getChild(el, childNum, options) {
- let currentChild = 0,
- i = 0,
- children = el.children;
-
- while (i < children.length) {
- if (
- children[i].style.display !== 'none' &&
- children[i] !== Sortable.ghost &&
- children[i] !== Sortable.dragged &&
- closest(children[i], options.draggable, el, false)
- ) {
- if (currentChild === childNum) {
- return children[i];
- }
- currentChild++;
- }
-
- i++;
- }
- return null;
- }
-
- /**
- * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
- * @param {HTMLElement} el Parent element
- * @param {selector} selector Any other elements that should be ignored
- * @return {HTMLElement} The last child, ignoring ghostEl
- */
- function lastChild(el, selector) {
- let last = el.lastElementChild;
-
- while (
- last &&
- (
- last === Sortable.ghost ||
- css(last, 'display') === 'none' ||
- selector && !matches(last, selector)
- )
- ) {
- last = last.previousElementSibling;
- }
-
- return last || null;
- }
-
-
- /**
- * Returns the index of an element within its parent for a selected set of
- * elements
- * @param {HTMLElement} el
- * @param {selector} selector
- * @return {number}
- */
- function index(el, selector) {
- let index = 0;
-
- if (!el || !el.parentNode) {
- return -1;
- }
-
- /* jshint boss:true */
- while (el = el.previousElementSibling) {
- if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && el !== Sortable.clone && (!selector || matches(el, selector))) {
- index++;
- }
- }
-
- return index;
- }
-
- /**
- * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
- * The value is returned in real pixels.
- * @param {HTMLElement} el
- * @return {Array} Offsets in the format of [left, top]
- */
- function getRelativeScrollOffset(el) {
- let offsetLeft = 0,
- offsetTop = 0,
- winScroller = getWindowScrollingElement();
-
- if (el) {
- do {
- let elMatrix = matrix(el),
- scaleX = elMatrix.a,
- scaleY = elMatrix.d;
-
- offsetLeft += el.scrollLeft * scaleX;
- offsetTop += el.scrollTop * scaleY;
- } while (el !== winScroller && (el = el.parentNode));
- }
-
- return [offsetLeft, offsetTop];
- }
-
- /**
- * Returns the index of the object within the given array
- * @param {Array} arr Array that may or may not hold the object
- * @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
- * @return {Number} The index of the object in the array, or -1
- */
- function indexOfObject(arr, obj) {
- for (let i in arr) {
- if (!arr.hasOwnProperty(i)) continue;
- for (let key in obj) {
- if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
- }
- }
- return -1;
- }
-
-
- function getParentAutoScrollElement(el, includeSelf) {
- // skip to window
- if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
-
- let elem = el;
- let gotSelf = false;
- do {
- // we don't need to get elem css if it isn't even overflowing in the first place (performance)
- if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
- let elemCSS = css(elem);
- if (
- elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') ||
- elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')
- ) {
- if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
-
- if (gotSelf || includeSelf) return elem;
- gotSelf = true;
- }
- }
- /* jshint boss:true */
- } while (elem = elem.parentNode);
-
- return getWindowScrollingElement();
- }
-
- function extend(dst, src) {
- if (dst && src) {
- for (let key in src) {
- if (src.hasOwnProperty(key)) {
- dst[key] = src[key];
- }
- }
- }
-
- return dst;
- }
-
-
- function isRectEqual(rect1, rect2) {
- return Math.round(rect1.top) === Math.round(rect2.top) &&
- Math.round(rect1.left) === Math.round(rect2.left) &&
- Math.round(rect1.height) === Math.round(rect2.height) &&
- Math.round(rect1.width) === Math.round(rect2.width);
- }
-
-
- let _throttleTimeout;
- function throttle(callback, ms) {
- return function () {
- if (!_throttleTimeout) {
- let args = arguments,
- _this = this;
-
- if (args.length === 1) {
- callback.call(_this, args[0]);
- } else {
- callback.apply(_this, args);
- }
-
- _throttleTimeout = setTimeout(function () {
- _throttleTimeout = void 0;
- }, ms);
- }
- };
- }
-
-
- function cancelThrottle() {
- clearTimeout(_throttleTimeout);
- _throttleTimeout = void 0;
- }
-
-
- function scrollBy(el, x, y) {
- el.scrollLeft += x;
- el.scrollTop += y;
- }
-
-
- function clone(el) {
- let Polymer = window.Polymer;
- let $ = window.jQuery || window.Zepto;
-
- if (Polymer && Polymer.dom) {
- return Polymer.dom(el).cloneNode(true);
- }
- else if ($) {
- return $(el).clone(true)[0];
- }
- else {
- return el.cloneNode(true);
- }
- }
-
-
- function setRect(el, rect) {
- css(el, 'position', 'absolute');
- css(el, 'top', rect.top);
- css(el, 'left', rect.left);
- css(el, 'width', rect.width);
- css(el, 'height', rect.height);
- }
-
- function unsetRect(el) {
- css(el, 'position', '');
- css(el, 'top', '');
- css(el, 'left', '');
- css(el, 'width', '');
- css(el, 'height', '');
- }
-
-
- const expando = 'Sortable' + (new Date).getTime();
-
-
- export {
- on,
- off,
- matches,
- getParentOrHost,
- closest,
- toggleClass,
- css,
- matrix,
- find,
- getWindowScrollingElement,
- getRect,
- isScrolledPast,
- getChild,
- lastChild,
- index,
- getRelativeScrollOffset,
- indexOfObject,
- getParentAutoScrollElement,
- extend,
- isRectEqual,
- throttle,
- cancelThrottle,
- scrollBy,
- clone,
- setRect,
- unsetRect,
- expando
- };
|