From ef63dfd70a75a3470dab6d865fa3f54719876928 Mon Sep 17 00:00:00 2001 From: owen-m1 Date: Sat, 1 Jun 2019 10:54:21 -0400 Subject: [PATCH] Next version (#1524) --- .gitignore | 1 - .jshintrc | 3 +- README.md | 142 +- Sortable.js | 6053 ++++++++++++++++++------------ Sortable.min.js | 3 +- babel.config.js | 27 + build/banner.js | 8 + build/build.js | 17 + build/esm-build.js | 28 + build/minify.js | 11 + build/umd-build.js | 15 + entry/entry-complete.js | 8 + entry/entry-core.js | 19 + entry/entry-defaults.js | 19 + gulpfile.js | 45 - modular/sortable.complete.esm.js | 3601 ++++++++++++++++++ modular/sortable.core.esm.js | 3598 ++++++++++++++++++ modular/sortable.esm.js | 3599 ++++++++++++++++++ package-lock.json | 2311 ++++++++++++ package.json | 33 +- plugins/AutoScroll/AutoScroll.js | 266 ++ plugins/AutoScroll/README.md | 69 + plugins/AutoScroll/index.js | 1 + plugins/MultiDrag/MultiDrag.js | 590 +++ plugins/MultiDrag/README.md | 75 + plugins/MultiDrag/index.js | 1 + plugins/OnSpill/OnSpill.js | 71 + plugins/OnSpill/README.md | 41 + plugins/OnSpill/index.js | 1 + plugins/README.md | 176 + plugins/Swap/README.md | 44 + plugins/Swap/Swap.js | 89 + plugins/Swap/index.js | 1 + src/Animation.js | 198 + src/BrowserInfo.js | 17 + src/EventDispatcher.js | 55 + src/PluginManager.js | 81 + src/Sortable.js | 1900 ++++++++++ src/utils.js | 550 +++ 39 files changed, 21184 insertions(+), 2583 deletions(-) create mode 100644 babel.config.js create mode 100644 build/banner.js create mode 100644 build/build.js create mode 100644 build/esm-build.js create mode 100644 build/minify.js create mode 100644 build/umd-build.js create mode 100644 entry/entry-complete.js create mode 100644 entry/entry-core.js create mode 100644 entry/entry-defaults.js delete mode 100644 gulpfile.js create mode 100644 modular/sortable.complete.esm.js create mode 100644 modular/sortable.core.esm.js create mode 100644 modular/sortable.esm.js create mode 100644 package-lock.json create mode 100644 plugins/AutoScroll/AutoScroll.js create mode 100644 plugins/AutoScroll/README.md create mode 100644 plugins/AutoScroll/index.js create mode 100644 plugins/MultiDrag/MultiDrag.js create mode 100644 plugins/MultiDrag/README.md create mode 100644 plugins/MultiDrag/index.js create mode 100644 plugins/OnSpill/OnSpill.js create mode 100644 plugins/OnSpill/README.md create mode 100644 plugins/OnSpill/index.js create mode 100644 plugins/README.md create mode 100644 plugins/Swap/README.md create mode 100644 plugins/Swap/Swap.js create mode 100644 plugins/Swap/index.js create mode 100644 src/Animation.js create mode 100644 src/BrowserInfo.js create mode 100644 src/EventDispatcher.js create mode 100644 src/PluginManager.js create mode 100644 src/Sortable.js create mode 100644 src/utils.js diff --git a/.gitignore b/.gitignore index f9f1ef482..bb83eae77 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ mock.png .build* jquery.fn.* .idea/ -package-lock.json diff --git a/.jshintrc b/.jshintrc index 3f67a098b..ffbcc18f9 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,10 +1,11 @@ { - "strict": true, + "strict": false, "newcap": false, "node": true, "expr": true, "supernew": true, "laxbreak": true, + "esversion": 9, "white": true, "globals": { "define": true, diff --git a/README.md b/README.md index 8aedcee6c..225a15328 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Sortable +# Sortable   [![DeepScan grade](https://deepscan.io/api/teams/3901/projects/5666/branches/43977/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=3901&pid=5666&bid=43977) [![](https://data.jsdelivr.com/v1/package/npm/sortablejs/badge)](https://www.jsdelivr.com/package/npm/sortablejs) [![npm](https://img.shields.io/npm/v/sortablejs.svg)](https://www.npmjs.com/package/sortablejs) + Sortable is a JavaScript library for reorderable drag-and-drop lists. Demo: http://sortablejs.github.io/Sortable/ @@ -13,6 +14,8 @@ Supported by [ * @author owenm * @license MIT */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.Sortable = factory()); +}(this, function () { 'use strict'; + + function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } + + return _typeof(obj); + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); + } + + function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; + } + + function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; + } + + function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + + var target = _objectWithoutPropertiesLoose(source, excluded); + + var key, i; + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + + return target; + } + + function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); + } + + function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } + } + + function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); + } + + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance"); + } + + var version = "1.9.0"; + + function userAgent(pattern) { + return !!navigator.userAgent.match(pattern); + } + + var IE11OrLess = + /*@__PURE__*/ + userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile)/i); + var Edge = + /*@__PURE__*/ + userAgent(/Edge/i); + var FireFox = + /*@__PURE__*/ + userAgent(/firefox/i); + var Safari = + /*@__PURE__*/ + userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); + var IOS = + /*@__PURE__*/ + userAgent(/iP(ad|od|hone)/i); + + var 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; + } + + var R_SPACE = /\s+/g; + + function toggleClass(el, name, state) { + if (el && name) { + if (el.classList) { + el.classList[state ? 'add' : 'remove'](name); + } else { + var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); + el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); + } + } + } + + function css(el, prop, val) { + var 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) { + var appliedTransforms = ''; + + do { + var transform = css(el, 'transform'); + + if (transform && transform !== 'none') { + appliedTransforms = transform + ' ' + appliedTransforms; + } + /* jshint boss:true */ + + } while (!selfOnly && (el = el.parentNode)); + + var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix; + /*jshint -W056 */ + + return matrixFn && new matrixFn(appliedTransforms); + } + + function find(ctx, tagName, iterator) { + if (ctx) { + var list = ctx.getElementsByTagName(tagName), + i = 0, + n = list.length; + + if (iterator) { + for (; i < n; i++) { + iterator(list[i], i); + } + } + + return list; + } + + return []; + } + + function getWindowScrollingElement() { + if (IE11OrLess) { + return document.documentElement; + } else { + return document.scrollingElement; + } + } + /** + * 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; + var 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')) { + var 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() + var 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 {[DOMRect]} rect Optional rect of `el` to use + * @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, rect, elSide, parentSide) { + var parent = getParentAutoScrollElement(el, true), + elSideVal = (rect ? rect : getRect(el))[elSide]; + /* jshint boss:true */ + + while (parent) { + var parentSideVal = getRect(parent)[parentSide], + visible = void 0; + + 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) { + var currentChild = 0, + i = 0, + children = el.children; + + while (i < children.length) { + if (children[i].style.display !== 'none' && children[i] !== Sortable$1.ghost && children[i] !== Sortable$1.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) { + var last = el.lastElementChild; + + while (last && (last === Sortable$1.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) { + var index = 0; + + if (!el || !el.parentNode) { + return -1; + } + /* jshint boss:true */ + + + while (el = el.previousElementSibling) { + if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable$1.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) { + var offsetLeft = 0, + offsetTop = 0, + winScroller = getWindowScrollingElement(); + + if (el) { + do { + var 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 (var i in arr) { + for (var key in obj) { + if (obj[key] === arr[i][key]) return Number(i); + } + } + + return -1; + } + + function getParentAutoScrollElement(el, includeSelf) { + // skip to window + if (!el || !el.getBoundingClientRect) return getWindowScrollingElement(); + var elem = el; + var 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) { + var 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 (var 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); + } + + var _throttleTimeout; + + function throttle(callback, ms) { + return function () { + if (!_throttleTimeout) { + var 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) { + var Polymer = window.Polymer; + var $ = 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', ''); + } + + var expando = 'Sortable' + new Date().getTime(); + + function AnimationStateManager() { + var animationStates = [], + animationCallbackId; + return { + captureAnimationState: function captureAnimationState() { + animationStates = []; + if (!this.options.animation) return; + var children = [].slice.call(this.el.children); + + for (var i in children) { + if (css(children[i], 'display') === 'none' || children[i] === Sortable$1.ghost) continue; + animationStates.push({ + target: children[i], + rect: getRect(children[i]) + }); + var fromRect = getRect(children[i]); // If animating: compensate for current animation + + if (children[i].thisAnimationDuration) { + var childMatrix = matrix(children[i], true); + + if (childMatrix) { + fromRect.top -= childMatrix.f; + fromRect.left -= childMatrix.e; + } + } + + children[i].fromRect = fromRect; + } + }, + addAnimationState: function addAnimationState(state) { + animationStates.push(state); + }, + removeAnimationState: function removeAnimationState(target) { + animationStates.splice(indexOfObject(animationStates, { + target: target + }), 1); + }, + animateAll: function animateAll(callback) { + if (!this.options.animation) { + clearTimeout(animationCallbackId); + if (typeof callback === 'function') callback(); + return; + } + + var animating = false, + animationTime = 0; + + for (var i in animationStates) { + var time = 0, + target = animationStates[i].target, + fromRect = target.fromRect, + toRect = getRect(target), + prevFromRect = target.prevFromRect, + prevToRect = target.prevToRect, + animatingRect = animationStates[i].rect, + targetMatrix = matrix(target, true); + + if (targetMatrix) { + // Compensate for current animation + toRect.top -= targetMatrix.f; + toRect.left -= targetMatrix.e; + } + + target.toRect = toRect; // If element is scrolled out of view: Do not animate + + if ((isScrolledPast(target, toRect, 'bottom', 'top') || isScrolledPast(target, toRect, 'top', 'bottom') || isScrolledPast(target, toRect, 'right', 'left') || isScrolledPast(target, toRect, 'left', 'right')) && (isScrolledPast(target, animatingRect, 'bottom', 'top') || isScrolledPast(target, animatingRect, 'top', 'bottom') || isScrolledPast(target, animatingRect, 'right', 'left') || isScrolledPast(target, animatingRect, 'left', 'right')) && (isScrolledPast(target, fromRect, 'bottom', 'top') || isScrolledPast(target, fromRect, 'top', 'bottom') || isScrolledPast(target, fromRect, 'right', 'left') || isScrolledPast(target, fromRect, 'left', 'right'))) continue; + + if (target.thisAnimationDuration) { + // Could also check if animatingRect is between fromRect and toRect + if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect + (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) { + // If returning to same place as started from animation and on same axis + time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options); + } + } // if fromRect != toRect: animate + + + if (!isRectEqual(toRect, fromRect)) { + target.prevFromRect = fromRect; + target.prevToRect = toRect; + + if (!time) { + time = this.options.animation; + } + + this.animate(target, animatingRect, time); + } + + if (time) { + animating = true; + animationTime = Math.max(animationTime, time); + clearTimeout(target.animationResetTimer); + target.animationResetTimer = setTimeout(function () { + this.animationStates[this.i].target.animationTime = 0; + this.animationStates[this.i].target.prevFromRect = null; + this.animationStates[this.i].target.fromRect = null; + this.animationStates[this.i].target.prevToRect = null; + this.animationStates[this.i].target.thisAnimationDuration = null; + }.bind({ + animationStates: animationStates, + i: Number(i) + }), time); + target.thisAnimationDuration = time; + } + } + + clearTimeout(animationCallbackId); + + if (!animating) { + if (typeof callback === 'function') callback(); + } else { + animationCallbackId = setTimeout(function () { + if (typeof callback === 'function') callback(); + }, animationTime); + } + + animationStates = []; + }, + animate: function animate(target, prev, duration) { + if (duration) { + css(target, 'transition', ''); + css(target, 'transform', ''); + var currentRect = getRect(target), + elMatrix = matrix(this.el), + scaleX = elMatrix && elMatrix.a, + scaleY = elMatrix && elMatrix.d, + translateX = (prev.left - currentRect.left) / (scaleX || 1), + translateY = (prev.top - currentRect.top) / (scaleY || 1); + target.animatingX = !!translateX; + target.animatingY = !!translateY; + css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); + repaint(target); // repaint + + css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); + css(target, 'transform', 'translate3d(0,0,0)'); + typeof target.animated === 'number' && clearTimeout(target.animated); + target.animated = setTimeout(function () { + css(target, 'transition', ''); + css(target, 'transform', ''); + target.animated = false; + target.animatingX = false; + target.animatingY = false; + }, duration); + } + } + }; + } + + function repaint(target) { + return target.offsetWidth; + } + + function calculateRealTime(animatingRect, fromRect, toRect, options) { + return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation; + } + + var plugins = []; + var defaults = { + initializeByDefault: true + }; + var PluginManager = { + mount: function mount(plugin) { + // Set default static properties + for (var option in defaults) { + !(option in plugin) && (plugin[option] = defaults[option]); + } + + plugins.push(plugin); + }, + pluginEvent: function pluginEvent(eventName, sortable, evt) { + this.eventCanceled = false; + var eventNameGlobal = eventName + 'Global'; + + for (var i in plugins) { + if (!sortable[plugins[i].pluginName]) continue; // Fire global events if it exists in this sortable + + if (sortable[plugins[i].pluginName][eventNameGlobal]) { + this.eventCanceled = !!sortable[plugins[i].pluginName][eventNameGlobal](_objectSpread({ + sortable: sortable + }, evt)); + } // Only fire plugin event if plugin is enabled in this sortable, + // and plugin has event defined + + + if (sortable.options[plugins[i].pluginName] && sortable[plugins[i].pluginName][eventName]) { + this.eventCanceled = this.eventCanceled || !!sortable[plugins[i].pluginName][eventName](_objectSpread({ + sortable: sortable + }, evt)); + } + } + }, + initializePlugins: function initializePlugins(sortable, el, defaults) { + for (var i in plugins) { + var pluginName = plugins[i].pluginName; + if (!sortable.options[pluginName] && !plugins[i].initializeByDefault) continue; + var initialized = new plugins[i](sortable, el); + initialized.sortable = sortable; + sortable[pluginName] = initialized; // Add default options from plugin + + _extends(defaults, initialized.options); + } + + for (var option in sortable.options) { + var modified = this.modifyOption(sortable, option, sortable.options[option]); + + if (typeof modified !== 'undefined') { + sortable.options[option] = modified; + } + } + }, + getEventOptions: function getEventOptions(name, sortable) { + var eventOptions = {}; + + for (var i in plugins) { + if (typeof plugins[i].eventOptions !== 'function') continue; + eventOptions = _objectSpread({}, eventOptions, plugins[i].eventOptions(name, sortable)); + } + + return eventOptions; + }, + modifyOption: function modifyOption(sortable, name, value) { + var modifiedValue; + + for (var i in plugins) { + // Plugin must exist on the Sortable + if (!sortable[plugins[i].pluginName]) continue; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin + + if (plugins[i].optionListeners && typeof plugins[i].optionListeners[name] === 'function') { + modifiedValue = plugins[i].optionListeners[name].call(sortable[plugins[i].pluginName], value); + } + } + + return modifiedValue; + } + }; + + function dispatchEvent(_ref) { + var sortable = _ref.sortable, + rootEl = _ref.rootEl, + name = _ref.name, + targetEl = _ref.targetEl, + cloneEl = _ref.cloneEl, + toEl = _ref.toEl, + fromEl = _ref.fromEl, + oldIndex = _ref.oldIndex, + newIndex = _ref.newIndex, + oldDraggableIndex = _ref.oldDraggableIndex, + newDraggableIndex = _ref.newDraggableIndex, + originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + eventOptions = _ref.eventOptions; + sortable = sortable || rootEl[expando]; + var evt, + options = sortable.options, + onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent(name, { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent(name, true, true); + } + + evt.to = toEl || rootEl; + evt.from = fromEl || rootEl; + evt.item = targetEl || rootEl; + evt.clone = cloneEl; + evt.oldIndex = oldIndex; + evt.newIndex = newIndex; + evt.oldDraggableIndex = oldDraggableIndex; + evt.newDraggableIndex = newDraggableIndex; + evt.originalEvent = originalEvent; + evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; + + var allEventOptions = _objectSpread({}, eventOptions, PluginManager.getEventOptions(name, sortable)); + + for (var option in allEventOptions) { + evt[option] = allEventOptions[option]; + } + + if (rootEl) { + rootEl.dispatchEvent(evt); + } + + if (options[onName]) { + options[onName].call(sortable, evt); + } + } + + var pluginEvent = function pluginEvent(eventName, sortable) { + var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + originalEvent = _ref.evt, + data = _objectWithoutProperties(_ref, ["evt"]); + + PluginManager.pluginEvent.bind(Sortable$1)(eventName, sortable, _objectSpread({ + dragEl: dragEl, + parentEl: parentEl, + ghostEl: ghostEl, + rootEl: rootEl, + nextEl: nextEl, + lastDownEl: lastDownEl, + cloneEl: cloneEl, + cloneHidden: cloneHidden, + dragStarted: moved, + putSortable: putSortable, + activeSortable: Sortable$1.active, + originalEvent: originalEvent, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + hideGhostForTarget: _hideGhostForTarget, + unhideGhostForTarget: _unhideGhostForTarget, + cloneNowHidden: function cloneNowHidden() { + cloneHidden = true; + }, + cloneNowShown: function cloneNowShown() { + cloneHidden = false; + }, + dispatchSortableEvent: function dispatchSortableEvent(name) { + _dispatchEvent({ + sortable: sortable, + name: name, + originalEvent: originalEvent + }); + } + }, data)); + }; + + function _dispatchEvent(info) { + dispatchEvent(_objectSpread({ + putSortable: putSortable, + cloneEl: cloneEl, + targetEl: dragEl, + rootEl: rootEl, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex + }, info)); + } + + if (typeof window === "undefined" || !window.document) { + throw new Error("Sortable.js requires a window with a document"); + } + + var dragEl, + parentEl, + ghostEl, + rootEl, + nextEl, + lastDownEl, + cloneEl, + cloneHidden, + oldIndex, + newIndex, + oldDraggableIndex, + newDraggableIndex, + activeGroup, + putSortable, + awaitingDragStarted = false, + ignoreNextClick = false, + sortables = [], + tapEvt, + touchEvt, + moved, + lastTarget, + lastDirection, + pastFirstInvertThresh = false, + isCircumstantialInvert = false, + targetMoveDistance, + // For positioning ghost absolutely + ghostRelativeParent, + ghostRelativeParentInitialScroll = [], + // (left, top) + _silent = false, + savedInputChecked = []; + /** @const */ + + var PositionGhostAbsolutely = IOS, + CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', + // This will not pass for IE9, because IE9 DnD only works on anchors + supportDraggable = 'draggable' in document.createElement('div'), + supportCssPointerEvents = function () { + // false when <= IE11 + if (IE11OrLess) { + return false; + } + + var el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; + }(), + _detectDirection = function _detectDirection(el, options) { + var elCSS = css(el), + elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth), + child1 = getChild(el, 0, options), + child2 = getChild(el, 1, options), + firstChildCSS = child1 && css(child1), + secondChildCSS = child2 && css(child2), + firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width, + secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width; + + if (elCSS.display === 'flex') { + return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal'; + } + + if (elCSS.display === 'grid') { + return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; + } + + if (child1 && firstChildCSS["float"] !== 'none') { + var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right'; + return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal'; + } + + return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal'; + }, + + /** + * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. + * @param {Number} x X position + * @param {Number} y Y position + * @return {HTMLElement} Element of the first found nearest Sortable + */ + _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) { + for (var i in sortables) { + if (lastChild(sortables[i])) continue; + var rect = getRect(sortables[i]), + threshold = sortables[i][expando].options.emptyInsertThreshold, + insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold, + insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold; + + if (threshold && insideHorizontally && insideVertically) { + return sortables[i]; + } + } + }, + _prepareGroup = function _prepareGroup(options) { + function toFn(value, pull) { + return function (to, from, dragEl, evt) { + var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name; + + if (value == null && (pull || sameGroup)) { + // Default pull value + // Default pull and put value if same group + return true; + } else if (value == null || value === false) { + return false; + } else if (pull && value === 'clone') { + return value; + } else if (typeof value === 'function') { + return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); + } else { + var otherGroup = (pull ? to : from).options.group.name; + return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1; + } + }; + } + + var group = {}; + var originalGroup = options.group; + + if (!originalGroup || _typeof(originalGroup) != 'object') { + originalGroup = { + name: originalGroup + }; + } + + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + group.revertClone = originalGroup.revertClone; + options.group = group; + }, + _hideGhostForTarget = function _hideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', 'none'); + } + }, + _unhideGhostForTarget = function _unhideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', ''); + } + }; // #1184 fix - Prevent click event on fallback if dragged but item not changed position + + + document.addEventListener('click', function (evt) { + if (ignoreNextClick) { + evt.preventDefault(); + evt.stopPropagation && evt.stopPropagation(); + evt.stopImmediatePropagation && evt.stopImmediatePropagation(); + ignoreNextClick = false; + return false; + } + }, true); + + var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) { + if (dragEl) { + evt = evt.touches ? evt.touches[0] : evt; + + var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); + + if (nearest) { + // Create imitation event + var event = {}; + + for (var i in evt) { + event[i] = evt[i]; + } + + event.target = event.rootEl = nearest; + event.preventDefault = void 0; + event.stopPropagation = void 0; + + nearest[expando]._onDragOver(event); + } + } + }; + + var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) { + if (dragEl) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); + } + }; + /** + * @class Sortable + * @param {HTMLElement} el + * @param {Object} [options] + */ + + + function Sortable$1(el, options) { + if (!(el && el.nodeType && el.nodeType === 1)) { + throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el)); + } + + this.el = el; // root element + + this.options = options = _extends({}, options); // Export instance + + el[expando] = this; + var defaults = { + group: null, + sort: true, + disabled: false, + store: null, + handle: null, + draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*', + swapThreshold: 1, + // percentage; 0 <= x <= 1 + invertSwap: false, + // invert always + invertedSwapThreshold: null, + // will be set to same as swapThreshold if default + removeCloneOnHide: true, + direction: function direction() { + return _detectDirection(el, this.options); + }, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + ignore: 'a, img', + filter: null, + preventOnFilter: true, + animation: 0, + easing: null, + setData: function setData(dataTransfer, dragEl) { + dataTransfer.setData('Text', dragEl.textContent); + }, + dropBubble: false, + dragoverBubble: false, + dataIdAttr: 'data-id', + delay: 0, + delayOnTouchOnly: false, + touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, + forceFallback: false, + fallbackClass: 'sortable-fallback', + fallbackOnBody: false, + fallbackTolerance: 0, + fallbackOffset: { + x: 0, + y: 0 + }, + supportPointer: Sortable$1.supportPointer !== false && 'PointerEvent' in window, + emptyInsertThreshold: 5 + }; + PluginManager.initializePlugins(this, el, defaults); // Set default options + + for (var name in defaults) { + !(name in options) && (options[name] = defaults[name]); + } + + _prepareGroup(options); // Bind all private methods + + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } // Setup drag mode + + + this.nativeDraggable = options.forceFallback ? false : supportDraggable; + + if (this.nativeDraggable) { + // Touch start threshold cannot be greater than the native dragstart threshold + this.options.touchStartThreshold = 1; + } // Bind events + + + if (options.supportPointer) { + on(el, 'pointerdown', this._onTapStart); + } else { + on(el, 'mousedown', this._onTapStart); + on(el, 'touchstart', this._onTapStart); + } + + if (this.nativeDraggable) { + on(el, 'dragover', this); + on(el, 'dragenter', this); + } + + sortables.push(this.el); // Restore sorting + + options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager + + _extends(this, AnimationStateManager()); + } + + Sortable$1.prototype = + /** @lends Sortable.prototype */ + { + constructor: Sortable$1, + _isOutsideThisEl: function _isOutsideThisEl(target) { + if (!this.el.contains(target) && target !== this.el) { + lastTarget = null; + } + }, + _getDirection: function _getDirection(evt, target) { + return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; + }, + _onTapStart: function _onTapStart( + /** Event|TouchEvent */ + evt) { + if (!evt.cancelable) return; + + var _this = this, + el = this.el, + options = this.options, + preventOnFilter = options.preventOnFilter, + type = evt.type, + touch = evt.touches && evt.touches[0], + target = (touch || evt).target, + originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target, + filter = options.filter; + + _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. + + + if (dragEl) { + return; + } + + if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { + return; // only left button and enabled + } // cancel dnd if original target is content editable + + + if (originalTarget.isContentEditable) { + return; + } + + target = closest(target, options.draggable, el, false); + + if (target && target.animated) { + return; + } + + if (lastDownEl === target) { + // Ignoring duplicate `down` + return; + } // Get the index of the dragged element within its parent + + + oldIndex = index(target); + oldDraggableIndex = index(target, options.draggable); // Check filter + + if (typeof filter === 'function') { + if (filter.call(this, evt, target, this)) { + _dispatchEvent({ + sortable: _this, + rootEl: originalTarget, + name: 'filter', + targetEl: target, + toEl: el, + fromEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } else if (filter) { + filter = filter.split(',').some(function (criteria) { + criteria = closest(originalTarget, criteria.trim(), el, false); + + if (criteria) { + _dispatchEvent({ + sortable: _this, + rootEl: criteria, + name: 'filter', + targetEl: target, + fromEl: el, + toEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + return true; + } + }); + + if (filter) { + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } + + if (options.handle && !closest(originalTarget, options.handle, el, false)) { + return; + } // Prepare `dragstart` + + + this._prepareDragStart(evt, touch, target); + }, + _prepareDragStart: function _prepareDragStart( + /** Event */ + evt, + /** Touch */ + touch, + /** HTMLElement */ + target) { + var _this = this, + el = _this.el, + options = _this.options, + ownerDocument = el.ownerDocument, + dragStartFn; + + if (target && !dragEl && target.parentNode === el) { + rootEl = el; + dragEl = target; + parentEl = dragEl.parentNode; + nextEl = dragEl.nextSibling; + lastDownEl = target; + activeGroup = options.group; + Sortable$1.dragged = dragEl; + tapEvt = { + target: dragEl, + clientX: (touch || evt).clientX, + clientY: (touch || evt).clientY + }; + this._lastX = (touch || evt).clientX; + this._lastY = (touch || evt).clientY; + dragEl.style['will-change'] = 'all'; + + dragStartFn = function dragStartFn() { + pluginEvent('delayEnded', _this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + _this._onDrop(); + + return; + } // Delayed drag has been triggered + // we can re-enable the events: touchmove/mousemove + + + _this._disableDelayedDragEvents(); + + if (!FireFox && _this.nativeDraggable) { + dragEl.draggable = true; + } // Bind the events: dragstart/dragend + + + _this._triggerDragStart(evt, touch); // Drag start event + + + _dispatchEvent({ + sortable: _this, + name: 'choose', + originalEvent: evt + }); // Chosen item + + + toggleClass(dragEl, options.chosenClass, true); + }; // Disable "draggable" + + + options.ignore.split(',').forEach(function (criteria) { + find(dragEl, criteria.trim(), _disableDraggable); + }); + on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mouseup', _this._onDrop); + on(ownerDocument, 'touchend', _this._onDrop); + on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox) + + if (FireFox && this.nativeDraggable) { + this.options.touchStartThreshold = 4; + dragEl.draggable = true; + } + + pluginEvent('delayStart', this, { + evt: evt + }); // Delay is impossible for native DnD in Edge or IE + + if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } // If the user moves the pointer or let go the click or touch + // before the delay has been reached: + // disable the delayed drag + + + on(ownerDocument, 'mouseup', _this._disableDelayedDrag); + on(ownerDocument, 'touchend', _this._disableDelayedDrag); + on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); + on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); + on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); + options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); + _this._dragStartTimer = setTimeout(dragStartFn, options.delay); + } else { + dragStartFn(); + } + } + }, + _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( + /** TouchEvent|PointerEvent **/ + e) { + var touch = e.touches ? e.touches[0] : e; + + if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) { + this._disableDelayedDrag(); + } + }, + _disableDelayedDrag: function _disableDelayedDrag() { + dragEl && _disableDraggable(dragEl); + clearTimeout(this._dragStartTimer); + + this._disableDelayedDragEvents(); + }, + _disableDelayedDragEvents: function _disableDelayedDragEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._disableDelayedDrag); + off(ownerDocument, 'touchend', this._disableDelayedDrag); + off(ownerDocument, 'touchcancel', this._disableDelayedDrag); + off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); + }, + _triggerDragStart: function _triggerDragStart( + /** Event */ + evt, + /** Touch */ + touch) { + touch = touch || (evt.pointerType == 'touch' ? evt : null); + + if (!this.nativeDraggable || touch) { + if (this.options.supportPointer) { + on(document, 'pointermove', this._onTouchMove); + } else if (touch) { + on(document, 'touchmove', this._onTouchMove); + } else { + on(document, 'mousemove', this._onTouchMove); + } + } else { + on(dragEl, 'dragend', this); + on(rootEl, 'dragstart', this._onDragStart); + } + + try { + if (document.selection) { + // Timeout neccessary for IE9 + _nextTick(function () { + document.selection.empty(); + }); + } else { + window.getSelection().removeAllRanges(); + } + } catch (err) {} + }, + _dragStarted: function _dragStarted(fallback, evt) { + + awaitingDragStarted = false; + + if (rootEl && dragEl) { + pluginEvent('dragStarted', this, { + evt: evt + }); + + if (this.nativeDraggable) { + on(document, 'dragover', _checkOutsideTargetEl); + } + + var options = this.options; // Apply effect + + !fallback && toggleClass(dragEl, options.dragClass, false); + toggleClass(dragEl, options.ghostClass, true); + Sortable$1.active = this; + fallback && this._appendGhost(); // Drag start event + + _dispatchEvent({ + sortable: this, + name: 'start', + originalEvent: evt + }); + } else { + this._nulling(); + } + }, + _emulateDragOver: function _emulateDragOver() { + if (touchEvt) { + this._lastX = touchEvt.clientX; + this._lastY = touchEvt.clientY; + + _hideGhostForTarget(); + + var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + var parent = target; + + while (target && target.shadowRoot) { + target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + if (target === parent) break; + parent = target; + } + + dragEl.parentNode[expando]._isOutsideThisEl(target); + + if (parent) { + do { + if (parent[expando]) { + var inserted = void 0; + inserted = parent[expando]._onDragOver({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); + + if (inserted && !this.options.dragoverBubble) { + break; + } + } + + target = parent; // store last element + } + /* jshint boss:true */ + while (parent = parent.parentNode); + } + + _unhideGhostForTarget(); + } + }, + _onTouchMove: function _onTouchMove( + /**TouchEvent*/ + evt) { + if (tapEvt) { + var options = this.options, + fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, + touch = evt.touches ? evt.touches[0] : evt, + ghostMatrix = ghostEl && matrix(ghostEl), + scaleX = ghostEl && ghostMatrix && ghostMatrix.a, + scaleY = ghostEl && ghostMatrix && ghostMatrix.d, + relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent), + dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1), + dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1), + translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging + + if (!Sortable$1.active && !awaitingDragStarted) { + if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) { + return; + } + + this._onDragStart(evt, true); + } + + touchEvt = touch; + css(ghostEl, 'webkitTransform', translate3d); + css(ghostEl, 'mozTransform', translate3d); + css(ghostEl, 'msTransform', translate3d); + css(ghostEl, 'transform', translate3d); + evt.cancelable && evt.preventDefault(); + } + }, + _appendGhost: function _appendGhost() { + // Bug if using scale(): https://stackoverflow.com/questions/2637058 + // Not being adjusted for + if (!ghostEl) { + var container = this.options.fallbackOnBody ? document.body : rootEl, + rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container), + options = this.options; // Position absolutely + + if (PositionGhostAbsolutely) { + // Get relatively positioned parent + ghostRelativeParent = container; + + while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) { + ghostRelativeParent = ghostRelativeParent.parentNode; + } + + if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { + if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement(); + rect.top += ghostRelativeParent.scrollTop; + rect.left += ghostRelativeParent.scrollLeft; + } else { + ghostRelativeParent = getWindowScrollingElement(); + } + + ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent); + } + + ghostEl = dragEl.cloneNode(true); + toggleClass(ghostEl, options.ghostClass, false); + toggleClass(ghostEl, options.fallbackClass, true); + toggleClass(ghostEl, options.dragClass, true); + css(ghostEl, 'transition', ''); + css(ghostEl, 'transform', ''); + css(ghostEl, 'box-sizing', 'border-box'); + css(ghostEl, 'margin', 0); + css(ghostEl, 'top', rect.top); + css(ghostEl, 'left', rect.left); + css(ghostEl, 'width', rect.width); + css(ghostEl, 'height', rect.height); + css(ghostEl, 'opacity', '0.8'); + css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed'); + css(ghostEl, 'zIndex', '100000'); + css(ghostEl, 'pointerEvents', 'none'); + Sortable$1.ghost = ghostEl; + container.appendChild(ghostEl); + } + }, + _onDragStart: function _onDragStart( + /**Event*/ + evt, + /**boolean*/ + fallback) { + var _this = this; + + var dataTransfer = evt.dataTransfer; + var options = _this.options; + pluginEvent('dragStart', this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } + + pluginEvent('setupClone', this); + + if (!Sortable$1.eventCanceled) { + cloneEl = clone(dragEl); + cloneEl.draggable = false; + cloneEl.style['will-change'] = ''; + + this._hideClone(); + + toggleClass(cloneEl, this.options.chosenClass, false); + Sortable$1.clone = cloneEl; + } // #1143: IFrame support workaround + + + _this.cloneId = _nextTick(function () { + pluginEvent('clone', _this); + if (Sortable$1.eventCanceled) return; + + if (!_this.options.removeCloneOnHide) { + rootEl.insertBefore(cloneEl, dragEl); + } + + _this._hideClone(); + + _dispatchEvent({ + sortable: _this, + name: 'clone' + }); + }); + !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events + + if (fallback) { + ignoreNextClick = true; + _this._loopId = setInterval(_this._emulateDragOver, 50); + } else { + // Undo what was set in _prepareDragStart before drag started + off(document, 'mouseup', _this._onDrop); + off(document, 'touchend', _this._onDrop); + off(document, 'touchcancel', _this._onDrop); + + if (dataTransfer) { + dataTransfer.effectAllowed = 'move'; + options.setData && options.setData.call(_this, dataTransfer, dragEl); + } + + on(document, 'drop', _this); // #1276 fix: + + css(dragEl, 'transform', 'translateZ(0)'); + } + + awaitingDragStarted = true; + _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); + on(document, 'selectstart', _this); + moved = true; + + if (Safari) { + css(document.body, 'user-select', 'none'); + } + }, + // Returns true - if no further action is needed (either inserted or another condition) + _onDragOver: function _onDragOver( + /**Event*/ + evt) { + var el = this.el, + target = evt.target, + dragRect, + targetRect, + revert, + options = this.options, + group = options.group, + activeSortable = Sortable$1.active, + isOwner = activeGroup === group, + canSort = options.sort, + fromSortable = putSortable || activeSortable, + vertical, + _this = this, + completedFired = false; + + if (_silent) return; + + function dragOverEvent(name, extra) { + pluginEvent(name, _this, _objectSpread({ + evt: evt, + isOwner: isOwner, + axis: vertical ? 'vertical' : 'horizontal', + revert: revert, + dragRect: dragRect, + targetRect: targetRect, + canSort: canSort, + fromSortable: fromSortable, + target: target, + completed: completed, + onMove: function onMove(target, after) { + _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after); + }, + changed: changed + }, extra)); + } // Capture animation state + + + function capture() { + dragOverEvent('dragOverAnimationCapture'); + + _this.captureAnimationState(); + + if (_this !== fromSortable) { + fromSortable.captureAnimationState(); + } + } // Return invocation when dragEl is inserted (or completed) + + + function completed(insertion) { + dragOverEvent('dragOverCompleted', { + insertion: insertion + }); + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } else { + activeSortable._showClone(_this); + } + + if (_this !== fromSortable) { + // Set ghost class to new sortable's ghost class + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); + toggleClass(dragEl, options.ghostClass, true); + } + + if (putSortable !== _this && _this !== Sortable$1.active) { + putSortable = _this; + } else if (_this === Sortable$1.active && putSortable) { + putSortable = null; + } // Animation + + + if (fromSortable === _this) { + _this._ignoreWhileAnimating = target; + } + + _this.animateAll(function () { + dragOverEvent('dragOverAnimationComplete'); + _this._ignoreWhileAnimating = null; + }); + + if (_this !== fromSortable) { + fromSortable.animateAll(); + fromSortable._ignoreWhileAnimating = null; + } + } // Null lastTarget if it is not inside a previously swapped element + + + if (target === dragEl && !dragEl.animated || target === el && !target.animated) { + lastTarget = null; + } // no bubbling and not fallback + + + if (!options.dragoverBubble && !evt.rootEl && target !== document) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted + + + !insertion && nearestEmptyInsertDetectEvent(evt); + } + + !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); + return completedFired = true; + } // Call when dragEl has been inserted + + + function changed() { + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + _dispatchEvent({ + sortable: _this, + name: 'change', + toEl: el, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + originalEvent: evt + }); + } + + if (evt.preventDefault !== void 0) { + evt.cancelable && evt.preventDefault(); + } + + target = closest(target, options.draggable, el, true); + dragOverEvent('dragOver'); + if (Sortable$1.eventCanceled) return completedFired; -(function sortableModule(factory) { - "use strict"; + if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) { + return completed(false); + } - if (typeof define === "function" && define.amd) { - define(factory); - } - else if (typeof module != "undefined" && typeof module.exports != "undefined") { - module.exports = factory(); - } - else { - /* jshint sub:true */ - window["Sortable"] = factory(); - } -})(function sortableFactory() { - "use strict"; - - if (typeof window === "undefined" || !window.document) { - return function sortableError() { - throw new Error("Sortable.js requires a window with a document"); - }; - } + ignoreNextClick = false; - var dragEl, - parentEl, - ghostEl, - cloneEl, - rootEl, - nextEl, - lastDownEl, - - scrollEl, - scrollParentEl, - scrollCustomFn, - - oldIndex, - newIndex, - oldDraggableIndex, - newDraggableIndex, - - activeGroup, - putSortable, - - autoScrolls = [], - scrolling = false, - - awaitingDragStarted = false, - ignoreNextClick = false, - sortables = [], - - pointerElemChangedInterval, - lastPointerElemX, - lastPointerElemY, - - tapEvt, - touchEvt, - - moved, - - - lastTarget, - lastDirection, - pastFirstInvertThresh = false, - isCircumstantialInvert = false, - lastMode, // 'swap' or 'insert' - - targetMoveDistance, - - // For positioning ghost absolutely - ghostRelativeParent, - ghostRelativeParentInitialScroll = [], // (left, top) - - realDragElRect, // dragEl rect after current animation - - /** @const */ - R_SPACE = /\s+/g, - - expando = 'Sortable' + (new Date).getTime(), - - win = window, - document = win.document, - parseInt = win.parseInt, - setTimeout = win.setTimeout, - - $ = win.jQuery || win.Zepto, - Polymer = win.Polymer, - - captureMode = { - capture: false, - passive: false - }, - - IE11OrLess = !!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie|iemobile)/i), - Edge = !!navigator.userAgent.match(/Edge/i), - FireFox = !!navigator.userAgent.match(/firefox/i), - Safari = !!(navigator.userAgent.match(/safari/i) && !navigator.userAgent.match(/chrome/i) && !navigator.userAgent.match(/android/i)), - IOS = !!(navigator.userAgent.match(/iP(ad|od|hone)/i)), - - PositionGhostAbsolutely = IOS, - - CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', - - // This will not pass for IE9, because IE9 DnD only works on anchors - supportDraggable = ('draggable' in document.createElement('div')), - - supportCssPointerEvents = (function() { - // false when <= IE11 - if (IE11OrLess) { - return false; - } - var el = document.createElement('x'); - el.style.cssText = 'pointer-events:auto'; - return el.style.pointerEvents === 'auto'; - })(), - - _silent = false, - _alignedSilent = false, - - abs = Math.abs, - min = Math.min, - max = Math.max, - - savedInputChecked = [], - - _detectDirection = function(el, options) { - var elCSS = _css(el), - elWidth = parseInt(elCSS.width) - - parseInt(elCSS.paddingLeft) - - parseInt(elCSS.paddingRight) - - parseInt(elCSS.borderLeftWidth) - - parseInt(elCSS.borderRightWidth), - child1 = _getChild(el, 0, options), - child2 = _getChild(el, 1, options), - firstChildCSS = child1 && _css(child1), - secondChildCSS = child2 && _css(child2), - firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + _getRect(child1).width, - secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + _getRect(child2).width; - - if (elCSS.display === 'flex') { - return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' - ? 'vertical' : 'horizontal'; - } - - if (elCSS.display === 'grid') { - return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; - } - - if (child1 && firstChildCSS.float !== 'none') { - var touchingSideChild2 = firstChildCSS.float === 'left' ? 'left' : 'right'; - - return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? - 'vertical' : 'horizontal'; - } - - return (child1 && - ( - firstChildCSS.display === 'block' || - firstChildCSS.display === 'flex' || - firstChildCSS.display === 'table' || - firstChildCSS.display === 'grid' || - firstChildWidth >= elWidth && - elCSS[CSSFloatProperty] === 'none' || - child2 && - elCSS[CSSFloatProperty] === 'none' && - firstChildWidth + secondChildWidth > elWidth - ) ? - 'vertical' : 'horizontal' - ); - }, - - /** - * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. - * @param {Number} x X position - * @param {Number} y Y position - * @return {HTMLElement} Element of the first found nearest Sortable - */ - _detectNearestEmptySortable = function(x, y) { - for (var i = 0; i < sortables.length; i++) { - if (_lastChild(sortables[i])) continue; - - var rect = _getRect(sortables[i]), - threshold = sortables[i][expando].options.emptyInsertThreshold, - insideHorizontally = x >= (rect.left - threshold) && x <= (rect.right + threshold), - insideVertically = y >= (rect.top - threshold) && y <= (rect.bottom + threshold); - - if (threshold && insideHorizontally && insideVertically) { - return sortables[i]; - } - } - }, - - _isClientInRowColumn = function(x, y, el, axis, options) { - var targetRect = _getRect(el), - targetS1Opp = axis === 'vertical' ? targetRect.left : targetRect.top, - targetS2Opp = axis === 'vertical' ? targetRect.right : targetRect.bottom, - mouseOnOppAxis = axis === 'vertical' ? x : y; - - return targetS1Opp < mouseOnOppAxis && mouseOnOppAxis < targetS2Opp; - }, - - _isElInRowColumn = function(el1, el2, axis) { - var el1Rect = el1 === dragEl && realDragElRect || _getRect(el1), - el2Rect = el2 === dragEl && realDragElRect || _getRect(el2), - el1S1Opp = axis === 'vertical' ? el1Rect.left : el1Rect.top, - el1S2Opp = axis === 'vertical' ? el1Rect.right : el1Rect.bottom, - el1OppLength = axis === 'vertical' ? el1Rect.width : el1Rect.height, - el2S1Opp = axis === 'vertical' ? el2Rect.left : el2Rect.top, - el2S2Opp = axis === 'vertical' ? el2Rect.right : el2Rect.bottom, - el2OppLength = axis === 'vertical' ? el2Rect.width : el2Rect.height; - - return ( - el1S1Opp === el2S1Opp || - el1S2Opp === el2S2Opp || - (el1S1Opp + el1OppLength / 2) === (el2S1Opp + el2OppLength / 2) - ); - }, - - _getParentAutoScrollElement = function(el, includeSelf) { - // skip to window - if (!el || !el.getBoundingClientRect) return _getWindowScrollingElement(); - - var elem = el; - var 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) { - var 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 || !elem.getBoundingClientRect || elem === document.body) return _getWindowScrollingElement(); - - if (gotSelf || includeSelf) return elem; - gotSelf = true; - } - } - /* jshint boss:true */ - } while (elem = elem.parentNode); - - return _getWindowScrollingElement(); - }, - - _getWindowScrollingElement = function() { - if (IE11OrLess) { - return document.documentElement; - } else { - return document.scrollingElement; - } - }, - - _scrollBy = function(el, x, y) { - el.scrollLeft += x; - el.scrollTop += y; - }, - - _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl, /**Boolean*/isFallback) { - // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 - if (options.scroll) { - var _this = rootEl ? rootEl[expando] : window, - sens = options.scrollSensitivity, - speed = options.scrollSpeed, - - x = evt.clientX, - y = evt.clientY, - - winScroller = _getWindowScrollingElement(), - - scrollThisInstance = false; - - // Detect scrollEl - if (scrollParentEl !== rootEl) { - _clearAutoScrolls(); - - scrollEl = options.scroll; - scrollCustomFn = options.scrollFn; - - if (scrollEl === true) { - scrollEl = _getParentAutoScrollElement(rootEl, true); - scrollParentEl = scrollEl; - } - } - - - var layersOut = 0; - var currentParent = scrollEl; - do { - var el = currentParent, - rect = _getRect(el), - - top = rect.top, - bottom = rect.bottom, - left = rect.left, - right = rect.right, - - width = rect.width, - height = rect.height, - - scrollWidth, - scrollHeight, - - css, - - vx, - vy, - - canScrollX, - canScrollY, - - scrollPosX, - scrollPosY; - - - scrollWidth = el.scrollWidth; - scrollHeight = el.scrollHeight; - - css = _css(el); - - scrollPosX = el.scrollLeft; - scrollPosY = el.scrollTop; - - if (el === winScroller) { - canScrollX = width < scrollWidth && (css.overflowX === 'auto' || css.overflowX === 'scroll' || css.overflowX === 'visible'); - canScrollY = height < scrollHeight && (css.overflowY === 'auto' || css.overflowY === 'scroll' || css.overflowY === 'visible'); - } else { - canScrollX = width < scrollWidth && (css.overflowX === 'auto' || css.overflowX === 'scroll'); - canScrollY = height < scrollHeight && (css.overflowY === 'auto' || css.overflowY === 'scroll'); - } - - vx = canScrollX && (abs(right - x) <= sens && (scrollPosX + width) < scrollWidth) - (abs(left - x) <= sens && !!scrollPosX); - - vy = canScrollY && (abs(bottom - y) <= sens && (scrollPosY + height) < scrollHeight) - (abs(top - y) <= sens && !!scrollPosY); - - - if (!autoScrolls[layersOut]) { - for (var i = 0; i <= layersOut; i++) { - if (!autoScrolls[i]) { - autoScrolls[i] = {}; - } - } - } - - if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { - autoScrolls[layersOut].el = el; - autoScrolls[layersOut].vx = vx; - autoScrolls[layersOut].vy = vy; - - clearInterval(autoScrolls[layersOut].pid); - - if (el && (vx != 0 || vy != 0)) { - scrollThisInstance = true; - /* jshint loopfunc:true */ - autoScrolls[layersOut].pid = setInterval((function () { - // emulate drag over during autoscroll (fallback), emulating native DnD behaviour - if (isFallback && this.layer === 0) { - Sortable.active._emulateDragOver(true); - Sortable.active._onTouchMove(touchEvt, true); - } - var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; - var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; - - if ('function' === typeof(scrollCustomFn)) { - if (scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt, touchEvt, autoScrolls[this.layer].el) !== 'continue') { - return; - } - } - - _scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); - }).bind({layer: layersOut}), 24); - } - } - layersOut++; - } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = _getParentAutoScrollElement(currentParent, false))); - scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not - } - }, 30), - - _clearAutoScrolls = function () { - autoScrolls.forEach(function(autoScroll) { - clearInterval(autoScroll.pid); - }); - autoScrolls = []; - }, - - _prepareGroup = function (options) { - function toFn(value, pull) { - return function(to, from, dragEl, evt) { - var sameGroup = to.options.group.name && - from.options.group.name && - to.options.group.name === from.options.group.name; - - if (value == null && (pull || sameGroup)) { - // Default pull value - // Default pull and put value if same group - return true; - } else if (value == null || value === false) { - return false; - } else if (pull && value === 'clone') { - return value; - } else if (typeof value === 'function') { - return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); - } else { - var otherGroup = (pull ? to : from).options.group.name; - - return (value === true || - (typeof value === 'string' && value === otherGroup) || - (value.join && value.indexOf(otherGroup) > -1)); - } - }; - } - - var group = {}; - var originalGroup = options.group; - - if (!originalGroup || typeof originalGroup != 'object') { - originalGroup = {name: originalGroup}; - } - - group.name = originalGroup.name; - group.checkPull = toFn(originalGroup.pull, true); - group.checkPut = toFn(originalGroup.put); - group.revertClone = originalGroup.revertClone; - - options.group = group; - }, - - _checkAlignment = function(evt) { - if (!dragEl || !dragEl.parentNode) return; - dragEl.parentNode[expando] && dragEl.parentNode[expando]._computeIsAligned(evt); - }, - - _hideGhostForTarget = function() { - if (!supportCssPointerEvents && ghostEl) { - _css(ghostEl, 'display', 'none'); - } - }, - - _unhideGhostForTarget = function() { - if (!supportCssPointerEvents && ghostEl) { - _css(ghostEl, 'display', ''); - } - }; - - - // #1184 fix - Prevent click event on fallback if dragged but item not changed position - document.addEventListener('click', function(evt) { - if (ignoreNextClick) { - evt.preventDefault(); - evt.stopPropagation && evt.stopPropagation(); - evt.stopImmediatePropagation && evt.stopImmediatePropagation(); - ignoreNextClick = false; - return false; - } - }, true); - - var nearestEmptyInsertDetectEvent = function(evt) { - if (dragEl) { - evt = evt.touches ? evt.touches[0] : evt; - var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); - - if (nearest) { - // Create imitation event - var event = {}; - for (var i in evt) { - event[i] = evt[i]; - } - event.target = event.rootEl = nearest; - event.preventDefault = void 0; - event.stopPropagation = void 0; - nearest[expando]._onDragOver(event); - } - } - }; - - /** - * @class Sortable - * @param {HTMLElement} el - * @param {Object} [options] - */ - function Sortable(el, options) { - if (!(el && el.nodeType && el.nodeType === 1)) { - throw 'Sortable: `el` must be HTMLElement, not ' + {}.toString.call(el); - } - - this.el = el; // root element - this.options = options = _extend({}, options); - - - // Export instance - el[expando] = this; - - // Default options - var defaults = { - group: null, - sort: true, - disabled: false, - store: null, - handle: null, - scroll: true, - scrollSensitivity: 30, - scrollSpeed: 10, - bubbleScroll: true, - draggable: /[uo]l/i.test(el.nodeName) ? '>li' : '>*', - swapThreshold: 1, // percentage; 0 <= x <= 1 - invertSwap: false, // invert always - invertedSwapThreshold: null, // will be set to same as swapThreshold if default - removeCloneOnHide: true, - direction: function() { - return _detectDirection(el, this.options); - }, - ghostClass: 'sortable-ghost', - chosenClass: 'sortable-chosen', - dragClass: 'sortable-drag', - ignore: 'a, img', - filter: null, - preventOnFilter: true, - animation: 0, - easing: null, - setData: function (dataTransfer, dragEl) { - dataTransfer.setData('Text', dragEl.textContent); - }, - dropBubble: false, - dragoverBubble: false, - dataIdAttr: 'data-id', - delay: 0, - delayOnTouchOnly: false, - touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, - forceFallback: false, - fallbackClass: 'sortable-fallback', - fallbackOnBody: false, - fallbackTolerance: 0, - fallbackOffset: {x: 0, y: 0}, - supportPointer: Sortable.supportPointer !== false && ('PointerEvent' in window), - emptyInsertThreshold: 5 - }; - - - // Set default options - for (var name in defaults) { - !(name in options) && (options[name] = defaults[name]); - } - - _prepareGroup(options); - - // Bind all private methods - for (var fn in this) { - if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { - this[fn] = this[fn].bind(this); - } - } - - // Setup drag mode - this.nativeDraggable = options.forceFallback ? false : supportDraggable; - - if (this.nativeDraggable) { - // Touch start threshold cannot be greater than the native dragstart threshold - this.options.touchStartThreshold = 1; - } - - // Bind events - if (options.supportPointer) { - _on(el, 'pointerdown', this._onTapStart); - } else { - _on(el, 'mousedown', this._onTapStart); - _on(el, 'touchstart', this._onTapStart); - } - - if (this.nativeDraggable) { - _on(el, 'dragover', this); - _on(el, 'dragenter', this); - } - - sortables.push(this.el); - - // Restore sorting - options.store && options.store.get && this.sort(options.store.get(this) || []); - } - - Sortable.prototype = /** @lends Sortable.prototype */ { - constructor: Sortable, - - _computeIsAligned: function(evt) { - var target; - - if (ghostEl && !supportCssPointerEvents) { - _hideGhostForTarget(); - target = document.elementFromPoint(evt.clientX, evt.clientY); - _unhideGhostForTarget(); - } else { - target = evt.target; - } - - target = _closest(target, this.options.draggable, this.el, false); - if (_alignedSilent) return; - if (!dragEl || dragEl.parentNode !== this.el) return; - - var children = this.el.children; - for (var i = 0; i < children.length; i++) { - // Don't change for target in case it is changed to aligned before onDragOver is fired - if (_closest(children[i], this.options.draggable, this.el, false) && children[i] !== target) { - children[i].sortableMouseAligned = _isClientInRowColumn(evt.clientX, evt.clientY, children[i], this._getDirection(evt, null), this.options); - } - } - // Used for nulling last target when not in element, nothing to do with checking if aligned - if (!_closest(target, this.options.draggable, this.el, true)) { - lastTarget = null; - } - - _alignedSilent = true; - setTimeout(function() { - _alignedSilent = false; - }, 30); - - }, - - _getDirection: function(evt, target) { - return (typeof this.options.direction === 'function') ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; - }, - - _onTapStart: function (/** Event|TouchEvent */evt) { - if (!evt.cancelable) return; - var _this = this, - el = this.el, - options = this.options, - preventOnFilter = options.preventOnFilter, - type = evt.type, - touch = evt.touches && evt.touches[0], - target = (touch || evt).target, - originalTarget = evt.target.shadowRoot && ((evt.path && evt.path[0]) || (evt.composedPath && evt.composedPath()[0])) || target, - filter = options.filter, - startIndex, - startDraggableIndex; - - _saveInputCheckedState(el); - - // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. - if (dragEl) { - return; - } - - if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { - return; // only left button and enabled - } - - // cancel dnd if original target is content editable - if (originalTarget.isContentEditable) { - return; - } - - target = _closest(target, options.draggable, el, false); - - - if (lastDownEl === target) { - // Ignoring duplicate `down` - return; - } - - // Get the index of the dragged element within its parent - startIndex = _index(target); - startDraggableIndex = _index(target, options.draggable); - - // Check filter - if (typeof filter === 'function') { - if (filter.call(this, evt, target, this)) { - _dispatchEvent(_this, originalTarget, 'filter', target, el, el, startIndex, undefined, startDraggableIndex); - preventOnFilter && evt.cancelable && evt.preventDefault(); - return; // cancel dnd - } - } - else if (filter) { - filter = filter.split(',').some(function (criteria) { - criteria = _closest(originalTarget, criteria.trim(), el, false); - - if (criteria) { - _dispatchEvent(_this, criteria, 'filter', target, el, el, startIndex, undefined, startDraggableIndex); - return true; - } - }); - - if (filter) { - preventOnFilter && evt.cancelable && evt.preventDefault(); - return; // cancel dnd - } - } - - if (options.handle && !_closest(originalTarget, options.handle, el, false)) { - return; - } - - // Prepare `dragstart` - this._prepareDragStart(evt, touch, target, startIndex, startDraggableIndex); - }, - - - _handleAutoScroll: function(evt, fallback) { - if (!dragEl || !this.options.scroll) return; - var x = evt.clientX, - y = evt.clientY, - - elem = document.elementFromPoint(x, y), - _this = this; - - // IE does not seem to have native autoscroll, - // Edge's autoscroll seems too conditional, - // MACOS Safari does not have autoscroll, - // Firefox and Chrome are good - if (fallback || Edge || IE11OrLess || Safari) { - _autoScroll(evt, _this.options, elem, fallback); - - // Listener for pointer element change - var ogElemScroller = _getParentAutoScrollElement(elem, true); - if ( - scrolling && - ( - !pointerElemChangedInterval || - x !== lastPointerElemX || - y !== lastPointerElemY - ) - ) { - - pointerElemChangedInterval && clearInterval(pointerElemChangedInterval); - // Detect for pointer elem change, emulating native DnD behaviour - pointerElemChangedInterval = setInterval(function() { - if (!dragEl) return; - // could also check if scroll direction on newElem changes due to parent autoscrolling - var newElem = _getParentAutoScrollElement(document.elementFromPoint(x, y), true); - if (newElem !== ogElemScroller) { - ogElemScroller = newElem; - _clearAutoScrolls(); - _autoScroll(evt, _this.options, ogElemScroller, fallback); - } - }, 10); - lastPointerElemX = x; - lastPointerElemY = y; - } - - } else { - // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll - if (!_this.options.bubbleScroll || _getParentAutoScrollElement(elem, true) === _getWindowScrollingElement()) { - _clearAutoScrolls(); - return; - } - _autoScroll(evt, _this.options, _getParentAutoScrollElement(elem, false), false); - } - }, - - _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target, /** Number */startIndex, /** Number */startDraggableIndex) { - var _this = this, - el = _this.el, - options = _this.options, - ownerDocument = el.ownerDocument, - dragStartFn; - - if (target && !dragEl && (target.parentNode === el)) { - rootEl = el; - dragEl = target; - parentEl = dragEl.parentNode; - nextEl = dragEl.nextSibling; - lastDownEl = target; - activeGroup = options.group; - oldIndex = startIndex; - oldDraggableIndex = startDraggableIndex; - - tapEvt = { - target: dragEl, - clientX: (touch || evt).clientX, - clientY: (touch || evt).clientY - }; - - this._lastX = (touch || evt).clientX; - this._lastY = (touch || evt).clientY; - - dragEl.style['will-change'] = 'all'; - // undo animation if needed - dragEl.style.transition = ''; - dragEl.style.transform = ''; - - dragStartFn = function () { - // Delayed drag has been triggered - // we can re-enable the events: touchmove/mousemove - _this._disableDelayedDragEvents(); - - if (!FireFox && _this.nativeDraggable) { - dragEl.draggable = true; - } - - // Bind the events: dragstart/dragend - _this._triggerDragStart(evt, touch); - - // Drag start event - _dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, rootEl, oldIndex, undefined, oldDraggableIndex); - - // Chosen item - _toggleClass(dragEl, options.chosenClass, true); - }; - - // Disable "draggable" - options.ignore.split(',').forEach(function (criteria) { - _find(dragEl, criteria.trim(), _disableDraggable); - }); - - _on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); - _on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); - _on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); - - _on(ownerDocument, 'mouseup', _this._onDrop); - _on(ownerDocument, 'touchend', _this._onDrop); - _on(ownerDocument, 'touchcancel', _this._onDrop); - - // Make dragEl draggable (must be before delay for FireFox) - if (FireFox && this.nativeDraggable) { - this.options.touchStartThreshold = 4; - dragEl.draggable = true; - } - - // Delay is impossible for native DnD in Edge or IE - if (options.delay && (options.delayOnTouchOnly ? touch : true) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { - // If the user moves the pointer or let go the click or touch - // before the delay has been reached: - // disable the delayed drag - _on(ownerDocument, 'mouseup', _this._disableDelayedDrag); - _on(ownerDocument, 'touchend', _this._disableDelayedDrag); - _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); - _on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); - _on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); - options.supportPointer && _on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); - - _this._dragStartTimer = setTimeout(dragStartFn, options.delay); - } else { - dragStartFn(); - } - } - }, - - _delayedDragTouchMoveHandler: function (/** TouchEvent|PointerEvent **/e) { - var touch = e.touches ? e.touches[0] : e; - if (max(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) - >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1)) - ) { - this._disableDelayedDrag(); - } - }, - - _disableDelayedDrag: function () { - dragEl && _disableDraggable(dragEl); - clearTimeout(this._dragStartTimer); - - this._disableDelayedDragEvents(); - }, - - _disableDelayedDragEvents: function () { - var ownerDocument = this.el.ownerDocument; - _off(ownerDocument, 'mouseup', this._disableDelayedDrag); - _off(ownerDocument, 'touchend', this._disableDelayedDrag); - _off(ownerDocument, 'touchcancel', this._disableDelayedDrag); - _off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); - _off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); - _off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); - }, - - _triggerDragStart: function (/** Event */evt, /** Touch */touch) { - touch = touch || (evt.pointerType == 'touch' ? evt : null); - - if (!this.nativeDraggable || touch) { - if (this.options.supportPointer) { - _on(document, 'pointermove', this._onTouchMove); - } else if (touch) { - _on(document, 'touchmove', this._onTouchMove); - } else { - _on(document, 'mousemove', this._onTouchMove); - } - } else { - _on(dragEl, 'dragend', this); - _on(rootEl, 'dragstart', this._onDragStart); - } - - try { - if (document.selection) { - // Timeout neccessary for IE9 - _nextTick(function () { - document.selection.empty(); - }); - } else { - window.getSelection().removeAllRanges(); - } - } catch (err) { - } - }, - - _dragStarted: function (fallback, evt) { - awaitingDragStarted = false; - if (rootEl && dragEl) { - if (this.nativeDraggable) { - _on(document, 'dragover', this._handleAutoScroll); - _on(document, 'dragover', _checkAlignment); - } - var options = this.options; - - // Apply effect - !fallback && _toggleClass(dragEl, options.dragClass, false); - _toggleClass(dragEl, options.ghostClass, true); - - // In case dragging an animated element - _css(dragEl, 'transform', ''); - - Sortable.active = this; - - fallback && this._appendGhost(); - - // Drag start event - _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, rootEl, oldIndex, undefined, oldDraggableIndex, undefined, evt); - } else { - this._nulling(); - } - }, - - _emulateDragOver: function (forAutoScroll) { - if (touchEvt) { - if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY && !forAutoScroll) { - return; - } - this._lastX = touchEvt.clientX; - this._lastY = touchEvt.clientY; - - _hideGhostForTarget(); - - var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); - var parent = target; - - while (target && target.shadowRoot) { - target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); - if (target === parent) break; - parent = target; - } - - if (parent) { - do { - if (parent[expando]) { - var inserted; - - inserted = parent[expando]._onDragOver({ - clientX: touchEvt.clientX, - clientY: touchEvt.clientY, - target: target, - rootEl: parent - }); - - if (inserted && !this.options.dragoverBubble) { - break; - } - } - - target = parent; // store last element - } - /* jshint boss:true */ - while (parent = parent.parentNode); - } - dragEl.parentNode[expando]._computeIsAligned(touchEvt); - - _unhideGhostForTarget(); - } - }, - - - _onTouchMove: function (/**TouchEvent*/evt, forAutoScroll) { - if (tapEvt) { - var options = this.options, - fallbackTolerance = options.fallbackTolerance, - fallbackOffset = options.fallbackOffset, - touch = evt.touches ? evt.touches[0] : evt, - matrix = ghostEl && _matrix(ghostEl), - scaleX = ghostEl && matrix && matrix.a, - scaleY = ghostEl && matrix && matrix.d, - relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && _getRelativeScrollOffset(ghostRelativeParent), - dx = ((touch.clientX - tapEvt.clientX) - + fallbackOffset.x) / (scaleX || 1) - + (relativeScrollOffset ? (relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0]) : 0) / (scaleX || 1), - dy = ((touch.clientY - tapEvt.clientY) - + fallbackOffset.y) / (scaleY || 1) - + (relativeScrollOffset ? (relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1]) : 0) / (scaleY || 1), - translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; - - // only set the status to dragging, when we are actually dragging - if (!Sortable.active && !awaitingDragStarted) { - if (fallbackTolerance && - min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < fallbackTolerance - ) { - return; - } - this._onDragStart(evt, true); - } - - !forAutoScroll && this._handleAutoScroll(touch, true); - - moved = true; - touchEvt = touch; - - _css(ghostEl, 'webkitTransform', translate3d); - _css(ghostEl, 'mozTransform', translate3d); - _css(ghostEl, 'msTransform', translate3d); - _css(ghostEl, 'transform', translate3d); - - evt.cancelable && evt.preventDefault(); - } - }, - - _appendGhost: function () { - // Bug if using scale(): https://stackoverflow.com/questions/2637058 - // Not being adjusted for - if (!ghostEl) { - var container = this.options.fallbackOnBody ? document.body : rootEl, - rect = _getRect(dragEl, true, container, !PositionGhostAbsolutely), - css = _css(dragEl), - options = this.options; - - // Position absolutely - if (PositionGhostAbsolutely) { - // Get relatively positioned parent - ghostRelativeParent = container; - - while ( - _css(ghostRelativeParent, 'position') === 'static' && - _css(ghostRelativeParent, 'transform') === 'none' && - ghostRelativeParent !== document - ) { - ghostRelativeParent = ghostRelativeParent.parentNode; - } - - if (ghostRelativeParent !== document) { - var ghostRelativeParentRect = _getRect(ghostRelativeParent, true); - - rect.top -= ghostRelativeParentRect.top; - rect.left -= ghostRelativeParentRect.left; - } - - if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { - if (ghostRelativeParent === document) ghostRelativeParent = _getWindowScrollingElement(); - - rect.top += ghostRelativeParent.scrollTop; - rect.left += ghostRelativeParent.scrollLeft; - } else { - ghostRelativeParent = _getWindowScrollingElement(); - } - ghostRelativeParentInitialScroll = _getRelativeScrollOffset(ghostRelativeParent); - } - - - ghostEl = dragEl.cloneNode(true); - - _toggleClass(ghostEl, options.ghostClass, false); - _toggleClass(ghostEl, options.fallbackClass, true); - _toggleClass(ghostEl, options.dragClass, true); - - _css(ghostEl, 'box-sizing', 'border-box'); - _css(ghostEl, 'margin', 0); - _css(ghostEl, 'top', rect.top); - _css(ghostEl, 'left', rect.left); - _css(ghostEl, 'width', rect.width); - _css(ghostEl, 'height', rect.height); - _css(ghostEl, 'opacity', '0.8'); - _css(ghostEl, 'position', (PositionGhostAbsolutely ? 'absolute' : 'fixed')); - _css(ghostEl, 'zIndex', '100000'); - _css(ghostEl, 'pointerEvents', 'none'); - - container.appendChild(ghostEl); - } - }, - - _onDragStart: function (/**Event*/evt, /**boolean*/fallback) { - var _this = this; - var dataTransfer = evt.dataTransfer; - var options = _this.options; - - // Setup clone - cloneEl = _clone(dragEl); - - cloneEl.draggable = false; - cloneEl.style['will-change'] = ''; - - this._hideClone(); - - _toggleClass(cloneEl, _this.options.chosenClass, false); - - - // #1143: IFrame support workaround - _this._cloneId = _nextTick(function () { - if (!_this.options.removeCloneOnHide) { - rootEl.insertBefore(cloneEl, dragEl); - } - _dispatchEvent(_this, rootEl, 'clone', dragEl); - }); - - - !fallback && _toggleClass(dragEl, options.dragClass, true); - - // Set proper drop events - if (fallback) { - ignoreNextClick = true; - _this._loopId = setInterval(_this._emulateDragOver, 50); - } else { - // Undo what was set in _prepareDragStart before drag started - _off(document, 'mouseup', _this._onDrop); - _off(document, 'touchend', _this._onDrop); - _off(document, 'touchcancel', _this._onDrop); - - if (dataTransfer) { - dataTransfer.effectAllowed = 'move'; - options.setData && options.setData.call(_this, dataTransfer, dragEl); - } - - _on(document, 'drop', _this); - - // #1276 fix: - _css(dragEl, 'transform', 'translateZ(0)'); - } - - awaitingDragStarted = true; - - _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); - _on(document, 'selectstart', _this); - if (Safari) { - _css(document.body, 'user-select', 'none'); - } - }, - - - // Returns true - if no further action is needed (either inserted or another condition) - _onDragOver: function (/**Event*/evt) { - var el = this.el, - target = evt.target, - dragRect, - targetRect, - revert, - options = this.options, - group = options.group, - activeSortable = Sortable.active, - isOwner = (activeGroup === group), - canSort = options.sort, - _this = this; - - if (_silent) return; - - // Return invocation when dragEl is inserted (or completed) - function completed(insertion) { - if (insertion) { - if (isOwner) { - activeSortable._hideClone(); - } else { - activeSortable._showClone(_this); - } - - if (activeSortable) { - // Set ghost class to new sortable's ghost class - _toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); - _toggleClass(dragEl, options.ghostClass, true); - } - - if (putSortable !== _this && _this !== Sortable.active) { - putSortable = _this; - } else if (_this === Sortable.active) { - putSortable = null; - } - - // Animation - dragRect && _this._animate(dragRect, dragEl); - target && targetRect && _this._animate(targetRect, target); - } - - - // Null lastTarget if it is not inside a previously swapped element - if ((target === dragEl && !dragEl.animated) || (target === el && !target.animated)) { - lastTarget = null; - } - - // no bubbling and not fallback - if (!options.dragoverBubble && !evt.rootEl && target !== document) { - _this._handleAutoScroll(evt); - dragEl.parentNode[expando]._computeIsAligned(evt); - - // Do not detect for empty insert if already inserted - !insertion && nearestEmptyInsertDetectEvent(evt); - } - - !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); - - return true; - } - - // Call when dragEl has been inserted - function changed() { - _dispatchEvent(_this, rootEl, 'change', target, el, rootEl, oldIndex, _index(dragEl), oldDraggableIndex, _index(dragEl, options.draggable), evt); - } - - - if (evt.preventDefault !== void 0) { - evt.cancelable && evt.preventDefault(); - } - - - moved = true; - - target = _closest(target, options.draggable, el, true); - - // target is dragEl or target is animated - if (dragEl.contains(evt.target) || target.animated) { - return completed(false); - } - - if (target !== dragEl) { - ignoreNextClick = false; - } - - if (activeSortable && !options.disabled && - (isOwner - ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list - : ( - putSortable === this || - ( - (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && - group.checkPut(this, activeSortable, dragEl, evt) - ) - ) - ) - ) { - var axis = this._getDirection(evt, target); - - dragRect = _getRect(dragEl); - - if (revert) { - this._hideClone(); - parentEl = rootEl; // actualization - - if (nextEl) { - rootEl.insertBefore(dragEl, nextEl); - } else { - rootEl.appendChild(dragEl); - } - - return completed(true); - } - - var elLastChild = _lastChild(el); - - if (!elLastChild || _ghostIsLast(evt, axis, el) && !elLastChild.animated) { - // assign target only if condition is true - if (elLastChild && el === evt.target) { - target = elLastChild; - } - - if (target) { - targetRect = _getRect(target); - } - - if (isOwner) { - activeSortable._hideClone(); - } else { - activeSortable._showClone(this); - } - - if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { - el.appendChild(dragEl); - parentEl = el; // actualization - realDragElRect = null; - - changed(); - return completed(true); - } - } - else if (target && target !== dragEl && target.parentNode === el) { - var direction = 0, - targetBeforeFirstSwap, - aligned = target.sortableMouseAligned, - differentLevel = dragEl.parentNode !== el, - side1 = axis === 'vertical' ? 'top' : 'left', - scrolledPastTop = _isScrolledPast(target, 'top') || _isScrolledPast(dragEl, 'top'), - scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; - - - if (lastTarget !== target) { - lastMode = null; - targetBeforeFirstSwap = _getRect(target)[side1]; - pastFirstInvertThresh = false; - } - - // Reference: https://www.lucidchart.com/documents/view/10fa0e93-e362-4126-aca2-b709ee56bd8b/0 - if ( - _isElInRowColumn(dragEl, target, axis) && aligned || - differentLevel || - scrolledPastTop || - options.invertSwap || - lastMode === 'insert' || - // Needed, in the case that we are inside target and inserted because not aligned... aligned will stay false while inside - // and lastMode will change to 'insert', but we must swap - lastMode === 'swap' - ) { - // New target that we will be inside - if (lastMode !== 'swap') { - isCircumstantialInvert = options.invertSwap || differentLevel; - } - - direction = _getSwapDirection(evt, target, axis, - options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, - isCircumstantialInvert, - lastTarget === target); - lastMode = 'swap'; - } else { - // Insert at position - direction = _getInsertDirection(target); - lastMode = 'insert'; - } - if (direction === 0) return completed(false); - - realDragElRect = null; - lastTarget = target; - - lastDirection = direction; - - targetRect = _getRect(target); - - var nextSibling = target.nextElementSibling, - after = false; - - after = direction === 1; - - var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); - - if (moveVector !== false) { - if (moveVector === 1 || moveVector === -1) { - after = (moveVector === 1); - } - - _silent = true; - setTimeout(_unsilent, 30); - - if (isOwner) { - activeSortable._hideClone(); - } else { - activeSortable._showClone(this); - } - - if (after && !nextSibling) { - el.appendChild(dragEl); - } else { - target.parentNode.insertBefore(dragEl, after ? nextSibling : target); - } - - // Undo chrome's scroll adjustment - if (scrolledPastTop) { - _scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); - } - - parentEl = dragEl.parentNode; // actualization - - // must be done before animation - if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { - targetMoveDistance = abs(targetBeforeFirstSwap - _getRect(target)[side1]); - } - changed(); - - return completed(true); - } - } - - if (el.contains(dragEl)) { - return completed(false); - } - } - - return false; - }, - - _animate: function (prevRect, target) { - var ms = this.options.animation; - - if (ms) { - var currentRect = _getRect(target); - - if (target === dragEl) { - realDragElRect = currentRect; - } - - if (prevRect.nodeType === 1) { - prevRect = _getRect(prevRect); - } - - // Check if actually moving position - if ((prevRect.left + prevRect.width / 2) !== (currentRect.left + currentRect.width / 2) - || (prevRect.top + prevRect.height / 2) !== (currentRect.top + currentRect.height / 2) - ) { - var matrix = _matrix(this.el), - scaleX = matrix && matrix.a, - scaleY = matrix && matrix.d; - - _css(target, 'transition', 'none'); - _css(target, 'transform', 'translate3d(' - + (prevRect.left - currentRect.left) / (scaleX ? scaleX : 1) + 'px,' - + (prevRect.top - currentRect.top) / (scaleY ? scaleY : 1) + 'px,0)' - ); - - this._repaint(target); - _css(target, 'transition', 'transform ' + ms + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); - _css(target, 'transform', 'translate3d(0,0,0)'); - } - - (typeof target.animated === 'number') && clearTimeout(target.animated); - target.animated = setTimeout(function () { - _css(target, 'transition', ''); - _css(target, 'transform', ''); - target.animated = false; - }, ms); - } - }, - - _repaint: function(target) { - return target.offsetWidth; - }, - - _offMoveEvents: function() { - _off(document, 'touchmove', this._onTouchMove); - _off(document, 'pointermove', this._onTouchMove); - _off(document, 'dragover', nearestEmptyInsertDetectEvent); - _off(document, 'mousemove', nearestEmptyInsertDetectEvent); - _off(document, 'touchmove', nearestEmptyInsertDetectEvent); - }, - - _offUpEvents: function () { - var ownerDocument = this.el.ownerDocument; - - _off(ownerDocument, 'mouseup', this._onDrop); - _off(ownerDocument, 'touchend', this._onDrop); - _off(ownerDocument, 'pointerup', this._onDrop); - _off(ownerDocument, 'touchcancel', this._onDrop); - _off(document, 'selectstart', this); - }, - - _onDrop: function (/**Event*/evt) { - var el = this.el, - options = this.options; - awaitingDragStarted = false; - scrolling = false; - isCircumstantialInvert = false; - pastFirstInvertThresh = false; - - clearInterval(this._loopId); - - clearInterval(pointerElemChangedInterval); - _clearAutoScrolls(); - _cancelThrottle(); - - clearTimeout(this._dragStartTimer); - - _cancelNextTick(this._cloneId); - _cancelNextTick(this._dragStartId); - - // Unbind events - _off(document, 'mousemove', this._onTouchMove); - - - if (this.nativeDraggable) { - _off(document, 'drop', this); - _off(el, 'dragstart', this._onDragStart); - _off(document, 'dragover', this._handleAutoScroll); - _off(document, 'dragover', _checkAlignment); - } - - if (Safari) { - _css(document.body, 'user-select', ''); - } - - this._offMoveEvents(); - this._offUpEvents(); - - if (evt) { - if (moved) { - evt.cancelable && evt.preventDefault(); - !options.dropBubble && evt.stopPropagation(); - } - - ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); - - if (rootEl === parentEl || (putSortable && putSortable.lastPutMode !== 'clone')) { - // Remove clone - cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); - } - - if (dragEl) { - if (this.nativeDraggable) { - _off(dragEl, 'dragend', this); - } - - _disableDraggable(dragEl); - dragEl.style['will-change'] = ''; - - // Remove class's - _toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); - _toggleClass(dragEl, this.options.chosenClass, false); - - // Drag stop event - _dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex, null, oldDraggableIndex, null, evt); - - if (rootEl !== parentEl) { - newIndex = _index(dragEl); - newDraggableIndex = _index(dragEl, options.draggable); - - if (newIndex >= 0) { - // Add event - _dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - - // Remove event - _dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - - // drag from one list and drop into another - _dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - } - - putSortable && putSortable.save(); - } - else { - if (dragEl.nextSibling !== nextEl) { - // Get the index of the dragged element within its parent - newIndex = _index(dragEl); - newDraggableIndex = _index(dragEl, options.draggable); - - if (newIndex >= 0) { - // drag & drop within the same list - _dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - } - } - } - - if (Sortable.active) { - /* jshint eqnull:true */ - if (newIndex == null || newIndex === -1) { - newIndex = oldIndex; - newDraggableIndex = oldDraggableIndex; - } - _dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, evt); - - // Save sorting - this.save(); - } - } - - } - this._nulling(); - }, - - _nulling: function() { - rootEl = - dragEl = - parentEl = - ghostEl = - nextEl = - cloneEl = - lastDownEl = - - scrollEl = - scrollParentEl = - autoScrolls.length = - - pointerElemChangedInterval = - lastPointerElemX = - lastPointerElemY = - - tapEvt = - touchEvt = - - moved = - newIndex = - oldIndex = - - lastTarget = - lastDirection = - - realDragElRect = - - putSortable = - activeGroup = - Sortable.active = null; - - savedInputChecked.forEach(function (el) { - el.checked = true; - }); - - savedInputChecked.length = 0; - }, - - handleEvent: function (/**Event*/evt) { - switch (evt.type) { - case 'drop': - case 'dragend': - this._onDrop(evt); - break; - - case 'dragenter': - case 'dragover': - if (dragEl) { - this._onDragOver(evt); - _globalDragOver(evt); - } - break; - - case 'selectstart': - evt.preventDefault(); - break; - } - }, - - - /** - * Serializes the item into an array of string. - * @returns {String[]} - */ - toArray: function () { - var order = [], - el, - children = this.el.children, - i = 0, - n = children.length, - options = this.options; - - for (; i < n; i++) { - el = children[i]; - if (_closest(el, options.draggable, this.el, false)) { - order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); - } - } - - return order; - }, - - - /** - * Sorts the elements according to the array. - * @param {String[]} order order of the items - */ - sort: function (order) { - var items = {}, rootEl = this.el; - - this.toArray().forEach(function (id, i) { - var el = rootEl.children[i]; - - if (_closest(el, this.options.draggable, rootEl, false)) { - items[id] = el; - } - }, this); - - order.forEach(function (id) { - if (items[id]) { - rootEl.removeChild(items[id]); - rootEl.appendChild(items[id]); - } - }); - }, - - - /** - * Save the current sorting - */ - save: function () { - var store = this.options.store; - store && store.set && store.set(this); - }, - - - /** - * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. - * @param {HTMLElement} el - * @param {String} [selector] default: `options.draggable` - * @returns {HTMLElement|null} - */ - closest: function (el, selector) { - return _closest(el, selector || this.options.draggable, this.el, false); - }, - - - /** - * Set/get option - * @param {string} name - * @param {*} [value] - * @returns {*} - */ - option: function (name, value) { - var options = this.options; - - if (value === void 0) { - return options[name]; - } else { - options[name] = value; - - if (name === 'group') { - _prepareGroup(options); - } - } - }, - - - /** - * Destroy - */ - destroy: function () { - var el = this.el; - - el[expando] = null; - - _off(el, 'mousedown', this._onTapStart); - _off(el, 'touchstart', this._onTapStart); - _off(el, 'pointerdown', this._onTapStart); - - if (this.nativeDraggable) { - _off(el, 'dragover', this); - _off(el, 'dragenter', this); - } - // Remove draggable attributes - Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { - el.removeAttribute('draggable'); - }); - - this._onDrop(); - - sortables.splice(sortables.indexOf(this.el), 1); - - this.el = el = null; - }, - - _hideClone: function() { - if (!cloneEl.cloneHidden) { - _css(cloneEl, 'display', 'none'); - cloneEl.cloneHidden = true; - if (cloneEl.parentNode && this.options.removeCloneOnHide) { - cloneEl.parentNode.removeChild(cloneEl); - } - } - }, - - _showClone: function(putSortable) { - if (putSortable.lastPutMode !== 'clone') { - this._hideClone(); - return; - } - - if (cloneEl.cloneHidden) { - // show clone at dragEl or original position - if (rootEl.contains(dragEl) && !this.options.group.revertClone) { - rootEl.insertBefore(cloneEl, dragEl); - } else if (nextEl) { - rootEl.insertBefore(cloneEl, nextEl); - } else { - rootEl.appendChild(cloneEl); - } - - if (this.options.group.revertClone) { - this._animate(dragEl, cloneEl); - } - _css(cloneEl, 'display', ''); - cloneEl.cloneHidden = false; - } - } - }; - - 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; - } - - - function _getParentOrHost(el) { - return (el.host && el !== document && el.host.nodeType) - ? el.host - : el.parentNode; - } - - - function _globalDragOver(/**Event*/evt) { - if (evt.dataTransfer) { - evt.dataTransfer.dropEffect = 'move'; - } - evt.cancelable && evt.preventDefault(); - } - - - function _on(el, event, fn) { - el.addEventListener(event, fn, IE11OrLess ? false : captureMode); - } - - - function _off(el, event, fn) { - el.removeEventListener(event, fn, IE11OrLess ? false : captureMode); - } - - - function _toggleClass(el, name, state) { - if (el && name) { - if (el.classList) { - el.classList[state ? 'add' : 'remove'](name); - } - else { - var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); - el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); - } - } - } - - - function _css(el, prop, val) { - var 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) { - var appliedTransforms = ''; - do { - var transform = _css(el, 'transform'); - - if (transform && transform !== 'none') { - appliedTransforms = transform + ' ' + appliedTransforms; - } - /* jshint boss:true */ - } while (el = el.parentNode); - - if (window.DOMMatrix) { - return new DOMMatrix(appliedTransforms); - } else if (window.WebKitCSSMatrix) { - return new WebKitCSSMatrix(appliedTransforms); - } else if (window.CSSMatrix) { - return new CSSMatrix(appliedTransforms); - } - } - - - function _find(ctx, tagName, iterator) { - if (ctx) { - var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length; - - if (iterator) { - for (; i < n; i++) { - iterator(list[i], i); - } - } - - return list; - } - - return []; - } - - - - function _dispatchEvent( - sortable, rootEl, name, - targetEl, toEl, fromEl, - startIndex, newIndex, - startDraggableIndex, newDraggableIndex, - originalEvt - ) { - sortable = (sortable || rootEl[expando]); - var evt, - options = sortable.options, - onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); - // Support for new CustomEvent feature - if (window.CustomEvent && !IE11OrLess && !Edge) { - evt = new CustomEvent(name, { - bubbles: true, - cancelable: true - }); - } else { - evt = document.createEvent('Event'); - evt.initEvent(name, true, true); - } - - evt.to = toEl || rootEl; - evt.from = fromEl || rootEl; - evt.item = targetEl || rootEl; - evt.clone = cloneEl; - - evt.oldIndex = startIndex; - evt.newIndex = newIndex; - - evt.oldDraggableIndex = startDraggableIndex; - evt.newDraggableIndex = newDraggableIndex; - - evt.originalEvent = originalEvt; - evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; - - if (rootEl) { - rootEl.dispatchEvent(evt); - } - - if (options[onName]) { - options[onName].call(sortable, evt); - } - } - - - function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt, willInsertAfter) { - var evt, - sortable = fromEl[expando], - onMoveFn = sortable.options.onMove, - retVal; - // Support for new CustomEvent feature - if (window.CustomEvent && !IE11OrLess && !Edge) { - evt = new CustomEvent('move', { - bubbles: true, - cancelable: true - }); - } else { - evt = document.createEvent('Event'); - evt.initEvent('move', true, true); - } - - evt.to = toEl; - evt.from = fromEl; - evt.dragged = dragEl; - evt.draggedRect = dragRect; - evt.related = targetEl || toEl; - evt.relatedRect = targetRect || _getRect(toEl); - evt.willInsertAfter = willInsertAfter; - - evt.originalEvent = originalEvt; - - fromEl.dispatchEvent(evt); - - if (onMoveFn) { - retVal = onMoveFn.call(sortable, evt, originalEvt); - } - - return retVal; - } - - function _disableDraggable(el) { - el.draggable = false; - } - - function _unsilent() { - _silent = 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) { - var currentChild = 0, - i = 0, - children = el.children; - - while (i < children.length) { - if ( - children[i].style.display !== 'none' && - children[i] !== ghostEl && - children[i] !== dragEl && - _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 - * @return {HTMLElement} The last child, ignoring ghostEl - */ - function _lastChild(el) { - var last = el.lastElementChild; - - while (last && (last === ghostEl || _css(last, 'display') === 'none')) { - last = last.previousElementSibling; - } - - return last || null; - } - - function _ghostIsLast(evt, axis, el) { - var elRect = _getRect(_lastChild(el)), - mouseOnAxis = axis === 'vertical' ? evt.clientY : evt.clientX, - mouseOnOppAxis = axis === 'vertical' ? evt.clientX : evt.clientY, - targetS2 = axis === 'vertical' ? elRect.bottom : elRect.right, - targetS1Opp = axis === 'vertical' ? elRect.left : elRect.top, - targetS2Opp = axis === 'vertical' ? elRect.right : elRect.bottom, - spacer = 10; - - return ( - axis === 'vertical' ? - (mouseOnOppAxis > targetS2Opp + spacer || mouseOnOppAxis <= targetS2Opp && mouseOnAxis > targetS2 && mouseOnOppAxis >= targetS1Opp) : - (mouseOnAxis > targetS2 && mouseOnOppAxis > targetS1Opp || mouseOnAxis <= targetS2 && mouseOnOppAxis > targetS2Opp + spacer) - ); - } - - function _getSwapDirection(evt, target, axis, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { - var targetRect = _getRect(target), - mouseOnAxis = axis === 'vertical' ? evt.clientY : evt.clientX, - targetLength = axis === 'vertical' ? targetRect.height : targetRect.width, - targetS1 = axis === 'vertical' ? targetRect.top : targetRect.left, - targetS2 = axis === 'vertical' ? targetRect.bottom : targetRect.right, - dragRect = _getRect(dragEl), - invert = false; - - - if (!invertSwap) { - // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold - if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 - // check if past first invert threshold on side opposite of lastDirection - if (!pastFirstInvertThresh && - (lastDirection === 1 ? - ( - mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 - ) : - ( - mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2 - ) - ) - ) - { - // past first invert threshold, do not restrict inverted threshold to dragEl shadow - pastFirstInvertThresh = true; - } - - if (!pastFirstInvertThresh) { - var dragS1 = axis === 'vertical' ? dragRect.top : dragRect.left, - dragS2 = axis === 'vertical' ? dragRect.bottom : dragRect.right; - // dragEl shadow (target move distance shadow) - if ( - lastDirection === 1 ? - ( - mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow - ) : - ( - mouseOnAxis > targetS2 - targetMoveDistance - ) - ) - { - return lastDirection * -1; - } - } else { - invert = true; - } - } else { - // Regular - if ( - mouseOnAxis > targetS1 + (targetLength * (1 - swapThreshold) / 2) && - mouseOnAxis < targetS2 - (targetLength * (1 - swapThreshold) / 2) - ) { - return _getInsertDirection(target); - } - } - } - - invert = invert || invertSwap; - - if (invert) { - // Invert of regular - if ( - mouseOnAxis < targetS1 + (targetLength * invertedSwapThreshold / 2) || - mouseOnAxis > targetS2 - (targetLength * invertedSwapThreshold / 2) - ) - { - return ((mouseOnAxis > targetS1 + targetLength / 2) ? 1 : -1); - } - } - - return 0; - } - - /** - * Gets the direction dragEl must be swapped relative to target in order to make it - * seem that dragEl has been "inserted" into that element's position - * @param {HTMLElement} target The target whose position dragEl is being inserted at - * @return {Number} Direction dragEl must be swapped - */ - function _getInsertDirection(target) { - var dragElIndex = _index(dragEl), - targetIndex = _index(target); - - if (dragElIndex < targetIndex) { - return 1; - } else { - return -1; - } - } - - - /** - * Generate id - * @param {HTMLElement} el - * @returns {String} - * @private - */ - function _generateId(el) { - var str = el.tagName + el.className + el.src + el.href + el.textContent, - i = str.length, - sum = 0; - - while (i--) { - sum += str.charCodeAt(i); - } - - return sum.toString(36); - } - - /** - * 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) { - var index = 0; - - if (!el || !el.parentNode) { - return -1; - } - - while (el && (el = el.previousElementSibling)) { - if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && el !== cloneEl && (!selector || _matches(el, selector))) { - index++; - } - } - - return index; - } - - 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; - } - - var _throttleTimeout; - function _throttle(callback, ms) { - return function () { - if (!_throttleTimeout) { - var args = arguments, - _this = this; - - _throttleTimeout = setTimeout(function () { - if (args.length === 1) { - callback.call(_this, args[0]); - } else { - callback.apply(_this, args); - } - - _throttleTimeout = void 0; - }, ms); - } - }; - } - - function _cancelThrottle() { - clearTimeout(_throttleTimeout); - _throttleTimeout = void 0; - } - - function _extend(dst, src) { - if (dst && src) { - for (var key in src) { - if (src.hasOwnProperty(key)) { - dst[key] = src[key]; - } - } - } - - return dst; - } - - function _clone(el) { - if (Polymer && Polymer.dom) { - return Polymer.dom(el).cloneNode(true); - } - else if ($) { - return $(el).clone(true)[0]; - } - else { - return el.cloneNode(true); - } - } - - function _saveInputCheckedState(root) { - savedInputChecked.length = 0; - - var inputs = root.getElementsByTagName('input'); - var idx = inputs.length; - - while (idx--) { - var el = inputs[idx]; - el.checked && savedInputChecked.push(el); - } - } - - function _nextTick(fn) { - return setTimeout(fn, 0); - } - - function _cancelNextTick(id) { - return clearTimeout(id); - } - - - /** - * Returns the "bounding client rect" of given element - * @param {HTMLElement} el The element whose boundingClientRect is wanted - * @param {[HTMLElement]} container the parent the element will be placed in - * @param {[Boolean]} adjustForTransform Whether the rect should compensate for parent's transform - * @return {Object} The boundingClientRect of el - */ - function _getRect(el, adjustForTransform, container, adjustForFixed) { - if (!el.getBoundingClientRect && el !== win) return; - - var elRect, - top, - left, - bottom, - right, - height, - width; - - if (el !== win && 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 (adjustForFixed && el !== win) { - // 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') { - var 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 (adjustForTransform && el !== win) { - // Adjust for scale() - var matrix = _matrix(container || el), - scaleX = matrix && matrix.a, - scaleY = matrix && matrix.d; - - if (matrix) { - 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 it's parents - * @param {HTMLElement} el The element who's side being scrolled out of view is in question - * @param {String} side Side of the element 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, side) { - var parent = _getParentAutoScrollElement(el, true), - elSide = _getRect(el)[side]; - - /* jshint boss:true */ - while (parent) { - var parentSide = _getRect(parent)[side], - visible; - - if (side === 'top' || side === 'left') { - visible = elSide >= parentSide; - } else { - visible = elSide <= parentSide; - } - - if (!visible) return parent; - - if (parent === _getWindowScrollingElement()) break; - - parent = _getParentAutoScrollElement(parent, false); - } - - return false; - } - - /** - * 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) { - var offsetLeft = 0, - offsetTop = 0, - winScroller = _getWindowScrollingElement(); - - if (el) { - do { - var matrix = _matrix(el), - scaleX = matrix.a, - scaleY = matrix.d; - - offsetLeft += el.scrollLeft * scaleX; - offsetTop += el.scrollTop * scaleY; - } while (el !== winScroller && (el = el.parentNode)); - } - - return [offsetLeft, offsetTop]; - } - - // Fixed #973: - _on(document, 'touchmove', function(evt) { - if ((Sortable.active || awaitingDragStarted) && evt.cancelable) { - evt.preventDefault(); - } - }); - - - // Export utils - Sortable.utils = { - on: _on, - off: _off, - css: _css, - find: _find, - is: function (el, selector) { - return !!_closest(el, selector, el, false); - }, - extend: _extend, - throttle: _throttle, - closest: _closest, - toggleClass: _toggleClass, - clone: _clone, - index: _index, - nextTick: _nextTick, - cancelNextTick: _cancelNextTick, - detectDirection: _detectDirection, - getChild: _getChild - }; - - - /** - * Create sortable instance - * @param {HTMLElement} el - * @param {Object} [options] - */ - Sortable.create = function (el, options) { - return new Sortable(el, options); - }; - - - // Export - Sortable.version = '1.9.0'; - return Sortable; -}); + if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list + : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) { + vertical = this._getDirection(evt, target) === 'vertical'; + dragRect = getRect(dragEl); + dragOverEvent('dragOverValid'); + if (Sortable$1.eventCanceled) return completedFired; + + if (revert) { + parentEl = rootEl; // actualization + + capture(); + + this._hideClone(); + + dragOverEvent('revert'); + + if (!Sortable$1.eventCanceled) { + if (nextEl) { + rootEl.insertBefore(dragEl, nextEl); + } else { + rootEl.appendChild(dragEl); + } + } + + return completed(true); + } + + var elLastChild = lastChild(el, options.draggable); + + if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) { + // If already at end of list: Do not insert + if (elLastChild === dragEl) { + return completed(false); + } // assign target only if condition is true + + + if (elLastChild && el === evt.target) { + target = elLastChild; + } + + if (target) { + targetRect = getRect(target); + } + + if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { + capture(); + el.appendChild(dragEl); + parentEl = el; // actualization + + changed(); + return completed(true); + } + } else if (target.parentNode === el) { + var direction = 0, + targetBeforeFirstSwap, + differentLevel = dragEl.parentNode !== el, + side1 = vertical ? 'top' : 'left', + scrolledPastTop = isScrolledPast(target, null, 'top', 'top') || isScrolledPast(dragEl, null, 'top', 'top'), + scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; + + if (lastTarget !== target) { + targetBeforeFirstSwap = getRect(target)[side1]; + pastFirstInvertThresh = false; + isCircumstantialInvert = options.invertSwap || differentLevel; + } + + direction = _getSwapDirection(evt, target, vertical, options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target); + var sibling; + + if (direction !== 0) { + // Check if target is beside dragEl in respective direction (ignoring hidden elements) + var dragIndex = index(dragEl); + + do { + dragIndex -= direction; + sibling = parentEl.children[dragIndex]; + } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl)); + } // If dragEl is already beside target: Do not insert + + + if (direction === 0 || sibling === target) { + return completed(false); + } + + lastTarget = target; + lastDirection = direction; + targetRect = getRect(target); + var nextSibling = target.nextElementSibling, + after = false; + after = direction === 1; + + var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); + + if (moveVector !== false) { + if (moveVector === 1 || moveVector === -1) { + after = moveVector === 1; + } + + _silent = true; + setTimeout(_unsilent, 30); + capture(); + + if (after && !nextSibling) { + el.appendChild(dragEl); + } else { + target.parentNode.insertBefore(dragEl, after ? nextSibling : target); + } // Undo chrome's scroll adjustment (has no effect on other browsers) + + + if (scrolledPastTop) { + scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); + } + + parentEl = dragEl.parentNode; // actualization + // must be done before animation + + if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { + targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]); + } + + changed(); + return completed(true); + } + } + + if (el.contains(dragEl)) { + return completed(false); + } + } + + return false; + }, + _ignoreWhileAnimating: null, + _offMoveEvents: function _offMoveEvents() { + off(document, 'mousemove', this._onTouchMove); + off(document, 'touchmove', this._onTouchMove); + off(document, 'pointermove', this._onTouchMove); + off(document, 'dragover', nearestEmptyInsertDetectEvent); + off(document, 'mousemove', nearestEmptyInsertDetectEvent); + off(document, 'touchmove', nearestEmptyInsertDetectEvent); + }, + _offUpEvents: function _offUpEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._onDrop); + off(ownerDocument, 'touchend', this._onDrop); + off(ownerDocument, 'pointerup', this._onDrop); + off(ownerDocument, 'touchcancel', this._onDrop); + off(document, 'selectstart', this); + }, + _onDrop: function _onDrop( + /**Event*/ + evt) { + var el = this.el, + options = this.options; // Get the index of the dragged element within its parent + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + pluginEvent('drop', this, { + evt: evt + }); // Get again after plugin event + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + if (Sortable$1.eventCanceled) { + this._nulling(); + + return; + } + + awaitingDragStarted = false; + isCircumstantialInvert = false; + pastFirstInvertThresh = false; + clearInterval(this._loopId); + clearTimeout(this._dragStartTimer); + + _cancelNextTick(this.cloneId); + + _cancelNextTick(this._dragStartId); // Unbind events + + + if (this.nativeDraggable) { + off(document, 'drop', this); + off(el, 'dragstart', this._onDragStart); + } + + this._offMoveEvents(); + + this._offUpEvents(); + + if (Safari) { + css(document.body, 'user-select', ''); + } + + if (evt) { + if (moved) { + evt.cancelable && evt.preventDefault(); + !options.dropBubble && evt.stopPropagation(); + } + + ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + // Remove clone(s) + cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); + } + + if (dragEl) { + if (this.nativeDraggable) { + off(dragEl, 'dragend', this); + } + + _disableDraggable(dragEl); + + dragEl.style['will-change'] = ''; // Remove classes + // ghostClass is added in dragStarted + + if (moved && !awaitingDragStarted) { + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); + } + + toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event + + _dispatchEvent({ + sortable: this, + name: 'unchoose', + toEl: parentEl, + newIndex: null, + newDraggableIndex: null, + originalEvent: evt + }); + + if (rootEl !== parentEl) { + if (newIndex >= 0) { + // Add event + _dispatchEvent({ + rootEl: parentEl, + name: 'add', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); // Remove event + + + _dispatchEvent({ + sortable: this, + name: 'remove', + toEl: parentEl, + originalEvent: evt + }); // drag from one list and drop into another + + + _dispatchEvent({ + rootEl: parentEl, + name: 'sort', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + + putSortable && putSortable.save(); + } else { + if (newIndex !== oldIndex) { + if (newIndex >= 0) { + // drag & drop within the same list + _dispatchEvent({ + sortable: this, + name: 'update', + toEl: parentEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + } + } + + if (Sortable$1.active) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { + newIndex = oldIndex; + newDraggableIndex = oldDraggableIndex; + } + + _dispatchEvent({ + sortable: this, + name: 'end', + toEl: parentEl, + originalEvent: evt + }); // Save sorting + + + this.save(); + } + } + } + + this._nulling(); + }, + _nulling: function _nulling() { + pluginEvent('nulling', this); + rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable$1.dragged = Sortable$1.ghost = Sortable$1.clone = Sortable$1.active = null; + savedInputChecked.forEach(function (el) { + el.checked = true; + }); + savedInputChecked.length = 0; + }, + handleEvent: function handleEvent( + /**Event*/ + evt) { + switch (evt.type) { + case 'drop': + case 'dragend': + this._onDrop(evt); + + break; + + case 'dragenter': + case 'dragover': + if (dragEl) { + this._onDragOver(evt); + + _globalDragOver(evt); + } + + break; + + case 'selectstart': + evt.preventDefault(); + break; + } + }, + + /** + * Serializes the item into an array of string. + * @returns {String[]} + */ + toArray: function toArray() { + var order = [], + el, + children = this.el.children, + i = 0, + n = children.length, + options = this.options; + + for (; i < n; i++) { + el = children[i]; + + if (closest(el, options.draggable, this.el, false)) { + order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); + } + } + + return order; + }, + + /** + * Sorts the elements according to the array. + * @param {String[]} order order of the items + */ + sort: function sort(order) { + var items = {}, + rootEl = this.el; + this.toArray().forEach(function (id, i) { + var el = rootEl.children[i]; + + if (closest(el, this.options.draggable, rootEl, false)) { + items[id] = el; + } + }, this); + order.forEach(function (id) { + if (items[id]) { + rootEl.removeChild(items[id]); + rootEl.appendChild(items[id]); + } + }); + }, + + /** + * Save the current sorting + */ + save: function save() { + var store = this.options.store; + store && store.set && store.set(this); + }, + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * @param {HTMLElement} el + * @param {String} [selector] default: `options.draggable` + * @returns {HTMLElement|null} + */ + closest: function closest$1(el, selector) { + return closest(el, selector || this.options.draggable, this.el, false); + }, + + /** + * Set/get option + * @param {string} name + * @param {*} [value] + * @returns {*} + */ + option: function option(name, value) { + var options = this.options; + + if (value === void 0) { + return options[name]; + } else { + var modifiedValue = PluginManager.modifyOption(this, name, value); + + if (typeof modifiedValue !== 'undefined') { + options[name] = modifiedValue; + } else { + options[name] = value; + } + + if (name === 'group') { + _prepareGroup(options); + } + } + }, + + /** + * Destroy + */ + destroy: function destroy() { + pluginEvent('destroy', this); + var el = this.el; + el[expando] = null; + off(el, 'mousedown', this._onTapStart); + off(el, 'touchstart', this._onTapStart); + off(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + off(el, 'dragover', this); + off(el, 'dragenter', this); + } // Remove draggable attributes + + + Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { + el.removeAttribute('draggable'); + }); + + this._onDrop(); + + sortables.splice(sortables.indexOf(this.el), 1); + this.el = el = null; + }, + _hideClone: function _hideClone() { + if (!cloneHidden) { + pluginEvent('hideClone', this); + if (Sortable$1.eventCanceled) return; + css(cloneEl, 'display', 'none'); + + if (this.options.removeCloneOnHide && cloneEl.parentNode) { + cloneEl.parentNode.removeChild(cloneEl); + } + + cloneHidden = true; + } + }, + _showClone: function _showClone(putSortable) { + if (putSortable.lastPutMode !== 'clone') { + this._hideClone(); + + return; + } + + if (cloneHidden) { + pluginEvent('showClone', this); + if (Sortable$1.eventCanceled) return; // show clone at dragEl or original position + + if (rootEl.contains(dragEl) && !this.options.group.revertClone) { + rootEl.insertBefore(cloneEl, dragEl); + } else if (nextEl) { + rootEl.insertBefore(cloneEl, nextEl); + } else { + rootEl.appendChild(cloneEl); + } + + if (this.options.group.revertClone) { + this._animate(dragEl, cloneEl); + } + + css(cloneEl, 'display', ''); + cloneHidden = false; + } + } + }; + + function _globalDragOver( + /**Event*/ + evt) { + if (evt.dataTransfer) { + evt.dataTransfer.dropEffect = 'move'; + } + + evt.cancelable && evt.preventDefault(); + } + + function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) { + var evt, + sortable = fromEl[expando], + onMoveFn = sortable.options.onMove, + retVal; // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent('move', { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent('move', true, true); + } + + evt.to = toEl; + evt.from = fromEl; + evt.dragged = dragEl; + evt.draggedRect = dragRect; + evt.related = targetEl || toEl; + evt.relatedRect = targetRect || getRect(toEl); + evt.willInsertAfter = willInsertAfter; + evt.originalEvent = originalEvent; + fromEl.dispatchEvent(evt); + + if (onMoveFn) { + retVal = onMoveFn.call(sortable, evt, originalEvent); + } + + return retVal; + } + + function _disableDraggable(el) { + el.draggable = false; + } + + function _unsilent() { + _silent = false; + } + + function _ghostIsLast(evt, vertical, sortable) { + var elRect = getRect(lastChild(sortable.el, sortable.options.draggable)), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + mouseOnOppAxis = vertical ? evt.clientX : evt.clientY, + targetS2 = vertical ? elRect.bottom : elRect.right, + targetS1Opp = vertical ? elRect.left : elRect.top, + targetS2Opp = vertical ? elRect.right : elRect.bottom; + return mouseOnAxis > targetS2 && mouseOnOppAxis > targetS1Opp && mouseOnOppAxis < targetS2Opp; + } + + function _getSwapDirection(evt, target, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { + var targetRect = getRect(target), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + targetLength = vertical ? targetRect.height : targetRect.width, + targetS1 = vertical ? targetRect.top : targetRect.left, + targetS2 = vertical ? targetRect.bottom : targetRect.right, + invert = false; + + if (!invertSwap) { + // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold + if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { + // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 + // check if past first invert threshold on side opposite of lastDirection + if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) { + // past first invert threshold, do not restrict inverted threshold to dragEl shadow + pastFirstInvertThresh = true; + } + + if (!pastFirstInvertThresh) { + // dragEl shadow (target move distance shadow) + if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow + : mouseOnAxis > targetS2 - targetMoveDistance) { + return -lastDirection; + } + } else { + invert = true; + } + } else { + // Regular + if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) { + return _getInsertDirection(target); + } + } + } + + invert = invert || invertSwap; + + if (invert) { + // Invert of regular + if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) { + return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1; + } + } + + return 0; + } + /** + * Gets the direction dragEl must be swapped relative to target in order to make it + * seem that dragEl has been "inserted" into that element's position + * @param {HTMLElement} target The target whose position dragEl is being inserted at + * @return {Number} Direction dragEl must be swapped + */ + + + function _getInsertDirection(target) { + if (index(dragEl) < index(target)) { + return 1; + } else { + return -1; + } + } + /** + * Generate id + * @param {HTMLElement} el + * @returns {String} + * @private + */ + + + function _generateId(el) { + var str = el.tagName + el.className + el.src + el.href + el.textContent, + i = str.length, + sum = 0; + + while (i--) { + sum += str.charCodeAt(i); + } + + return sum.toString(36); + } + + function _saveInputCheckedState(root) { + savedInputChecked.length = 0; + var inputs = root.getElementsByTagName('input'); + var idx = inputs.length; + + while (idx--) { + var _el = inputs[idx]; + _el.checked && savedInputChecked.push(_el); + } + } + + function _nextTick(fn) { + return setTimeout(fn, 0); + } + + function _cancelNextTick(id) { + return clearTimeout(id); + } // Fixed #973: + + + on(document, 'touchmove', function (evt) { + if ((Sortable$1.active || awaitingDragStarted) && evt.cancelable) { + evt.preventDefault(); + } + }); // Export utils + + Sortable$1.utils = { + on: on, + off: off, + css: css, + find: find, + is: function is(el, selector) { + return !!closest(el, selector, el, false); + }, + extend: extend, + throttle: throttle, + closest: closest, + toggleClass: toggleClass, + clone: clone, + index: index, + nextTick: _nextTick, + cancelNextTick: _cancelNextTick, + detectDirection: _detectDirection, + getChild: getChild + }; + /** + * Mount a plugin to Sortable + * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted + */ + + Sortable$1.mount = function () { + for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) { + plugins[_key] = arguments[_key]; + } + + if (plugins[0].constructor === Array) plugins = plugins[0]; + + for (var i in plugins) { + var plugin = plugins[i]; + + if (!plugin.prototype || !plugin.prototype.constructor) { + throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(el)); + } + + if (plugin.utils) Sortable$1.utils = _objectSpread({}, Sortable$1.utils, plugin.utils); + PluginManager.mount(plugin); + } + }; + /** + * Create sortable instance + * @param {HTMLElement} el + * @param {Object} [options] + */ + + + Sortable$1.create = function (el, options) { + return new Sortable$1(el, options); + }; // Export + + + Sortable$1.version = version; + + var autoScrolls = [], + scrollEl, + scrollRootEl, + scrolling = false, + lastAutoScrollX, + lastAutoScrollY, + touchEvt$1, + pointerElemChangedInterval; + + function AutoScrollPlugin() { + function AutoScroll() { + this.options = { + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, + bubbleScroll: true + }; // Bind all private methods + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + } + + AutoScroll.prototype = { + dragStarted: function dragStarted(_ref) { + var originalEvent = _ref.originalEvent; + + if (this.sortable.nativeDraggable) { + on(document, 'dragover', this._handleAutoScroll); + } else { + if (this.sortable.options.supportPointer) { + on(document, 'pointermove', this._handleFallbackAutoScroll); + } else if (originalEvent.touches) { + on(document, 'touchmove', this._handleFallbackAutoScroll); + } else { + on(document, 'mousemove', this._handleFallbackAutoScroll); + } + } + }, + dragOverCompleted: function dragOverCompleted(_ref2) { + var originalEvent = _ref2.originalEvent; + + // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) + if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) { + this._handleAutoScroll(originalEvent); + } + }, + drop: function drop() { + if (this.sortable.nativeDraggable) { + off(document, 'dragover', this._handleAutoScroll); + } else { + off(document, 'pointermove', this._handleFallbackAutoScroll); + off(document, 'touchmove', this._handleFallbackAutoScroll); + off(document, 'mousemove', this._handleFallbackAutoScroll); + } + + clearPointerElemChangedInterval(); + clearAutoScrolls(); + cancelThrottle(); + }, + nulling: function nulling() { + touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null; + autoScrolls.length = 0; + }, + _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) { + this._handleAutoScroll(evt, true); + }, + _handleAutoScroll: function _handleAutoScroll(evt, fallback) { + var _this = this; + + var x = evt.clientX, + y = evt.clientY, + elem = document.elementFromPoint(x, y); + touchEvt$1 = evt; // IE does not seem to have native autoscroll, + // Edge's autoscroll seems too conditional, + // MACOS Safari does not have autoscroll, + // Firefox and Chrome are good + + if (fallback || Edge || IE11OrLess || Safari) { + autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change + + var ogElemScroller = getParentAutoScrollElement(elem, true); + + if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) { + pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour + + pointerElemChangedInterval = setInterval(function () { + var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true); + + if (newElem !== ogElemScroller) { + ogElemScroller = newElem; + clearAutoScrolls(); + } + + autoScroll(evt, _this.options, newElem, fallback); + }, 10); + lastAutoScrollX = x; + lastAutoScrollY = y; + } + } else { + // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll + if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) { + clearAutoScrolls(); + return; + } + + autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false); + } + } + }; + return _extends(AutoScroll, { + pluginName: 'scroll', + initializeByDefault: true + }); + } + + function clearAutoScrolls() { + autoScrolls.forEach(function (autoScroll) { + clearInterval(autoScroll.pid); + }); + autoScrolls = []; + } + + function clearPointerElemChangedInterval() { + clearInterval(pointerElemChangedInterval); + } + + var autoScroll = throttle(function (evt, options, rootEl, isFallback) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + if (!options.scroll) return; + var sens = options.scrollSensitivity, + speed = options.scrollSpeed, + winScroller = getWindowScrollingElement(); + var scrollThisInstance = false, + scrollCustomFn; // New scroll root, set scrollEl + + if (scrollRootEl !== rootEl) { + scrollRootEl = rootEl; + clearAutoScrolls(); + scrollEl = options.scroll; + scrollCustomFn = options.scrollFn; + + if (scrollEl === true) { + scrollEl = getParentAutoScrollElement(rootEl, true); + } + } + + var layersOut = 0; + var currentParent = scrollEl; + + do { + var el = currentParent, + rect = getRect(el), + top = rect.top, + bottom = rect.bottom, + left = rect.left, + right = rect.right, + width = rect.width, + height = rect.height, + canScrollX = void 0, + canScrollY = void 0, + scrollWidth = el.scrollWidth, + scrollHeight = el.scrollHeight, + elCSS = css(el), + scrollPosX = el.scrollLeft, + scrollPosY = el.scrollTop; + + if (el === winScroller) { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible'); + } else { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll'); + } + + var vx = canScrollX && (Math.abs(right - evt.clientX) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - evt.clientX) <= sens && !!scrollPosX); + var vy = canScrollY && (Math.abs(bottom - evt.clientY) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - evt.clientY) <= sens && !!scrollPosY); + + if (!autoScrolls[layersOut]) { + for (var i = 0; i <= layersOut; i++) { + if (!autoScrolls[i]) { + autoScrolls[i] = {}; + } + } + } + + if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { + autoScrolls[layersOut].el = el; + autoScrolls[layersOut].vx = vx; + autoScrolls[layersOut].vy = vy; + clearInterval(autoScrolls[layersOut].pid); + + if (vx != 0 || vy != 0) { + scrollThisInstance = true; + /* jshint loopfunc:true */ + + autoScrolls[layersOut].pid = setInterval(function () { + // emulate drag over during autoscroll (fallback), emulating native DnD behaviour + if (isFallback && this.layer === 0) { + Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely + + } + + var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; + var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; + + if (typeof scrollCustomFn === 'function') { + if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') { + return; + } + } + + scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); + }.bind({ + layer: layersOut + }), 24); + } + } + + layersOut++; + } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false))); + + scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not + }, 30); + + var drop = function drop(_ref) { + var originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + dragEl = _ref.dragEl, + activeSortable = _ref.activeSortable, + dispatchSortableEvent = _ref.dispatchSortableEvent, + hideGhostForTarget = _ref.hideGhostForTarget, + unhideGhostForTarget = _ref.unhideGhostForTarget; + var toSortable = putSortable || activeSortable; + hideGhostForTarget(); + var target = document.elementFromPoint(originalEvent.clientX, originalEvent.clientY); + unhideGhostForTarget(); + + if (toSortable && !toSortable.el.contains(target)) { + dispatchSortableEvent('spill'); + this.onSpill(dragEl); + } + }; + + function Revert() {} + + Revert.prototype = { + startIndex: null, + dragStart: function dragStart(_ref2) { + var oldDraggableIndex = _ref2.oldDraggableIndex; + this.startIndex = oldDraggableIndex; + }, + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + var nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options); + + if (nextSibling) { + this.sortable.el.insertBefore(dragEl, nextSibling); + } else { + this.sortable.el.appendChild(dragEl); + } + + this.sortable.animateAll(); + }, + drop: drop + }; + + _extends(Revert, { + pluginName: 'revertOnSpill' + }); + + function Remove() {} + + Remove.prototype = { + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + dragEl.parentNode && dragEl.parentNode.removeChild(dragEl); + this.sortable.animateAll(); + }, + drop: drop + }; + + _extends(Remove, { + pluginName: 'removeOnSpill' + }); + + var lastSwapEl; + + function SwapPlugin() { + function Swap() { + this.options = { + swapClass: 'sortable-swap-highlight' + }; + } + + Swap.prototype = { + dragStart: function dragStart(_ref) { + var dragEl = _ref.dragEl; + lastSwapEl = dragEl; + }, + dragOverValid: function dragOverValid(_ref2) { + var completed = _ref2.completed, + target = _ref2.target, + onMove = _ref2.onMove, + activeSortable = _ref2.activeSortable, + changed = _ref2.changed; + if (!activeSortable.options.swap) return; + var el = this.sortable.el, + options = this.sortable.options; + + if (target && target !== el) { + var prevSwapEl = lastSwapEl; + + if (onMove(target) !== false) { + toggleClass(target, options.swapClass, true); + lastSwapEl = target; + } else { + lastSwapEl = null; + } + + if (prevSwapEl && prevSwapEl !== lastSwapEl) { + toggleClass(prevSwapEl, options.swapClass, false); + } + } + + changed(); + return completed(true); + }, + drop: function drop(_ref3) { + var activeSortable = _ref3.activeSortable, + putSortable = _ref3.putSortable, + dragEl = _ref3.dragEl; + var toSortable = putSortable || this.sortable; + var options = this.sortable.options; + lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false); + + if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) { + if (dragEl !== lastSwapEl) { + toSortable.captureAnimationState(); + if (toSortable !== activeSortable) activeSortable.captureAnimationState(); + swapNodes(dragEl, lastSwapEl); + toSortable.animateAll(); + if (toSortable !== activeSortable) activeSortable.animateAll(); + } + } + }, + nulling: function nulling() { + lastSwapEl = null; + } + }; + return _extends(Swap, { + pluginName: 'swap', + eventOptions: function eventOptions() { + return { + swapItem: lastSwapEl + }; + } + }); + } + + function swapNodes(n1, n2) { + var p1 = n1.parentNode, + p2 = n2.parentNode, + i1, + i2; + if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return; + i1 = index(n1); + i2 = index(n2); + + if (p1.isEqualNode(p2) && i1 < i2) { + i2++; + } + + p1.insertBefore(n2, p1.children[i1]); + p2.insertBefore(n1, p2.children[i2]); + } + + var multiDragElements = [], + multiDragClones = [], + lastMultiDragSelect, + // for selection with modifier key down (SHIFT) + multiDragSortable, + initialFolding = false, + // Initial multi-drag fold when drag started + folding = false, + // Folding any other time + dragStarted = false, + dragEl$1, + clonesFromRect, + clonesHidden; + + function MultiDragPlugin() { + function MultiDrag(sortable) { + // Bind all private methods + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + if (sortable.options.supportPointer) { + on(document, 'pointerup', this._deselectMultiDrag); + } else { + on(document, 'mouseup', this._deselectMultiDrag); + on(document, 'touchend', this._deselectMultiDrag); + } + + on(document, 'keydown', this._checkKeyDown); + on(document, 'keyup', this._checkKeyUp); + this.options = { + selectedClass: 'sortable-selected', + multiDragKey: null, + setData: function setData(dataTransfer, dragEl) { + var data = ''; + + if (multiDragElements.length && multiDragSortable === sortable) { + for (var i in multiDragElements) { + data += (!i ? '' : ', ') + multiDragElements[i].textContent; + } + } else { + data = dragEl.textContent; + } + + dataTransfer.setData('Text', data); + } + }; + } + + MultiDrag.prototype = { + multiDragKeyDown: false, + isMultiDrag: false, + delayStartGlobal: function delayStartGlobal(_ref) { + var dragged = _ref.dragEl; + dragEl$1 = dragged; + }, + delayEnded: function delayEnded() { + this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1); + }, + setupClone: function setupClone(_ref2) { + var sortable = _ref2.sortable; + if (!this.isMultiDrag) return; + + for (var i in multiDragElements) { + multiDragClones.push(clone(multiDragElements[i])); + multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex; + multiDragClones[i].draggable = false; + multiDragClones[i].style['will-change'] = ''; + toggleClass(multiDragClones[i], sortable.options.selectedClass, false); + multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], sortable.options.chosenClass, false); + } + + sortable._hideClone(); + + return true; + }, + clone: function clone(_ref3) { + var sortable = _ref3.sortable, + rootEl = _ref3.rootEl, + dispatchSortableEvent = _ref3.dispatchSortableEvent; + if (!this.isMultiDrag) return; + + if (!sortable.options.removeCloneOnHide) { + if (multiDragElements.length && multiDragSortable === sortable) { + insertMultiDragClones(true, rootEl); + dispatchSortableEvent('clone'); + return true; + } + } + }, + showClone: function showClone(_ref4) { + var cloneNowShown = _ref4.cloneNowShown, + rootEl = _ref4.rootEl; + if (!this.isMultiDrag) return; + insertMultiDragClones(false, rootEl); + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', ''); + } + + cloneNowShown(); + clonesHidden = false; + return true; + }, + hideClone: function hideClone(_ref5) { + var sortable = _ref5.sortable, + cloneNowHidden = _ref5.cloneNowHidden; + if (!this.isMultiDrag) return; + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', 'none'); + + if (sortable.options.removeCloneOnHide && multiDragClones[i].parentNode) { + multiDragClones[i].parentNode.removeChild(multiDragClones[i]); + } + } + + cloneNowHidden(); + clonesHidden = true; + return true; + }, + dragStartGlobal: function dragStartGlobal(_ref6) { + var sortable = _ref6.sortable; + + if (!this.isMultiDrag && multiDragSortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + } + + for (var i in multiDragElements) { + multiDragElements[i].sortableIndex = index(multiDragElements[i]); + } // Sort multi-drag elements + + + multiDragElements = multiDragElements.sort(function (a, b) { + return a.sortableIndex - b.sortableIndex; + }); + dragStarted = true; + }, + dragStarted: function dragStarted(_ref7) { + var sortable = _ref7.sortable; + if (!this.isMultiDrag) return; + + if (sortable.options.sort) { + // Capture rects, + // hide multi drag elements (by positioning them absolute), + // set multi drag elements rects to dragRect, + // show multi drag elements, + // animate to rects, + // unset rects & remove from DOM + sortable.captureAnimationState(); + + if (sortable.options.animation) { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + css(multiDragElements[i], 'position', 'absolute'); + } + + var dragRect = getRect(dragEl$1, false, true, true); + + for (var _i in multiDragElements) { + if (multiDragElements[_i] === dragEl$1) continue; + setRect(multiDragElements[_i], dragRect); + } + + folding = true; + initialFolding = true; + } + } + + sortable.animateAll(function () { + folding = false; + initialFolding = false; + + if (sortable.options.animation) { + for (var _i2 in multiDragElements) { + unsetRect(multiDragElements[_i2]); + } + } // Remove all auxiliary multidrag items from el, if sorting enabled + + + if (sortable.options.sort) { + removeMultiDragElements(); + } + }); + }, + dragOver: function dragOver(_ref8) { + var target = _ref8.target, + completed = _ref8.completed; + + if (folding && ~multiDragElements.indexOf(target)) { + return completed(false); + } + }, + revert: function revert(_ref9) { + var fromSortable = _ref9.fromSortable, + rootEl = _ref9.rootEl, + sortable = _ref9.sortable, + dragRect = _ref9.dragRect; + + if (multiDragElements.length > 1) { + // Setup unfold animation + for (var i in multiDragElements) { + sortable.addAnimationState({ + target: multiDragElements[i], + rect: folding ? getRect(multiDragElements[i]) : dragRect + }); + unsetRect(multiDragElements[i]); + multiDragElements[i].fromRect = dragRect; + fromSortable.removeAnimationState(multiDragElements[i]); + } + + folding = false; + insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl); + } + }, + dragOverCompleted: function dragOverCompleted(_ref10) { + var sortable = _ref10.sortable, + isOwner = _ref10.isOwner, + insertion = _ref10.insertion, + activeSortable = _ref10.activeSortable, + parentEl = _ref10.parentEl, + putSortable = _ref10.putSortable; + var options = sortable.options; + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } + + initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location + + if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) { + // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible + var dragRectAbsolute = getRect(dragEl$1, false, true, true); + + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + setRect(multiDragElements[i], dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted + // while folding, and so that we can capture them again because old sortable will no longer be fromSortable + + parentEl.appendChild(multiDragElements[i]); + } + + folding = true; + } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out + + + if (!isOwner) { + // Only remove if not folding (folding will remove them anyways) + if (!folding) { + removeMultiDragElements(); + } + + if (multiDragElements.length > 1) { + var clonesHiddenBefore = clonesHidden; + + activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden + + + if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) { + for (var _i3 in multiDragClones) { + activeSortable.addAnimationState({ + target: multiDragClones[_i3], + rect: clonesFromRect + }); + multiDragClones[_i3].fromRect = clonesFromRect; + multiDragClones[_i3].thisAnimationDuration = null; + } + } + } else { + activeSortable._showClone(sortable); + } + } + } + }, + dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) { + var dragRect = _ref11.dragRect, + isOwner = _ref11.isOwner, + activeSortable = _ref11.activeSortable; + + for (var i in multiDragElements) { + multiDragElements[i].thisAnimationDuration = null; + } + + if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) { + clonesFromRect = _extends({}, dragRect); + var dragMatrix = matrix(dragEl$1, true); + clonesFromRect.top -= dragMatrix.f; + clonesFromRect.left -= dragMatrix.e; + } + }, + dragOverAnimationComplete: function dragOverAnimationComplete() { + if (folding) { + folding = false; + removeMultiDragElements(); + } + }, + drop: function drop(_ref12) { + var evt = _ref12.originalEvent, + rootEl = _ref12.rootEl, + parentEl = _ref12.parentEl, + sortable = _ref12.sortable, + dispatchSortableEvent = _ref12.dispatchSortableEvent, + oldIndex = _ref12.oldIndex, + putSortable = _ref12.putSortable; + var toSortable = putSortable || this.sortable; + if (!evt) return; + var options = sortable.options, + children = parentEl.children; // Multi-drag selection + + if (!dragStarted) { + if (options.multiDragKey && !this.multiDragKeyDown) { + this._deselectMultiDrag(); + } + + toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1)); + + if (!~multiDragElements.indexOf(dragEl$1)) { + multiDragElements.push(dragEl$1); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: dragEl$1, + originalEvt: evt + }); // Modifier activated, select from last to dragEl + + if ((!options.multiDragKey || this.multiDragKeyDown) && evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) { + var lastIndex = index(lastMultiDragSelect), + currentIndex = index(dragEl$1); + + if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) { + // Must include lastMultiDragSelect (select it), in case modified selection from no selection + // (but previous selection existed) + var n, i; + + if (currentIndex > lastIndex) { + i = lastIndex; + n = currentIndex; + } else { + i = currentIndex; + n = lastIndex + 1; + } + + for (; i < n; i++) { + if (~multiDragElements.indexOf(children[i])) continue; + toggleClass(children[i], options.selectedClass, true); + multiDragElements.push(children[i]); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: children[i], + originalEvt: evt + }); + } + } + } else { + lastMultiDragSelect = dragEl$1; + } + + multiDragSortable = toSortable; + } else { + multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1); + lastMultiDragSelect = null; + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'deselect', + targetEl: dragEl$1, + originalEvt: evt + }); + } + } // Multi-drag drop + + + if (dragStarted && this.isMultiDrag) { + // Do not "unfold" after around dragEl if reverted + if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) { + var dragRect = getRect(dragEl$1), + multiDragIndex = index(dragEl$1, ':not(.' + Sortable.active.options.selectedClass + ')'); + if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null; + toSortable.captureAnimationState(); + + if (!initialFolding) { + if (options.animation) { + dragEl$1.fromRect = dragRect; + + for (var _i4 in multiDragElements) { + multiDragElements[_i4].thisAnimationDuration = null; + + if (multiDragElements[_i4] !== dragEl$1) { + var rect = folding ? getRect(multiDragElements[_i4]) : dragRect; + multiDragElements[_i4].fromRect = rect; // Prepare unfold animation + + toSortable.addAnimationState({ + target: multiDragElements[_i4], + rect: rect + }); + } + } + } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert + // properly they must all be removed + + + removeMultiDragElements(); + + for (var _i5 in multiDragElements) { + if (children[multiDragIndex]) { + parentEl.insertBefore(multiDragElements[_i5], children[multiDragIndex]); + } else { + parentEl.appendChild(multiDragElements[_i5]); + } + + multiDragIndex++; + } // If initial folding is done, the elements may have changed position because they are now + // unfolding around dragEl, even though dragEl may not have his index changed, so update event + // must be fired here as Sortable will not. + + + if (oldIndex === index(dragEl$1)) { + var update = false; + + for (var _i6 in multiDragElements) { + if (multiDragElements[_i6].sortableIndex !== index(multiDragElements[_i6])) { + update = true; + break; + } + } + + if (update) { + dispatchSortableEvent('update'); + } + } + } // Must be done after capturing individual rects (scroll bar) + + + for (var _i7 in multiDragElements) { + unsetRect(multiDragElements[_i7]); + } + + toSortable.animateAll(); + } + + multiDragSortable = toSortable; + } // Remove clones if necessary + + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + for (var _i8 in multiDragClones) { + multiDragClones[_i8].parentNode && multiDragClones[_i8].parentNode.removeChild(multiDragClones[_i8]); + } + } + }, + nullingGlobal: function nullingGlobal() { + this.isMultiDrag = dragStarted = false; + multiDragClones.length = 0; + }, + destroy: function destroy() { + this._deselectMultiDrag(); + + off(document, 'pointerup', this._deselectMultiDrag); + off(document, 'mouseup', this._deselectMultiDrag); + off(document, 'touchend', this._deselectMultiDrag); + off(document, 'keydown', this._checkKeyDown); + off(document, 'keyup', this._checkKeyUp); + }, + _deselectMultiDrag: function _deselectMultiDrag(evt) { + if (dragStarted) return; // Only deselect if selection is in this sortable + + if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable + + if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return; // Only deselect if left click + + if (evt && evt.button !== 0) return; + + while (multiDragElements.length) { + var el = multiDragElements[0]; + toggleClass(el, this.sortable.options.selectedClass, false); + multiDragElements.shift(); + dispatchEvent({ + sortable: this.sortable, + rootEl: this.sortable.el, + name: 'deselect', + targetEl: el, + originalEvt: evt + }); + } + }, + _checkKeyDown: function _checkKeyDown(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = true; + } + }, + _checkKeyUp: function _checkKeyUp(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = false; + } + } + }; + return _extends(MultiDrag, { + // Static methods & properties + pluginName: 'multiDrag', + utils: { + /** + * Selects the provided multi-drag item + * @param {HTMLElement} el The element to be selected + */ + select: function select(el) { + var sortable = el.parentNode[expando]; + if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return; + + if (multiDragSortable && multiDragSortable !== sortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + + multiDragSortable = sortable; + } + + toggleClass(el, sortable.options.selectedClass, true); + multiDragElements.push(el); + }, + + /** + * Deselects the provided multi-drag item + * @param {HTMLElement} el The element to be deselected + */ + deselect: function deselect(el) { + var sortable = el.parentNode[expando], + index = multiDragElements.indexOf(el); + if (!sortable || !sortable.options.multiDrag || !~index) return; + toggleClass(el, sortable.options.selectedClass, false); + multiDragElements.splice(index, 1); + } + }, + eventOptions: function eventOptions() { + return { + items: _toConsumableArray(multiDragElements), + clones: [].concat(multiDragClones) + }; + }, + optionListeners: { + multiDragKey: function multiDragKey(key) { + key = key.toLowerCase(); + + if (key === 'ctrl') { + key = 'Control'; + } else if (key.length > 1) { + key = key.charAt(0).toUpperCase() + key.substr(1); + } + + return key; + } + } + }); + } + + function insertMultiDragElements(clonesInserted, rootEl) { + for (var i in multiDragElements) { + var target = rootEl.children[multiDragElements[i].sortableIndex + (clonesInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragElements[i], target); + } else { + rootEl.appendChild(multiDragElements[i]); + } + } + } + /** + * Insert multi-drag clones + * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted + * @param {HTMLElement} rootEl + */ + + + function insertMultiDragClones(elementsInserted, rootEl) { + for (var i in multiDragClones) { + var target = rootEl.children[multiDragClones[i].sortableIndex + (elementsInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragClones[i], target); + } else { + rootEl.appendChild(multiDragClones[i]); + } + } + } + + function removeMultiDragElements() { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + multiDragElements[i].parentNode && multiDragElements[i].parentNode.removeChild(multiDragElements[i]); + } + } + + Sortable$1.mount(new AutoScrollPlugin()); + Sortable$1.mount(Remove, Revert); + + Sortable$1.mount(new SwapPlugin()); + Sortable$1.mount(new MultiDragPlugin()); + + return Sortable$1; + +})); diff --git a/Sortable.min.js b/Sortable.min.js index 3dcf767c3..fc4ea7501 100644 --- a/Sortable.min.js +++ b/Sortable.min.js @@ -1,3 +1,2 @@ /*! Sortable 1.9.0 - MIT | git://github.com/SortableJS/Sortable.git */ - -!function(t){"use strict";"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&void 0!==module.exports?module.exports=t():window.Sortable=t()}(function(){"use strict";if("undefined"==typeof window||!window.document)return function(){throw new Error("Sortable.js requires a window with a document")};function A(t,e){if(!t||!t.getBoundingClientRect)return ut();var o=t,n=!1;do{if(o.clientWidth=n.left-i&&t<=n.right+i,a=e>=n.top-i&&e<=n.bottom+i;if(i&&r&&a)return d[o]}}((t=t.touches?t.touches[0]:t).clientX,t.clientY);if(e){var o={};for(var n in t)o[n]=t[n];o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[Q]._onDragOver(o)}}}var mt;function bt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be HTMLElement, not "+{}.toString.call(t);this.el=t,this.options=e=Ot({},e),t[Q]=this;var o={group:null,sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,bubbleScroll:!0,draggable:/[uo]l/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return ht(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:D(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==bt.supportPointer&&"PointerEvent"in window,emptyInsertThreshold:5};for(var n in o)!(n in e)&&(e[n]=o[n]);for(var i in vt(e),this)"_"===i.charAt(0)&&"function"==typeof this[i]&&(this[i]=this[i].bind(this));this.nativeDraggable=!e.forceFallback&&nt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?_t(t,"pointerdown",this._onTapStart):(_t(t,"mousedown",this._onTapStart),_t(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(_t(t,"dragover",this),_t(t,"dragenter",this)),d.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[])}function wt(t,e,o,n){if(t){o=o||J;do{if(null!=e&&(">"===e[0]?t.parentNode===o&&It(t,e):It(t,e))||n&&t===o)return t;if(t===o)break}while(t=(i=t).host&&i!==J&&i.host.nodeType?i.host:i.parentNode)}var i;return null}function _t(t,e,o){t.addEventListener(e,o,!T&&h)}function yt(t,e,o){t.removeEventListener(e,o,!T&&h)}function Dt(t,e,o){if(t&&e)if(t.classList)t.classList[o?"add":"remove"](e);else{var n=(" "+t.className+" ").replace(a," ").replace(" "+e+" "," ");t.className=(n+(o?" "+e:"")).replace(a," ")}}function Tt(t,e,o){var n=t&&t.style;if(n){if(void 0===o)return J.defaultView&&J.defaultView.getComputedStyle?o=J.defaultView.getComputedStyle(t,""):t.currentStyle&&(o=t.currentStyle),void 0===e?o:o[e];e in n||-1!==e.indexOf("webkit")||(e="-webkit-"+e),n[e]=o+("string"==typeof o?"":"px")}}function St(t){var e="";do{var o=Tt(t,"transform");o&&"none"!==o&&(e=o+" "+e)}while(t=t.parentNode);return window.DOMMatrix?new DOMMatrix(e):window.WebKitCSSMatrix?new WebKitCSSMatrix(e):window.CSSMatrix?new CSSMatrix(e):void 0}function Ct(t,e,o){if(t){var n=t.getElementsByTagName(e),i=0,r=n.length;if(o)for(;i"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return!1}return!1}}function t(o,n){return function(){if(!mt){var t=arguments,e=this;mt=$(function(){1===t.length?o.call(e,t[0]):o.apply(e,t),mt=void 0},n)}}}function Ot(t,e){if(t&&e)for(var o in e)e.hasOwnProperty(o)&&(t[o]=e[o]);return t}function Ht(t){return o&&o.dom?o.dom(t).cloneNode(!0):e?e(t).clone(!0)[0]:t.cloneNode(!0)}function Bt(t){return $(t,0)}function Rt(t){return clearTimeout(t)}function Lt(t,e,o,n){if(t.getBoundingClientRect||t===y){var i,r,a,l,s,c,d;if(d=t!==y&&t!==ut()?(r=(i=t.getBoundingClientRect()).top,a=i.left,l=i.bottom,s=i.right,c=i.height,i.width):(a=r=0,l=window.innerHeight,s=window.innerWidth,c=window.innerHeight,window.innerWidth),n&&t!==y&&(o=o||t.parentNode,!T))do{if(o&&o.getBoundingClientRect&&"none"!==Tt(o,"transform")){var h=o.getBoundingClientRect();r-=h.top+D(Tt(o,"border-top-width")),a-=h.left+D(Tt(o,"border-left-width")),l=r+i.height,s=a+i.width;break}}while(o=o.parentNode);if(e&&t!==y){var u=St(o||t),f=u&&u.a,p=u&&u.d;u&&(l=(r/=p)+(c/=p),s=(a/=f)+(d/=f))}return{top:r,left:a,bottom:l,right:s,width:d,height:c}}}function Wt(t,e){for(var o=A(t,!0),n=Lt(t)[e];o;){var i=Lt(o)[e];if(!("top"===e||"left"===e?i<=n:n<=i))return o;if(o===ut())break;o=A(o,!1)}return!1}function Ft(t){var e=0,o=0,n=ut();if(t)do{var i=St(t),r=i.a,a=i.d;e+=t.scrollLeft*r,o+=t.scrollTop*a}while(t!==n&&(t=t.parentNode));return[e,o]}return bt.prototype={constructor:bt,_computeIsAligned:function(t){var e;if(p&&!it?(u(),e=J.elementFromPoint(t.clientX,t.clientY),f()):e=t.target,e=wt(e,this.options.draggable,this.el,!1),!at&&E&&E.parentNode===this.el){for(var o,n,i,r,a,l,s,c,d=this.el.children,h=0;h=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){E&&Mt(E),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;yt(t,"mouseup",this._disableDelayedDrag),yt(t,"touchend",this._disableDelayedDrag),yt(t,"touchcancel",this._disableDelayedDrag),yt(t,"mousemove",this._delayedDragTouchMoveHandler),yt(t,"touchmove",this._delayedDragTouchMoveHandler),yt(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||("touch"==t.pointerType?t:null),!this.nativeDraggable||e?this.options.supportPointer?_t(J,"pointermove",this._onTouchMove):_t(J,e?"touchmove":"mousemove",this._onTouchMove):(_t(E,"dragend",this),_t(M,"dragstart",this._onDragStart));try{J.selection?Bt(function(){J.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){if(w=!1,M&&E){this.nativeDraggable&&(_t(J,"dragover",this._handleAutoScroll),_t(J,"dragover",n));var o=this.options;!t&&Dt(E,o.dragClass,!1),Dt(E,o.ghostClass,!0),Tt(E,"transform",""),bt.active=this,t&&this._appendGhost(),Et(this,M,"start",E,M,M,P,void 0,O,void 0,e)}else this._nulling()},_emulateDragOver:function(t){if(R){if(this._lastX===R.clientX&&this._lastY===R.clientY&&!t)return;this._lastX=R.clientX,this._lastY=R.clientY,u();for(var e=J.elementFromPoint(R.clientX,R.clientY),o=e;e&&e.shadowRoot&&(e=e.shadowRoot.elementFromPoint(R.clientX,R.clientY))!==o;)o=e;if(o)do{if(o[Q])if(o[Q]._onDragOver({clientX:R.clientX,clientY:R.clientY,target:e,rootEl:o})&&!this.options.dragoverBubble)break;e=o}while(o=o.parentNode);E.parentNode[Q]._computeIsAligned(R),f()}},_onTouchMove:function(t,e){if(m){var o=this.options,n=o.fallbackTolerance,i=o.fallbackOffset,r=t.touches?t.touches[0]:t,a=p&&St(p),l=p&&a&&a.a,s=p&&a&&a.d,c=et&&b&&Ft(b),d=(r.clientX-m.clientX+i.x)/(l||1)+(c?c[0]-_[0]:0)/(l||1),h=(r.clientY-m.clientY+i.y)/(s||1)+(c?c[1]-_[1]:0)/(s||1),u=t.touches?"translate3d("+d+"px,"+h+"px,0)":"translate("+d+"px,"+h+"px)";if(!bt.active&&!w){if(n&&st(lt(r.clientX-this._lastX),lt(r.clientY-this._lastY))"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return!1}return!1}}function I(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"===e[0]?t.parentNode===n&&d(t,e):d(t,e))||o&&t===n)return t;if(t===n)break}while(t=(i=t).host&&i!==document&&i.host.nodeType?i.host:i.parentNode)}var i;return null}var h,f=/\s+/g;function k(t,e,n){if(t&&e)if(t.classList)t.classList[n?"add":"remove"](e);else{var o=(" "+t.className+" ").replace(f," ").replace(" "+e+" "," ");t.className=(o+(n?" "+e:"")).replace(f," ")}}function P(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];e in o||-1!==e.indexOf("webkit")||(e="-webkit-"+e),o[e]=n+("string"==typeof n?"":"px")}}function b(t,e){var n="";do{var o=P(t,"transform");o&&"none"!==o&&(n=o+" "+n)}while(!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix;return i&&new i(n)}function p(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=o.left-i&&t<=o.right+i,a=e>=o.top-i&&e<=o.bottom+i;if(i&&r&&a)return ft[n]}}((t=t.touches?t.touches[0]:t).clientX,t.clientY);if(e){var n={};for(var o in t)n[o]=t[o];n.target=n.rootEl=e,n.preventDefault=void 0,n.stopPropagation=void 0,e[H]._onDragOver(n)}}}function Ot(t){W&&W.parentNode[H]._isOutsideThisEl(t.target)}function Mt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=s({},e),t[H]=this;var n={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return St(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Mt.supportPointer&&"PointerEvent"in window,emptyInsertThreshold:5};for(var o in O.initializePlugins(this,t,n),n)o in e||(e[o]=n[o]);for(var i in _t(e),this)"_"===i.charAt(0)&&"function"==typeof this[i]&&(this[i]=this[i].bind(this));this.nativeDraggable=!e.forceFallback&&Dt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?u(t,"pointerdown",this._onTapStart):(u(t,"mousedown",this._onTapStart),u(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(u(t,"dragover",this),u(t,"dragenter",this)),ft.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),s(this,C())}function At(t,e,n,o,i,r,a,l){var s,c,u=t[H],d=u.options.onMove;return!window.CustomEvent||w||D?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||R(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),d&&(c=d.call(u,s,a)),c}function Nt(t){t.draggable=!1}function It(){mt=!1}function kt(t){for(var e=t.tagName+t.className+t.src+t.href+t.textContent,n=e.length,o=0;n--;)o+=e.charCodeAt(n);return o.toString(36)}function Pt(t){return setTimeout(t,0)}function Rt(t){return clearTimeout(t)}Mt.prototype={constructor:Mt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(lt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,W):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0],l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(function(t){bt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&bt.push(o)}}(o),!W&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled||s.isContentEditable||(l=I(l,t.draggable,o,!1))&&l.animated||V===l)){if($=B(l),tt=B(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return K({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),j("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c&&(c=c.split(",").some(function(t){if(t=I(s,t.trim(),o,!1))return K({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),j("filter",n,{evt:e}),!0})))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!I(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;if(n&&!W&&n.parentNode===r)if(U=r,z=(W=n).parentNode,q=W.nextSibling,V=n,nt=a.group,it={target:Mt.dragged=W,clientX:(e||t).clientX,clientY:(e||t).clientY},this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,W.style["will-change"]="all",o=function(){j("delayEnded",i,{evt:t}),Mt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!c&&i.nativeDraggable&&(W.draggable=!0),i._triggerDragStart(t,e),K({sortable:i,name:"choose",originalEvent:t}),k(W,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){p(W,t.trim(),Nt)}),u(l,"dragover",xt),u(l,"mousemove",xt),u(l,"touchmove",xt),u(l,"mouseup",i._onDrop),u(l,"touchend",i._onDrop),u(l,"touchcancel",i._onDrop),c&&this.nativeDraggable&&(this.options.touchStartThreshold=4,W.draggable=!0),j("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(D||w))o();else{if(Mt.eventCanceled)return void this._onDrop();u(l,"mouseup",i._disableDelayedDrag),u(l,"touchend",i._disableDelayedDrag),u(l,"touchcancel",i._disableDelayedDrag),u(l,"mousemove",i._delayedDragTouchMoveHandler),u(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&u(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)}},_delayedDragTouchMoveHandler:function(t){var e=t.touches?t.touches[0]:t;Math.max(Math.abs(e.clientX-this._lastX),Math.abs(e.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){W&&Nt(W),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;r(t,"mouseup",this._disableDelayedDrag),r(t,"touchend",this._disableDelayedDrag),r(t,"touchcancel",this._disableDelayedDrag),r(t,"mousemove",this._delayedDragTouchMoveHandler),r(t,"touchmove",this._delayedDragTouchMoveHandler),r(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||("touch"==t.pointerType?t:null),!this.nativeDraggable||e?this.options.supportPointer?u(document,"pointermove",this._onTouchMove):u(document,e?"touchmove":"mousemove",this._onTouchMove):(u(W,"dragend",this),u(U,"dragstart",this._onDragStart));try{document.selection?Pt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){if(dt=!1,U&&W){j("dragStarted",this,{evt:e}),this.nativeDraggable&&u(document,"dragover",Ot);var n=this.options;t||k(W,n.dragClass,!1),k(W,n.ghostClass,!0),Mt.active=this,t&&this._appendGhost(),K({sortable:this,name:"start",originalEvent:e})}else this._nulling()},_emulateDragOver:function(){if(rt){this._lastX=rt.clientX,this._lastY=rt.clientY,Ct();for(var t=document.elementFromPoint(rt.clientX,rt.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(rt.clientX,rt.clientY))!==e;)e=t;if(W.parentNode[H]._isOutsideThisEl(t),e)do{if(e[H]){if(e[H]._onDragOver({clientX:rt.clientX,clientY:rt.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}t=e}while(e=e.parentNode);Tt()}},_onTouchMove:function(t){if(it){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=G&&b(G),a=G&&r&&r.a,l=G&&r&&r.d,s=yt&&ut&&v(ut),c=(i.clientX-it.clientX+o.x)/(a||1)+(s?s[0]-vt[0]:0)/(a||1),u=(i.clientY-it.clientY+o.y)/(l||1)+(s?s[1]-vt[1]:0)/(l||1),d=t.touches?"translate3d("+c+"px,"+u+"px,0)":"translate("+c+"px,"+u+"px)";if(!Mt.active&&!dt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY)) + * @author owenm + * @license MIT + */`; diff --git a/build/build.js b/build/build.js new file mode 100644 index 000000000..11cf99d35 --- /dev/null +++ b/build/build.js @@ -0,0 +1,17 @@ +import babel from 'rollup-plugin-babel'; +import json from 'rollup-plugin-json'; +import resolve from 'rollup-plugin-node-resolve'; +import banner from './banner.js'; + + +export default { + output: { + banner, + name: 'Sortable' + }, + plugins: [ + json(), + babel(), + resolve() + ] +}; diff --git a/build/esm-build.js b/build/esm-build.js new file mode 100644 index 000000000..9caff74d0 --- /dev/null +++ b/build/esm-build.js @@ -0,0 +1,28 @@ +import build from './build.js'; + +export default ([ + { + input: 'entry/entry-core.js', + output: Object.assign({}, build.output, { + file: 'modular/sortable.core.esm.js', + format: 'esm' + }) + }, + { + input: 'entry/entry-defaults.js', + output: Object.assign({}, build.output, { + file: 'modular/sortable.esm.js', + format: 'esm' + }) + }, + { + input: 'entry/entry-complete.js', + output: Object.assign({}, build.output, { + file: 'modular/sortable.complete.esm.js', + format: 'esm' + }) + } +]).map(config => { + let buildCopy = { ...build }; + return Object.assign(buildCopy, config); +}); diff --git a/build/minify.js b/build/minify.js new file mode 100644 index 000000000..e2051a2c2 --- /dev/null +++ b/build/minify.js @@ -0,0 +1,11 @@ +const UglifyJS = require('uglify-js'), + fs = require('fs'), + package = require('../package.json'); + +const banner = `/*! Sortable ${ package.version } - ${ package.license } | ${ package.repository.url } */\n`; + +fs.writeFileSync( + `./Sortable.min.js`, + banner + UglifyJS.minify(fs.readFileSync(`./Sortable.js`, 'utf8')).code, + 'utf8' +); diff --git a/build/umd-build.js b/build/umd-build.js new file mode 100644 index 000000000..ec179fdb9 --- /dev/null +++ b/build/umd-build.js @@ -0,0 +1,15 @@ +import build from './build.js'; + + +export default ([ + { + input: 'entry/entry-complete.js', + output: Object.assign({}, build.output, { + file: './Sortable.js', + format: 'umd' + }) + } +]).map(config => { + let buildCopy = { ...build }; + return Object.assign(buildCopy, config); +}); diff --git a/entry/entry-complete.js b/entry/entry-complete.js new file mode 100644 index 000000000..bf3dc5c13 --- /dev/null +++ b/entry/entry-complete.js @@ -0,0 +1,8 @@ +import Sortable from './entry-defaults.js'; +import Swap from '../plugins/Swap'; +import MultiDrag from '../plugins/MultiDrag'; + +Sortable.mount(new Swap()); +Sortable.mount(new MultiDrag()); + +export default Sortable; diff --git a/entry/entry-core.js b/entry/entry-core.js new file mode 100644 index 000000000..b5c3f77f7 --- /dev/null +++ b/entry/entry-core.js @@ -0,0 +1,19 @@ +import Sortable from '../src/Sortable.js'; +import AutoScroll from '../plugins/AutoScroll'; +import OnSpill from '../plugins/OnSpill'; +import Swap from '../plugins/Swap'; +import MultiDrag from '../plugins/MultiDrag'; + +export default Sortable; + +export { + Sortable, + + // Default + AutoScroll, + OnSpill, + + // Extra + Swap, + MultiDrag +}; diff --git a/entry/entry-defaults.js b/entry/entry-defaults.js new file mode 100644 index 000000000..9d3fb6830 --- /dev/null +++ b/entry/entry-defaults.js @@ -0,0 +1,19 @@ +import Sortable from '../src/Sortable.js'; +import AutoScroll from '../plugins/AutoScroll'; +import { RemoveOnSpill, RevertOnSpill } from '../plugins/OnSpill'; +// Extra +import Swap from '../plugins/Swap'; +import MultiDrag from '../plugins/MultiDrag'; + +Sortable.mount(new AutoScroll()); +Sortable.mount(RemoveOnSpill, RevertOnSpill); + +export default Sortable; + +export { + Sortable, + + // Extra + Swap, + MultiDrag +}; diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 8e45f1fdf..000000000 --- a/gulpfile.js +++ /dev/null @@ -1,45 +0,0 @@ -/* jshint ignore:start */ -const gulp = require('gulp'), - uglify = require('gulp-uglify'), - rename = require('gulp-rename'), - each = require('gulp-each'), - path = require('path'), - pump = require('pump') -; - -const package = require('./package.json'), - name = package.exportName, - versionExp = /(?<=\"version\":\s{0,}\")(.{0,})(?=\")/i; - -gulp.task('version', function() { - let version = package.version; - return pump([ - gulp.src('./*.json'), - each(function(content, file, callback){ - let prevVersion = content.match(versionExp); - prevVersion && (prevVersion = prevVersion[0]); - content = content.replace(versionExp, version); - prevVersion && prevVersion !== version && console.info(`Updated version in ${ path.basename(file.history[0]) }:\t${ prevVersion } -> ${ version }`); - callback(null, content); - }), - gulp.dest('./') - ]); -}); - -gulp.task('minify', function() { - return pump([ - gulp.src(`./${ name }.js`), - uglify({ - output: { - preamble: `/*! ${ name } ${ package.version } - ${ package.license } | ${ package.repository.url } */\n` - } - }), - rename({ - suffix: '.min' - }), - gulp.dest(`./`) - ]); -}); - -gulp.task('build', gulp.series('version', 'minify')); -/* jshint ignore:end */ diff --git a/modular/sortable.complete.esm.js b/modular/sortable.complete.esm.js new file mode 100644 index 000000000..201d9f6cf --- /dev/null +++ b/modular/sortable.complete.esm.js @@ -0,0 +1,3601 @@ +/**! + * Sortable 1.9.0 + * @author RubaXa + * @author owenm + * @license MIT + */ +function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } + + return _typeof(obj); +} + +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; +} + +function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); +} + +function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; +} + +function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; +} + +function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + + var target = _objectWithoutPropertiesLoose(source, excluded); + + var key, i; + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + + return target; +} + +function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); +} + +function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } +} + +function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); +} + +function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance"); +} + +var version = "1.9.0"; + +function userAgent(pattern) { + return !!navigator.userAgent.match(pattern); +} + +var IE11OrLess = +/*@__PURE__*/ +userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile)/i); +var Edge = +/*@__PURE__*/ +userAgent(/Edge/i); +var FireFox = +/*@__PURE__*/ +userAgent(/firefox/i); +var Safari = +/*@__PURE__*/ +userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); +var IOS = +/*@__PURE__*/ +userAgent(/iP(ad|od|hone)/i); + +var 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; +} + +var R_SPACE = /\s+/g; + +function toggleClass(el, name, state) { + if (el && name) { + if (el.classList) { + el.classList[state ? 'add' : 'remove'](name); + } else { + var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); + el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); + } + } +} + +function css(el, prop, val) { + var 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) { + var appliedTransforms = ''; + + do { + var transform = css(el, 'transform'); + + if (transform && transform !== 'none') { + appliedTransforms = transform + ' ' + appliedTransforms; + } + /* jshint boss:true */ + + } while (!selfOnly && (el = el.parentNode)); + + var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix; + /*jshint -W056 */ + + return matrixFn && new matrixFn(appliedTransforms); +} + +function find(ctx, tagName, iterator) { + if (ctx) { + var list = ctx.getElementsByTagName(tagName), + i = 0, + n = list.length; + + if (iterator) { + for (; i < n; i++) { + iterator(list[i], i); + } + } + + return list; + } + + return []; +} + +function getWindowScrollingElement() { + if (IE11OrLess) { + return document.documentElement; + } else { + return document.scrollingElement; + } +} +/** + * 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; + var 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')) { + var 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() + var 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 {[DOMRect]} rect Optional rect of `el` to use + * @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, rect, elSide, parentSide) { + var parent = getParentAutoScrollElement(el, true), + elSideVal = (rect ? rect : getRect(el))[elSide]; + /* jshint boss:true */ + + while (parent) { + var parentSideVal = getRect(parent)[parentSide], + visible = void 0; + + 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) { + var currentChild = 0, + i = 0, + children = el.children; + + while (i < children.length) { + if (children[i].style.display !== 'none' && children[i] !== Sortable$1.ghost && children[i] !== Sortable$1.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) { + var last = el.lastElementChild; + + while (last && (last === Sortable$1.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) { + var index = 0; + + if (!el || !el.parentNode) { + return -1; + } + /* jshint boss:true */ + + + while (el = el.previousElementSibling) { + if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable$1.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) { + var offsetLeft = 0, + offsetTop = 0, + winScroller = getWindowScrollingElement(); + + if (el) { + do { + var 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 (var i in arr) { + for (var key in obj) { + if (obj[key] === arr[i][key]) return Number(i); + } + } + + return -1; +} + +function getParentAutoScrollElement(el, includeSelf) { + // skip to window + if (!el || !el.getBoundingClientRect) return getWindowScrollingElement(); + var elem = el; + var 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) { + var 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 (var 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); +} + +var _throttleTimeout; + +function throttle(callback, ms) { + return function () { + if (!_throttleTimeout) { + var 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) { + var Polymer = window.Polymer; + var $ = 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', ''); +} + +var expando = 'Sortable' + new Date().getTime(); + +function AnimationStateManager() { + var animationStates = [], + animationCallbackId; + return { + captureAnimationState: function captureAnimationState() { + animationStates = []; + if (!this.options.animation) return; + var children = [].slice.call(this.el.children); + + for (var i in children) { + if (css(children[i], 'display') === 'none' || children[i] === Sortable$1.ghost) continue; + animationStates.push({ + target: children[i], + rect: getRect(children[i]) + }); + var fromRect = getRect(children[i]); // If animating: compensate for current animation + + if (children[i].thisAnimationDuration) { + var childMatrix = matrix(children[i], true); + + if (childMatrix) { + fromRect.top -= childMatrix.f; + fromRect.left -= childMatrix.e; + } + } + + children[i].fromRect = fromRect; + } + }, + addAnimationState: function addAnimationState(state) { + animationStates.push(state); + }, + removeAnimationState: function removeAnimationState(target) { + animationStates.splice(indexOfObject(animationStates, { + target: target + }), 1); + }, + animateAll: function animateAll(callback) { + if (!this.options.animation) { + clearTimeout(animationCallbackId); + if (typeof callback === 'function') callback(); + return; + } + + var animating = false, + animationTime = 0; + + for (var i in animationStates) { + var time = 0, + target = animationStates[i].target, + fromRect = target.fromRect, + toRect = getRect(target), + prevFromRect = target.prevFromRect, + prevToRect = target.prevToRect, + animatingRect = animationStates[i].rect, + targetMatrix = matrix(target, true); + + if (targetMatrix) { + // Compensate for current animation + toRect.top -= targetMatrix.f; + toRect.left -= targetMatrix.e; + } + + target.toRect = toRect; // If element is scrolled out of view: Do not animate + + if ((isScrolledPast(target, toRect, 'bottom', 'top') || isScrolledPast(target, toRect, 'top', 'bottom') || isScrolledPast(target, toRect, 'right', 'left') || isScrolledPast(target, toRect, 'left', 'right')) && (isScrolledPast(target, animatingRect, 'bottom', 'top') || isScrolledPast(target, animatingRect, 'top', 'bottom') || isScrolledPast(target, animatingRect, 'right', 'left') || isScrolledPast(target, animatingRect, 'left', 'right')) && (isScrolledPast(target, fromRect, 'bottom', 'top') || isScrolledPast(target, fromRect, 'top', 'bottom') || isScrolledPast(target, fromRect, 'right', 'left') || isScrolledPast(target, fromRect, 'left', 'right'))) continue; + + if (target.thisAnimationDuration) { + // Could also check if animatingRect is between fromRect and toRect + if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect + (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) { + // If returning to same place as started from animation and on same axis + time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options); + } + } // if fromRect != toRect: animate + + + if (!isRectEqual(toRect, fromRect)) { + target.prevFromRect = fromRect; + target.prevToRect = toRect; + + if (!time) { + time = this.options.animation; + } + + this.animate(target, animatingRect, time); + } + + if (time) { + animating = true; + animationTime = Math.max(animationTime, time); + clearTimeout(target.animationResetTimer); + target.animationResetTimer = setTimeout(function () { + this.animationStates[this.i].target.animationTime = 0; + this.animationStates[this.i].target.prevFromRect = null; + this.animationStates[this.i].target.fromRect = null; + this.animationStates[this.i].target.prevToRect = null; + this.animationStates[this.i].target.thisAnimationDuration = null; + }.bind({ + animationStates: animationStates, + i: Number(i) + }), time); + target.thisAnimationDuration = time; + } + } + + clearTimeout(animationCallbackId); + + if (!animating) { + if (typeof callback === 'function') callback(); + } else { + animationCallbackId = setTimeout(function () { + if (typeof callback === 'function') callback(); + }, animationTime); + } + + animationStates = []; + }, + animate: function animate(target, prev, duration) { + if (duration) { + css(target, 'transition', ''); + css(target, 'transform', ''); + var currentRect = getRect(target), + elMatrix = matrix(this.el), + scaleX = elMatrix && elMatrix.a, + scaleY = elMatrix && elMatrix.d, + translateX = (prev.left - currentRect.left) / (scaleX || 1), + translateY = (prev.top - currentRect.top) / (scaleY || 1); + target.animatingX = !!translateX; + target.animatingY = !!translateY; + css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); + repaint(target); // repaint + + css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); + css(target, 'transform', 'translate3d(0,0,0)'); + typeof target.animated === 'number' && clearTimeout(target.animated); + target.animated = setTimeout(function () { + css(target, 'transition', ''); + css(target, 'transform', ''); + target.animated = false; + target.animatingX = false; + target.animatingY = false; + }, duration); + } + } + }; +} + +function repaint(target) { + return target.offsetWidth; +} + +function calculateRealTime(animatingRect, fromRect, toRect, options) { + return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation; +} + +var plugins = []; +var defaults = { + initializeByDefault: true +}; +var PluginManager = { + mount: function mount(plugin) { + // Set default static properties + for (var option in defaults) { + !(option in plugin) && (plugin[option] = defaults[option]); + } + + plugins.push(plugin); + }, + pluginEvent: function pluginEvent(eventName, sortable, evt) { + this.eventCanceled = false; + var eventNameGlobal = eventName + 'Global'; + + for (var i in plugins) { + if (!sortable[plugins[i].pluginName]) continue; // Fire global events if it exists in this sortable + + if (sortable[plugins[i].pluginName][eventNameGlobal]) { + this.eventCanceled = !!sortable[plugins[i].pluginName][eventNameGlobal](_objectSpread({ + sortable: sortable + }, evt)); + } // Only fire plugin event if plugin is enabled in this sortable, + // and plugin has event defined + + + if (sortable.options[plugins[i].pluginName] && sortable[plugins[i].pluginName][eventName]) { + this.eventCanceled = this.eventCanceled || !!sortable[plugins[i].pluginName][eventName](_objectSpread({ + sortable: sortable + }, evt)); + } + } + }, + initializePlugins: function initializePlugins(sortable, el, defaults) { + for (var i in plugins) { + var pluginName = plugins[i].pluginName; + if (!sortable.options[pluginName] && !plugins[i].initializeByDefault) continue; + var initialized = new plugins[i](sortable, el); + initialized.sortable = sortable; + sortable[pluginName] = initialized; // Add default options from plugin + + _extends(defaults, initialized.options); + } + + for (var option in sortable.options) { + var modified = this.modifyOption(sortable, option, sortable.options[option]); + + if (typeof modified !== 'undefined') { + sortable.options[option] = modified; + } + } + }, + getEventOptions: function getEventOptions(name, sortable) { + var eventOptions = {}; + + for (var i in plugins) { + if (typeof plugins[i].eventOptions !== 'function') continue; + eventOptions = _objectSpread({}, eventOptions, plugins[i].eventOptions(name, sortable)); + } + + return eventOptions; + }, + modifyOption: function modifyOption(sortable, name, value) { + var modifiedValue; + + for (var i in plugins) { + // Plugin must exist on the Sortable + if (!sortable[plugins[i].pluginName]) continue; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin + + if (plugins[i].optionListeners && typeof plugins[i].optionListeners[name] === 'function') { + modifiedValue = plugins[i].optionListeners[name].call(sortable[plugins[i].pluginName], value); + } + } + + return modifiedValue; + } +}; + +function dispatchEvent(_ref) { + var sortable = _ref.sortable, + rootEl = _ref.rootEl, + name = _ref.name, + targetEl = _ref.targetEl, + cloneEl = _ref.cloneEl, + toEl = _ref.toEl, + fromEl = _ref.fromEl, + oldIndex = _ref.oldIndex, + newIndex = _ref.newIndex, + oldDraggableIndex = _ref.oldDraggableIndex, + newDraggableIndex = _ref.newDraggableIndex, + originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + eventOptions = _ref.eventOptions; + sortable = sortable || rootEl[expando]; + var evt, + options = sortable.options, + onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent(name, { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent(name, true, true); + } + + evt.to = toEl || rootEl; + evt.from = fromEl || rootEl; + evt.item = targetEl || rootEl; + evt.clone = cloneEl; + evt.oldIndex = oldIndex; + evt.newIndex = newIndex; + evt.oldDraggableIndex = oldDraggableIndex; + evt.newDraggableIndex = newDraggableIndex; + evt.originalEvent = originalEvent; + evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; + + var allEventOptions = _objectSpread({}, eventOptions, PluginManager.getEventOptions(name, sortable)); + + for (var option in allEventOptions) { + evt[option] = allEventOptions[option]; + } + + if (rootEl) { + rootEl.dispatchEvent(evt); + } + + if (options[onName]) { + options[onName].call(sortable, evt); + } +} + +var pluginEvent = function pluginEvent(eventName, sortable) { + var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + originalEvent = _ref.evt, + data = _objectWithoutProperties(_ref, ["evt"]); + + PluginManager.pluginEvent.bind(Sortable$1)(eventName, sortable, _objectSpread({ + dragEl: dragEl, + parentEl: parentEl, + ghostEl: ghostEl, + rootEl: rootEl, + nextEl: nextEl, + lastDownEl: lastDownEl, + cloneEl: cloneEl, + cloneHidden: cloneHidden, + dragStarted: moved, + putSortable: putSortable, + activeSortable: Sortable$1.active, + originalEvent: originalEvent, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + hideGhostForTarget: _hideGhostForTarget, + unhideGhostForTarget: _unhideGhostForTarget, + cloneNowHidden: function cloneNowHidden() { + cloneHidden = true; + }, + cloneNowShown: function cloneNowShown() { + cloneHidden = false; + }, + dispatchSortableEvent: function dispatchSortableEvent(name) { + _dispatchEvent({ + sortable: sortable, + name: name, + originalEvent: originalEvent + }); + } + }, data)); +}; + +function _dispatchEvent(info) { + dispatchEvent(_objectSpread({ + putSortable: putSortable, + cloneEl: cloneEl, + targetEl: dragEl, + rootEl: rootEl, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex + }, info)); +} + +if (typeof window === "undefined" || !window.document) { + throw new Error("Sortable.js requires a window with a document"); +} + +var dragEl, + parentEl, + ghostEl, + rootEl, + nextEl, + lastDownEl, + cloneEl, + cloneHidden, + oldIndex, + newIndex, + oldDraggableIndex, + newDraggableIndex, + activeGroup, + putSortable, + awaitingDragStarted = false, + ignoreNextClick = false, + sortables = [], + tapEvt, + touchEvt, + moved, + lastTarget, + lastDirection, + pastFirstInvertThresh = false, + isCircumstantialInvert = false, + targetMoveDistance, + // For positioning ghost absolutely +ghostRelativeParent, + ghostRelativeParentInitialScroll = [], + // (left, top) +_silent = false, + savedInputChecked = []; +/** @const */ + +var PositionGhostAbsolutely = IOS, + CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', + // This will not pass for IE9, because IE9 DnD only works on anchors +supportDraggable = 'draggable' in document.createElement('div'), + supportCssPointerEvents = function () { + // false when <= IE11 + if (IE11OrLess) { + return false; + } + + var el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; +}(), + _detectDirection = function _detectDirection(el, options) { + var elCSS = css(el), + elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth), + child1 = getChild(el, 0, options), + child2 = getChild(el, 1, options), + firstChildCSS = child1 && css(child1), + secondChildCSS = child2 && css(child2), + firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width, + secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width; + + if (elCSS.display === 'flex') { + return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal'; + } + + if (elCSS.display === 'grid') { + return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; + } + + if (child1 && firstChildCSS["float"] !== 'none') { + var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right'; + return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal'; + } + + return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal'; +}, + +/** + * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. + * @param {Number} x X position + * @param {Number} y Y position + * @return {HTMLElement} Element of the first found nearest Sortable + */ +_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) { + for (var i in sortables) { + if (lastChild(sortables[i])) continue; + var rect = getRect(sortables[i]), + threshold = sortables[i][expando].options.emptyInsertThreshold, + insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold, + insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold; + + if (threshold && insideHorizontally && insideVertically) { + return sortables[i]; + } + } +}, + _prepareGroup = function _prepareGroup(options) { + function toFn(value, pull) { + return function (to, from, dragEl, evt) { + var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name; + + if (value == null && (pull || sameGroup)) { + // Default pull value + // Default pull and put value if same group + return true; + } else if (value == null || value === false) { + return false; + } else if (pull && value === 'clone') { + return value; + } else if (typeof value === 'function') { + return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); + } else { + var otherGroup = (pull ? to : from).options.group.name; + return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1; + } + }; + } + + var group = {}; + var originalGroup = options.group; + + if (!originalGroup || _typeof(originalGroup) != 'object') { + originalGroup = { + name: originalGroup + }; + } + + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + group.revertClone = originalGroup.revertClone; + options.group = group; +}, + _hideGhostForTarget = function _hideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', 'none'); + } +}, + _unhideGhostForTarget = function _unhideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', ''); + } +}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position + + +document.addEventListener('click', function (evt) { + if (ignoreNextClick) { + evt.preventDefault(); + evt.stopPropagation && evt.stopPropagation(); + evt.stopImmediatePropagation && evt.stopImmediatePropagation(); + ignoreNextClick = false; + return false; + } +}, true); + +var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) { + if (dragEl) { + evt = evt.touches ? evt.touches[0] : evt; + + var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); + + if (nearest) { + // Create imitation event + var event = {}; + + for (var i in evt) { + event[i] = evt[i]; + } + + event.target = event.rootEl = nearest; + event.preventDefault = void 0; + event.stopPropagation = void 0; + + nearest[expando]._onDragOver(event); + } + } +}; + +var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) { + if (dragEl) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); + } +}; +/** + * @class Sortable + * @param {HTMLElement} el + * @param {Object} [options] + */ + + +function Sortable$1(el, options) { + if (!(el && el.nodeType && el.nodeType === 1)) { + throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el)); + } + + this.el = el; // root element + + this.options = options = _extends({}, options); // Export instance + + el[expando] = this; + var defaults = { + group: null, + sort: true, + disabled: false, + store: null, + handle: null, + draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*', + swapThreshold: 1, + // percentage; 0 <= x <= 1 + invertSwap: false, + // invert always + invertedSwapThreshold: null, + // will be set to same as swapThreshold if default + removeCloneOnHide: true, + direction: function direction() { + return _detectDirection(el, this.options); + }, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + ignore: 'a, img', + filter: null, + preventOnFilter: true, + animation: 0, + easing: null, + setData: function setData(dataTransfer, dragEl) { + dataTransfer.setData('Text', dragEl.textContent); + }, + dropBubble: false, + dragoverBubble: false, + dataIdAttr: 'data-id', + delay: 0, + delayOnTouchOnly: false, + touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, + forceFallback: false, + fallbackClass: 'sortable-fallback', + fallbackOnBody: false, + fallbackTolerance: 0, + fallbackOffset: { + x: 0, + y: 0 + }, + supportPointer: Sortable$1.supportPointer !== false && 'PointerEvent' in window, + emptyInsertThreshold: 5 + }; + PluginManager.initializePlugins(this, el, defaults); // Set default options + + for (var name in defaults) { + !(name in options) && (options[name] = defaults[name]); + } + + _prepareGroup(options); // Bind all private methods + + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } // Setup drag mode + + + this.nativeDraggable = options.forceFallback ? false : supportDraggable; + + if (this.nativeDraggable) { + // Touch start threshold cannot be greater than the native dragstart threshold + this.options.touchStartThreshold = 1; + } // Bind events + + + if (options.supportPointer) { + on(el, 'pointerdown', this._onTapStart); + } else { + on(el, 'mousedown', this._onTapStart); + on(el, 'touchstart', this._onTapStart); + } + + if (this.nativeDraggable) { + on(el, 'dragover', this); + on(el, 'dragenter', this); + } + + sortables.push(this.el); // Restore sorting + + options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager + + _extends(this, AnimationStateManager()); +} + +Sortable$1.prototype = +/** @lends Sortable.prototype */ +{ + constructor: Sortable$1, + _isOutsideThisEl: function _isOutsideThisEl(target) { + if (!this.el.contains(target) && target !== this.el) { + lastTarget = null; + } + }, + _getDirection: function _getDirection(evt, target) { + return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; + }, + _onTapStart: function _onTapStart( + /** Event|TouchEvent */ + evt) { + if (!evt.cancelable) return; + + var _this = this, + el = this.el, + options = this.options, + preventOnFilter = options.preventOnFilter, + type = evt.type, + touch = evt.touches && evt.touches[0], + target = (touch || evt).target, + originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target, + filter = options.filter; + + _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. + + + if (dragEl) { + return; + } + + if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { + return; // only left button and enabled + } // cancel dnd if original target is content editable + + + if (originalTarget.isContentEditable) { + return; + } + + target = closest(target, options.draggable, el, false); + + if (target && target.animated) { + return; + } + + if (lastDownEl === target) { + // Ignoring duplicate `down` + return; + } // Get the index of the dragged element within its parent + + + oldIndex = index(target); + oldDraggableIndex = index(target, options.draggable); // Check filter + + if (typeof filter === 'function') { + if (filter.call(this, evt, target, this)) { + _dispatchEvent({ + sortable: _this, + rootEl: originalTarget, + name: 'filter', + targetEl: target, + toEl: el, + fromEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } else if (filter) { + filter = filter.split(',').some(function (criteria) { + criteria = closest(originalTarget, criteria.trim(), el, false); + + if (criteria) { + _dispatchEvent({ + sortable: _this, + rootEl: criteria, + name: 'filter', + targetEl: target, + fromEl: el, + toEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + return true; + } + }); + + if (filter) { + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } + + if (options.handle && !closest(originalTarget, options.handle, el, false)) { + return; + } // Prepare `dragstart` + + + this._prepareDragStart(evt, touch, target); + }, + _prepareDragStart: function _prepareDragStart( + /** Event */ + evt, + /** Touch */ + touch, + /** HTMLElement */ + target) { + var _this = this, + el = _this.el, + options = _this.options, + ownerDocument = el.ownerDocument, + dragStartFn; + + if (target && !dragEl && target.parentNode === el) { + rootEl = el; + dragEl = target; + parentEl = dragEl.parentNode; + nextEl = dragEl.nextSibling; + lastDownEl = target; + activeGroup = options.group; + Sortable$1.dragged = dragEl; + tapEvt = { + target: dragEl, + clientX: (touch || evt).clientX, + clientY: (touch || evt).clientY + }; + this._lastX = (touch || evt).clientX; + this._lastY = (touch || evt).clientY; + dragEl.style['will-change'] = 'all'; + + dragStartFn = function dragStartFn() { + pluginEvent('delayEnded', _this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + _this._onDrop(); + + return; + } // Delayed drag has been triggered + // we can re-enable the events: touchmove/mousemove + + + _this._disableDelayedDragEvents(); + + if (!FireFox && _this.nativeDraggable) { + dragEl.draggable = true; + } // Bind the events: dragstart/dragend + + + _this._triggerDragStart(evt, touch); // Drag start event + + + _dispatchEvent({ + sortable: _this, + name: 'choose', + originalEvent: evt + }); // Chosen item + + + toggleClass(dragEl, options.chosenClass, true); + }; // Disable "draggable" + + + options.ignore.split(',').forEach(function (criteria) { + find(dragEl, criteria.trim(), _disableDraggable); + }); + on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mouseup', _this._onDrop); + on(ownerDocument, 'touchend', _this._onDrop); + on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox) + + if (FireFox && this.nativeDraggable) { + this.options.touchStartThreshold = 4; + dragEl.draggable = true; + } + + pluginEvent('delayStart', this, { + evt: evt + }); // Delay is impossible for native DnD in Edge or IE + + if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } // If the user moves the pointer or let go the click or touch + // before the delay has been reached: + // disable the delayed drag + + + on(ownerDocument, 'mouseup', _this._disableDelayedDrag); + on(ownerDocument, 'touchend', _this._disableDelayedDrag); + on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); + on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); + on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); + options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); + _this._dragStartTimer = setTimeout(dragStartFn, options.delay); + } else { + dragStartFn(); + } + } + }, + _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( + /** TouchEvent|PointerEvent **/ + e) { + var touch = e.touches ? e.touches[0] : e; + + if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) { + this._disableDelayedDrag(); + } + }, + _disableDelayedDrag: function _disableDelayedDrag() { + dragEl && _disableDraggable(dragEl); + clearTimeout(this._dragStartTimer); + + this._disableDelayedDragEvents(); + }, + _disableDelayedDragEvents: function _disableDelayedDragEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._disableDelayedDrag); + off(ownerDocument, 'touchend', this._disableDelayedDrag); + off(ownerDocument, 'touchcancel', this._disableDelayedDrag); + off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); + }, + _triggerDragStart: function _triggerDragStart( + /** Event */ + evt, + /** Touch */ + touch) { + touch = touch || (evt.pointerType == 'touch' ? evt : null); + + if (!this.nativeDraggable || touch) { + if (this.options.supportPointer) { + on(document, 'pointermove', this._onTouchMove); + } else if (touch) { + on(document, 'touchmove', this._onTouchMove); + } else { + on(document, 'mousemove', this._onTouchMove); + } + } else { + on(dragEl, 'dragend', this); + on(rootEl, 'dragstart', this._onDragStart); + } + + try { + if (document.selection) { + // Timeout neccessary for IE9 + _nextTick(function () { + document.selection.empty(); + }); + } else { + window.getSelection().removeAllRanges(); + } + } catch (err) {} + }, + _dragStarted: function _dragStarted(fallback, evt) { + + awaitingDragStarted = false; + + if (rootEl && dragEl) { + pluginEvent('dragStarted', this, { + evt: evt + }); + + if (this.nativeDraggable) { + on(document, 'dragover', _checkOutsideTargetEl); + } + + var options = this.options; // Apply effect + + !fallback && toggleClass(dragEl, options.dragClass, false); + toggleClass(dragEl, options.ghostClass, true); + Sortable$1.active = this; + fallback && this._appendGhost(); // Drag start event + + _dispatchEvent({ + sortable: this, + name: 'start', + originalEvent: evt + }); + } else { + this._nulling(); + } + }, + _emulateDragOver: function _emulateDragOver() { + if (touchEvt) { + this._lastX = touchEvt.clientX; + this._lastY = touchEvt.clientY; + + _hideGhostForTarget(); + + var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + var parent = target; + + while (target && target.shadowRoot) { + target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + if (target === parent) break; + parent = target; + } + + dragEl.parentNode[expando]._isOutsideThisEl(target); + + if (parent) { + do { + if (parent[expando]) { + var inserted = void 0; + inserted = parent[expando]._onDragOver({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); + + if (inserted && !this.options.dragoverBubble) { + break; + } + } + + target = parent; // store last element + } + /* jshint boss:true */ + while (parent = parent.parentNode); + } + + _unhideGhostForTarget(); + } + }, + _onTouchMove: function _onTouchMove( + /**TouchEvent*/ + evt) { + if (tapEvt) { + var options = this.options, + fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, + touch = evt.touches ? evt.touches[0] : evt, + ghostMatrix = ghostEl && matrix(ghostEl), + scaleX = ghostEl && ghostMatrix && ghostMatrix.a, + scaleY = ghostEl && ghostMatrix && ghostMatrix.d, + relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent), + dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1), + dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1), + translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging + + if (!Sortable$1.active && !awaitingDragStarted) { + if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) { + return; + } + + this._onDragStart(evt, true); + } + + touchEvt = touch; + css(ghostEl, 'webkitTransform', translate3d); + css(ghostEl, 'mozTransform', translate3d); + css(ghostEl, 'msTransform', translate3d); + css(ghostEl, 'transform', translate3d); + evt.cancelable && evt.preventDefault(); + } + }, + _appendGhost: function _appendGhost() { + // Bug if using scale(): https://stackoverflow.com/questions/2637058 + // Not being adjusted for + if (!ghostEl) { + var container = this.options.fallbackOnBody ? document.body : rootEl, + rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container), + options = this.options; // Position absolutely + + if (PositionGhostAbsolutely) { + // Get relatively positioned parent + ghostRelativeParent = container; + + while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) { + ghostRelativeParent = ghostRelativeParent.parentNode; + } + + if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { + if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement(); + rect.top += ghostRelativeParent.scrollTop; + rect.left += ghostRelativeParent.scrollLeft; + } else { + ghostRelativeParent = getWindowScrollingElement(); + } + + ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent); + } + + ghostEl = dragEl.cloneNode(true); + toggleClass(ghostEl, options.ghostClass, false); + toggleClass(ghostEl, options.fallbackClass, true); + toggleClass(ghostEl, options.dragClass, true); + css(ghostEl, 'transition', ''); + css(ghostEl, 'transform', ''); + css(ghostEl, 'box-sizing', 'border-box'); + css(ghostEl, 'margin', 0); + css(ghostEl, 'top', rect.top); + css(ghostEl, 'left', rect.left); + css(ghostEl, 'width', rect.width); + css(ghostEl, 'height', rect.height); + css(ghostEl, 'opacity', '0.8'); + css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed'); + css(ghostEl, 'zIndex', '100000'); + css(ghostEl, 'pointerEvents', 'none'); + Sortable$1.ghost = ghostEl; + container.appendChild(ghostEl); + } + }, + _onDragStart: function _onDragStart( + /**Event*/ + evt, + /**boolean*/ + fallback) { + var _this = this; + + var dataTransfer = evt.dataTransfer; + var options = _this.options; + pluginEvent('dragStart', this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } + + pluginEvent('setupClone', this); + + if (!Sortable$1.eventCanceled) { + cloneEl = clone(dragEl); + cloneEl.draggable = false; + cloneEl.style['will-change'] = ''; + + this._hideClone(); + + toggleClass(cloneEl, this.options.chosenClass, false); + Sortable$1.clone = cloneEl; + } // #1143: IFrame support workaround + + + _this.cloneId = _nextTick(function () { + pluginEvent('clone', _this); + if (Sortable$1.eventCanceled) return; + + if (!_this.options.removeCloneOnHide) { + rootEl.insertBefore(cloneEl, dragEl); + } + + _this._hideClone(); + + _dispatchEvent({ + sortable: _this, + name: 'clone' + }); + }); + !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events + + if (fallback) { + ignoreNextClick = true; + _this._loopId = setInterval(_this._emulateDragOver, 50); + } else { + // Undo what was set in _prepareDragStart before drag started + off(document, 'mouseup', _this._onDrop); + off(document, 'touchend', _this._onDrop); + off(document, 'touchcancel', _this._onDrop); + + if (dataTransfer) { + dataTransfer.effectAllowed = 'move'; + options.setData && options.setData.call(_this, dataTransfer, dragEl); + } + + on(document, 'drop', _this); // #1276 fix: + + css(dragEl, 'transform', 'translateZ(0)'); + } + + awaitingDragStarted = true; + _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); + on(document, 'selectstart', _this); + moved = true; + + if (Safari) { + css(document.body, 'user-select', 'none'); + } + }, + // Returns true - if no further action is needed (either inserted or another condition) + _onDragOver: function _onDragOver( + /**Event*/ + evt) { + var el = this.el, + target = evt.target, + dragRect, + targetRect, + revert, + options = this.options, + group = options.group, + activeSortable = Sortable$1.active, + isOwner = activeGroup === group, + canSort = options.sort, + fromSortable = putSortable || activeSortable, + vertical, + _this = this, + completedFired = false; + + if (_silent) return; + + function dragOverEvent(name, extra) { + pluginEvent(name, _this, _objectSpread({ + evt: evt, + isOwner: isOwner, + axis: vertical ? 'vertical' : 'horizontal', + revert: revert, + dragRect: dragRect, + targetRect: targetRect, + canSort: canSort, + fromSortable: fromSortable, + target: target, + completed: completed, + onMove: function onMove(target, after) { + _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after); + }, + changed: changed + }, extra)); + } // Capture animation state + + + function capture() { + dragOverEvent('dragOverAnimationCapture'); + + _this.captureAnimationState(); + + if (_this !== fromSortable) { + fromSortable.captureAnimationState(); + } + } // Return invocation when dragEl is inserted (or completed) + + + function completed(insertion) { + dragOverEvent('dragOverCompleted', { + insertion: insertion + }); + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } else { + activeSortable._showClone(_this); + } + + if (_this !== fromSortable) { + // Set ghost class to new sortable's ghost class + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); + toggleClass(dragEl, options.ghostClass, true); + } + + if (putSortable !== _this && _this !== Sortable$1.active) { + putSortable = _this; + } else if (_this === Sortable$1.active && putSortable) { + putSortable = null; + } // Animation + + + if (fromSortable === _this) { + _this._ignoreWhileAnimating = target; + } + + _this.animateAll(function () { + dragOverEvent('dragOverAnimationComplete'); + _this._ignoreWhileAnimating = null; + }); + + if (_this !== fromSortable) { + fromSortable.animateAll(); + fromSortable._ignoreWhileAnimating = null; + } + } // Null lastTarget if it is not inside a previously swapped element + + + if (target === dragEl && !dragEl.animated || target === el && !target.animated) { + lastTarget = null; + } // no bubbling and not fallback + + + if (!options.dragoverBubble && !evt.rootEl && target !== document) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted + + + !insertion && nearestEmptyInsertDetectEvent(evt); + } + + !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); + return completedFired = true; + } // Call when dragEl has been inserted + + + function changed() { + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + _dispatchEvent({ + sortable: _this, + name: 'change', + toEl: el, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + originalEvent: evt + }); + } + + if (evt.preventDefault !== void 0) { + evt.cancelable && evt.preventDefault(); + } + + target = closest(target, options.draggable, el, true); + dragOverEvent('dragOver'); + if (Sortable$1.eventCanceled) return completedFired; + + if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) { + return completed(false); + } + + ignoreNextClick = false; + + if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list + : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) { + vertical = this._getDirection(evt, target) === 'vertical'; + dragRect = getRect(dragEl); + dragOverEvent('dragOverValid'); + if (Sortable$1.eventCanceled) return completedFired; + + if (revert) { + parentEl = rootEl; // actualization + + capture(); + + this._hideClone(); + + dragOverEvent('revert'); + + if (!Sortable$1.eventCanceled) { + if (nextEl) { + rootEl.insertBefore(dragEl, nextEl); + } else { + rootEl.appendChild(dragEl); + } + } + + return completed(true); + } + + var elLastChild = lastChild(el, options.draggable); + + if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) { + // If already at end of list: Do not insert + if (elLastChild === dragEl) { + return completed(false); + } // assign target only if condition is true + + + if (elLastChild && el === evt.target) { + target = elLastChild; + } + + if (target) { + targetRect = getRect(target); + } + + if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { + capture(); + el.appendChild(dragEl); + parentEl = el; // actualization + + changed(); + return completed(true); + } + } else if (target.parentNode === el) { + var direction = 0, + targetBeforeFirstSwap, + differentLevel = dragEl.parentNode !== el, + side1 = vertical ? 'top' : 'left', + scrolledPastTop = isScrolledPast(target, null, 'top', 'top') || isScrolledPast(dragEl, null, 'top', 'top'), + scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; + + if (lastTarget !== target) { + targetBeforeFirstSwap = getRect(target)[side1]; + pastFirstInvertThresh = false; + isCircumstantialInvert = options.invertSwap || differentLevel; + } + + direction = _getSwapDirection(evt, target, vertical, options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target); + var sibling; + + if (direction !== 0) { + // Check if target is beside dragEl in respective direction (ignoring hidden elements) + var dragIndex = index(dragEl); + + do { + dragIndex -= direction; + sibling = parentEl.children[dragIndex]; + } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl)); + } // If dragEl is already beside target: Do not insert + + + if (direction === 0 || sibling === target) { + return completed(false); + } + + lastTarget = target; + lastDirection = direction; + targetRect = getRect(target); + var nextSibling = target.nextElementSibling, + after = false; + after = direction === 1; + + var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); + + if (moveVector !== false) { + if (moveVector === 1 || moveVector === -1) { + after = moveVector === 1; + } + + _silent = true; + setTimeout(_unsilent, 30); + capture(); + + if (after && !nextSibling) { + el.appendChild(dragEl); + } else { + target.parentNode.insertBefore(dragEl, after ? nextSibling : target); + } // Undo chrome's scroll adjustment (has no effect on other browsers) + + + if (scrolledPastTop) { + scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); + } + + parentEl = dragEl.parentNode; // actualization + // must be done before animation + + if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { + targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]); + } + + changed(); + return completed(true); + } + } + + if (el.contains(dragEl)) { + return completed(false); + } + } + + return false; + }, + _ignoreWhileAnimating: null, + _offMoveEvents: function _offMoveEvents() { + off(document, 'mousemove', this._onTouchMove); + off(document, 'touchmove', this._onTouchMove); + off(document, 'pointermove', this._onTouchMove); + off(document, 'dragover', nearestEmptyInsertDetectEvent); + off(document, 'mousemove', nearestEmptyInsertDetectEvent); + off(document, 'touchmove', nearestEmptyInsertDetectEvent); + }, + _offUpEvents: function _offUpEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._onDrop); + off(ownerDocument, 'touchend', this._onDrop); + off(ownerDocument, 'pointerup', this._onDrop); + off(ownerDocument, 'touchcancel', this._onDrop); + off(document, 'selectstart', this); + }, + _onDrop: function _onDrop( + /**Event*/ + evt) { + var el = this.el, + options = this.options; // Get the index of the dragged element within its parent + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + pluginEvent('drop', this, { + evt: evt + }); // Get again after plugin event + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + if (Sortable$1.eventCanceled) { + this._nulling(); + + return; + } + + awaitingDragStarted = false; + isCircumstantialInvert = false; + pastFirstInvertThresh = false; + clearInterval(this._loopId); + clearTimeout(this._dragStartTimer); + + _cancelNextTick(this.cloneId); + + _cancelNextTick(this._dragStartId); // Unbind events + + + if (this.nativeDraggable) { + off(document, 'drop', this); + off(el, 'dragstart', this._onDragStart); + } + + this._offMoveEvents(); + + this._offUpEvents(); + + if (Safari) { + css(document.body, 'user-select', ''); + } + + if (evt) { + if (moved) { + evt.cancelable && evt.preventDefault(); + !options.dropBubble && evt.stopPropagation(); + } + + ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + // Remove clone(s) + cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); + } + + if (dragEl) { + if (this.nativeDraggable) { + off(dragEl, 'dragend', this); + } + + _disableDraggable(dragEl); + + dragEl.style['will-change'] = ''; // Remove classes + // ghostClass is added in dragStarted + + if (moved && !awaitingDragStarted) { + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); + } + + toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event + + _dispatchEvent({ + sortable: this, + name: 'unchoose', + toEl: parentEl, + newIndex: null, + newDraggableIndex: null, + originalEvent: evt + }); + + if (rootEl !== parentEl) { + if (newIndex >= 0) { + // Add event + _dispatchEvent({ + rootEl: parentEl, + name: 'add', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); // Remove event + + + _dispatchEvent({ + sortable: this, + name: 'remove', + toEl: parentEl, + originalEvent: evt + }); // drag from one list and drop into another + + + _dispatchEvent({ + rootEl: parentEl, + name: 'sort', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + + putSortable && putSortable.save(); + } else { + if (newIndex !== oldIndex) { + if (newIndex >= 0) { + // drag & drop within the same list + _dispatchEvent({ + sortable: this, + name: 'update', + toEl: parentEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + } + } + + if (Sortable$1.active) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { + newIndex = oldIndex; + newDraggableIndex = oldDraggableIndex; + } + + _dispatchEvent({ + sortable: this, + name: 'end', + toEl: parentEl, + originalEvent: evt + }); // Save sorting + + + this.save(); + } + } + } + + this._nulling(); + }, + _nulling: function _nulling() { + pluginEvent('nulling', this); + rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable$1.dragged = Sortable$1.ghost = Sortable$1.clone = Sortable$1.active = null; + savedInputChecked.forEach(function (el) { + el.checked = true; + }); + savedInputChecked.length = 0; + }, + handleEvent: function handleEvent( + /**Event*/ + evt) { + switch (evt.type) { + case 'drop': + case 'dragend': + this._onDrop(evt); + + break; + + case 'dragenter': + case 'dragover': + if (dragEl) { + this._onDragOver(evt); + + _globalDragOver(evt); + } + + break; + + case 'selectstart': + evt.preventDefault(); + break; + } + }, + + /** + * Serializes the item into an array of string. + * @returns {String[]} + */ + toArray: function toArray() { + var order = [], + el, + children = this.el.children, + i = 0, + n = children.length, + options = this.options; + + for (; i < n; i++) { + el = children[i]; + + if (closest(el, options.draggable, this.el, false)) { + order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); + } + } + + return order; + }, + + /** + * Sorts the elements according to the array. + * @param {String[]} order order of the items + */ + sort: function sort(order) { + var items = {}, + rootEl = this.el; + this.toArray().forEach(function (id, i) { + var el = rootEl.children[i]; + + if (closest(el, this.options.draggable, rootEl, false)) { + items[id] = el; + } + }, this); + order.forEach(function (id) { + if (items[id]) { + rootEl.removeChild(items[id]); + rootEl.appendChild(items[id]); + } + }); + }, + + /** + * Save the current sorting + */ + save: function save() { + var store = this.options.store; + store && store.set && store.set(this); + }, + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * @param {HTMLElement} el + * @param {String} [selector] default: `options.draggable` + * @returns {HTMLElement|null} + */ + closest: function closest$1(el, selector) { + return closest(el, selector || this.options.draggable, this.el, false); + }, + + /** + * Set/get option + * @param {string} name + * @param {*} [value] + * @returns {*} + */ + option: function option(name, value) { + var options = this.options; + + if (value === void 0) { + return options[name]; + } else { + var modifiedValue = PluginManager.modifyOption(this, name, value); + + if (typeof modifiedValue !== 'undefined') { + options[name] = modifiedValue; + } else { + options[name] = value; + } + + if (name === 'group') { + _prepareGroup(options); + } + } + }, + + /** + * Destroy + */ + destroy: function destroy() { + pluginEvent('destroy', this); + var el = this.el; + el[expando] = null; + off(el, 'mousedown', this._onTapStart); + off(el, 'touchstart', this._onTapStart); + off(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + off(el, 'dragover', this); + off(el, 'dragenter', this); + } // Remove draggable attributes + + + Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { + el.removeAttribute('draggable'); + }); + + this._onDrop(); + + sortables.splice(sortables.indexOf(this.el), 1); + this.el = el = null; + }, + _hideClone: function _hideClone() { + if (!cloneHidden) { + pluginEvent('hideClone', this); + if (Sortable$1.eventCanceled) return; + css(cloneEl, 'display', 'none'); + + if (this.options.removeCloneOnHide && cloneEl.parentNode) { + cloneEl.parentNode.removeChild(cloneEl); + } + + cloneHidden = true; + } + }, + _showClone: function _showClone(putSortable) { + if (putSortable.lastPutMode !== 'clone') { + this._hideClone(); + + return; + } + + if (cloneHidden) { + pluginEvent('showClone', this); + if (Sortable$1.eventCanceled) return; // show clone at dragEl or original position + + if (rootEl.contains(dragEl) && !this.options.group.revertClone) { + rootEl.insertBefore(cloneEl, dragEl); + } else if (nextEl) { + rootEl.insertBefore(cloneEl, nextEl); + } else { + rootEl.appendChild(cloneEl); + } + + if (this.options.group.revertClone) { + this._animate(dragEl, cloneEl); + } + + css(cloneEl, 'display', ''); + cloneHidden = false; + } + } +}; + +function _globalDragOver( +/**Event*/ +evt) { + if (evt.dataTransfer) { + evt.dataTransfer.dropEffect = 'move'; + } + + evt.cancelable && evt.preventDefault(); +} + +function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) { + var evt, + sortable = fromEl[expando], + onMoveFn = sortable.options.onMove, + retVal; // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent('move', { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent('move', true, true); + } + + evt.to = toEl; + evt.from = fromEl; + evt.dragged = dragEl; + evt.draggedRect = dragRect; + evt.related = targetEl || toEl; + evt.relatedRect = targetRect || getRect(toEl); + evt.willInsertAfter = willInsertAfter; + evt.originalEvent = originalEvent; + fromEl.dispatchEvent(evt); + + if (onMoveFn) { + retVal = onMoveFn.call(sortable, evt, originalEvent); + } + + return retVal; +} + +function _disableDraggable(el) { + el.draggable = false; +} + +function _unsilent() { + _silent = false; +} + +function _ghostIsLast(evt, vertical, sortable) { + var elRect = getRect(lastChild(sortable.el, sortable.options.draggable)), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + mouseOnOppAxis = vertical ? evt.clientX : evt.clientY, + targetS2 = vertical ? elRect.bottom : elRect.right, + targetS1Opp = vertical ? elRect.left : elRect.top, + targetS2Opp = vertical ? elRect.right : elRect.bottom; + return mouseOnAxis > targetS2 && mouseOnOppAxis > targetS1Opp && mouseOnOppAxis < targetS2Opp; +} + +function _getSwapDirection(evt, target, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { + var targetRect = getRect(target), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + targetLength = vertical ? targetRect.height : targetRect.width, + targetS1 = vertical ? targetRect.top : targetRect.left, + targetS2 = vertical ? targetRect.bottom : targetRect.right, + invert = false; + + if (!invertSwap) { + // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold + if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { + // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 + // check if past first invert threshold on side opposite of lastDirection + if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) { + // past first invert threshold, do not restrict inverted threshold to dragEl shadow + pastFirstInvertThresh = true; + } + + if (!pastFirstInvertThresh) { + // dragEl shadow (target move distance shadow) + if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow + : mouseOnAxis > targetS2 - targetMoveDistance) { + return -lastDirection; + } + } else { + invert = true; + } + } else { + // Regular + if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) { + return _getInsertDirection(target); + } + } + } + + invert = invert || invertSwap; + + if (invert) { + // Invert of regular + if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) { + return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1; + } + } + + return 0; +} +/** + * Gets the direction dragEl must be swapped relative to target in order to make it + * seem that dragEl has been "inserted" into that element's position + * @param {HTMLElement} target The target whose position dragEl is being inserted at + * @return {Number} Direction dragEl must be swapped + */ + + +function _getInsertDirection(target) { + if (index(dragEl) < index(target)) { + return 1; + } else { + return -1; + } +} +/** + * Generate id + * @param {HTMLElement} el + * @returns {String} + * @private + */ + + +function _generateId(el) { + var str = el.tagName + el.className + el.src + el.href + el.textContent, + i = str.length, + sum = 0; + + while (i--) { + sum += str.charCodeAt(i); + } + + return sum.toString(36); +} + +function _saveInputCheckedState(root) { + savedInputChecked.length = 0; + var inputs = root.getElementsByTagName('input'); + var idx = inputs.length; + + while (idx--) { + var _el = inputs[idx]; + _el.checked && savedInputChecked.push(_el); + } +} + +function _nextTick(fn) { + return setTimeout(fn, 0); +} + +function _cancelNextTick(id) { + return clearTimeout(id); +} // Fixed #973: + + +on(document, 'touchmove', function (evt) { + if ((Sortable$1.active || awaitingDragStarted) && evt.cancelable) { + evt.preventDefault(); + } +}); // Export utils + +Sortable$1.utils = { + on: on, + off: off, + css: css, + find: find, + is: function is(el, selector) { + return !!closest(el, selector, el, false); + }, + extend: extend, + throttle: throttle, + closest: closest, + toggleClass: toggleClass, + clone: clone, + index: index, + nextTick: _nextTick, + cancelNextTick: _cancelNextTick, + detectDirection: _detectDirection, + getChild: getChild +}; +/** + * Mount a plugin to Sortable + * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted + */ + +Sortable$1.mount = function () { + for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) { + plugins[_key] = arguments[_key]; + } + + if (plugins[0].constructor === Array) plugins = plugins[0]; + + for (var i in plugins) { + var plugin = plugins[i]; + + if (!plugin.prototype || !plugin.prototype.constructor) { + throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(el)); + } + + if (plugin.utils) Sortable$1.utils = _objectSpread({}, Sortable$1.utils, plugin.utils); + PluginManager.mount(plugin); + } +}; +/** + * Create sortable instance + * @param {HTMLElement} el + * @param {Object} [options] + */ + + +Sortable$1.create = function (el, options) { + return new Sortable$1(el, options); +}; // Export + + +Sortable$1.version = version; + +var autoScrolls = [], + scrollEl, + scrollRootEl, + scrolling = false, + lastAutoScrollX, + lastAutoScrollY, + touchEvt$1, + pointerElemChangedInterval; + +function AutoScrollPlugin() { + function AutoScroll() { + this.options = { + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, + bubbleScroll: true + }; // Bind all private methods + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + } + + AutoScroll.prototype = { + dragStarted: function dragStarted(_ref) { + var originalEvent = _ref.originalEvent; + + if (this.sortable.nativeDraggable) { + on(document, 'dragover', this._handleAutoScroll); + } else { + if (this.sortable.options.supportPointer) { + on(document, 'pointermove', this._handleFallbackAutoScroll); + } else if (originalEvent.touches) { + on(document, 'touchmove', this._handleFallbackAutoScroll); + } else { + on(document, 'mousemove', this._handleFallbackAutoScroll); + } + } + }, + dragOverCompleted: function dragOverCompleted(_ref2) { + var originalEvent = _ref2.originalEvent; + + // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) + if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) { + this._handleAutoScroll(originalEvent); + } + }, + drop: function drop() { + if (this.sortable.nativeDraggable) { + off(document, 'dragover', this._handleAutoScroll); + } else { + off(document, 'pointermove', this._handleFallbackAutoScroll); + off(document, 'touchmove', this._handleFallbackAutoScroll); + off(document, 'mousemove', this._handleFallbackAutoScroll); + } + + clearPointerElemChangedInterval(); + clearAutoScrolls(); + cancelThrottle(); + }, + nulling: function nulling() { + touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null; + autoScrolls.length = 0; + }, + _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) { + this._handleAutoScroll(evt, true); + }, + _handleAutoScroll: function _handleAutoScroll(evt, fallback) { + var _this = this; + + var x = evt.clientX, + y = evt.clientY, + elem = document.elementFromPoint(x, y); + touchEvt$1 = evt; // IE does not seem to have native autoscroll, + // Edge's autoscroll seems too conditional, + // MACOS Safari does not have autoscroll, + // Firefox and Chrome are good + + if (fallback || Edge || IE11OrLess || Safari) { + autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change + + var ogElemScroller = getParentAutoScrollElement(elem, true); + + if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) { + pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour + + pointerElemChangedInterval = setInterval(function () { + var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true); + + if (newElem !== ogElemScroller) { + ogElemScroller = newElem; + clearAutoScrolls(); + } + + autoScroll(evt, _this.options, newElem, fallback); + }, 10); + lastAutoScrollX = x; + lastAutoScrollY = y; + } + } else { + // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll + if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) { + clearAutoScrolls(); + return; + } + + autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false); + } + } + }; + return _extends(AutoScroll, { + pluginName: 'scroll', + initializeByDefault: true + }); +} + +function clearAutoScrolls() { + autoScrolls.forEach(function (autoScroll) { + clearInterval(autoScroll.pid); + }); + autoScrolls = []; +} + +function clearPointerElemChangedInterval() { + clearInterval(pointerElemChangedInterval); +} + +var autoScroll = throttle(function (evt, options, rootEl, isFallback) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + if (!options.scroll) return; + var sens = options.scrollSensitivity, + speed = options.scrollSpeed, + winScroller = getWindowScrollingElement(); + var scrollThisInstance = false, + scrollCustomFn; // New scroll root, set scrollEl + + if (scrollRootEl !== rootEl) { + scrollRootEl = rootEl; + clearAutoScrolls(); + scrollEl = options.scroll; + scrollCustomFn = options.scrollFn; + + if (scrollEl === true) { + scrollEl = getParentAutoScrollElement(rootEl, true); + } + } + + var layersOut = 0; + var currentParent = scrollEl; + + do { + var el = currentParent, + rect = getRect(el), + top = rect.top, + bottom = rect.bottom, + left = rect.left, + right = rect.right, + width = rect.width, + height = rect.height, + canScrollX = void 0, + canScrollY = void 0, + scrollWidth = el.scrollWidth, + scrollHeight = el.scrollHeight, + elCSS = css(el), + scrollPosX = el.scrollLeft, + scrollPosY = el.scrollTop; + + if (el === winScroller) { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible'); + } else { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll'); + } + + var vx = canScrollX && (Math.abs(right - evt.clientX) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - evt.clientX) <= sens && !!scrollPosX); + var vy = canScrollY && (Math.abs(bottom - evt.clientY) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - evt.clientY) <= sens && !!scrollPosY); + + if (!autoScrolls[layersOut]) { + for (var i = 0; i <= layersOut; i++) { + if (!autoScrolls[i]) { + autoScrolls[i] = {}; + } + } + } + + if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { + autoScrolls[layersOut].el = el; + autoScrolls[layersOut].vx = vx; + autoScrolls[layersOut].vy = vy; + clearInterval(autoScrolls[layersOut].pid); + + if (vx != 0 || vy != 0) { + scrollThisInstance = true; + /* jshint loopfunc:true */ + + autoScrolls[layersOut].pid = setInterval(function () { + // emulate drag over during autoscroll (fallback), emulating native DnD behaviour + if (isFallback && this.layer === 0) { + Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely + + } + + var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; + var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; + + if (typeof scrollCustomFn === 'function') { + if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') { + return; + } + } + + scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); + }.bind({ + layer: layersOut + }), 24); + } + } + + layersOut++; + } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false))); + + scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not +}, 30); + +var drop = function drop(_ref) { + var originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + dragEl = _ref.dragEl, + activeSortable = _ref.activeSortable, + dispatchSortableEvent = _ref.dispatchSortableEvent, + hideGhostForTarget = _ref.hideGhostForTarget, + unhideGhostForTarget = _ref.unhideGhostForTarget; + var toSortable = putSortable || activeSortable; + hideGhostForTarget(); + var target = document.elementFromPoint(originalEvent.clientX, originalEvent.clientY); + unhideGhostForTarget(); + + if (toSortable && !toSortable.el.contains(target)) { + dispatchSortableEvent('spill'); + this.onSpill(dragEl); + } +}; + +function Revert() {} + +Revert.prototype = { + startIndex: null, + dragStart: function dragStart(_ref2) { + var oldDraggableIndex = _ref2.oldDraggableIndex; + this.startIndex = oldDraggableIndex; + }, + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + var nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options); + + if (nextSibling) { + this.sortable.el.insertBefore(dragEl, nextSibling); + } else { + this.sortable.el.appendChild(dragEl); + } + + this.sortable.animateAll(); + }, + drop: drop +}; + +_extends(Revert, { + pluginName: 'revertOnSpill' +}); + +function Remove() {} + +Remove.prototype = { + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + dragEl.parentNode && dragEl.parentNode.removeChild(dragEl); + this.sortable.animateAll(); + }, + drop: drop +}; + +_extends(Remove, { + pluginName: 'removeOnSpill' +}); + +var lastSwapEl; + +function SwapPlugin() { + function Swap() { + this.options = { + swapClass: 'sortable-swap-highlight' + }; + } + + Swap.prototype = { + dragStart: function dragStart(_ref) { + var dragEl = _ref.dragEl; + lastSwapEl = dragEl; + }, + dragOverValid: function dragOverValid(_ref2) { + var completed = _ref2.completed, + target = _ref2.target, + onMove = _ref2.onMove, + activeSortable = _ref2.activeSortable, + changed = _ref2.changed; + if (!activeSortable.options.swap) return; + var el = this.sortable.el, + options = this.sortable.options; + + if (target && target !== el) { + var prevSwapEl = lastSwapEl; + + if (onMove(target) !== false) { + toggleClass(target, options.swapClass, true); + lastSwapEl = target; + } else { + lastSwapEl = null; + } + + if (prevSwapEl && prevSwapEl !== lastSwapEl) { + toggleClass(prevSwapEl, options.swapClass, false); + } + } + + changed(); + return completed(true); + }, + drop: function drop(_ref3) { + var activeSortable = _ref3.activeSortable, + putSortable = _ref3.putSortable, + dragEl = _ref3.dragEl; + var toSortable = putSortable || this.sortable; + var options = this.sortable.options; + lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false); + + if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) { + if (dragEl !== lastSwapEl) { + toSortable.captureAnimationState(); + if (toSortable !== activeSortable) activeSortable.captureAnimationState(); + swapNodes(dragEl, lastSwapEl); + toSortable.animateAll(); + if (toSortable !== activeSortable) activeSortable.animateAll(); + } + } + }, + nulling: function nulling() { + lastSwapEl = null; + } + }; + return _extends(Swap, { + pluginName: 'swap', + eventOptions: function eventOptions() { + return { + swapItem: lastSwapEl + }; + } + }); +} + +function swapNodes(n1, n2) { + var p1 = n1.parentNode, + p2 = n2.parentNode, + i1, + i2; + if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return; + i1 = index(n1); + i2 = index(n2); + + if (p1.isEqualNode(p2) && i1 < i2) { + i2++; + } + + p1.insertBefore(n2, p1.children[i1]); + p2.insertBefore(n1, p2.children[i2]); +} + +var multiDragElements = [], + multiDragClones = [], + lastMultiDragSelect, + // for selection with modifier key down (SHIFT) +multiDragSortable, + initialFolding = false, + // Initial multi-drag fold when drag started +folding = false, + // Folding any other time +dragStarted = false, + dragEl$1, + clonesFromRect, + clonesHidden; + +function MultiDragPlugin() { + function MultiDrag(sortable) { + // Bind all private methods + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + if (sortable.options.supportPointer) { + on(document, 'pointerup', this._deselectMultiDrag); + } else { + on(document, 'mouseup', this._deselectMultiDrag); + on(document, 'touchend', this._deselectMultiDrag); + } + + on(document, 'keydown', this._checkKeyDown); + on(document, 'keyup', this._checkKeyUp); + this.options = { + selectedClass: 'sortable-selected', + multiDragKey: null, + setData: function setData(dataTransfer, dragEl) { + var data = ''; + + if (multiDragElements.length && multiDragSortable === sortable) { + for (var i in multiDragElements) { + data += (!i ? '' : ', ') + multiDragElements[i].textContent; + } + } else { + data = dragEl.textContent; + } + + dataTransfer.setData('Text', data); + } + }; + } + + MultiDrag.prototype = { + multiDragKeyDown: false, + isMultiDrag: false, + delayStartGlobal: function delayStartGlobal(_ref) { + var dragged = _ref.dragEl; + dragEl$1 = dragged; + }, + delayEnded: function delayEnded() { + this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1); + }, + setupClone: function setupClone(_ref2) { + var sortable = _ref2.sortable; + if (!this.isMultiDrag) return; + + for (var i in multiDragElements) { + multiDragClones.push(clone(multiDragElements[i])); + multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex; + multiDragClones[i].draggable = false; + multiDragClones[i].style['will-change'] = ''; + toggleClass(multiDragClones[i], sortable.options.selectedClass, false); + multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], sortable.options.chosenClass, false); + } + + sortable._hideClone(); + + return true; + }, + clone: function clone(_ref3) { + var sortable = _ref3.sortable, + rootEl = _ref3.rootEl, + dispatchSortableEvent = _ref3.dispatchSortableEvent; + if (!this.isMultiDrag) return; + + if (!sortable.options.removeCloneOnHide) { + if (multiDragElements.length && multiDragSortable === sortable) { + insertMultiDragClones(true, rootEl); + dispatchSortableEvent('clone'); + return true; + } + } + }, + showClone: function showClone(_ref4) { + var cloneNowShown = _ref4.cloneNowShown, + rootEl = _ref4.rootEl; + if (!this.isMultiDrag) return; + insertMultiDragClones(false, rootEl); + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', ''); + } + + cloneNowShown(); + clonesHidden = false; + return true; + }, + hideClone: function hideClone(_ref5) { + var sortable = _ref5.sortable, + cloneNowHidden = _ref5.cloneNowHidden; + if (!this.isMultiDrag) return; + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', 'none'); + + if (sortable.options.removeCloneOnHide && multiDragClones[i].parentNode) { + multiDragClones[i].parentNode.removeChild(multiDragClones[i]); + } + } + + cloneNowHidden(); + clonesHidden = true; + return true; + }, + dragStartGlobal: function dragStartGlobal(_ref6) { + var sortable = _ref6.sortable; + + if (!this.isMultiDrag && multiDragSortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + } + + for (var i in multiDragElements) { + multiDragElements[i].sortableIndex = index(multiDragElements[i]); + } // Sort multi-drag elements + + + multiDragElements = multiDragElements.sort(function (a, b) { + return a.sortableIndex - b.sortableIndex; + }); + dragStarted = true; + }, + dragStarted: function dragStarted(_ref7) { + var sortable = _ref7.sortable; + if (!this.isMultiDrag) return; + + if (sortable.options.sort) { + // Capture rects, + // hide multi drag elements (by positioning them absolute), + // set multi drag elements rects to dragRect, + // show multi drag elements, + // animate to rects, + // unset rects & remove from DOM + sortable.captureAnimationState(); + + if (sortable.options.animation) { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + css(multiDragElements[i], 'position', 'absolute'); + } + + var dragRect = getRect(dragEl$1, false, true, true); + + for (var _i in multiDragElements) { + if (multiDragElements[_i] === dragEl$1) continue; + setRect(multiDragElements[_i], dragRect); + } + + folding = true; + initialFolding = true; + } + } + + sortable.animateAll(function () { + folding = false; + initialFolding = false; + + if (sortable.options.animation) { + for (var _i2 in multiDragElements) { + unsetRect(multiDragElements[_i2]); + } + } // Remove all auxiliary multidrag items from el, if sorting enabled + + + if (sortable.options.sort) { + removeMultiDragElements(); + } + }); + }, + dragOver: function dragOver(_ref8) { + var target = _ref8.target, + completed = _ref8.completed; + + if (folding && ~multiDragElements.indexOf(target)) { + return completed(false); + } + }, + revert: function revert(_ref9) { + var fromSortable = _ref9.fromSortable, + rootEl = _ref9.rootEl, + sortable = _ref9.sortable, + dragRect = _ref9.dragRect; + + if (multiDragElements.length > 1) { + // Setup unfold animation + for (var i in multiDragElements) { + sortable.addAnimationState({ + target: multiDragElements[i], + rect: folding ? getRect(multiDragElements[i]) : dragRect + }); + unsetRect(multiDragElements[i]); + multiDragElements[i].fromRect = dragRect; + fromSortable.removeAnimationState(multiDragElements[i]); + } + + folding = false; + insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl); + } + }, + dragOverCompleted: function dragOverCompleted(_ref10) { + var sortable = _ref10.sortable, + isOwner = _ref10.isOwner, + insertion = _ref10.insertion, + activeSortable = _ref10.activeSortable, + parentEl = _ref10.parentEl, + putSortable = _ref10.putSortable; + var options = sortable.options; + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } + + initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location + + if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) { + // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible + var dragRectAbsolute = getRect(dragEl$1, false, true, true); + + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + setRect(multiDragElements[i], dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted + // while folding, and so that we can capture them again because old sortable will no longer be fromSortable + + parentEl.appendChild(multiDragElements[i]); + } + + folding = true; + } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out + + + if (!isOwner) { + // Only remove if not folding (folding will remove them anyways) + if (!folding) { + removeMultiDragElements(); + } + + if (multiDragElements.length > 1) { + var clonesHiddenBefore = clonesHidden; + + activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden + + + if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) { + for (var _i3 in multiDragClones) { + activeSortable.addAnimationState({ + target: multiDragClones[_i3], + rect: clonesFromRect + }); + multiDragClones[_i3].fromRect = clonesFromRect; + multiDragClones[_i3].thisAnimationDuration = null; + } + } + } else { + activeSortable._showClone(sortable); + } + } + } + }, + dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) { + var dragRect = _ref11.dragRect, + isOwner = _ref11.isOwner, + activeSortable = _ref11.activeSortable; + + for (var i in multiDragElements) { + multiDragElements[i].thisAnimationDuration = null; + } + + if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) { + clonesFromRect = _extends({}, dragRect); + var dragMatrix = matrix(dragEl$1, true); + clonesFromRect.top -= dragMatrix.f; + clonesFromRect.left -= dragMatrix.e; + } + }, + dragOverAnimationComplete: function dragOverAnimationComplete() { + if (folding) { + folding = false; + removeMultiDragElements(); + } + }, + drop: function drop(_ref12) { + var evt = _ref12.originalEvent, + rootEl = _ref12.rootEl, + parentEl = _ref12.parentEl, + sortable = _ref12.sortable, + dispatchSortableEvent = _ref12.dispatchSortableEvent, + oldIndex = _ref12.oldIndex, + putSortable = _ref12.putSortable; + var toSortable = putSortable || this.sortable; + if (!evt) return; + var options = sortable.options, + children = parentEl.children; // Multi-drag selection + + if (!dragStarted) { + if (options.multiDragKey && !this.multiDragKeyDown) { + this._deselectMultiDrag(); + } + + toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1)); + + if (!~multiDragElements.indexOf(dragEl$1)) { + multiDragElements.push(dragEl$1); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: dragEl$1, + originalEvt: evt + }); // Modifier activated, select from last to dragEl + + if ((!options.multiDragKey || this.multiDragKeyDown) && evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) { + var lastIndex = index(lastMultiDragSelect), + currentIndex = index(dragEl$1); + + if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) { + // Must include lastMultiDragSelect (select it), in case modified selection from no selection + // (but previous selection existed) + var n, i; + + if (currentIndex > lastIndex) { + i = lastIndex; + n = currentIndex; + } else { + i = currentIndex; + n = lastIndex + 1; + } + + for (; i < n; i++) { + if (~multiDragElements.indexOf(children[i])) continue; + toggleClass(children[i], options.selectedClass, true); + multiDragElements.push(children[i]); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: children[i], + originalEvt: evt + }); + } + } + } else { + lastMultiDragSelect = dragEl$1; + } + + multiDragSortable = toSortable; + } else { + multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1); + lastMultiDragSelect = null; + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'deselect', + targetEl: dragEl$1, + originalEvt: evt + }); + } + } // Multi-drag drop + + + if (dragStarted && this.isMultiDrag) { + // Do not "unfold" after around dragEl if reverted + if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) { + var dragRect = getRect(dragEl$1), + multiDragIndex = index(dragEl$1, ':not(.' + Sortable.active.options.selectedClass + ')'); + if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null; + toSortable.captureAnimationState(); + + if (!initialFolding) { + if (options.animation) { + dragEl$1.fromRect = dragRect; + + for (var _i4 in multiDragElements) { + multiDragElements[_i4].thisAnimationDuration = null; + + if (multiDragElements[_i4] !== dragEl$1) { + var rect = folding ? getRect(multiDragElements[_i4]) : dragRect; + multiDragElements[_i4].fromRect = rect; // Prepare unfold animation + + toSortable.addAnimationState({ + target: multiDragElements[_i4], + rect: rect + }); + } + } + } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert + // properly they must all be removed + + + removeMultiDragElements(); + + for (var _i5 in multiDragElements) { + if (children[multiDragIndex]) { + parentEl.insertBefore(multiDragElements[_i5], children[multiDragIndex]); + } else { + parentEl.appendChild(multiDragElements[_i5]); + } + + multiDragIndex++; + } // If initial folding is done, the elements may have changed position because they are now + // unfolding around dragEl, even though dragEl may not have his index changed, so update event + // must be fired here as Sortable will not. + + + if (oldIndex === index(dragEl$1)) { + var update = false; + + for (var _i6 in multiDragElements) { + if (multiDragElements[_i6].sortableIndex !== index(multiDragElements[_i6])) { + update = true; + break; + } + } + + if (update) { + dispatchSortableEvent('update'); + } + } + } // Must be done after capturing individual rects (scroll bar) + + + for (var _i7 in multiDragElements) { + unsetRect(multiDragElements[_i7]); + } + + toSortable.animateAll(); + } + + multiDragSortable = toSortable; + } // Remove clones if necessary + + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + for (var _i8 in multiDragClones) { + multiDragClones[_i8].parentNode && multiDragClones[_i8].parentNode.removeChild(multiDragClones[_i8]); + } + } + }, + nullingGlobal: function nullingGlobal() { + this.isMultiDrag = dragStarted = false; + multiDragClones.length = 0; + }, + destroy: function destroy() { + this._deselectMultiDrag(); + + off(document, 'pointerup', this._deselectMultiDrag); + off(document, 'mouseup', this._deselectMultiDrag); + off(document, 'touchend', this._deselectMultiDrag); + off(document, 'keydown', this._checkKeyDown); + off(document, 'keyup', this._checkKeyUp); + }, + _deselectMultiDrag: function _deselectMultiDrag(evt) { + if (dragStarted) return; // Only deselect if selection is in this sortable + + if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable + + if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return; // Only deselect if left click + + if (evt && evt.button !== 0) return; + + while (multiDragElements.length) { + var el = multiDragElements[0]; + toggleClass(el, this.sortable.options.selectedClass, false); + multiDragElements.shift(); + dispatchEvent({ + sortable: this.sortable, + rootEl: this.sortable.el, + name: 'deselect', + targetEl: el, + originalEvt: evt + }); + } + }, + _checkKeyDown: function _checkKeyDown(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = true; + } + }, + _checkKeyUp: function _checkKeyUp(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = false; + } + } + }; + return _extends(MultiDrag, { + // Static methods & properties + pluginName: 'multiDrag', + utils: { + /** + * Selects the provided multi-drag item + * @param {HTMLElement} el The element to be selected + */ + select: function select(el) { + var sortable = el.parentNode[expando]; + if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return; + + if (multiDragSortable && multiDragSortable !== sortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + + multiDragSortable = sortable; + } + + toggleClass(el, sortable.options.selectedClass, true); + multiDragElements.push(el); + }, + + /** + * Deselects the provided multi-drag item + * @param {HTMLElement} el The element to be deselected + */ + deselect: function deselect(el) { + var sortable = el.parentNode[expando], + index = multiDragElements.indexOf(el); + if (!sortable || !sortable.options.multiDrag || !~index) return; + toggleClass(el, sortable.options.selectedClass, false); + multiDragElements.splice(index, 1); + } + }, + eventOptions: function eventOptions() { + return { + items: _toConsumableArray(multiDragElements), + clones: [].concat(multiDragClones) + }; + }, + optionListeners: { + multiDragKey: function multiDragKey(key) { + key = key.toLowerCase(); + + if (key === 'ctrl') { + key = 'Control'; + } else if (key.length > 1) { + key = key.charAt(0).toUpperCase() + key.substr(1); + } + + return key; + } + } + }); +} + +function insertMultiDragElements(clonesInserted, rootEl) { + for (var i in multiDragElements) { + var target = rootEl.children[multiDragElements[i].sortableIndex + (clonesInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragElements[i], target); + } else { + rootEl.appendChild(multiDragElements[i]); + } + } +} +/** + * Insert multi-drag clones + * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted + * @param {HTMLElement} rootEl + */ + + +function insertMultiDragClones(elementsInserted, rootEl) { + for (var i in multiDragClones) { + var target = rootEl.children[multiDragClones[i].sortableIndex + (elementsInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragClones[i], target); + } else { + rootEl.appendChild(multiDragClones[i]); + } + } +} + +function removeMultiDragElements() { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + multiDragElements[i].parentNode && multiDragElements[i].parentNode.removeChild(multiDragElements[i]); + } +} + +Sortable$1.mount(new AutoScrollPlugin()); +Sortable$1.mount(Remove, Revert); + +Sortable$1.mount(new SwapPlugin()); +Sortable$1.mount(new MultiDragPlugin()); + +export default Sortable$1; diff --git a/modular/sortable.core.esm.js b/modular/sortable.core.esm.js new file mode 100644 index 000000000..564ff596f --- /dev/null +++ b/modular/sortable.core.esm.js @@ -0,0 +1,3598 @@ +/**! + * Sortable 1.9.0 + * @author RubaXa + * @author owenm + * @license MIT + */ +function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } + + return _typeof(obj); +} + +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; +} + +function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); +} + +function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; +} + +function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; +} + +function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + + var target = _objectWithoutPropertiesLoose(source, excluded); + + var key, i; + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + + return target; +} + +function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); +} + +function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } +} + +function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); +} + +function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance"); +} + +var version = "1.9.0"; + +function userAgent(pattern) { + return !!navigator.userAgent.match(pattern); +} + +var IE11OrLess = +/*@__PURE__*/ +userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile)/i); +var Edge = +/*@__PURE__*/ +userAgent(/Edge/i); +var FireFox = +/*@__PURE__*/ +userAgent(/firefox/i); +var Safari = +/*@__PURE__*/ +userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); +var IOS = +/*@__PURE__*/ +userAgent(/iP(ad|od|hone)/i); + +var 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; +} + +var R_SPACE = /\s+/g; + +function toggleClass(el, name, state) { + if (el && name) { + if (el.classList) { + el.classList[state ? 'add' : 'remove'](name); + } else { + var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); + el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); + } + } +} + +function css(el, prop, val) { + var 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) { + var appliedTransforms = ''; + + do { + var transform = css(el, 'transform'); + + if (transform && transform !== 'none') { + appliedTransforms = transform + ' ' + appliedTransforms; + } + /* jshint boss:true */ + + } while (!selfOnly && (el = el.parentNode)); + + var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix; + /*jshint -W056 */ + + return matrixFn && new matrixFn(appliedTransforms); +} + +function find(ctx, tagName, iterator) { + if (ctx) { + var list = ctx.getElementsByTagName(tagName), + i = 0, + n = list.length; + + if (iterator) { + for (; i < n; i++) { + iterator(list[i], i); + } + } + + return list; + } + + return []; +} + +function getWindowScrollingElement() { + if (IE11OrLess) { + return document.documentElement; + } else { + return document.scrollingElement; + } +} +/** + * 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; + var 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')) { + var 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() + var 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 {[DOMRect]} rect Optional rect of `el` to use + * @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, rect, elSide, parentSide) { + var parent = getParentAutoScrollElement(el, true), + elSideVal = (rect ? rect : getRect(el))[elSide]; + /* jshint boss:true */ + + while (parent) { + var parentSideVal = getRect(parent)[parentSide], + visible = void 0; + + 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) { + var currentChild = 0, + i = 0, + children = el.children; + + while (i < children.length) { + if (children[i].style.display !== 'none' && children[i] !== Sortable$1.ghost && children[i] !== Sortable$1.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) { + var last = el.lastElementChild; + + while (last && (last === Sortable$1.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) { + var index = 0; + + if (!el || !el.parentNode) { + return -1; + } + /* jshint boss:true */ + + + while (el = el.previousElementSibling) { + if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable$1.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) { + var offsetLeft = 0, + offsetTop = 0, + winScroller = getWindowScrollingElement(); + + if (el) { + do { + var 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 (var i in arr) { + for (var key in obj) { + if (obj[key] === arr[i][key]) return Number(i); + } + } + + return -1; +} + +function getParentAutoScrollElement(el, includeSelf) { + // skip to window + if (!el || !el.getBoundingClientRect) return getWindowScrollingElement(); + var elem = el; + var 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) { + var 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 (var 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); +} + +var _throttleTimeout; + +function throttle(callback, ms) { + return function () { + if (!_throttleTimeout) { + var 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) { + var Polymer = window.Polymer; + var $ = 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', ''); +} + +var expando = 'Sortable' + new Date().getTime(); + +function AnimationStateManager() { + var animationStates = [], + animationCallbackId; + return { + captureAnimationState: function captureAnimationState() { + animationStates = []; + if (!this.options.animation) return; + var children = [].slice.call(this.el.children); + + for (var i in children) { + if (css(children[i], 'display') === 'none' || children[i] === Sortable$1.ghost) continue; + animationStates.push({ + target: children[i], + rect: getRect(children[i]) + }); + var fromRect = getRect(children[i]); // If animating: compensate for current animation + + if (children[i].thisAnimationDuration) { + var childMatrix = matrix(children[i], true); + + if (childMatrix) { + fromRect.top -= childMatrix.f; + fromRect.left -= childMatrix.e; + } + } + + children[i].fromRect = fromRect; + } + }, + addAnimationState: function addAnimationState(state) { + animationStates.push(state); + }, + removeAnimationState: function removeAnimationState(target) { + animationStates.splice(indexOfObject(animationStates, { + target: target + }), 1); + }, + animateAll: function animateAll(callback) { + if (!this.options.animation) { + clearTimeout(animationCallbackId); + if (typeof callback === 'function') callback(); + return; + } + + var animating = false, + animationTime = 0; + + for (var i in animationStates) { + var time = 0, + target = animationStates[i].target, + fromRect = target.fromRect, + toRect = getRect(target), + prevFromRect = target.prevFromRect, + prevToRect = target.prevToRect, + animatingRect = animationStates[i].rect, + targetMatrix = matrix(target, true); + + if (targetMatrix) { + // Compensate for current animation + toRect.top -= targetMatrix.f; + toRect.left -= targetMatrix.e; + } + + target.toRect = toRect; // If element is scrolled out of view: Do not animate + + if ((isScrolledPast(target, toRect, 'bottom', 'top') || isScrolledPast(target, toRect, 'top', 'bottom') || isScrolledPast(target, toRect, 'right', 'left') || isScrolledPast(target, toRect, 'left', 'right')) && (isScrolledPast(target, animatingRect, 'bottom', 'top') || isScrolledPast(target, animatingRect, 'top', 'bottom') || isScrolledPast(target, animatingRect, 'right', 'left') || isScrolledPast(target, animatingRect, 'left', 'right')) && (isScrolledPast(target, fromRect, 'bottom', 'top') || isScrolledPast(target, fromRect, 'top', 'bottom') || isScrolledPast(target, fromRect, 'right', 'left') || isScrolledPast(target, fromRect, 'left', 'right'))) continue; + + if (target.thisAnimationDuration) { + // Could also check if animatingRect is between fromRect and toRect + if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect + (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) { + // If returning to same place as started from animation and on same axis + time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options); + } + } // if fromRect != toRect: animate + + + if (!isRectEqual(toRect, fromRect)) { + target.prevFromRect = fromRect; + target.prevToRect = toRect; + + if (!time) { + time = this.options.animation; + } + + this.animate(target, animatingRect, time); + } + + if (time) { + animating = true; + animationTime = Math.max(animationTime, time); + clearTimeout(target.animationResetTimer); + target.animationResetTimer = setTimeout(function () { + this.animationStates[this.i].target.animationTime = 0; + this.animationStates[this.i].target.prevFromRect = null; + this.animationStates[this.i].target.fromRect = null; + this.animationStates[this.i].target.prevToRect = null; + this.animationStates[this.i].target.thisAnimationDuration = null; + }.bind({ + animationStates: animationStates, + i: Number(i) + }), time); + target.thisAnimationDuration = time; + } + } + + clearTimeout(animationCallbackId); + + if (!animating) { + if (typeof callback === 'function') callback(); + } else { + animationCallbackId = setTimeout(function () { + if (typeof callback === 'function') callback(); + }, animationTime); + } + + animationStates = []; + }, + animate: function animate(target, prev, duration) { + if (duration) { + css(target, 'transition', ''); + css(target, 'transform', ''); + var currentRect = getRect(target), + elMatrix = matrix(this.el), + scaleX = elMatrix && elMatrix.a, + scaleY = elMatrix && elMatrix.d, + translateX = (prev.left - currentRect.left) / (scaleX || 1), + translateY = (prev.top - currentRect.top) / (scaleY || 1); + target.animatingX = !!translateX; + target.animatingY = !!translateY; + css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); + repaint(target); // repaint + + css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); + css(target, 'transform', 'translate3d(0,0,0)'); + typeof target.animated === 'number' && clearTimeout(target.animated); + target.animated = setTimeout(function () { + css(target, 'transition', ''); + css(target, 'transform', ''); + target.animated = false; + target.animatingX = false; + target.animatingY = false; + }, duration); + } + } + }; +} + +function repaint(target) { + return target.offsetWidth; +} + +function calculateRealTime(animatingRect, fromRect, toRect, options) { + return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation; +} + +var plugins = []; +var defaults = { + initializeByDefault: true +}; +var PluginManager = { + mount: function mount(plugin) { + // Set default static properties + for (var option in defaults) { + !(option in plugin) && (plugin[option] = defaults[option]); + } + + plugins.push(plugin); + }, + pluginEvent: function pluginEvent(eventName, sortable, evt) { + this.eventCanceled = false; + var eventNameGlobal = eventName + 'Global'; + + for (var i in plugins) { + if (!sortable[plugins[i].pluginName]) continue; // Fire global events if it exists in this sortable + + if (sortable[plugins[i].pluginName][eventNameGlobal]) { + this.eventCanceled = !!sortable[plugins[i].pluginName][eventNameGlobal](_objectSpread({ + sortable: sortable + }, evt)); + } // Only fire plugin event if plugin is enabled in this sortable, + // and plugin has event defined + + + if (sortable.options[plugins[i].pluginName] && sortable[plugins[i].pluginName][eventName]) { + this.eventCanceled = this.eventCanceled || !!sortable[plugins[i].pluginName][eventName](_objectSpread({ + sortable: sortable + }, evt)); + } + } + }, + initializePlugins: function initializePlugins(sortable, el, defaults) { + for (var i in plugins) { + var pluginName = plugins[i].pluginName; + if (!sortable.options[pluginName] && !plugins[i].initializeByDefault) continue; + var initialized = new plugins[i](sortable, el); + initialized.sortable = sortable; + sortable[pluginName] = initialized; // Add default options from plugin + + _extends(defaults, initialized.options); + } + + for (var option in sortable.options) { + var modified = this.modifyOption(sortable, option, sortable.options[option]); + + if (typeof modified !== 'undefined') { + sortable.options[option] = modified; + } + } + }, + getEventOptions: function getEventOptions(name, sortable) { + var eventOptions = {}; + + for (var i in plugins) { + if (typeof plugins[i].eventOptions !== 'function') continue; + eventOptions = _objectSpread({}, eventOptions, plugins[i].eventOptions(name, sortable)); + } + + return eventOptions; + }, + modifyOption: function modifyOption(sortable, name, value) { + var modifiedValue; + + for (var i in plugins) { + // Plugin must exist on the Sortable + if (!sortable[plugins[i].pluginName]) continue; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin + + if (plugins[i].optionListeners && typeof plugins[i].optionListeners[name] === 'function') { + modifiedValue = plugins[i].optionListeners[name].call(sortable[plugins[i].pluginName], value); + } + } + + return modifiedValue; + } +}; + +function dispatchEvent(_ref) { + var sortable = _ref.sortable, + rootEl = _ref.rootEl, + name = _ref.name, + targetEl = _ref.targetEl, + cloneEl = _ref.cloneEl, + toEl = _ref.toEl, + fromEl = _ref.fromEl, + oldIndex = _ref.oldIndex, + newIndex = _ref.newIndex, + oldDraggableIndex = _ref.oldDraggableIndex, + newDraggableIndex = _ref.newDraggableIndex, + originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + eventOptions = _ref.eventOptions; + sortable = sortable || rootEl[expando]; + var evt, + options = sortable.options, + onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent(name, { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent(name, true, true); + } + + evt.to = toEl || rootEl; + evt.from = fromEl || rootEl; + evt.item = targetEl || rootEl; + evt.clone = cloneEl; + evt.oldIndex = oldIndex; + evt.newIndex = newIndex; + evt.oldDraggableIndex = oldDraggableIndex; + evt.newDraggableIndex = newDraggableIndex; + evt.originalEvent = originalEvent; + evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; + + var allEventOptions = _objectSpread({}, eventOptions, PluginManager.getEventOptions(name, sortable)); + + for (var option in allEventOptions) { + evt[option] = allEventOptions[option]; + } + + if (rootEl) { + rootEl.dispatchEvent(evt); + } + + if (options[onName]) { + options[onName].call(sortable, evt); + } +} + +var pluginEvent = function pluginEvent(eventName, sortable) { + var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + originalEvent = _ref.evt, + data = _objectWithoutProperties(_ref, ["evt"]); + + PluginManager.pluginEvent.bind(Sortable$1)(eventName, sortable, _objectSpread({ + dragEl: dragEl, + parentEl: parentEl, + ghostEl: ghostEl, + rootEl: rootEl, + nextEl: nextEl, + lastDownEl: lastDownEl, + cloneEl: cloneEl, + cloneHidden: cloneHidden, + dragStarted: moved, + putSortable: putSortable, + activeSortable: Sortable$1.active, + originalEvent: originalEvent, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + hideGhostForTarget: _hideGhostForTarget, + unhideGhostForTarget: _unhideGhostForTarget, + cloneNowHidden: function cloneNowHidden() { + cloneHidden = true; + }, + cloneNowShown: function cloneNowShown() { + cloneHidden = false; + }, + dispatchSortableEvent: function dispatchSortableEvent(name) { + _dispatchEvent({ + sortable: sortable, + name: name, + originalEvent: originalEvent + }); + } + }, data)); +}; + +function _dispatchEvent(info) { + dispatchEvent(_objectSpread({ + putSortable: putSortable, + cloneEl: cloneEl, + targetEl: dragEl, + rootEl: rootEl, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex + }, info)); +} + +if (typeof window === "undefined" || !window.document) { + throw new Error("Sortable.js requires a window with a document"); +} + +var dragEl, + parentEl, + ghostEl, + rootEl, + nextEl, + lastDownEl, + cloneEl, + cloneHidden, + oldIndex, + newIndex, + oldDraggableIndex, + newDraggableIndex, + activeGroup, + putSortable, + awaitingDragStarted = false, + ignoreNextClick = false, + sortables = [], + tapEvt, + touchEvt, + moved, + lastTarget, + lastDirection, + pastFirstInvertThresh = false, + isCircumstantialInvert = false, + targetMoveDistance, + // For positioning ghost absolutely +ghostRelativeParent, + ghostRelativeParentInitialScroll = [], + // (left, top) +_silent = false, + savedInputChecked = []; +/** @const */ + +var PositionGhostAbsolutely = IOS, + CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', + // This will not pass for IE9, because IE9 DnD only works on anchors +supportDraggable = 'draggable' in document.createElement('div'), + supportCssPointerEvents = function () { + // false when <= IE11 + if (IE11OrLess) { + return false; + } + + var el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; +}(), + _detectDirection = function _detectDirection(el, options) { + var elCSS = css(el), + elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth), + child1 = getChild(el, 0, options), + child2 = getChild(el, 1, options), + firstChildCSS = child1 && css(child1), + secondChildCSS = child2 && css(child2), + firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width, + secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width; + + if (elCSS.display === 'flex') { + return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal'; + } + + if (elCSS.display === 'grid') { + return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; + } + + if (child1 && firstChildCSS["float"] !== 'none') { + var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right'; + return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal'; + } + + return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal'; +}, + +/** + * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. + * @param {Number} x X position + * @param {Number} y Y position + * @return {HTMLElement} Element of the first found nearest Sortable + */ +_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) { + for (var i in sortables) { + if (lastChild(sortables[i])) continue; + var rect = getRect(sortables[i]), + threshold = sortables[i][expando].options.emptyInsertThreshold, + insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold, + insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold; + + if (threshold && insideHorizontally && insideVertically) { + return sortables[i]; + } + } +}, + _prepareGroup = function _prepareGroup(options) { + function toFn(value, pull) { + return function (to, from, dragEl, evt) { + var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name; + + if (value == null && (pull || sameGroup)) { + // Default pull value + // Default pull and put value if same group + return true; + } else if (value == null || value === false) { + return false; + } else if (pull && value === 'clone') { + return value; + } else if (typeof value === 'function') { + return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); + } else { + var otherGroup = (pull ? to : from).options.group.name; + return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1; + } + }; + } + + var group = {}; + var originalGroup = options.group; + + if (!originalGroup || _typeof(originalGroup) != 'object') { + originalGroup = { + name: originalGroup + }; + } + + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + group.revertClone = originalGroup.revertClone; + options.group = group; +}, + _hideGhostForTarget = function _hideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', 'none'); + } +}, + _unhideGhostForTarget = function _unhideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', ''); + } +}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position + + +document.addEventListener('click', function (evt) { + if (ignoreNextClick) { + evt.preventDefault(); + evt.stopPropagation && evt.stopPropagation(); + evt.stopImmediatePropagation && evt.stopImmediatePropagation(); + ignoreNextClick = false; + return false; + } +}, true); + +var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) { + if (dragEl) { + evt = evt.touches ? evt.touches[0] : evt; + + var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); + + if (nearest) { + // Create imitation event + var event = {}; + + for (var i in evt) { + event[i] = evt[i]; + } + + event.target = event.rootEl = nearest; + event.preventDefault = void 0; + event.stopPropagation = void 0; + + nearest[expando]._onDragOver(event); + } + } +}; + +var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) { + if (dragEl) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); + } +}; +/** + * @class Sortable + * @param {HTMLElement} el + * @param {Object} [options] + */ + + +function Sortable$1(el, options) { + if (!(el && el.nodeType && el.nodeType === 1)) { + throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el)); + } + + this.el = el; // root element + + this.options = options = _extends({}, options); // Export instance + + el[expando] = this; + var defaults = { + group: null, + sort: true, + disabled: false, + store: null, + handle: null, + draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*', + swapThreshold: 1, + // percentage; 0 <= x <= 1 + invertSwap: false, + // invert always + invertedSwapThreshold: null, + // will be set to same as swapThreshold if default + removeCloneOnHide: true, + direction: function direction() { + return _detectDirection(el, this.options); + }, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + ignore: 'a, img', + filter: null, + preventOnFilter: true, + animation: 0, + easing: null, + setData: function setData(dataTransfer, dragEl) { + dataTransfer.setData('Text', dragEl.textContent); + }, + dropBubble: false, + dragoverBubble: false, + dataIdAttr: 'data-id', + delay: 0, + delayOnTouchOnly: false, + touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, + forceFallback: false, + fallbackClass: 'sortable-fallback', + fallbackOnBody: false, + fallbackTolerance: 0, + fallbackOffset: { + x: 0, + y: 0 + }, + supportPointer: Sortable$1.supportPointer !== false && 'PointerEvent' in window, + emptyInsertThreshold: 5 + }; + PluginManager.initializePlugins(this, el, defaults); // Set default options + + for (var name in defaults) { + !(name in options) && (options[name] = defaults[name]); + } + + _prepareGroup(options); // Bind all private methods + + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } // Setup drag mode + + + this.nativeDraggable = options.forceFallback ? false : supportDraggable; + + if (this.nativeDraggable) { + // Touch start threshold cannot be greater than the native dragstart threshold + this.options.touchStartThreshold = 1; + } // Bind events + + + if (options.supportPointer) { + on(el, 'pointerdown', this._onTapStart); + } else { + on(el, 'mousedown', this._onTapStart); + on(el, 'touchstart', this._onTapStart); + } + + if (this.nativeDraggable) { + on(el, 'dragover', this); + on(el, 'dragenter', this); + } + + sortables.push(this.el); // Restore sorting + + options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager + + _extends(this, AnimationStateManager()); +} + +Sortable$1.prototype = +/** @lends Sortable.prototype */ +{ + constructor: Sortable$1, + _isOutsideThisEl: function _isOutsideThisEl(target) { + if (!this.el.contains(target) && target !== this.el) { + lastTarget = null; + } + }, + _getDirection: function _getDirection(evt, target) { + return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; + }, + _onTapStart: function _onTapStart( + /** Event|TouchEvent */ + evt) { + if (!evt.cancelable) return; + + var _this = this, + el = this.el, + options = this.options, + preventOnFilter = options.preventOnFilter, + type = evt.type, + touch = evt.touches && evt.touches[0], + target = (touch || evt).target, + originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target, + filter = options.filter; + + _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. + + + if (dragEl) { + return; + } + + if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { + return; // only left button and enabled + } // cancel dnd if original target is content editable + + + if (originalTarget.isContentEditable) { + return; + } + + target = closest(target, options.draggable, el, false); + + if (target && target.animated) { + return; + } + + if (lastDownEl === target) { + // Ignoring duplicate `down` + return; + } // Get the index of the dragged element within its parent + + + oldIndex = index(target); + oldDraggableIndex = index(target, options.draggable); // Check filter + + if (typeof filter === 'function') { + if (filter.call(this, evt, target, this)) { + _dispatchEvent({ + sortable: _this, + rootEl: originalTarget, + name: 'filter', + targetEl: target, + toEl: el, + fromEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } else if (filter) { + filter = filter.split(',').some(function (criteria) { + criteria = closest(originalTarget, criteria.trim(), el, false); + + if (criteria) { + _dispatchEvent({ + sortable: _this, + rootEl: criteria, + name: 'filter', + targetEl: target, + fromEl: el, + toEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + return true; + } + }); + + if (filter) { + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } + + if (options.handle && !closest(originalTarget, options.handle, el, false)) { + return; + } // Prepare `dragstart` + + + this._prepareDragStart(evt, touch, target); + }, + _prepareDragStart: function _prepareDragStart( + /** Event */ + evt, + /** Touch */ + touch, + /** HTMLElement */ + target) { + var _this = this, + el = _this.el, + options = _this.options, + ownerDocument = el.ownerDocument, + dragStartFn; + + if (target && !dragEl && target.parentNode === el) { + rootEl = el; + dragEl = target; + parentEl = dragEl.parentNode; + nextEl = dragEl.nextSibling; + lastDownEl = target; + activeGroup = options.group; + Sortable$1.dragged = dragEl; + tapEvt = { + target: dragEl, + clientX: (touch || evt).clientX, + clientY: (touch || evt).clientY + }; + this._lastX = (touch || evt).clientX; + this._lastY = (touch || evt).clientY; + dragEl.style['will-change'] = 'all'; + + dragStartFn = function dragStartFn() { + pluginEvent('delayEnded', _this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + _this._onDrop(); + + return; + } // Delayed drag has been triggered + // we can re-enable the events: touchmove/mousemove + + + _this._disableDelayedDragEvents(); + + if (!FireFox && _this.nativeDraggable) { + dragEl.draggable = true; + } // Bind the events: dragstart/dragend + + + _this._triggerDragStart(evt, touch); // Drag start event + + + _dispatchEvent({ + sortable: _this, + name: 'choose', + originalEvent: evt + }); // Chosen item + + + toggleClass(dragEl, options.chosenClass, true); + }; // Disable "draggable" + + + options.ignore.split(',').forEach(function (criteria) { + find(dragEl, criteria.trim(), _disableDraggable); + }); + on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mouseup', _this._onDrop); + on(ownerDocument, 'touchend', _this._onDrop); + on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox) + + if (FireFox && this.nativeDraggable) { + this.options.touchStartThreshold = 4; + dragEl.draggable = true; + } + + pluginEvent('delayStart', this, { + evt: evt + }); // Delay is impossible for native DnD in Edge or IE + + if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } // If the user moves the pointer or let go the click or touch + // before the delay has been reached: + // disable the delayed drag + + + on(ownerDocument, 'mouseup', _this._disableDelayedDrag); + on(ownerDocument, 'touchend', _this._disableDelayedDrag); + on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); + on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); + on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); + options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); + _this._dragStartTimer = setTimeout(dragStartFn, options.delay); + } else { + dragStartFn(); + } + } + }, + _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( + /** TouchEvent|PointerEvent **/ + e) { + var touch = e.touches ? e.touches[0] : e; + + if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) { + this._disableDelayedDrag(); + } + }, + _disableDelayedDrag: function _disableDelayedDrag() { + dragEl && _disableDraggable(dragEl); + clearTimeout(this._dragStartTimer); + + this._disableDelayedDragEvents(); + }, + _disableDelayedDragEvents: function _disableDelayedDragEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._disableDelayedDrag); + off(ownerDocument, 'touchend', this._disableDelayedDrag); + off(ownerDocument, 'touchcancel', this._disableDelayedDrag); + off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); + }, + _triggerDragStart: function _triggerDragStart( + /** Event */ + evt, + /** Touch */ + touch) { + touch = touch || (evt.pointerType == 'touch' ? evt : null); + + if (!this.nativeDraggable || touch) { + if (this.options.supportPointer) { + on(document, 'pointermove', this._onTouchMove); + } else if (touch) { + on(document, 'touchmove', this._onTouchMove); + } else { + on(document, 'mousemove', this._onTouchMove); + } + } else { + on(dragEl, 'dragend', this); + on(rootEl, 'dragstart', this._onDragStart); + } + + try { + if (document.selection) { + // Timeout neccessary for IE9 + _nextTick(function () { + document.selection.empty(); + }); + } else { + window.getSelection().removeAllRanges(); + } + } catch (err) {} + }, + _dragStarted: function _dragStarted(fallback, evt) { + + awaitingDragStarted = false; + + if (rootEl && dragEl) { + pluginEvent('dragStarted', this, { + evt: evt + }); + + if (this.nativeDraggable) { + on(document, 'dragover', _checkOutsideTargetEl); + } + + var options = this.options; // Apply effect + + !fallback && toggleClass(dragEl, options.dragClass, false); + toggleClass(dragEl, options.ghostClass, true); + Sortable$1.active = this; + fallback && this._appendGhost(); // Drag start event + + _dispatchEvent({ + sortable: this, + name: 'start', + originalEvent: evt + }); + } else { + this._nulling(); + } + }, + _emulateDragOver: function _emulateDragOver() { + if (touchEvt) { + this._lastX = touchEvt.clientX; + this._lastY = touchEvt.clientY; + + _hideGhostForTarget(); + + var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + var parent = target; + + while (target && target.shadowRoot) { + target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + if (target === parent) break; + parent = target; + } + + dragEl.parentNode[expando]._isOutsideThisEl(target); + + if (parent) { + do { + if (parent[expando]) { + var inserted = void 0; + inserted = parent[expando]._onDragOver({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); + + if (inserted && !this.options.dragoverBubble) { + break; + } + } + + target = parent; // store last element + } + /* jshint boss:true */ + while (parent = parent.parentNode); + } + + _unhideGhostForTarget(); + } + }, + _onTouchMove: function _onTouchMove( + /**TouchEvent*/ + evt) { + if (tapEvt) { + var options = this.options, + fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, + touch = evt.touches ? evt.touches[0] : evt, + ghostMatrix = ghostEl && matrix(ghostEl), + scaleX = ghostEl && ghostMatrix && ghostMatrix.a, + scaleY = ghostEl && ghostMatrix && ghostMatrix.d, + relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent), + dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1), + dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1), + translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging + + if (!Sortable$1.active && !awaitingDragStarted) { + if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) { + return; + } + + this._onDragStart(evt, true); + } + + touchEvt = touch; + css(ghostEl, 'webkitTransform', translate3d); + css(ghostEl, 'mozTransform', translate3d); + css(ghostEl, 'msTransform', translate3d); + css(ghostEl, 'transform', translate3d); + evt.cancelable && evt.preventDefault(); + } + }, + _appendGhost: function _appendGhost() { + // Bug if using scale(): https://stackoverflow.com/questions/2637058 + // Not being adjusted for + if (!ghostEl) { + var container = this.options.fallbackOnBody ? document.body : rootEl, + rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container), + options = this.options; // Position absolutely + + if (PositionGhostAbsolutely) { + // Get relatively positioned parent + ghostRelativeParent = container; + + while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) { + ghostRelativeParent = ghostRelativeParent.parentNode; + } + + if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { + if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement(); + rect.top += ghostRelativeParent.scrollTop; + rect.left += ghostRelativeParent.scrollLeft; + } else { + ghostRelativeParent = getWindowScrollingElement(); + } + + ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent); + } + + ghostEl = dragEl.cloneNode(true); + toggleClass(ghostEl, options.ghostClass, false); + toggleClass(ghostEl, options.fallbackClass, true); + toggleClass(ghostEl, options.dragClass, true); + css(ghostEl, 'transition', ''); + css(ghostEl, 'transform', ''); + css(ghostEl, 'box-sizing', 'border-box'); + css(ghostEl, 'margin', 0); + css(ghostEl, 'top', rect.top); + css(ghostEl, 'left', rect.left); + css(ghostEl, 'width', rect.width); + css(ghostEl, 'height', rect.height); + css(ghostEl, 'opacity', '0.8'); + css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed'); + css(ghostEl, 'zIndex', '100000'); + css(ghostEl, 'pointerEvents', 'none'); + Sortable$1.ghost = ghostEl; + container.appendChild(ghostEl); + } + }, + _onDragStart: function _onDragStart( + /**Event*/ + evt, + /**boolean*/ + fallback) { + var _this = this; + + var dataTransfer = evt.dataTransfer; + var options = _this.options; + pluginEvent('dragStart', this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } + + pluginEvent('setupClone', this); + + if (!Sortable$1.eventCanceled) { + cloneEl = clone(dragEl); + cloneEl.draggable = false; + cloneEl.style['will-change'] = ''; + + this._hideClone(); + + toggleClass(cloneEl, this.options.chosenClass, false); + Sortable$1.clone = cloneEl; + } // #1143: IFrame support workaround + + + _this.cloneId = _nextTick(function () { + pluginEvent('clone', _this); + if (Sortable$1.eventCanceled) return; + + if (!_this.options.removeCloneOnHide) { + rootEl.insertBefore(cloneEl, dragEl); + } + + _this._hideClone(); + + _dispatchEvent({ + sortable: _this, + name: 'clone' + }); + }); + !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events + + if (fallback) { + ignoreNextClick = true; + _this._loopId = setInterval(_this._emulateDragOver, 50); + } else { + // Undo what was set in _prepareDragStart before drag started + off(document, 'mouseup', _this._onDrop); + off(document, 'touchend', _this._onDrop); + off(document, 'touchcancel', _this._onDrop); + + if (dataTransfer) { + dataTransfer.effectAllowed = 'move'; + options.setData && options.setData.call(_this, dataTransfer, dragEl); + } + + on(document, 'drop', _this); // #1276 fix: + + css(dragEl, 'transform', 'translateZ(0)'); + } + + awaitingDragStarted = true; + _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); + on(document, 'selectstart', _this); + moved = true; + + if (Safari) { + css(document.body, 'user-select', 'none'); + } + }, + // Returns true - if no further action is needed (either inserted or another condition) + _onDragOver: function _onDragOver( + /**Event*/ + evt) { + var el = this.el, + target = evt.target, + dragRect, + targetRect, + revert, + options = this.options, + group = options.group, + activeSortable = Sortable$1.active, + isOwner = activeGroup === group, + canSort = options.sort, + fromSortable = putSortable || activeSortable, + vertical, + _this = this, + completedFired = false; + + if (_silent) return; + + function dragOverEvent(name, extra) { + pluginEvent(name, _this, _objectSpread({ + evt: evt, + isOwner: isOwner, + axis: vertical ? 'vertical' : 'horizontal', + revert: revert, + dragRect: dragRect, + targetRect: targetRect, + canSort: canSort, + fromSortable: fromSortable, + target: target, + completed: completed, + onMove: function onMove(target, after) { + _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after); + }, + changed: changed + }, extra)); + } // Capture animation state + + + function capture() { + dragOverEvent('dragOverAnimationCapture'); + + _this.captureAnimationState(); + + if (_this !== fromSortable) { + fromSortable.captureAnimationState(); + } + } // Return invocation when dragEl is inserted (or completed) + + + function completed(insertion) { + dragOverEvent('dragOverCompleted', { + insertion: insertion + }); + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } else { + activeSortable._showClone(_this); + } + + if (_this !== fromSortable) { + // Set ghost class to new sortable's ghost class + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); + toggleClass(dragEl, options.ghostClass, true); + } + + if (putSortable !== _this && _this !== Sortable$1.active) { + putSortable = _this; + } else if (_this === Sortable$1.active && putSortable) { + putSortable = null; + } // Animation + + + if (fromSortable === _this) { + _this._ignoreWhileAnimating = target; + } + + _this.animateAll(function () { + dragOverEvent('dragOverAnimationComplete'); + _this._ignoreWhileAnimating = null; + }); + + if (_this !== fromSortable) { + fromSortable.animateAll(); + fromSortable._ignoreWhileAnimating = null; + } + } // Null lastTarget if it is not inside a previously swapped element + + + if (target === dragEl && !dragEl.animated || target === el && !target.animated) { + lastTarget = null; + } // no bubbling and not fallback + + + if (!options.dragoverBubble && !evt.rootEl && target !== document) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted + + + !insertion && nearestEmptyInsertDetectEvent(evt); + } + + !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); + return completedFired = true; + } // Call when dragEl has been inserted + + + function changed() { + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + _dispatchEvent({ + sortable: _this, + name: 'change', + toEl: el, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + originalEvent: evt + }); + } + + if (evt.preventDefault !== void 0) { + evt.cancelable && evt.preventDefault(); + } + + target = closest(target, options.draggable, el, true); + dragOverEvent('dragOver'); + if (Sortable$1.eventCanceled) return completedFired; + + if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) { + return completed(false); + } + + ignoreNextClick = false; + + if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list + : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) { + vertical = this._getDirection(evt, target) === 'vertical'; + dragRect = getRect(dragEl); + dragOverEvent('dragOverValid'); + if (Sortable$1.eventCanceled) return completedFired; + + if (revert) { + parentEl = rootEl; // actualization + + capture(); + + this._hideClone(); + + dragOverEvent('revert'); + + if (!Sortable$1.eventCanceled) { + if (nextEl) { + rootEl.insertBefore(dragEl, nextEl); + } else { + rootEl.appendChild(dragEl); + } + } + + return completed(true); + } + + var elLastChild = lastChild(el, options.draggable); + + if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) { + // If already at end of list: Do not insert + if (elLastChild === dragEl) { + return completed(false); + } // assign target only if condition is true + + + if (elLastChild && el === evt.target) { + target = elLastChild; + } + + if (target) { + targetRect = getRect(target); + } + + if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { + capture(); + el.appendChild(dragEl); + parentEl = el; // actualization + + changed(); + return completed(true); + } + } else if (target.parentNode === el) { + var direction = 0, + targetBeforeFirstSwap, + differentLevel = dragEl.parentNode !== el, + side1 = vertical ? 'top' : 'left', + scrolledPastTop = isScrolledPast(target, null, 'top', 'top') || isScrolledPast(dragEl, null, 'top', 'top'), + scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; + + if (lastTarget !== target) { + targetBeforeFirstSwap = getRect(target)[side1]; + pastFirstInvertThresh = false; + isCircumstantialInvert = options.invertSwap || differentLevel; + } + + direction = _getSwapDirection(evt, target, vertical, options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target); + var sibling; + + if (direction !== 0) { + // Check if target is beside dragEl in respective direction (ignoring hidden elements) + var dragIndex = index(dragEl); + + do { + dragIndex -= direction; + sibling = parentEl.children[dragIndex]; + } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl)); + } // If dragEl is already beside target: Do not insert + + + if (direction === 0 || sibling === target) { + return completed(false); + } + + lastTarget = target; + lastDirection = direction; + targetRect = getRect(target); + var nextSibling = target.nextElementSibling, + after = false; + after = direction === 1; + + var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); + + if (moveVector !== false) { + if (moveVector === 1 || moveVector === -1) { + after = moveVector === 1; + } + + _silent = true; + setTimeout(_unsilent, 30); + capture(); + + if (after && !nextSibling) { + el.appendChild(dragEl); + } else { + target.parentNode.insertBefore(dragEl, after ? nextSibling : target); + } // Undo chrome's scroll adjustment (has no effect on other browsers) + + + if (scrolledPastTop) { + scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); + } + + parentEl = dragEl.parentNode; // actualization + // must be done before animation + + if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { + targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]); + } + + changed(); + return completed(true); + } + } + + if (el.contains(dragEl)) { + return completed(false); + } + } + + return false; + }, + _ignoreWhileAnimating: null, + _offMoveEvents: function _offMoveEvents() { + off(document, 'mousemove', this._onTouchMove); + off(document, 'touchmove', this._onTouchMove); + off(document, 'pointermove', this._onTouchMove); + off(document, 'dragover', nearestEmptyInsertDetectEvent); + off(document, 'mousemove', nearestEmptyInsertDetectEvent); + off(document, 'touchmove', nearestEmptyInsertDetectEvent); + }, + _offUpEvents: function _offUpEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._onDrop); + off(ownerDocument, 'touchend', this._onDrop); + off(ownerDocument, 'pointerup', this._onDrop); + off(ownerDocument, 'touchcancel', this._onDrop); + off(document, 'selectstart', this); + }, + _onDrop: function _onDrop( + /**Event*/ + evt) { + var el = this.el, + options = this.options; // Get the index of the dragged element within its parent + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + pluginEvent('drop', this, { + evt: evt + }); // Get again after plugin event + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + if (Sortable$1.eventCanceled) { + this._nulling(); + + return; + } + + awaitingDragStarted = false; + isCircumstantialInvert = false; + pastFirstInvertThresh = false; + clearInterval(this._loopId); + clearTimeout(this._dragStartTimer); + + _cancelNextTick(this.cloneId); + + _cancelNextTick(this._dragStartId); // Unbind events + + + if (this.nativeDraggable) { + off(document, 'drop', this); + off(el, 'dragstart', this._onDragStart); + } + + this._offMoveEvents(); + + this._offUpEvents(); + + if (Safari) { + css(document.body, 'user-select', ''); + } + + if (evt) { + if (moved) { + evt.cancelable && evt.preventDefault(); + !options.dropBubble && evt.stopPropagation(); + } + + ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + // Remove clone(s) + cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); + } + + if (dragEl) { + if (this.nativeDraggable) { + off(dragEl, 'dragend', this); + } + + _disableDraggable(dragEl); + + dragEl.style['will-change'] = ''; // Remove classes + // ghostClass is added in dragStarted + + if (moved && !awaitingDragStarted) { + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); + } + + toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event + + _dispatchEvent({ + sortable: this, + name: 'unchoose', + toEl: parentEl, + newIndex: null, + newDraggableIndex: null, + originalEvent: evt + }); + + if (rootEl !== parentEl) { + if (newIndex >= 0) { + // Add event + _dispatchEvent({ + rootEl: parentEl, + name: 'add', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); // Remove event + + + _dispatchEvent({ + sortable: this, + name: 'remove', + toEl: parentEl, + originalEvent: evt + }); // drag from one list and drop into another + + + _dispatchEvent({ + rootEl: parentEl, + name: 'sort', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + + putSortable && putSortable.save(); + } else { + if (newIndex !== oldIndex) { + if (newIndex >= 0) { + // drag & drop within the same list + _dispatchEvent({ + sortable: this, + name: 'update', + toEl: parentEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + } + } + + if (Sortable$1.active) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { + newIndex = oldIndex; + newDraggableIndex = oldDraggableIndex; + } + + _dispatchEvent({ + sortable: this, + name: 'end', + toEl: parentEl, + originalEvent: evt + }); // Save sorting + + + this.save(); + } + } + } + + this._nulling(); + }, + _nulling: function _nulling() { + pluginEvent('nulling', this); + rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable$1.dragged = Sortable$1.ghost = Sortable$1.clone = Sortable$1.active = null; + savedInputChecked.forEach(function (el) { + el.checked = true; + }); + savedInputChecked.length = 0; + }, + handleEvent: function handleEvent( + /**Event*/ + evt) { + switch (evt.type) { + case 'drop': + case 'dragend': + this._onDrop(evt); + + break; + + case 'dragenter': + case 'dragover': + if (dragEl) { + this._onDragOver(evt); + + _globalDragOver(evt); + } + + break; + + case 'selectstart': + evt.preventDefault(); + break; + } + }, + + /** + * Serializes the item into an array of string. + * @returns {String[]} + */ + toArray: function toArray() { + var order = [], + el, + children = this.el.children, + i = 0, + n = children.length, + options = this.options; + + for (; i < n; i++) { + el = children[i]; + + if (closest(el, options.draggable, this.el, false)) { + order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); + } + } + + return order; + }, + + /** + * Sorts the elements according to the array. + * @param {String[]} order order of the items + */ + sort: function sort(order) { + var items = {}, + rootEl = this.el; + this.toArray().forEach(function (id, i) { + var el = rootEl.children[i]; + + if (closest(el, this.options.draggable, rootEl, false)) { + items[id] = el; + } + }, this); + order.forEach(function (id) { + if (items[id]) { + rootEl.removeChild(items[id]); + rootEl.appendChild(items[id]); + } + }); + }, + + /** + * Save the current sorting + */ + save: function save() { + var store = this.options.store; + store && store.set && store.set(this); + }, + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * @param {HTMLElement} el + * @param {String} [selector] default: `options.draggable` + * @returns {HTMLElement|null} + */ + closest: function closest$1(el, selector) { + return closest(el, selector || this.options.draggable, this.el, false); + }, + + /** + * Set/get option + * @param {string} name + * @param {*} [value] + * @returns {*} + */ + option: function option(name, value) { + var options = this.options; + + if (value === void 0) { + return options[name]; + } else { + var modifiedValue = PluginManager.modifyOption(this, name, value); + + if (typeof modifiedValue !== 'undefined') { + options[name] = modifiedValue; + } else { + options[name] = value; + } + + if (name === 'group') { + _prepareGroup(options); + } + } + }, + + /** + * Destroy + */ + destroy: function destroy() { + pluginEvent('destroy', this); + var el = this.el; + el[expando] = null; + off(el, 'mousedown', this._onTapStart); + off(el, 'touchstart', this._onTapStart); + off(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + off(el, 'dragover', this); + off(el, 'dragenter', this); + } // Remove draggable attributes + + + Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { + el.removeAttribute('draggable'); + }); + + this._onDrop(); + + sortables.splice(sortables.indexOf(this.el), 1); + this.el = el = null; + }, + _hideClone: function _hideClone() { + if (!cloneHidden) { + pluginEvent('hideClone', this); + if (Sortable$1.eventCanceled) return; + css(cloneEl, 'display', 'none'); + + if (this.options.removeCloneOnHide && cloneEl.parentNode) { + cloneEl.parentNode.removeChild(cloneEl); + } + + cloneHidden = true; + } + }, + _showClone: function _showClone(putSortable) { + if (putSortable.lastPutMode !== 'clone') { + this._hideClone(); + + return; + } + + if (cloneHidden) { + pluginEvent('showClone', this); + if (Sortable$1.eventCanceled) return; // show clone at dragEl or original position + + if (rootEl.contains(dragEl) && !this.options.group.revertClone) { + rootEl.insertBefore(cloneEl, dragEl); + } else if (nextEl) { + rootEl.insertBefore(cloneEl, nextEl); + } else { + rootEl.appendChild(cloneEl); + } + + if (this.options.group.revertClone) { + this._animate(dragEl, cloneEl); + } + + css(cloneEl, 'display', ''); + cloneHidden = false; + } + } +}; + +function _globalDragOver( +/**Event*/ +evt) { + if (evt.dataTransfer) { + evt.dataTransfer.dropEffect = 'move'; + } + + evt.cancelable && evt.preventDefault(); +} + +function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) { + var evt, + sortable = fromEl[expando], + onMoveFn = sortable.options.onMove, + retVal; // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent('move', { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent('move', true, true); + } + + evt.to = toEl; + evt.from = fromEl; + evt.dragged = dragEl; + evt.draggedRect = dragRect; + evt.related = targetEl || toEl; + evt.relatedRect = targetRect || getRect(toEl); + evt.willInsertAfter = willInsertAfter; + evt.originalEvent = originalEvent; + fromEl.dispatchEvent(evt); + + if (onMoveFn) { + retVal = onMoveFn.call(sortable, evt, originalEvent); + } + + return retVal; +} + +function _disableDraggable(el) { + el.draggable = false; +} + +function _unsilent() { + _silent = false; +} + +function _ghostIsLast(evt, vertical, sortable) { + var elRect = getRect(lastChild(sortable.el, sortable.options.draggable)), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + mouseOnOppAxis = vertical ? evt.clientX : evt.clientY, + targetS2 = vertical ? elRect.bottom : elRect.right, + targetS1Opp = vertical ? elRect.left : elRect.top, + targetS2Opp = vertical ? elRect.right : elRect.bottom; + return mouseOnAxis > targetS2 && mouseOnOppAxis > targetS1Opp && mouseOnOppAxis < targetS2Opp; +} + +function _getSwapDirection(evt, target, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { + var targetRect = getRect(target), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + targetLength = vertical ? targetRect.height : targetRect.width, + targetS1 = vertical ? targetRect.top : targetRect.left, + targetS2 = vertical ? targetRect.bottom : targetRect.right, + invert = false; + + if (!invertSwap) { + // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold + if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { + // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 + // check if past first invert threshold on side opposite of lastDirection + if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) { + // past first invert threshold, do not restrict inverted threshold to dragEl shadow + pastFirstInvertThresh = true; + } + + if (!pastFirstInvertThresh) { + // dragEl shadow (target move distance shadow) + if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow + : mouseOnAxis > targetS2 - targetMoveDistance) { + return -lastDirection; + } + } else { + invert = true; + } + } else { + // Regular + if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) { + return _getInsertDirection(target); + } + } + } + + invert = invert || invertSwap; + + if (invert) { + // Invert of regular + if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) { + return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1; + } + } + + return 0; +} +/** + * Gets the direction dragEl must be swapped relative to target in order to make it + * seem that dragEl has been "inserted" into that element's position + * @param {HTMLElement} target The target whose position dragEl is being inserted at + * @return {Number} Direction dragEl must be swapped + */ + + +function _getInsertDirection(target) { + if (index(dragEl) < index(target)) { + return 1; + } else { + return -1; + } +} +/** + * Generate id + * @param {HTMLElement} el + * @returns {String} + * @private + */ + + +function _generateId(el) { + var str = el.tagName + el.className + el.src + el.href + el.textContent, + i = str.length, + sum = 0; + + while (i--) { + sum += str.charCodeAt(i); + } + + return sum.toString(36); +} + +function _saveInputCheckedState(root) { + savedInputChecked.length = 0; + var inputs = root.getElementsByTagName('input'); + var idx = inputs.length; + + while (idx--) { + var _el = inputs[idx]; + _el.checked && savedInputChecked.push(_el); + } +} + +function _nextTick(fn) { + return setTimeout(fn, 0); +} + +function _cancelNextTick(id) { + return clearTimeout(id); +} // Fixed #973: + + +on(document, 'touchmove', function (evt) { + if ((Sortable$1.active || awaitingDragStarted) && evt.cancelable) { + evt.preventDefault(); + } +}); // Export utils + +Sortable$1.utils = { + on: on, + off: off, + css: css, + find: find, + is: function is(el, selector) { + return !!closest(el, selector, el, false); + }, + extend: extend, + throttle: throttle, + closest: closest, + toggleClass: toggleClass, + clone: clone, + index: index, + nextTick: _nextTick, + cancelNextTick: _cancelNextTick, + detectDirection: _detectDirection, + getChild: getChild +}; +/** + * Mount a plugin to Sortable + * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted + */ + +Sortable$1.mount = function () { + for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) { + plugins[_key] = arguments[_key]; + } + + if (plugins[0].constructor === Array) plugins = plugins[0]; + + for (var i in plugins) { + var plugin = plugins[i]; + + if (!plugin.prototype || !plugin.prototype.constructor) { + throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(el)); + } + + if (plugin.utils) Sortable$1.utils = _objectSpread({}, Sortable$1.utils, plugin.utils); + PluginManager.mount(plugin); + } +}; +/** + * Create sortable instance + * @param {HTMLElement} el + * @param {Object} [options] + */ + + +Sortable$1.create = function (el, options) { + return new Sortable$1(el, options); +}; // Export + + +Sortable$1.version = version; + +var autoScrolls = [], + scrollEl, + scrollRootEl, + scrolling = false, + lastAutoScrollX, + lastAutoScrollY, + touchEvt$1, + pointerElemChangedInterval; + +function AutoScrollPlugin() { + function AutoScroll() { + this.options = { + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, + bubbleScroll: true + }; // Bind all private methods + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + } + + AutoScroll.prototype = { + dragStarted: function dragStarted(_ref) { + var originalEvent = _ref.originalEvent; + + if (this.sortable.nativeDraggable) { + on(document, 'dragover', this._handleAutoScroll); + } else { + if (this.sortable.options.supportPointer) { + on(document, 'pointermove', this._handleFallbackAutoScroll); + } else if (originalEvent.touches) { + on(document, 'touchmove', this._handleFallbackAutoScroll); + } else { + on(document, 'mousemove', this._handleFallbackAutoScroll); + } + } + }, + dragOverCompleted: function dragOverCompleted(_ref2) { + var originalEvent = _ref2.originalEvent; + + // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) + if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) { + this._handleAutoScroll(originalEvent); + } + }, + drop: function drop() { + if (this.sortable.nativeDraggable) { + off(document, 'dragover', this._handleAutoScroll); + } else { + off(document, 'pointermove', this._handleFallbackAutoScroll); + off(document, 'touchmove', this._handleFallbackAutoScroll); + off(document, 'mousemove', this._handleFallbackAutoScroll); + } + + clearPointerElemChangedInterval(); + clearAutoScrolls(); + cancelThrottle(); + }, + nulling: function nulling() { + touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null; + autoScrolls.length = 0; + }, + _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) { + this._handleAutoScroll(evt, true); + }, + _handleAutoScroll: function _handleAutoScroll(evt, fallback) { + var _this = this; + + var x = evt.clientX, + y = evt.clientY, + elem = document.elementFromPoint(x, y); + touchEvt$1 = evt; // IE does not seem to have native autoscroll, + // Edge's autoscroll seems too conditional, + // MACOS Safari does not have autoscroll, + // Firefox and Chrome are good + + if (fallback || Edge || IE11OrLess || Safari) { + autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change + + var ogElemScroller = getParentAutoScrollElement(elem, true); + + if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) { + pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour + + pointerElemChangedInterval = setInterval(function () { + var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true); + + if (newElem !== ogElemScroller) { + ogElemScroller = newElem; + clearAutoScrolls(); + } + + autoScroll(evt, _this.options, newElem, fallback); + }, 10); + lastAutoScrollX = x; + lastAutoScrollY = y; + } + } else { + // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll + if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) { + clearAutoScrolls(); + return; + } + + autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false); + } + } + }; + return _extends(AutoScroll, { + pluginName: 'scroll', + initializeByDefault: true + }); +} + +function clearAutoScrolls() { + autoScrolls.forEach(function (autoScroll) { + clearInterval(autoScroll.pid); + }); + autoScrolls = []; +} + +function clearPointerElemChangedInterval() { + clearInterval(pointerElemChangedInterval); +} + +var autoScroll = throttle(function (evt, options, rootEl, isFallback) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + if (!options.scroll) return; + var sens = options.scrollSensitivity, + speed = options.scrollSpeed, + winScroller = getWindowScrollingElement(); + var scrollThisInstance = false, + scrollCustomFn; // New scroll root, set scrollEl + + if (scrollRootEl !== rootEl) { + scrollRootEl = rootEl; + clearAutoScrolls(); + scrollEl = options.scroll; + scrollCustomFn = options.scrollFn; + + if (scrollEl === true) { + scrollEl = getParentAutoScrollElement(rootEl, true); + } + } + + var layersOut = 0; + var currentParent = scrollEl; + + do { + var el = currentParent, + rect = getRect(el), + top = rect.top, + bottom = rect.bottom, + left = rect.left, + right = rect.right, + width = rect.width, + height = rect.height, + canScrollX = void 0, + canScrollY = void 0, + scrollWidth = el.scrollWidth, + scrollHeight = el.scrollHeight, + elCSS = css(el), + scrollPosX = el.scrollLeft, + scrollPosY = el.scrollTop; + + if (el === winScroller) { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible'); + } else { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll'); + } + + var vx = canScrollX && (Math.abs(right - evt.clientX) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - evt.clientX) <= sens && !!scrollPosX); + var vy = canScrollY && (Math.abs(bottom - evt.clientY) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - evt.clientY) <= sens && !!scrollPosY); + + if (!autoScrolls[layersOut]) { + for (var i = 0; i <= layersOut; i++) { + if (!autoScrolls[i]) { + autoScrolls[i] = {}; + } + } + } + + if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { + autoScrolls[layersOut].el = el; + autoScrolls[layersOut].vx = vx; + autoScrolls[layersOut].vy = vy; + clearInterval(autoScrolls[layersOut].pid); + + if (vx != 0 || vy != 0) { + scrollThisInstance = true; + /* jshint loopfunc:true */ + + autoScrolls[layersOut].pid = setInterval(function () { + // emulate drag over during autoscroll (fallback), emulating native DnD behaviour + if (isFallback && this.layer === 0) { + Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely + + } + + var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; + var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; + + if (typeof scrollCustomFn === 'function') { + if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') { + return; + } + } + + scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); + }.bind({ + layer: layersOut + }), 24); + } + } + + layersOut++; + } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false))); + + scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not +}, 30); + +var drop = function drop(_ref) { + var originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + dragEl = _ref.dragEl, + activeSortable = _ref.activeSortable, + dispatchSortableEvent = _ref.dispatchSortableEvent, + hideGhostForTarget = _ref.hideGhostForTarget, + unhideGhostForTarget = _ref.unhideGhostForTarget; + var toSortable = putSortable || activeSortable; + hideGhostForTarget(); + var target = document.elementFromPoint(originalEvent.clientX, originalEvent.clientY); + unhideGhostForTarget(); + + if (toSortable && !toSortable.el.contains(target)) { + dispatchSortableEvent('spill'); + this.onSpill(dragEl); + } +}; + +function Revert() {} + +Revert.prototype = { + startIndex: null, + dragStart: function dragStart(_ref2) { + var oldDraggableIndex = _ref2.oldDraggableIndex; + this.startIndex = oldDraggableIndex; + }, + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + var nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options); + + if (nextSibling) { + this.sortable.el.insertBefore(dragEl, nextSibling); + } else { + this.sortable.el.appendChild(dragEl); + } + + this.sortable.animateAll(); + }, + drop: drop +}; + +_extends(Revert, { + pluginName: 'revertOnSpill' +}); + +function Remove() {} + +Remove.prototype = { + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + dragEl.parentNode && dragEl.parentNode.removeChild(dragEl); + this.sortable.animateAll(); + }, + drop: drop +}; + +_extends(Remove, { + pluginName: 'removeOnSpill' +}); + +var OnSpill = [Remove, Revert]; + +var lastSwapEl; + +function SwapPlugin() { + function Swap() { + this.options = { + swapClass: 'sortable-swap-highlight' + }; + } + + Swap.prototype = { + dragStart: function dragStart(_ref) { + var dragEl = _ref.dragEl; + lastSwapEl = dragEl; + }, + dragOverValid: function dragOverValid(_ref2) { + var completed = _ref2.completed, + target = _ref2.target, + onMove = _ref2.onMove, + activeSortable = _ref2.activeSortable, + changed = _ref2.changed; + if (!activeSortable.options.swap) return; + var el = this.sortable.el, + options = this.sortable.options; + + if (target && target !== el) { + var prevSwapEl = lastSwapEl; + + if (onMove(target) !== false) { + toggleClass(target, options.swapClass, true); + lastSwapEl = target; + } else { + lastSwapEl = null; + } + + if (prevSwapEl && prevSwapEl !== lastSwapEl) { + toggleClass(prevSwapEl, options.swapClass, false); + } + } + + changed(); + return completed(true); + }, + drop: function drop(_ref3) { + var activeSortable = _ref3.activeSortable, + putSortable = _ref3.putSortable, + dragEl = _ref3.dragEl; + var toSortable = putSortable || this.sortable; + var options = this.sortable.options; + lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false); + + if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) { + if (dragEl !== lastSwapEl) { + toSortable.captureAnimationState(); + if (toSortable !== activeSortable) activeSortable.captureAnimationState(); + swapNodes(dragEl, lastSwapEl); + toSortable.animateAll(); + if (toSortable !== activeSortable) activeSortable.animateAll(); + } + } + }, + nulling: function nulling() { + lastSwapEl = null; + } + }; + return _extends(Swap, { + pluginName: 'swap', + eventOptions: function eventOptions() { + return { + swapItem: lastSwapEl + }; + } + }); +} + +function swapNodes(n1, n2) { + var p1 = n1.parentNode, + p2 = n2.parentNode, + i1, + i2; + if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return; + i1 = index(n1); + i2 = index(n2); + + if (p1.isEqualNode(p2) && i1 < i2) { + i2++; + } + + p1.insertBefore(n2, p1.children[i1]); + p2.insertBefore(n1, p2.children[i2]); +} + +var multiDragElements = [], + multiDragClones = [], + lastMultiDragSelect, + // for selection with modifier key down (SHIFT) +multiDragSortable, + initialFolding = false, + // Initial multi-drag fold when drag started +folding = false, + // Folding any other time +dragStarted = false, + dragEl$1, + clonesFromRect, + clonesHidden; + +function MultiDragPlugin() { + function MultiDrag(sortable) { + // Bind all private methods + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + if (sortable.options.supportPointer) { + on(document, 'pointerup', this._deselectMultiDrag); + } else { + on(document, 'mouseup', this._deselectMultiDrag); + on(document, 'touchend', this._deselectMultiDrag); + } + + on(document, 'keydown', this._checkKeyDown); + on(document, 'keyup', this._checkKeyUp); + this.options = { + selectedClass: 'sortable-selected', + multiDragKey: null, + setData: function setData(dataTransfer, dragEl) { + var data = ''; + + if (multiDragElements.length && multiDragSortable === sortable) { + for (var i in multiDragElements) { + data += (!i ? '' : ', ') + multiDragElements[i].textContent; + } + } else { + data = dragEl.textContent; + } + + dataTransfer.setData('Text', data); + } + }; + } + + MultiDrag.prototype = { + multiDragKeyDown: false, + isMultiDrag: false, + delayStartGlobal: function delayStartGlobal(_ref) { + var dragged = _ref.dragEl; + dragEl$1 = dragged; + }, + delayEnded: function delayEnded() { + this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1); + }, + setupClone: function setupClone(_ref2) { + var sortable = _ref2.sortable; + if (!this.isMultiDrag) return; + + for (var i in multiDragElements) { + multiDragClones.push(clone(multiDragElements[i])); + multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex; + multiDragClones[i].draggable = false; + multiDragClones[i].style['will-change'] = ''; + toggleClass(multiDragClones[i], sortable.options.selectedClass, false); + multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], sortable.options.chosenClass, false); + } + + sortable._hideClone(); + + return true; + }, + clone: function clone(_ref3) { + var sortable = _ref3.sortable, + rootEl = _ref3.rootEl, + dispatchSortableEvent = _ref3.dispatchSortableEvent; + if (!this.isMultiDrag) return; + + if (!sortable.options.removeCloneOnHide) { + if (multiDragElements.length && multiDragSortable === sortable) { + insertMultiDragClones(true, rootEl); + dispatchSortableEvent('clone'); + return true; + } + } + }, + showClone: function showClone(_ref4) { + var cloneNowShown = _ref4.cloneNowShown, + rootEl = _ref4.rootEl; + if (!this.isMultiDrag) return; + insertMultiDragClones(false, rootEl); + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', ''); + } + + cloneNowShown(); + clonesHidden = false; + return true; + }, + hideClone: function hideClone(_ref5) { + var sortable = _ref5.sortable, + cloneNowHidden = _ref5.cloneNowHidden; + if (!this.isMultiDrag) return; + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', 'none'); + + if (sortable.options.removeCloneOnHide && multiDragClones[i].parentNode) { + multiDragClones[i].parentNode.removeChild(multiDragClones[i]); + } + } + + cloneNowHidden(); + clonesHidden = true; + return true; + }, + dragStartGlobal: function dragStartGlobal(_ref6) { + var sortable = _ref6.sortable; + + if (!this.isMultiDrag && multiDragSortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + } + + for (var i in multiDragElements) { + multiDragElements[i].sortableIndex = index(multiDragElements[i]); + } // Sort multi-drag elements + + + multiDragElements = multiDragElements.sort(function (a, b) { + return a.sortableIndex - b.sortableIndex; + }); + dragStarted = true; + }, + dragStarted: function dragStarted(_ref7) { + var sortable = _ref7.sortable; + if (!this.isMultiDrag) return; + + if (sortable.options.sort) { + // Capture rects, + // hide multi drag elements (by positioning them absolute), + // set multi drag elements rects to dragRect, + // show multi drag elements, + // animate to rects, + // unset rects & remove from DOM + sortable.captureAnimationState(); + + if (sortable.options.animation) { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + css(multiDragElements[i], 'position', 'absolute'); + } + + var dragRect = getRect(dragEl$1, false, true, true); + + for (var _i in multiDragElements) { + if (multiDragElements[_i] === dragEl$1) continue; + setRect(multiDragElements[_i], dragRect); + } + + folding = true; + initialFolding = true; + } + } + + sortable.animateAll(function () { + folding = false; + initialFolding = false; + + if (sortable.options.animation) { + for (var _i2 in multiDragElements) { + unsetRect(multiDragElements[_i2]); + } + } // Remove all auxiliary multidrag items from el, if sorting enabled + + + if (sortable.options.sort) { + removeMultiDragElements(); + } + }); + }, + dragOver: function dragOver(_ref8) { + var target = _ref8.target, + completed = _ref8.completed; + + if (folding && ~multiDragElements.indexOf(target)) { + return completed(false); + } + }, + revert: function revert(_ref9) { + var fromSortable = _ref9.fromSortable, + rootEl = _ref9.rootEl, + sortable = _ref9.sortable, + dragRect = _ref9.dragRect; + + if (multiDragElements.length > 1) { + // Setup unfold animation + for (var i in multiDragElements) { + sortable.addAnimationState({ + target: multiDragElements[i], + rect: folding ? getRect(multiDragElements[i]) : dragRect + }); + unsetRect(multiDragElements[i]); + multiDragElements[i].fromRect = dragRect; + fromSortable.removeAnimationState(multiDragElements[i]); + } + + folding = false; + insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl); + } + }, + dragOverCompleted: function dragOverCompleted(_ref10) { + var sortable = _ref10.sortable, + isOwner = _ref10.isOwner, + insertion = _ref10.insertion, + activeSortable = _ref10.activeSortable, + parentEl = _ref10.parentEl, + putSortable = _ref10.putSortable; + var options = sortable.options; + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } + + initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location + + if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) { + // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible + var dragRectAbsolute = getRect(dragEl$1, false, true, true); + + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + setRect(multiDragElements[i], dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted + // while folding, and so that we can capture them again because old sortable will no longer be fromSortable + + parentEl.appendChild(multiDragElements[i]); + } + + folding = true; + } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out + + + if (!isOwner) { + // Only remove if not folding (folding will remove them anyways) + if (!folding) { + removeMultiDragElements(); + } + + if (multiDragElements.length > 1) { + var clonesHiddenBefore = clonesHidden; + + activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden + + + if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) { + for (var _i3 in multiDragClones) { + activeSortable.addAnimationState({ + target: multiDragClones[_i3], + rect: clonesFromRect + }); + multiDragClones[_i3].fromRect = clonesFromRect; + multiDragClones[_i3].thisAnimationDuration = null; + } + } + } else { + activeSortable._showClone(sortable); + } + } + } + }, + dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) { + var dragRect = _ref11.dragRect, + isOwner = _ref11.isOwner, + activeSortable = _ref11.activeSortable; + + for (var i in multiDragElements) { + multiDragElements[i].thisAnimationDuration = null; + } + + if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) { + clonesFromRect = _extends({}, dragRect); + var dragMatrix = matrix(dragEl$1, true); + clonesFromRect.top -= dragMatrix.f; + clonesFromRect.left -= dragMatrix.e; + } + }, + dragOverAnimationComplete: function dragOverAnimationComplete() { + if (folding) { + folding = false; + removeMultiDragElements(); + } + }, + drop: function drop(_ref12) { + var evt = _ref12.originalEvent, + rootEl = _ref12.rootEl, + parentEl = _ref12.parentEl, + sortable = _ref12.sortable, + dispatchSortableEvent = _ref12.dispatchSortableEvent, + oldIndex = _ref12.oldIndex, + putSortable = _ref12.putSortable; + var toSortable = putSortable || this.sortable; + if (!evt) return; + var options = sortable.options, + children = parentEl.children; // Multi-drag selection + + if (!dragStarted) { + if (options.multiDragKey && !this.multiDragKeyDown) { + this._deselectMultiDrag(); + } + + toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1)); + + if (!~multiDragElements.indexOf(dragEl$1)) { + multiDragElements.push(dragEl$1); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: dragEl$1, + originalEvt: evt + }); // Modifier activated, select from last to dragEl + + if ((!options.multiDragKey || this.multiDragKeyDown) && evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) { + var lastIndex = index(lastMultiDragSelect), + currentIndex = index(dragEl$1); + + if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) { + // Must include lastMultiDragSelect (select it), in case modified selection from no selection + // (but previous selection existed) + var n, i; + + if (currentIndex > lastIndex) { + i = lastIndex; + n = currentIndex; + } else { + i = currentIndex; + n = lastIndex + 1; + } + + for (; i < n; i++) { + if (~multiDragElements.indexOf(children[i])) continue; + toggleClass(children[i], options.selectedClass, true); + multiDragElements.push(children[i]); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: children[i], + originalEvt: evt + }); + } + } + } else { + lastMultiDragSelect = dragEl$1; + } + + multiDragSortable = toSortable; + } else { + multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1); + lastMultiDragSelect = null; + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'deselect', + targetEl: dragEl$1, + originalEvt: evt + }); + } + } // Multi-drag drop + + + if (dragStarted && this.isMultiDrag) { + // Do not "unfold" after around dragEl if reverted + if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) { + var dragRect = getRect(dragEl$1), + multiDragIndex = index(dragEl$1, ':not(.' + Sortable.active.options.selectedClass + ')'); + if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null; + toSortable.captureAnimationState(); + + if (!initialFolding) { + if (options.animation) { + dragEl$1.fromRect = dragRect; + + for (var _i4 in multiDragElements) { + multiDragElements[_i4].thisAnimationDuration = null; + + if (multiDragElements[_i4] !== dragEl$1) { + var rect = folding ? getRect(multiDragElements[_i4]) : dragRect; + multiDragElements[_i4].fromRect = rect; // Prepare unfold animation + + toSortable.addAnimationState({ + target: multiDragElements[_i4], + rect: rect + }); + } + } + } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert + // properly they must all be removed + + + removeMultiDragElements(); + + for (var _i5 in multiDragElements) { + if (children[multiDragIndex]) { + parentEl.insertBefore(multiDragElements[_i5], children[multiDragIndex]); + } else { + parentEl.appendChild(multiDragElements[_i5]); + } + + multiDragIndex++; + } // If initial folding is done, the elements may have changed position because they are now + // unfolding around dragEl, even though dragEl may not have his index changed, so update event + // must be fired here as Sortable will not. + + + if (oldIndex === index(dragEl$1)) { + var update = false; + + for (var _i6 in multiDragElements) { + if (multiDragElements[_i6].sortableIndex !== index(multiDragElements[_i6])) { + update = true; + break; + } + } + + if (update) { + dispatchSortableEvent('update'); + } + } + } // Must be done after capturing individual rects (scroll bar) + + + for (var _i7 in multiDragElements) { + unsetRect(multiDragElements[_i7]); + } + + toSortable.animateAll(); + } + + multiDragSortable = toSortable; + } // Remove clones if necessary + + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + for (var _i8 in multiDragClones) { + multiDragClones[_i8].parentNode && multiDragClones[_i8].parentNode.removeChild(multiDragClones[_i8]); + } + } + }, + nullingGlobal: function nullingGlobal() { + this.isMultiDrag = dragStarted = false; + multiDragClones.length = 0; + }, + destroy: function destroy() { + this._deselectMultiDrag(); + + off(document, 'pointerup', this._deselectMultiDrag); + off(document, 'mouseup', this._deselectMultiDrag); + off(document, 'touchend', this._deselectMultiDrag); + off(document, 'keydown', this._checkKeyDown); + off(document, 'keyup', this._checkKeyUp); + }, + _deselectMultiDrag: function _deselectMultiDrag(evt) { + if (dragStarted) return; // Only deselect if selection is in this sortable + + if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable + + if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return; // Only deselect if left click + + if (evt && evt.button !== 0) return; + + while (multiDragElements.length) { + var el = multiDragElements[0]; + toggleClass(el, this.sortable.options.selectedClass, false); + multiDragElements.shift(); + dispatchEvent({ + sortable: this.sortable, + rootEl: this.sortable.el, + name: 'deselect', + targetEl: el, + originalEvt: evt + }); + } + }, + _checkKeyDown: function _checkKeyDown(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = true; + } + }, + _checkKeyUp: function _checkKeyUp(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = false; + } + } + }; + return _extends(MultiDrag, { + // Static methods & properties + pluginName: 'multiDrag', + utils: { + /** + * Selects the provided multi-drag item + * @param {HTMLElement} el The element to be selected + */ + select: function select(el) { + var sortable = el.parentNode[expando]; + if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return; + + if (multiDragSortable && multiDragSortable !== sortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + + multiDragSortable = sortable; + } + + toggleClass(el, sortable.options.selectedClass, true); + multiDragElements.push(el); + }, + + /** + * Deselects the provided multi-drag item + * @param {HTMLElement} el The element to be deselected + */ + deselect: function deselect(el) { + var sortable = el.parentNode[expando], + index = multiDragElements.indexOf(el); + if (!sortable || !sortable.options.multiDrag || !~index) return; + toggleClass(el, sortable.options.selectedClass, false); + multiDragElements.splice(index, 1); + } + }, + eventOptions: function eventOptions() { + return { + items: _toConsumableArray(multiDragElements), + clones: [].concat(multiDragClones) + }; + }, + optionListeners: { + multiDragKey: function multiDragKey(key) { + key = key.toLowerCase(); + + if (key === 'ctrl') { + key = 'Control'; + } else if (key.length > 1) { + key = key.charAt(0).toUpperCase() + key.substr(1); + } + + return key; + } + } + }); +} + +function insertMultiDragElements(clonesInserted, rootEl) { + for (var i in multiDragElements) { + var target = rootEl.children[multiDragElements[i].sortableIndex + (clonesInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragElements[i], target); + } else { + rootEl.appendChild(multiDragElements[i]); + } + } +} +/** + * Insert multi-drag clones + * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted + * @param {HTMLElement} rootEl + */ + + +function insertMultiDragClones(elementsInserted, rootEl) { + for (var i in multiDragClones) { + var target = rootEl.children[multiDragClones[i].sortableIndex + (elementsInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragClones[i], target); + } else { + rootEl.appendChild(multiDragClones[i]); + } + } +} + +function removeMultiDragElements() { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + multiDragElements[i].parentNode && multiDragElements[i].parentNode.removeChild(multiDragElements[i]); + } +} + +export default Sortable$1; +export { AutoScrollPlugin as AutoScroll, MultiDragPlugin as MultiDrag, OnSpill, Sortable$1 as Sortable, SwapPlugin as Swap }; diff --git a/modular/sortable.esm.js b/modular/sortable.esm.js new file mode 100644 index 000000000..5549f4910 --- /dev/null +++ b/modular/sortable.esm.js @@ -0,0 +1,3599 @@ +/**! + * Sortable 1.9.0 + * @author RubaXa + * @author owenm + * @license MIT + */ +function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } + + return _typeof(obj); +} + +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; +} + +function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); +} + +function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; +} + +function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; +} + +function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + + var target = _objectWithoutPropertiesLoose(source, excluded); + + var key, i; + + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + + return target; +} + +function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); +} + +function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } +} + +function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); +} + +function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance"); +} + +var version = "1.9.0"; + +function userAgent(pattern) { + return !!navigator.userAgent.match(pattern); +} + +var IE11OrLess = +/*@__PURE__*/ +userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile)/i); +var Edge = +/*@__PURE__*/ +userAgent(/Edge/i); +var FireFox = +/*@__PURE__*/ +userAgent(/firefox/i); +var Safari = +/*@__PURE__*/ +userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); +var IOS = +/*@__PURE__*/ +userAgent(/iP(ad|od|hone)/i); + +var 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; +} + +var R_SPACE = /\s+/g; + +function toggleClass(el, name, state) { + if (el && name) { + if (el.classList) { + el.classList[state ? 'add' : 'remove'](name); + } else { + var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); + el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); + } + } +} + +function css(el, prop, val) { + var 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) { + var appliedTransforms = ''; + + do { + var transform = css(el, 'transform'); + + if (transform && transform !== 'none') { + appliedTransforms = transform + ' ' + appliedTransforms; + } + /* jshint boss:true */ + + } while (!selfOnly && (el = el.parentNode)); + + var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix; + /*jshint -W056 */ + + return matrixFn && new matrixFn(appliedTransforms); +} + +function find(ctx, tagName, iterator) { + if (ctx) { + var list = ctx.getElementsByTagName(tagName), + i = 0, + n = list.length; + + if (iterator) { + for (; i < n; i++) { + iterator(list[i], i); + } + } + + return list; + } + + return []; +} + +function getWindowScrollingElement() { + if (IE11OrLess) { + return document.documentElement; + } else { + return document.scrollingElement; + } +} +/** + * 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; + var 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')) { + var 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() + var 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 {[DOMRect]} rect Optional rect of `el` to use + * @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, rect, elSide, parentSide) { + var parent = getParentAutoScrollElement(el, true), + elSideVal = (rect ? rect : getRect(el))[elSide]; + /* jshint boss:true */ + + while (parent) { + var parentSideVal = getRect(parent)[parentSide], + visible = void 0; + + 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) { + var currentChild = 0, + i = 0, + children = el.children; + + while (i < children.length) { + if (children[i].style.display !== 'none' && children[i] !== Sortable$1.ghost && children[i] !== Sortable$1.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) { + var last = el.lastElementChild; + + while (last && (last === Sortable$1.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) { + var index = 0; + + if (!el || !el.parentNode) { + return -1; + } + /* jshint boss:true */ + + + while (el = el.previousElementSibling) { + if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable$1.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) { + var offsetLeft = 0, + offsetTop = 0, + winScroller = getWindowScrollingElement(); + + if (el) { + do { + var 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 (var i in arr) { + for (var key in obj) { + if (obj[key] === arr[i][key]) return Number(i); + } + } + + return -1; +} + +function getParentAutoScrollElement(el, includeSelf) { + // skip to window + if (!el || !el.getBoundingClientRect) return getWindowScrollingElement(); + var elem = el; + var 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) { + var 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 (var 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); +} + +var _throttleTimeout; + +function throttle(callback, ms) { + return function () { + if (!_throttleTimeout) { + var 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) { + var Polymer = window.Polymer; + var $ = 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', ''); +} + +var expando = 'Sortable' + new Date().getTime(); + +function AnimationStateManager() { + var animationStates = [], + animationCallbackId; + return { + captureAnimationState: function captureAnimationState() { + animationStates = []; + if (!this.options.animation) return; + var children = [].slice.call(this.el.children); + + for (var i in children) { + if (css(children[i], 'display') === 'none' || children[i] === Sortable$1.ghost) continue; + animationStates.push({ + target: children[i], + rect: getRect(children[i]) + }); + var fromRect = getRect(children[i]); // If animating: compensate for current animation + + if (children[i].thisAnimationDuration) { + var childMatrix = matrix(children[i], true); + + if (childMatrix) { + fromRect.top -= childMatrix.f; + fromRect.left -= childMatrix.e; + } + } + + children[i].fromRect = fromRect; + } + }, + addAnimationState: function addAnimationState(state) { + animationStates.push(state); + }, + removeAnimationState: function removeAnimationState(target) { + animationStates.splice(indexOfObject(animationStates, { + target: target + }), 1); + }, + animateAll: function animateAll(callback) { + if (!this.options.animation) { + clearTimeout(animationCallbackId); + if (typeof callback === 'function') callback(); + return; + } + + var animating = false, + animationTime = 0; + + for (var i in animationStates) { + var time = 0, + target = animationStates[i].target, + fromRect = target.fromRect, + toRect = getRect(target), + prevFromRect = target.prevFromRect, + prevToRect = target.prevToRect, + animatingRect = animationStates[i].rect, + targetMatrix = matrix(target, true); + + if (targetMatrix) { + // Compensate for current animation + toRect.top -= targetMatrix.f; + toRect.left -= targetMatrix.e; + } + + target.toRect = toRect; // If element is scrolled out of view: Do not animate + + if ((isScrolledPast(target, toRect, 'bottom', 'top') || isScrolledPast(target, toRect, 'top', 'bottom') || isScrolledPast(target, toRect, 'right', 'left') || isScrolledPast(target, toRect, 'left', 'right')) && (isScrolledPast(target, animatingRect, 'bottom', 'top') || isScrolledPast(target, animatingRect, 'top', 'bottom') || isScrolledPast(target, animatingRect, 'right', 'left') || isScrolledPast(target, animatingRect, 'left', 'right')) && (isScrolledPast(target, fromRect, 'bottom', 'top') || isScrolledPast(target, fromRect, 'top', 'bottom') || isScrolledPast(target, fromRect, 'right', 'left') || isScrolledPast(target, fromRect, 'left', 'right'))) continue; + + if (target.thisAnimationDuration) { + // Could also check if animatingRect is between fromRect and toRect + if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect + (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) { + // If returning to same place as started from animation and on same axis + time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options); + } + } // if fromRect != toRect: animate + + + if (!isRectEqual(toRect, fromRect)) { + target.prevFromRect = fromRect; + target.prevToRect = toRect; + + if (!time) { + time = this.options.animation; + } + + this.animate(target, animatingRect, time); + } + + if (time) { + animating = true; + animationTime = Math.max(animationTime, time); + clearTimeout(target.animationResetTimer); + target.animationResetTimer = setTimeout(function () { + this.animationStates[this.i].target.animationTime = 0; + this.animationStates[this.i].target.prevFromRect = null; + this.animationStates[this.i].target.fromRect = null; + this.animationStates[this.i].target.prevToRect = null; + this.animationStates[this.i].target.thisAnimationDuration = null; + }.bind({ + animationStates: animationStates, + i: Number(i) + }), time); + target.thisAnimationDuration = time; + } + } + + clearTimeout(animationCallbackId); + + if (!animating) { + if (typeof callback === 'function') callback(); + } else { + animationCallbackId = setTimeout(function () { + if (typeof callback === 'function') callback(); + }, animationTime); + } + + animationStates = []; + }, + animate: function animate(target, prev, duration) { + if (duration) { + css(target, 'transition', ''); + css(target, 'transform', ''); + var currentRect = getRect(target), + elMatrix = matrix(this.el), + scaleX = elMatrix && elMatrix.a, + scaleY = elMatrix && elMatrix.d, + translateX = (prev.left - currentRect.left) / (scaleX || 1), + translateY = (prev.top - currentRect.top) / (scaleY || 1); + target.animatingX = !!translateX; + target.animatingY = !!translateY; + css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); + repaint(target); // repaint + + css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); + css(target, 'transform', 'translate3d(0,0,0)'); + typeof target.animated === 'number' && clearTimeout(target.animated); + target.animated = setTimeout(function () { + css(target, 'transition', ''); + css(target, 'transform', ''); + target.animated = false; + target.animatingX = false; + target.animatingY = false; + }, duration); + } + } + }; +} + +function repaint(target) { + return target.offsetWidth; +} + +function calculateRealTime(animatingRect, fromRect, toRect, options) { + return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation; +} + +var plugins = []; +var defaults = { + initializeByDefault: true +}; +var PluginManager = { + mount: function mount(plugin) { + // Set default static properties + for (var option in defaults) { + !(option in plugin) && (plugin[option] = defaults[option]); + } + + plugins.push(plugin); + }, + pluginEvent: function pluginEvent(eventName, sortable, evt) { + this.eventCanceled = false; + var eventNameGlobal = eventName + 'Global'; + + for (var i in plugins) { + if (!sortable[plugins[i].pluginName]) continue; // Fire global events if it exists in this sortable + + if (sortable[plugins[i].pluginName][eventNameGlobal]) { + this.eventCanceled = !!sortable[plugins[i].pluginName][eventNameGlobal](_objectSpread({ + sortable: sortable + }, evt)); + } // Only fire plugin event if plugin is enabled in this sortable, + // and plugin has event defined + + + if (sortable.options[plugins[i].pluginName] && sortable[plugins[i].pluginName][eventName]) { + this.eventCanceled = this.eventCanceled || !!sortable[plugins[i].pluginName][eventName](_objectSpread({ + sortable: sortable + }, evt)); + } + } + }, + initializePlugins: function initializePlugins(sortable, el, defaults) { + for (var i in plugins) { + var pluginName = plugins[i].pluginName; + if (!sortable.options[pluginName] && !plugins[i].initializeByDefault) continue; + var initialized = new plugins[i](sortable, el); + initialized.sortable = sortable; + sortable[pluginName] = initialized; // Add default options from plugin + + _extends(defaults, initialized.options); + } + + for (var option in sortable.options) { + var modified = this.modifyOption(sortable, option, sortable.options[option]); + + if (typeof modified !== 'undefined') { + sortable.options[option] = modified; + } + } + }, + getEventOptions: function getEventOptions(name, sortable) { + var eventOptions = {}; + + for (var i in plugins) { + if (typeof plugins[i].eventOptions !== 'function') continue; + eventOptions = _objectSpread({}, eventOptions, plugins[i].eventOptions(name, sortable)); + } + + return eventOptions; + }, + modifyOption: function modifyOption(sortable, name, value) { + var modifiedValue; + + for (var i in plugins) { + // Plugin must exist on the Sortable + if (!sortable[plugins[i].pluginName]) continue; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin + + if (plugins[i].optionListeners && typeof plugins[i].optionListeners[name] === 'function') { + modifiedValue = plugins[i].optionListeners[name].call(sortable[plugins[i].pluginName], value); + } + } + + return modifiedValue; + } +}; + +function dispatchEvent(_ref) { + var sortable = _ref.sortable, + rootEl = _ref.rootEl, + name = _ref.name, + targetEl = _ref.targetEl, + cloneEl = _ref.cloneEl, + toEl = _ref.toEl, + fromEl = _ref.fromEl, + oldIndex = _ref.oldIndex, + newIndex = _ref.newIndex, + oldDraggableIndex = _ref.oldDraggableIndex, + newDraggableIndex = _ref.newDraggableIndex, + originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + eventOptions = _ref.eventOptions; + sortable = sortable || rootEl[expando]; + var evt, + options = sortable.options, + onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent(name, { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent(name, true, true); + } + + evt.to = toEl || rootEl; + evt.from = fromEl || rootEl; + evt.item = targetEl || rootEl; + evt.clone = cloneEl; + evt.oldIndex = oldIndex; + evt.newIndex = newIndex; + evt.oldDraggableIndex = oldDraggableIndex; + evt.newDraggableIndex = newDraggableIndex; + evt.originalEvent = originalEvent; + evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; + + var allEventOptions = _objectSpread({}, eventOptions, PluginManager.getEventOptions(name, sortable)); + + for (var option in allEventOptions) { + evt[option] = allEventOptions[option]; + } + + if (rootEl) { + rootEl.dispatchEvent(evt); + } + + if (options[onName]) { + options[onName].call(sortable, evt); + } +} + +var pluginEvent = function pluginEvent(eventName, sortable) { + var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + originalEvent = _ref.evt, + data = _objectWithoutProperties(_ref, ["evt"]); + + PluginManager.pluginEvent.bind(Sortable$1)(eventName, sortable, _objectSpread({ + dragEl: dragEl, + parentEl: parentEl, + ghostEl: ghostEl, + rootEl: rootEl, + nextEl: nextEl, + lastDownEl: lastDownEl, + cloneEl: cloneEl, + cloneHidden: cloneHidden, + dragStarted: moved, + putSortable: putSortable, + activeSortable: Sortable$1.active, + originalEvent: originalEvent, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + hideGhostForTarget: _hideGhostForTarget, + unhideGhostForTarget: _unhideGhostForTarget, + cloneNowHidden: function cloneNowHidden() { + cloneHidden = true; + }, + cloneNowShown: function cloneNowShown() { + cloneHidden = false; + }, + dispatchSortableEvent: function dispatchSortableEvent(name) { + _dispatchEvent({ + sortable: sortable, + name: name, + originalEvent: originalEvent + }); + } + }, data)); +}; + +function _dispatchEvent(info) { + dispatchEvent(_objectSpread({ + putSortable: putSortable, + cloneEl: cloneEl, + targetEl: dragEl, + rootEl: rootEl, + oldIndex: oldIndex, + oldDraggableIndex: oldDraggableIndex, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex + }, info)); +} + +if (typeof window === "undefined" || !window.document) { + throw new Error("Sortable.js requires a window with a document"); +} + +var dragEl, + parentEl, + ghostEl, + rootEl, + nextEl, + lastDownEl, + cloneEl, + cloneHidden, + oldIndex, + newIndex, + oldDraggableIndex, + newDraggableIndex, + activeGroup, + putSortable, + awaitingDragStarted = false, + ignoreNextClick = false, + sortables = [], + tapEvt, + touchEvt, + moved, + lastTarget, + lastDirection, + pastFirstInvertThresh = false, + isCircumstantialInvert = false, + targetMoveDistance, + // For positioning ghost absolutely +ghostRelativeParent, + ghostRelativeParentInitialScroll = [], + // (left, top) +_silent = false, + savedInputChecked = []; +/** @const */ + +var PositionGhostAbsolutely = IOS, + CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', + // This will not pass for IE9, because IE9 DnD only works on anchors +supportDraggable = 'draggable' in document.createElement('div'), + supportCssPointerEvents = function () { + // false when <= IE11 + if (IE11OrLess) { + return false; + } + + var el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; +}(), + _detectDirection = function _detectDirection(el, options) { + var elCSS = css(el), + elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth), + child1 = getChild(el, 0, options), + child2 = getChild(el, 1, options), + firstChildCSS = child1 && css(child1), + secondChildCSS = child2 && css(child2), + firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width, + secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width; + + if (elCSS.display === 'flex') { + return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal'; + } + + if (elCSS.display === 'grid') { + return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; + } + + if (child1 && firstChildCSS["float"] !== 'none') { + var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right'; + return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal'; + } + + return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal'; +}, + +/** + * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. + * @param {Number} x X position + * @param {Number} y Y position + * @return {HTMLElement} Element of the first found nearest Sortable + */ +_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) { + for (var i in sortables) { + if (lastChild(sortables[i])) continue; + var rect = getRect(sortables[i]), + threshold = sortables[i][expando].options.emptyInsertThreshold, + insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold, + insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold; + + if (threshold && insideHorizontally && insideVertically) { + return sortables[i]; + } + } +}, + _prepareGroup = function _prepareGroup(options) { + function toFn(value, pull) { + return function (to, from, dragEl, evt) { + var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name; + + if (value == null && (pull || sameGroup)) { + // Default pull value + // Default pull and put value if same group + return true; + } else if (value == null || value === false) { + return false; + } else if (pull && value === 'clone') { + return value; + } else if (typeof value === 'function') { + return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); + } else { + var otherGroup = (pull ? to : from).options.group.name; + return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1; + } + }; + } + + var group = {}; + var originalGroup = options.group; + + if (!originalGroup || _typeof(originalGroup) != 'object') { + originalGroup = { + name: originalGroup + }; + } + + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + group.revertClone = originalGroup.revertClone; + options.group = group; +}, + _hideGhostForTarget = function _hideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', 'none'); + } +}, + _unhideGhostForTarget = function _unhideGhostForTarget() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', ''); + } +}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position + + +document.addEventListener('click', function (evt) { + if (ignoreNextClick) { + evt.preventDefault(); + evt.stopPropagation && evt.stopPropagation(); + evt.stopImmediatePropagation && evt.stopImmediatePropagation(); + ignoreNextClick = false; + return false; + } +}, true); + +var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) { + if (dragEl) { + evt = evt.touches ? evt.touches[0] : evt; + + var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); + + if (nearest) { + // Create imitation event + var event = {}; + + for (var i in evt) { + event[i] = evt[i]; + } + + event.target = event.rootEl = nearest; + event.preventDefault = void 0; + event.stopPropagation = void 0; + + nearest[expando]._onDragOver(event); + } + } +}; + +var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) { + if (dragEl) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); + } +}; +/** + * @class Sortable + * @param {HTMLElement} el + * @param {Object} [options] + */ + + +function Sortable$1(el, options) { + if (!(el && el.nodeType && el.nodeType === 1)) { + throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el)); + } + + this.el = el; // root element + + this.options = options = _extends({}, options); // Export instance + + el[expando] = this; + var defaults = { + group: null, + sort: true, + disabled: false, + store: null, + handle: null, + draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*', + swapThreshold: 1, + // percentage; 0 <= x <= 1 + invertSwap: false, + // invert always + invertedSwapThreshold: null, + // will be set to same as swapThreshold if default + removeCloneOnHide: true, + direction: function direction() { + return _detectDirection(el, this.options); + }, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + ignore: 'a, img', + filter: null, + preventOnFilter: true, + animation: 0, + easing: null, + setData: function setData(dataTransfer, dragEl) { + dataTransfer.setData('Text', dragEl.textContent); + }, + dropBubble: false, + dragoverBubble: false, + dataIdAttr: 'data-id', + delay: 0, + delayOnTouchOnly: false, + touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, + forceFallback: false, + fallbackClass: 'sortable-fallback', + fallbackOnBody: false, + fallbackTolerance: 0, + fallbackOffset: { + x: 0, + y: 0 + }, + supportPointer: Sortable$1.supportPointer !== false && 'PointerEvent' in window, + emptyInsertThreshold: 5 + }; + PluginManager.initializePlugins(this, el, defaults); // Set default options + + for (var name in defaults) { + !(name in options) && (options[name] = defaults[name]); + } + + _prepareGroup(options); // Bind all private methods + + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } // Setup drag mode + + + this.nativeDraggable = options.forceFallback ? false : supportDraggable; + + if (this.nativeDraggable) { + // Touch start threshold cannot be greater than the native dragstart threshold + this.options.touchStartThreshold = 1; + } // Bind events + + + if (options.supportPointer) { + on(el, 'pointerdown', this._onTapStart); + } else { + on(el, 'mousedown', this._onTapStart); + on(el, 'touchstart', this._onTapStart); + } + + if (this.nativeDraggable) { + on(el, 'dragover', this); + on(el, 'dragenter', this); + } + + sortables.push(this.el); // Restore sorting + + options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager + + _extends(this, AnimationStateManager()); +} + +Sortable$1.prototype = +/** @lends Sortable.prototype */ +{ + constructor: Sortable$1, + _isOutsideThisEl: function _isOutsideThisEl(target) { + if (!this.el.contains(target) && target !== this.el) { + lastTarget = null; + } + }, + _getDirection: function _getDirection(evt, target) { + return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; + }, + _onTapStart: function _onTapStart( + /** Event|TouchEvent */ + evt) { + if (!evt.cancelable) return; + + var _this = this, + el = this.el, + options = this.options, + preventOnFilter = options.preventOnFilter, + type = evt.type, + touch = evt.touches && evt.touches[0], + target = (touch || evt).target, + originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target, + filter = options.filter; + + _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. + + + if (dragEl) { + return; + } + + if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { + return; // only left button and enabled + } // cancel dnd if original target is content editable + + + if (originalTarget.isContentEditable) { + return; + } + + target = closest(target, options.draggable, el, false); + + if (target && target.animated) { + return; + } + + if (lastDownEl === target) { + // Ignoring duplicate `down` + return; + } // Get the index of the dragged element within its parent + + + oldIndex = index(target); + oldDraggableIndex = index(target, options.draggable); // Check filter + + if (typeof filter === 'function') { + if (filter.call(this, evt, target, this)) { + _dispatchEvent({ + sortable: _this, + rootEl: originalTarget, + name: 'filter', + targetEl: target, + toEl: el, + fromEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } else if (filter) { + filter = filter.split(',').some(function (criteria) { + criteria = closest(originalTarget, criteria.trim(), el, false); + + if (criteria) { + _dispatchEvent({ + sortable: _this, + rootEl: criteria, + name: 'filter', + targetEl: target, + fromEl: el, + toEl: el + }); + + pluginEvent('filter', _this, { + evt: evt + }); + return true; + } + }); + + if (filter) { + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } + + if (options.handle && !closest(originalTarget, options.handle, el, false)) { + return; + } // Prepare `dragstart` + + + this._prepareDragStart(evt, touch, target); + }, + _prepareDragStart: function _prepareDragStart( + /** Event */ + evt, + /** Touch */ + touch, + /** HTMLElement */ + target) { + var _this = this, + el = _this.el, + options = _this.options, + ownerDocument = el.ownerDocument, + dragStartFn; + + if (target && !dragEl && target.parentNode === el) { + rootEl = el; + dragEl = target; + parentEl = dragEl.parentNode; + nextEl = dragEl.nextSibling; + lastDownEl = target; + activeGroup = options.group; + Sortable$1.dragged = dragEl; + tapEvt = { + target: dragEl, + clientX: (touch || evt).clientX, + clientY: (touch || evt).clientY + }; + this._lastX = (touch || evt).clientX; + this._lastY = (touch || evt).clientY; + dragEl.style['will-change'] = 'all'; + + dragStartFn = function dragStartFn() { + pluginEvent('delayEnded', _this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + _this._onDrop(); + + return; + } // Delayed drag has been triggered + // we can re-enable the events: touchmove/mousemove + + + _this._disableDelayedDragEvents(); + + if (!FireFox && _this.nativeDraggable) { + dragEl.draggable = true; + } // Bind the events: dragstart/dragend + + + _this._triggerDragStart(evt, touch); // Drag start event + + + _dispatchEvent({ + sortable: _this, + name: 'choose', + originalEvent: evt + }); // Chosen item + + + toggleClass(dragEl, options.chosenClass, true); + }; // Disable "draggable" + + + options.ignore.split(',').forEach(function (criteria) { + find(dragEl, criteria.trim(), _disableDraggable); + }); + on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mouseup', _this._onDrop); + on(ownerDocument, 'touchend', _this._onDrop); + on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox) + + if (FireFox && this.nativeDraggable) { + this.options.touchStartThreshold = 4; + dragEl.draggable = true; + } + + pluginEvent('delayStart', this, { + evt: evt + }); // Delay is impossible for native DnD in Edge or IE + + if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } // If the user moves the pointer or let go the click or touch + // before the delay has been reached: + // disable the delayed drag + + + on(ownerDocument, 'mouseup', _this._disableDelayedDrag); + on(ownerDocument, 'touchend', _this._disableDelayedDrag); + on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); + on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); + on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); + options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); + _this._dragStartTimer = setTimeout(dragStartFn, options.delay); + } else { + dragStartFn(); + } + } + }, + _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( + /** TouchEvent|PointerEvent **/ + e) { + var touch = e.touches ? e.touches[0] : e; + + if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) { + this._disableDelayedDrag(); + } + }, + _disableDelayedDrag: function _disableDelayedDrag() { + dragEl && _disableDraggable(dragEl); + clearTimeout(this._dragStartTimer); + + this._disableDelayedDragEvents(); + }, + _disableDelayedDragEvents: function _disableDelayedDragEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._disableDelayedDrag); + off(ownerDocument, 'touchend', this._disableDelayedDrag); + off(ownerDocument, 'touchcancel', this._disableDelayedDrag); + off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); + }, + _triggerDragStart: function _triggerDragStart( + /** Event */ + evt, + /** Touch */ + touch) { + touch = touch || (evt.pointerType == 'touch' ? evt : null); + + if (!this.nativeDraggable || touch) { + if (this.options.supportPointer) { + on(document, 'pointermove', this._onTouchMove); + } else if (touch) { + on(document, 'touchmove', this._onTouchMove); + } else { + on(document, 'mousemove', this._onTouchMove); + } + } else { + on(dragEl, 'dragend', this); + on(rootEl, 'dragstart', this._onDragStart); + } + + try { + if (document.selection) { + // Timeout neccessary for IE9 + _nextTick(function () { + document.selection.empty(); + }); + } else { + window.getSelection().removeAllRanges(); + } + } catch (err) {} + }, + _dragStarted: function _dragStarted(fallback, evt) { + + awaitingDragStarted = false; + + if (rootEl && dragEl) { + pluginEvent('dragStarted', this, { + evt: evt + }); + + if (this.nativeDraggable) { + on(document, 'dragover', _checkOutsideTargetEl); + } + + var options = this.options; // Apply effect + + !fallback && toggleClass(dragEl, options.dragClass, false); + toggleClass(dragEl, options.ghostClass, true); + Sortable$1.active = this; + fallback && this._appendGhost(); // Drag start event + + _dispatchEvent({ + sortable: this, + name: 'start', + originalEvent: evt + }); + } else { + this._nulling(); + } + }, + _emulateDragOver: function _emulateDragOver() { + if (touchEvt) { + this._lastX = touchEvt.clientX; + this._lastY = touchEvt.clientY; + + _hideGhostForTarget(); + + var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + var parent = target; + + while (target && target.shadowRoot) { + target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + if (target === parent) break; + parent = target; + } + + dragEl.parentNode[expando]._isOutsideThisEl(target); + + if (parent) { + do { + if (parent[expando]) { + var inserted = void 0; + inserted = parent[expando]._onDragOver({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); + + if (inserted && !this.options.dragoverBubble) { + break; + } + } + + target = parent; // store last element + } + /* jshint boss:true */ + while (parent = parent.parentNode); + } + + _unhideGhostForTarget(); + } + }, + _onTouchMove: function _onTouchMove( + /**TouchEvent*/ + evt) { + if (tapEvt) { + var options = this.options, + fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, + touch = evt.touches ? evt.touches[0] : evt, + ghostMatrix = ghostEl && matrix(ghostEl), + scaleX = ghostEl && ghostMatrix && ghostMatrix.a, + scaleY = ghostEl && ghostMatrix && ghostMatrix.d, + relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent), + dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1), + dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1), + translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging + + if (!Sortable$1.active && !awaitingDragStarted) { + if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) { + return; + } + + this._onDragStart(evt, true); + } + + touchEvt = touch; + css(ghostEl, 'webkitTransform', translate3d); + css(ghostEl, 'mozTransform', translate3d); + css(ghostEl, 'msTransform', translate3d); + css(ghostEl, 'transform', translate3d); + evt.cancelable && evt.preventDefault(); + } + }, + _appendGhost: function _appendGhost() { + // Bug if using scale(): https://stackoverflow.com/questions/2637058 + // Not being adjusted for + if (!ghostEl) { + var container = this.options.fallbackOnBody ? document.body : rootEl, + rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container), + options = this.options; // Position absolutely + + if (PositionGhostAbsolutely) { + // Get relatively positioned parent + ghostRelativeParent = container; + + while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) { + ghostRelativeParent = ghostRelativeParent.parentNode; + } + + if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { + if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement(); + rect.top += ghostRelativeParent.scrollTop; + rect.left += ghostRelativeParent.scrollLeft; + } else { + ghostRelativeParent = getWindowScrollingElement(); + } + + ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent); + } + + ghostEl = dragEl.cloneNode(true); + toggleClass(ghostEl, options.ghostClass, false); + toggleClass(ghostEl, options.fallbackClass, true); + toggleClass(ghostEl, options.dragClass, true); + css(ghostEl, 'transition', ''); + css(ghostEl, 'transform', ''); + css(ghostEl, 'box-sizing', 'border-box'); + css(ghostEl, 'margin', 0); + css(ghostEl, 'top', rect.top); + css(ghostEl, 'left', rect.left); + css(ghostEl, 'width', rect.width); + css(ghostEl, 'height', rect.height); + css(ghostEl, 'opacity', '0.8'); + css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed'); + css(ghostEl, 'zIndex', '100000'); + css(ghostEl, 'pointerEvents', 'none'); + Sortable$1.ghost = ghostEl; + container.appendChild(ghostEl); + } + }, + _onDragStart: function _onDragStart( + /**Event*/ + evt, + /**boolean*/ + fallback) { + var _this = this; + + var dataTransfer = evt.dataTransfer; + var options = _this.options; + pluginEvent('dragStart', this, { + evt: evt + }); + + if (Sortable$1.eventCanceled) { + this._onDrop(); + + return; + } + + pluginEvent('setupClone', this); + + if (!Sortable$1.eventCanceled) { + cloneEl = clone(dragEl); + cloneEl.draggable = false; + cloneEl.style['will-change'] = ''; + + this._hideClone(); + + toggleClass(cloneEl, this.options.chosenClass, false); + Sortable$1.clone = cloneEl; + } // #1143: IFrame support workaround + + + _this.cloneId = _nextTick(function () { + pluginEvent('clone', _this); + if (Sortable$1.eventCanceled) return; + + if (!_this.options.removeCloneOnHide) { + rootEl.insertBefore(cloneEl, dragEl); + } + + _this._hideClone(); + + _dispatchEvent({ + sortable: _this, + name: 'clone' + }); + }); + !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events + + if (fallback) { + ignoreNextClick = true; + _this._loopId = setInterval(_this._emulateDragOver, 50); + } else { + // Undo what was set in _prepareDragStart before drag started + off(document, 'mouseup', _this._onDrop); + off(document, 'touchend', _this._onDrop); + off(document, 'touchcancel', _this._onDrop); + + if (dataTransfer) { + dataTransfer.effectAllowed = 'move'; + options.setData && options.setData.call(_this, dataTransfer, dragEl); + } + + on(document, 'drop', _this); // #1276 fix: + + css(dragEl, 'transform', 'translateZ(0)'); + } + + awaitingDragStarted = true; + _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); + on(document, 'selectstart', _this); + moved = true; + + if (Safari) { + css(document.body, 'user-select', 'none'); + } + }, + // Returns true - if no further action is needed (either inserted or another condition) + _onDragOver: function _onDragOver( + /**Event*/ + evt) { + var el = this.el, + target = evt.target, + dragRect, + targetRect, + revert, + options = this.options, + group = options.group, + activeSortable = Sortable$1.active, + isOwner = activeGroup === group, + canSort = options.sort, + fromSortable = putSortable || activeSortable, + vertical, + _this = this, + completedFired = false; + + if (_silent) return; + + function dragOverEvent(name, extra) { + pluginEvent(name, _this, _objectSpread({ + evt: evt, + isOwner: isOwner, + axis: vertical ? 'vertical' : 'horizontal', + revert: revert, + dragRect: dragRect, + targetRect: targetRect, + canSort: canSort, + fromSortable: fromSortable, + target: target, + completed: completed, + onMove: function onMove(target, after) { + _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after); + }, + changed: changed + }, extra)); + } // Capture animation state + + + function capture() { + dragOverEvent('dragOverAnimationCapture'); + + _this.captureAnimationState(); + + if (_this !== fromSortable) { + fromSortable.captureAnimationState(); + } + } // Return invocation when dragEl is inserted (or completed) + + + function completed(insertion) { + dragOverEvent('dragOverCompleted', { + insertion: insertion + }); + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } else { + activeSortable._showClone(_this); + } + + if (_this !== fromSortable) { + // Set ghost class to new sortable's ghost class + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); + toggleClass(dragEl, options.ghostClass, true); + } + + if (putSortable !== _this && _this !== Sortable$1.active) { + putSortable = _this; + } else if (_this === Sortable$1.active && putSortable) { + putSortable = null; + } // Animation + + + if (fromSortable === _this) { + _this._ignoreWhileAnimating = target; + } + + _this.animateAll(function () { + dragOverEvent('dragOverAnimationComplete'); + _this._ignoreWhileAnimating = null; + }); + + if (_this !== fromSortable) { + fromSortable.animateAll(); + fromSortable._ignoreWhileAnimating = null; + } + } // Null lastTarget if it is not inside a previously swapped element + + + if (target === dragEl && !dragEl.animated || target === el && !target.animated) { + lastTarget = null; + } // no bubbling and not fallback + + + if (!options.dragoverBubble && !evt.rootEl && target !== document) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted + + + !insertion && nearestEmptyInsertDetectEvent(evt); + } + + !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); + return completedFired = true; + } // Call when dragEl has been inserted + + + function changed() { + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + _dispatchEvent({ + sortable: _this, + name: 'change', + toEl: el, + newIndex: newIndex, + newDraggableIndex: newDraggableIndex, + originalEvent: evt + }); + } + + if (evt.preventDefault !== void 0) { + evt.cancelable && evt.preventDefault(); + } + + target = closest(target, options.draggable, el, true); + dragOverEvent('dragOver'); + if (Sortable$1.eventCanceled) return completedFired; + + if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) { + return completed(false); + } + + ignoreNextClick = false; + + if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list + : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) { + vertical = this._getDirection(evt, target) === 'vertical'; + dragRect = getRect(dragEl); + dragOverEvent('dragOverValid'); + if (Sortable$1.eventCanceled) return completedFired; + + if (revert) { + parentEl = rootEl; // actualization + + capture(); + + this._hideClone(); + + dragOverEvent('revert'); + + if (!Sortable$1.eventCanceled) { + if (nextEl) { + rootEl.insertBefore(dragEl, nextEl); + } else { + rootEl.appendChild(dragEl); + } + } + + return completed(true); + } + + var elLastChild = lastChild(el, options.draggable); + + if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) { + // If already at end of list: Do not insert + if (elLastChild === dragEl) { + return completed(false); + } // assign target only if condition is true + + + if (elLastChild && el === evt.target) { + target = elLastChild; + } + + if (target) { + targetRect = getRect(target); + } + + if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { + capture(); + el.appendChild(dragEl); + parentEl = el; // actualization + + changed(); + return completed(true); + } + } else if (target.parentNode === el) { + var direction = 0, + targetBeforeFirstSwap, + differentLevel = dragEl.parentNode !== el, + side1 = vertical ? 'top' : 'left', + scrolledPastTop = isScrolledPast(target, null, 'top', 'top') || isScrolledPast(dragEl, null, 'top', 'top'), + scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; + + if (lastTarget !== target) { + targetBeforeFirstSwap = getRect(target)[side1]; + pastFirstInvertThresh = false; + isCircumstantialInvert = options.invertSwap || differentLevel; + } + + direction = _getSwapDirection(evt, target, vertical, options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target); + var sibling; + + if (direction !== 0) { + // Check if target is beside dragEl in respective direction (ignoring hidden elements) + var dragIndex = index(dragEl); + + do { + dragIndex -= direction; + sibling = parentEl.children[dragIndex]; + } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl)); + } // If dragEl is already beside target: Do not insert + + + if (direction === 0 || sibling === target) { + return completed(false); + } + + lastTarget = target; + lastDirection = direction; + targetRect = getRect(target); + var nextSibling = target.nextElementSibling, + after = false; + after = direction === 1; + + var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); + + if (moveVector !== false) { + if (moveVector === 1 || moveVector === -1) { + after = moveVector === 1; + } + + _silent = true; + setTimeout(_unsilent, 30); + capture(); + + if (after && !nextSibling) { + el.appendChild(dragEl); + } else { + target.parentNode.insertBefore(dragEl, after ? nextSibling : target); + } // Undo chrome's scroll adjustment (has no effect on other browsers) + + + if (scrolledPastTop) { + scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); + } + + parentEl = dragEl.parentNode; // actualization + // must be done before animation + + if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { + targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]); + } + + changed(); + return completed(true); + } + } + + if (el.contains(dragEl)) { + return completed(false); + } + } + + return false; + }, + _ignoreWhileAnimating: null, + _offMoveEvents: function _offMoveEvents() { + off(document, 'mousemove', this._onTouchMove); + off(document, 'touchmove', this._onTouchMove); + off(document, 'pointermove', this._onTouchMove); + off(document, 'dragover', nearestEmptyInsertDetectEvent); + off(document, 'mousemove', nearestEmptyInsertDetectEvent); + off(document, 'touchmove', nearestEmptyInsertDetectEvent); + }, + _offUpEvents: function _offUpEvents() { + var ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._onDrop); + off(ownerDocument, 'touchend', this._onDrop); + off(ownerDocument, 'pointerup', this._onDrop); + off(ownerDocument, 'touchcancel', this._onDrop); + off(document, 'selectstart', this); + }, + _onDrop: function _onDrop( + /**Event*/ + evt) { + var el = this.el, + options = this.options; // Get the index of the dragged element within its parent + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + pluginEvent('drop', this, { + evt: evt + }); // Get again after plugin event + + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + if (Sortable$1.eventCanceled) { + this._nulling(); + + return; + } + + awaitingDragStarted = false; + isCircumstantialInvert = false; + pastFirstInvertThresh = false; + clearInterval(this._loopId); + clearTimeout(this._dragStartTimer); + + _cancelNextTick(this.cloneId); + + _cancelNextTick(this._dragStartId); // Unbind events + + + if (this.nativeDraggable) { + off(document, 'drop', this); + off(el, 'dragstart', this._onDragStart); + } + + this._offMoveEvents(); + + this._offUpEvents(); + + if (Safari) { + css(document.body, 'user-select', ''); + } + + if (evt) { + if (moved) { + evt.cancelable && evt.preventDefault(); + !options.dropBubble && evt.stopPropagation(); + } + + ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + // Remove clone(s) + cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); + } + + if (dragEl) { + if (this.nativeDraggable) { + off(dragEl, 'dragend', this); + } + + _disableDraggable(dragEl); + + dragEl.style['will-change'] = ''; // Remove classes + // ghostClass is added in dragStarted + + if (moved && !awaitingDragStarted) { + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); + } + + toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event + + _dispatchEvent({ + sortable: this, + name: 'unchoose', + toEl: parentEl, + newIndex: null, + newDraggableIndex: null, + originalEvent: evt + }); + + if (rootEl !== parentEl) { + if (newIndex >= 0) { + // Add event + _dispatchEvent({ + rootEl: parentEl, + name: 'add', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); // Remove event + + + _dispatchEvent({ + sortable: this, + name: 'remove', + toEl: parentEl, + originalEvent: evt + }); // drag from one list and drop into another + + + _dispatchEvent({ + rootEl: parentEl, + name: 'sort', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + + putSortable && putSortable.save(); + } else { + if (newIndex !== oldIndex) { + if (newIndex >= 0) { + // drag & drop within the same list + _dispatchEvent({ + sortable: this, + name: 'update', + toEl: parentEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + } + } + + if (Sortable$1.active) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { + newIndex = oldIndex; + newDraggableIndex = oldDraggableIndex; + } + + _dispatchEvent({ + sortable: this, + name: 'end', + toEl: parentEl, + originalEvent: evt + }); // Save sorting + + + this.save(); + } + } + } + + this._nulling(); + }, + _nulling: function _nulling() { + pluginEvent('nulling', this); + rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable$1.dragged = Sortable$1.ghost = Sortable$1.clone = Sortable$1.active = null; + savedInputChecked.forEach(function (el) { + el.checked = true; + }); + savedInputChecked.length = 0; + }, + handleEvent: function handleEvent( + /**Event*/ + evt) { + switch (evt.type) { + case 'drop': + case 'dragend': + this._onDrop(evt); + + break; + + case 'dragenter': + case 'dragover': + if (dragEl) { + this._onDragOver(evt); + + _globalDragOver(evt); + } + + break; + + case 'selectstart': + evt.preventDefault(); + break; + } + }, + + /** + * Serializes the item into an array of string. + * @returns {String[]} + */ + toArray: function toArray() { + var order = [], + el, + children = this.el.children, + i = 0, + n = children.length, + options = this.options; + + for (; i < n; i++) { + el = children[i]; + + if (closest(el, options.draggable, this.el, false)) { + order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); + } + } + + return order; + }, + + /** + * Sorts the elements according to the array. + * @param {String[]} order order of the items + */ + sort: function sort(order) { + var items = {}, + rootEl = this.el; + this.toArray().forEach(function (id, i) { + var el = rootEl.children[i]; + + if (closest(el, this.options.draggable, rootEl, false)) { + items[id] = el; + } + }, this); + order.forEach(function (id) { + if (items[id]) { + rootEl.removeChild(items[id]); + rootEl.appendChild(items[id]); + } + }); + }, + + /** + * Save the current sorting + */ + save: function save() { + var store = this.options.store; + store && store.set && store.set(this); + }, + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * @param {HTMLElement} el + * @param {String} [selector] default: `options.draggable` + * @returns {HTMLElement|null} + */ + closest: function closest$1(el, selector) { + return closest(el, selector || this.options.draggable, this.el, false); + }, + + /** + * Set/get option + * @param {string} name + * @param {*} [value] + * @returns {*} + */ + option: function option(name, value) { + var options = this.options; + + if (value === void 0) { + return options[name]; + } else { + var modifiedValue = PluginManager.modifyOption(this, name, value); + + if (typeof modifiedValue !== 'undefined') { + options[name] = modifiedValue; + } else { + options[name] = value; + } + + if (name === 'group') { + _prepareGroup(options); + } + } + }, + + /** + * Destroy + */ + destroy: function destroy() { + pluginEvent('destroy', this); + var el = this.el; + el[expando] = null; + off(el, 'mousedown', this._onTapStart); + off(el, 'touchstart', this._onTapStart); + off(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + off(el, 'dragover', this); + off(el, 'dragenter', this); + } // Remove draggable attributes + + + Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { + el.removeAttribute('draggable'); + }); + + this._onDrop(); + + sortables.splice(sortables.indexOf(this.el), 1); + this.el = el = null; + }, + _hideClone: function _hideClone() { + if (!cloneHidden) { + pluginEvent('hideClone', this); + if (Sortable$1.eventCanceled) return; + css(cloneEl, 'display', 'none'); + + if (this.options.removeCloneOnHide && cloneEl.parentNode) { + cloneEl.parentNode.removeChild(cloneEl); + } + + cloneHidden = true; + } + }, + _showClone: function _showClone(putSortable) { + if (putSortable.lastPutMode !== 'clone') { + this._hideClone(); + + return; + } + + if (cloneHidden) { + pluginEvent('showClone', this); + if (Sortable$1.eventCanceled) return; // show clone at dragEl or original position + + if (rootEl.contains(dragEl) && !this.options.group.revertClone) { + rootEl.insertBefore(cloneEl, dragEl); + } else if (nextEl) { + rootEl.insertBefore(cloneEl, nextEl); + } else { + rootEl.appendChild(cloneEl); + } + + if (this.options.group.revertClone) { + this._animate(dragEl, cloneEl); + } + + css(cloneEl, 'display', ''); + cloneHidden = false; + } + } +}; + +function _globalDragOver( +/**Event*/ +evt) { + if (evt.dataTransfer) { + evt.dataTransfer.dropEffect = 'move'; + } + + evt.cancelable && evt.preventDefault(); +} + +function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) { + var evt, + sortable = fromEl[expando], + onMoveFn = sortable.options.onMove, + retVal; // Support for new CustomEvent feature + + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent('move', { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent('move', true, true); + } + + evt.to = toEl; + evt.from = fromEl; + evt.dragged = dragEl; + evt.draggedRect = dragRect; + evt.related = targetEl || toEl; + evt.relatedRect = targetRect || getRect(toEl); + evt.willInsertAfter = willInsertAfter; + evt.originalEvent = originalEvent; + fromEl.dispatchEvent(evt); + + if (onMoveFn) { + retVal = onMoveFn.call(sortable, evt, originalEvent); + } + + return retVal; +} + +function _disableDraggable(el) { + el.draggable = false; +} + +function _unsilent() { + _silent = false; +} + +function _ghostIsLast(evt, vertical, sortable) { + var elRect = getRect(lastChild(sortable.el, sortable.options.draggable)), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + mouseOnOppAxis = vertical ? evt.clientX : evt.clientY, + targetS2 = vertical ? elRect.bottom : elRect.right, + targetS1Opp = vertical ? elRect.left : elRect.top, + targetS2Opp = vertical ? elRect.right : elRect.bottom; + return mouseOnAxis > targetS2 && mouseOnOppAxis > targetS1Opp && mouseOnOppAxis < targetS2Opp; +} + +function _getSwapDirection(evt, target, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { + var targetRect = getRect(target), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + targetLength = vertical ? targetRect.height : targetRect.width, + targetS1 = vertical ? targetRect.top : targetRect.left, + targetS2 = vertical ? targetRect.bottom : targetRect.right, + invert = false; + + if (!invertSwap) { + // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold + if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { + // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 + // check if past first invert threshold on side opposite of lastDirection + if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) { + // past first invert threshold, do not restrict inverted threshold to dragEl shadow + pastFirstInvertThresh = true; + } + + if (!pastFirstInvertThresh) { + // dragEl shadow (target move distance shadow) + if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow + : mouseOnAxis > targetS2 - targetMoveDistance) { + return -lastDirection; + } + } else { + invert = true; + } + } else { + // Regular + if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) { + return _getInsertDirection(target); + } + } + } + + invert = invert || invertSwap; + + if (invert) { + // Invert of regular + if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) { + return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1; + } + } + + return 0; +} +/** + * Gets the direction dragEl must be swapped relative to target in order to make it + * seem that dragEl has been "inserted" into that element's position + * @param {HTMLElement} target The target whose position dragEl is being inserted at + * @return {Number} Direction dragEl must be swapped + */ + + +function _getInsertDirection(target) { + if (index(dragEl) < index(target)) { + return 1; + } else { + return -1; + } +} +/** + * Generate id + * @param {HTMLElement} el + * @returns {String} + * @private + */ + + +function _generateId(el) { + var str = el.tagName + el.className + el.src + el.href + el.textContent, + i = str.length, + sum = 0; + + while (i--) { + sum += str.charCodeAt(i); + } + + return sum.toString(36); +} + +function _saveInputCheckedState(root) { + savedInputChecked.length = 0; + var inputs = root.getElementsByTagName('input'); + var idx = inputs.length; + + while (idx--) { + var _el = inputs[idx]; + _el.checked && savedInputChecked.push(_el); + } +} + +function _nextTick(fn) { + return setTimeout(fn, 0); +} + +function _cancelNextTick(id) { + return clearTimeout(id); +} // Fixed #973: + + +on(document, 'touchmove', function (evt) { + if ((Sortable$1.active || awaitingDragStarted) && evt.cancelable) { + evt.preventDefault(); + } +}); // Export utils + +Sortable$1.utils = { + on: on, + off: off, + css: css, + find: find, + is: function is(el, selector) { + return !!closest(el, selector, el, false); + }, + extend: extend, + throttle: throttle, + closest: closest, + toggleClass: toggleClass, + clone: clone, + index: index, + nextTick: _nextTick, + cancelNextTick: _cancelNextTick, + detectDirection: _detectDirection, + getChild: getChild +}; +/** + * Mount a plugin to Sortable + * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted + */ + +Sortable$1.mount = function () { + for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) { + plugins[_key] = arguments[_key]; + } + + if (plugins[0].constructor === Array) plugins = plugins[0]; + + for (var i in plugins) { + var plugin = plugins[i]; + + if (!plugin.prototype || !plugin.prototype.constructor) { + throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(el)); + } + + if (plugin.utils) Sortable$1.utils = _objectSpread({}, Sortable$1.utils, plugin.utils); + PluginManager.mount(plugin); + } +}; +/** + * Create sortable instance + * @param {HTMLElement} el + * @param {Object} [options] + */ + + +Sortable$1.create = function (el, options) { + return new Sortable$1(el, options); +}; // Export + + +Sortable$1.version = version; + +var autoScrolls = [], + scrollEl, + scrollRootEl, + scrolling = false, + lastAutoScrollX, + lastAutoScrollY, + touchEvt$1, + pointerElemChangedInterval; + +function AutoScrollPlugin() { + function AutoScroll() { + this.options = { + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, + bubbleScroll: true + }; // Bind all private methods + + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + } + + AutoScroll.prototype = { + dragStarted: function dragStarted(_ref) { + var originalEvent = _ref.originalEvent; + + if (this.sortable.nativeDraggable) { + on(document, 'dragover', this._handleAutoScroll); + } else { + if (this.sortable.options.supportPointer) { + on(document, 'pointermove', this._handleFallbackAutoScroll); + } else if (originalEvent.touches) { + on(document, 'touchmove', this._handleFallbackAutoScroll); + } else { + on(document, 'mousemove', this._handleFallbackAutoScroll); + } + } + }, + dragOverCompleted: function dragOverCompleted(_ref2) { + var originalEvent = _ref2.originalEvent; + + // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) + if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) { + this._handleAutoScroll(originalEvent); + } + }, + drop: function drop() { + if (this.sortable.nativeDraggable) { + off(document, 'dragover', this._handleAutoScroll); + } else { + off(document, 'pointermove', this._handleFallbackAutoScroll); + off(document, 'touchmove', this._handleFallbackAutoScroll); + off(document, 'mousemove', this._handleFallbackAutoScroll); + } + + clearPointerElemChangedInterval(); + clearAutoScrolls(); + cancelThrottle(); + }, + nulling: function nulling() { + touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null; + autoScrolls.length = 0; + }, + _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) { + this._handleAutoScroll(evt, true); + }, + _handleAutoScroll: function _handleAutoScroll(evt, fallback) { + var _this = this; + + var x = evt.clientX, + y = evt.clientY, + elem = document.elementFromPoint(x, y); + touchEvt$1 = evt; // IE does not seem to have native autoscroll, + // Edge's autoscroll seems too conditional, + // MACOS Safari does not have autoscroll, + // Firefox and Chrome are good + + if (fallback || Edge || IE11OrLess || Safari) { + autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change + + var ogElemScroller = getParentAutoScrollElement(elem, true); + + if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) { + pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour + + pointerElemChangedInterval = setInterval(function () { + var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true); + + if (newElem !== ogElemScroller) { + ogElemScroller = newElem; + clearAutoScrolls(); + } + + autoScroll(evt, _this.options, newElem, fallback); + }, 10); + lastAutoScrollX = x; + lastAutoScrollY = y; + } + } else { + // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll + if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) { + clearAutoScrolls(); + return; + } + + autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false); + } + } + }; + return _extends(AutoScroll, { + pluginName: 'scroll', + initializeByDefault: true + }); +} + +function clearAutoScrolls() { + autoScrolls.forEach(function (autoScroll) { + clearInterval(autoScroll.pid); + }); + autoScrolls = []; +} + +function clearPointerElemChangedInterval() { + clearInterval(pointerElemChangedInterval); +} + +var autoScroll = throttle(function (evt, options, rootEl, isFallback) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + if (!options.scroll) return; + var sens = options.scrollSensitivity, + speed = options.scrollSpeed, + winScroller = getWindowScrollingElement(); + var scrollThisInstance = false, + scrollCustomFn; // New scroll root, set scrollEl + + if (scrollRootEl !== rootEl) { + scrollRootEl = rootEl; + clearAutoScrolls(); + scrollEl = options.scroll; + scrollCustomFn = options.scrollFn; + + if (scrollEl === true) { + scrollEl = getParentAutoScrollElement(rootEl, true); + } + } + + var layersOut = 0; + var currentParent = scrollEl; + + do { + var el = currentParent, + rect = getRect(el), + top = rect.top, + bottom = rect.bottom, + left = rect.left, + right = rect.right, + width = rect.width, + height = rect.height, + canScrollX = void 0, + canScrollY = void 0, + scrollWidth = el.scrollWidth, + scrollHeight = el.scrollHeight, + elCSS = css(el), + scrollPosX = el.scrollLeft, + scrollPosY = el.scrollTop; + + if (el === winScroller) { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible'); + } else { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll'); + } + + var vx = canScrollX && (Math.abs(right - evt.clientX) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - evt.clientX) <= sens && !!scrollPosX); + var vy = canScrollY && (Math.abs(bottom - evt.clientY) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - evt.clientY) <= sens && !!scrollPosY); + + if (!autoScrolls[layersOut]) { + for (var i = 0; i <= layersOut; i++) { + if (!autoScrolls[i]) { + autoScrolls[i] = {}; + } + } + } + + if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { + autoScrolls[layersOut].el = el; + autoScrolls[layersOut].vx = vx; + autoScrolls[layersOut].vy = vy; + clearInterval(autoScrolls[layersOut].pid); + + if (vx != 0 || vy != 0) { + scrollThisInstance = true; + /* jshint loopfunc:true */ + + autoScrolls[layersOut].pid = setInterval(function () { + // emulate drag over during autoscroll (fallback), emulating native DnD behaviour + if (isFallback && this.layer === 0) { + Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely + + } + + var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; + var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; + + if (typeof scrollCustomFn === 'function') { + if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') { + return; + } + } + + scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); + }.bind({ + layer: layersOut + }), 24); + } + } + + layersOut++; + } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false))); + + scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not +}, 30); + +var drop = function drop(_ref) { + var originalEvent = _ref.originalEvent, + putSortable = _ref.putSortable, + dragEl = _ref.dragEl, + activeSortable = _ref.activeSortable, + dispatchSortableEvent = _ref.dispatchSortableEvent, + hideGhostForTarget = _ref.hideGhostForTarget, + unhideGhostForTarget = _ref.unhideGhostForTarget; + var toSortable = putSortable || activeSortable; + hideGhostForTarget(); + var target = document.elementFromPoint(originalEvent.clientX, originalEvent.clientY); + unhideGhostForTarget(); + + if (toSortable && !toSortable.el.contains(target)) { + dispatchSortableEvent('spill'); + this.onSpill(dragEl); + } +}; + +function Revert() {} + +Revert.prototype = { + startIndex: null, + dragStart: function dragStart(_ref2) { + var oldDraggableIndex = _ref2.oldDraggableIndex; + this.startIndex = oldDraggableIndex; + }, + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + var nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options); + + if (nextSibling) { + this.sortable.el.insertBefore(dragEl, nextSibling); + } else { + this.sortable.el.appendChild(dragEl); + } + + this.sortable.animateAll(); + }, + drop: drop +}; + +_extends(Revert, { + pluginName: 'revertOnSpill' +}); + +function Remove() {} + +Remove.prototype = { + onSpill: function onSpill(dragEl) { + this.sortable.captureAnimationState(); + dragEl.parentNode && dragEl.parentNode.removeChild(dragEl); + this.sortable.animateAll(); + }, + drop: drop +}; + +_extends(Remove, { + pluginName: 'removeOnSpill' +}); + +var lastSwapEl; + +function SwapPlugin() { + function Swap() { + this.options = { + swapClass: 'sortable-swap-highlight' + }; + } + + Swap.prototype = { + dragStart: function dragStart(_ref) { + var dragEl = _ref.dragEl; + lastSwapEl = dragEl; + }, + dragOverValid: function dragOverValid(_ref2) { + var completed = _ref2.completed, + target = _ref2.target, + onMove = _ref2.onMove, + activeSortable = _ref2.activeSortable, + changed = _ref2.changed; + if (!activeSortable.options.swap) return; + var el = this.sortable.el, + options = this.sortable.options; + + if (target && target !== el) { + var prevSwapEl = lastSwapEl; + + if (onMove(target) !== false) { + toggleClass(target, options.swapClass, true); + lastSwapEl = target; + } else { + lastSwapEl = null; + } + + if (prevSwapEl && prevSwapEl !== lastSwapEl) { + toggleClass(prevSwapEl, options.swapClass, false); + } + } + + changed(); + return completed(true); + }, + drop: function drop(_ref3) { + var activeSortable = _ref3.activeSortable, + putSortable = _ref3.putSortable, + dragEl = _ref3.dragEl; + var toSortable = putSortable || this.sortable; + var options = this.sortable.options; + lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false); + + if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) { + if (dragEl !== lastSwapEl) { + toSortable.captureAnimationState(); + if (toSortable !== activeSortable) activeSortable.captureAnimationState(); + swapNodes(dragEl, lastSwapEl); + toSortable.animateAll(); + if (toSortable !== activeSortable) activeSortable.animateAll(); + } + } + }, + nulling: function nulling() { + lastSwapEl = null; + } + }; + return _extends(Swap, { + pluginName: 'swap', + eventOptions: function eventOptions() { + return { + swapItem: lastSwapEl + }; + } + }); +} + +function swapNodes(n1, n2) { + var p1 = n1.parentNode, + p2 = n2.parentNode, + i1, + i2; + if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return; + i1 = index(n1); + i2 = index(n2); + + if (p1.isEqualNode(p2) && i1 < i2) { + i2++; + } + + p1.insertBefore(n2, p1.children[i1]); + p2.insertBefore(n1, p2.children[i2]); +} + +var multiDragElements = [], + multiDragClones = [], + lastMultiDragSelect, + // for selection with modifier key down (SHIFT) +multiDragSortable, + initialFolding = false, + // Initial multi-drag fold when drag started +folding = false, + // Folding any other time +dragStarted = false, + dragEl$1, + clonesFromRect, + clonesHidden; + +function MultiDragPlugin() { + function MultiDrag(sortable) { + // Bind all private methods + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + if (sortable.options.supportPointer) { + on(document, 'pointerup', this._deselectMultiDrag); + } else { + on(document, 'mouseup', this._deselectMultiDrag); + on(document, 'touchend', this._deselectMultiDrag); + } + + on(document, 'keydown', this._checkKeyDown); + on(document, 'keyup', this._checkKeyUp); + this.options = { + selectedClass: 'sortable-selected', + multiDragKey: null, + setData: function setData(dataTransfer, dragEl) { + var data = ''; + + if (multiDragElements.length && multiDragSortable === sortable) { + for (var i in multiDragElements) { + data += (!i ? '' : ', ') + multiDragElements[i].textContent; + } + } else { + data = dragEl.textContent; + } + + dataTransfer.setData('Text', data); + } + }; + } + + MultiDrag.prototype = { + multiDragKeyDown: false, + isMultiDrag: false, + delayStartGlobal: function delayStartGlobal(_ref) { + var dragged = _ref.dragEl; + dragEl$1 = dragged; + }, + delayEnded: function delayEnded() { + this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1); + }, + setupClone: function setupClone(_ref2) { + var sortable = _ref2.sortable; + if (!this.isMultiDrag) return; + + for (var i in multiDragElements) { + multiDragClones.push(clone(multiDragElements[i])); + multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex; + multiDragClones[i].draggable = false; + multiDragClones[i].style['will-change'] = ''; + toggleClass(multiDragClones[i], sortable.options.selectedClass, false); + multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], sortable.options.chosenClass, false); + } + + sortable._hideClone(); + + return true; + }, + clone: function clone(_ref3) { + var sortable = _ref3.sortable, + rootEl = _ref3.rootEl, + dispatchSortableEvent = _ref3.dispatchSortableEvent; + if (!this.isMultiDrag) return; + + if (!sortable.options.removeCloneOnHide) { + if (multiDragElements.length && multiDragSortable === sortable) { + insertMultiDragClones(true, rootEl); + dispatchSortableEvent('clone'); + return true; + } + } + }, + showClone: function showClone(_ref4) { + var cloneNowShown = _ref4.cloneNowShown, + rootEl = _ref4.rootEl; + if (!this.isMultiDrag) return; + insertMultiDragClones(false, rootEl); + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', ''); + } + + cloneNowShown(); + clonesHidden = false; + return true; + }, + hideClone: function hideClone(_ref5) { + var sortable = _ref5.sortable, + cloneNowHidden = _ref5.cloneNowHidden; + if (!this.isMultiDrag) return; + + for (var i in multiDragClones) { + css(multiDragClones[i], 'display', 'none'); + + if (sortable.options.removeCloneOnHide && multiDragClones[i].parentNode) { + multiDragClones[i].parentNode.removeChild(multiDragClones[i]); + } + } + + cloneNowHidden(); + clonesHidden = true; + return true; + }, + dragStartGlobal: function dragStartGlobal(_ref6) { + var sortable = _ref6.sortable; + + if (!this.isMultiDrag && multiDragSortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + } + + for (var i in multiDragElements) { + multiDragElements[i].sortableIndex = index(multiDragElements[i]); + } // Sort multi-drag elements + + + multiDragElements = multiDragElements.sort(function (a, b) { + return a.sortableIndex - b.sortableIndex; + }); + dragStarted = true; + }, + dragStarted: function dragStarted(_ref7) { + var sortable = _ref7.sortable; + if (!this.isMultiDrag) return; + + if (sortable.options.sort) { + // Capture rects, + // hide multi drag elements (by positioning them absolute), + // set multi drag elements rects to dragRect, + // show multi drag elements, + // animate to rects, + // unset rects & remove from DOM + sortable.captureAnimationState(); + + if (sortable.options.animation) { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + css(multiDragElements[i], 'position', 'absolute'); + } + + var dragRect = getRect(dragEl$1, false, true, true); + + for (var _i in multiDragElements) { + if (multiDragElements[_i] === dragEl$1) continue; + setRect(multiDragElements[_i], dragRect); + } + + folding = true; + initialFolding = true; + } + } + + sortable.animateAll(function () { + folding = false; + initialFolding = false; + + if (sortable.options.animation) { + for (var _i2 in multiDragElements) { + unsetRect(multiDragElements[_i2]); + } + } // Remove all auxiliary multidrag items from el, if sorting enabled + + + if (sortable.options.sort) { + removeMultiDragElements(); + } + }); + }, + dragOver: function dragOver(_ref8) { + var target = _ref8.target, + completed = _ref8.completed; + + if (folding && ~multiDragElements.indexOf(target)) { + return completed(false); + } + }, + revert: function revert(_ref9) { + var fromSortable = _ref9.fromSortable, + rootEl = _ref9.rootEl, + sortable = _ref9.sortable, + dragRect = _ref9.dragRect; + + if (multiDragElements.length > 1) { + // Setup unfold animation + for (var i in multiDragElements) { + sortable.addAnimationState({ + target: multiDragElements[i], + rect: folding ? getRect(multiDragElements[i]) : dragRect + }); + unsetRect(multiDragElements[i]); + multiDragElements[i].fromRect = dragRect; + fromSortable.removeAnimationState(multiDragElements[i]); + } + + folding = false; + insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl); + } + }, + dragOverCompleted: function dragOverCompleted(_ref10) { + var sortable = _ref10.sortable, + isOwner = _ref10.isOwner, + insertion = _ref10.insertion, + activeSortable = _ref10.activeSortable, + parentEl = _ref10.parentEl, + putSortable = _ref10.putSortable; + var options = sortable.options; + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } + + initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location + + if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) { + // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible + var dragRectAbsolute = getRect(dragEl$1, false, true, true); + + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + setRect(multiDragElements[i], dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted + // while folding, and so that we can capture them again because old sortable will no longer be fromSortable + + parentEl.appendChild(multiDragElements[i]); + } + + folding = true; + } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out + + + if (!isOwner) { + // Only remove if not folding (folding will remove them anyways) + if (!folding) { + removeMultiDragElements(); + } + + if (multiDragElements.length > 1) { + var clonesHiddenBefore = clonesHidden; + + activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden + + + if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) { + for (var _i3 in multiDragClones) { + activeSortable.addAnimationState({ + target: multiDragClones[_i3], + rect: clonesFromRect + }); + multiDragClones[_i3].fromRect = clonesFromRect; + multiDragClones[_i3].thisAnimationDuration = null; + } + } + } else { + activeSortable._showClone(sortable); + } + } + } + }, + dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) { + var dragRect = _ref11.dragRect, + isOwner = _ref11.isOwner, + activeSortable = _ref11.activeSortable; + + for (var i in multiDragElements) { + multiDragElements[i].thisAnimationDuration = null; + } + + if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) { + clonesFromRect = _extends({}, dragRect); + var dragMatrix = matrix(dragEl$1, true); + clonesFromRect.top -= dragMatrix.f; + clonesFromRect.left -= dragMatrix.e; + } + }, + dragOverAnimationComplete: function dragOverAnimationComplete() { + if (folding) { + folding = false; + removeMultiDragElements(); + } + }, + drop: function drop(_ref12) { + var evt = _ref12.originalEvent, + rootEl = _ref12.rootEl, + parentEl = _ref12.parentEl, + sortable = _ref12.sortable, + dispatchSortableEvent = _ref12.dispatchSortableEvent, + oldIndex = _ref12.oldIndex, + putSortable = _ref12.putSortable; + var toSortable = putSortable || this.sortable; + if (!evt) return; + var options = sortable.options, + children = parentEl.children; // Multi-drag selection + + if (!dragStarted) { + if (options.multiDragKey && !this.multiDragKeyDown) { + this._deselectMultiDrag(); + } + + toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1)); + + if (!~multiDragElements.indexOf(dragEl$1)) { + multiDragElements.push(dragEl$1); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: dragEl$1, + originalEvt: evt + }); // Modifier activated, select from last to dragEl + + if ((!options.multiDragKey || this.multiDragKeyDown) && evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) { + var lastIndex = index(lastMultiDragSelect), + currentIndex = index(dragEl$1); + + if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) { + // Must include lastMultiDragSelect (select it), in case modified selection from no selection + // (but previous selection existed) + var n, i; + + if (currentIndex > lastIndex) { + i = lastIndex; + n = currentIndex; + } else { + i = currentIndex; + n = lastIndex + 1; + } + + for (; i < n; i++) { + if (~multiDragElements.indexOf(children[i])) continue; + toggleClass(children[i], options.selectedClass, true); + multiDragElements.push(children[i]); + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'select', + targetEl: children[i], + originalEvt: evt + }); + } + } + } else { + lastMultiDragSelect = dragEl$1; + } + + multiDragSortable = toSortable; + } else { + multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1); + lastMultiDragSelect = null; + dispatchEvent({ + sortable: sortable, + rootEl: rootEl, + name: 'deselect', + targetEl: dragEl$1, + originalEvt: evt + }); + } + } // Multi-drag drop + + + if (dragStarted && this.isMultiDrag) { + // Do not "unfold" after around dragEl if reverted + if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) { + var dragRect = getRect(dragEl$1), + multiDragIndex = index(dragEl$1, ':not(.' + Sortable.active.options.selectedClass + ')'); + if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null; + toSortable.captureAnimationState(); + + if (!initialFolding) { + if (options.animation) { + dragEl$1.fromRect = dragRect; + + for (var _i4 in multiDragElements) { + multiDragElements[_i4].thisAnimationDuration = null; + + if (multiDragElements[_i4] !== dragEl$1) { + var rect = folding ? getRect(multiDragElements[_i4]) : dragRect; + multiDragElements[_i4].fromRect = rect; // Prepare unfold animation + + toSortable.addAnimationState({ + target: multiDragElements[_i4], + rect: rect + }); + } + } + } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert + // properly they must all be removed + + + removeMultiDragElements(); + + for (var _i5 in multiDragElements) { + if (children[multiDragIndex]) { + parentEl.insertBefore(multiDragElements[_i5], children[multiDragIndex]); + } else { + parentEl.appendChild(multiDragElements[_i5]); + } + + multiDragIndex++; + } // If initial folding is done, the elements may have changed position because they are now + // unfolding around dragEl, even though dragEl may not have his index changed, so update event + // must be fired here as Sortable will not. + + + if (oldIndex === index(dragEl$1)) { + var update = false; + + for (var _i6 in multiDragElements) { + if (multiDragElements[_i6].sortableIndex !== index(multiDragElements[_i6])) { + update = true; + break; + } + } + + if (update) { + dispatchSortableEvent('update'); + } + } + } // Must be done after capturing individual rects (scroll bar) + + + for (var _i7 in multiDragElements) { + unsetRect(multiDragElements[_i7]); + } + + toSortable.animateAll(); + } + + multiDragSortable = toSortable; + } // Remove clones if necessary + + + if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') { + for (var _i8 in multiDragClones) { + multiDragClones[_i8].parentNode && multiDragClones[_i8].parentNode.removeChild(multiDragClones[_i8]); + } + } + }, + nullingGlobal: function nullingGlobal() { + this.isMultiDrag = dragStarted = false; + multiDragClones.length = 0; + }, + destroy: function destroy() { + this._deselectMultiDrag(); + + off(document, 'pointerup', this._deselectMultiDrag); + off(document, 'mouseup', this._deselectMultiDrag); + off(document, 'touchend', this._deselectMultiDrag); + off(document, 'keydown', this._checkKeyDown); + off(document, 'keyup', this._checkKeyUp); + }, + _deselectMultiDrag: function _deselectMultiDrag(evt) { + if (dragStarted) return; // Only deselect if selection is in this sortable + + if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable + + if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return; // Only deselect if left click + + if (evt && evt.button !== 0) return; + + while (multiDragElements.length) { + var el = multiDragElements[0]; + toggleClass(el, this.sortable.options.selectedClass, false); + multiDragElements.shift(); + dispatchEvent({ + sortable: this.sortable, + rootEl: this.sortable.el, + name: 'deselect', + targetEl: el, + originalEvt: evt + }); + } + }, + _checkKeyDown: function _checkKeyDown(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = true; + } + }, + _checkKeyUp: function _checkKeyUp(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = false; + } + } + }; + return _extends(MultiDrag, { + // Static methods & properties + pluginName: 'multiDrag', + utils: { + /** + * Selects the provided multi-drag item + * @param {HTMLElement} el The element to be selected + */ + select: function select(el) { + var sortable = el.parentNode[expando]; + if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return; + + if (multiDragSortable && multiDragSortable !== sortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + + multiDragSortable = sortable; + } + + toggleClass(el, sortable.options.selectedClass, true); + multiDragElements.push(el); + }, + + /** + * Deselects the provided multi-drag item + * @param {HTMLElement} el The element to be deselected + */ + deselect: function deselect(el) { + var sortable = el.parentNode[expando], + index = multiDragElements.indexOf(el); + if (!sortable || !sortable.options.multiDrag || !~index) return; + toggleClass(el, sortable.options.selectedClass, false); + multiDragElements.splice(index, 1); + } + }, + eventOptions: function eventOptions() { + return { + items: _toConsumableArray(multiDragElements), + clones: [].concat(multiDragClones) + }; + }, + optionListeners: { + multiDragKey: function multiDragKey(key) { + key = key.toLowerCase(); + + if (key === 'ctrl') { + key = 'Control'; + } else if (key.length > 1) { + key = key.charAt(0).toUpperCase() + key.substr(1); + } + + return key; + } + } + }); +} + +function insertMultiDragElements(clonesInserted, rootEl) { + for (var i in multiDragElements) { + var target = rootEl.children[multiDragElements[i].sortableIndex + (clonesInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragElements[i], target); + } else { + rootEl.appendChild(multiDragElements[i]); + } + } +} +/** + * Insert multi-drag clones + * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted + * @param {HTMLElement} rootEl + */ + + +function insertMultiDragClones(elementsInserted, rootEl) { + for (var i in multiDragClones) { + var target = rootEl.children[multiDragClones[i].sortableIndex + (elementsInserted ? Number(i) : 0)]; + + if (target) { + rootEl.insertBefore(multiDragClones[i], target); + } else { + rootEl.appendChild(multiDragClones[i]); + } + } +} + +function removeMultiDragElements() { + for (var i in multiDragElements) { + if (multiDragElements[i] === dragEl$1) continue; + multiDragElements[i].parentNode && multiDragElements[i].parentNode.removeChild(multiDragElements[i]); + } +} + +Sortable$1.mount(new AutoScrollPlugin()); +Sortable$1.mount(Remove, Revert); + +export default Sortable$1; +export { MultiDragPlugin as MultiDrag, Sortable$1 as Sortable, SwapPlugin as Swap }; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..43b2d051b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2311 @@ +{ + "name": "sortablejs", + "version": "1.9.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", + "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helpers": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.5", + "@babel/types": "^7.4.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-define-map": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", + "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", + "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", + "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", + "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", + "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", + "dev": true, + "requires": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", + "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz", + "integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", + "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", + "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz", + "integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.11" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", + "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.4", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", + "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", + "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", + "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", + "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", + "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", + "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz", + "integrity": "sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==", + "dev": true, + "requires": { + "regexp-tree": "^0.1.6" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-assign": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.2.0.tgz", + "integrity": "sha512-nmE55cZBPFgUktbF2OuoZgPRadfxosLOpSgzEPYotKSls9J4pEPcembi8r78RU37Rph6UApCpNmsQA4QMWK9Ng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", + "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", + "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", + "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/preset-env": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", + "integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.4.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.4.4", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.4.4", + "@babel/plugin-transform-classes": "^7.4.4", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.4.4", + "@babel/plugin-transform-modules-systemjs": "^7.4.4", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + } + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", + "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/node": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", + "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserslist": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.0.tgz", + "integrity": "sha512-Jk0YFwXBuMOOol8n6FhgkDzn3mY9PYLYGk29zybF05SbRTsMgPqmTNeQQhOghCxq5oFqAXE3u4sYddr4C0uRhg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000967", + "electron-to-chromium": "^1.3.133", + "node-releases": "^1.1.19" + } + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000971", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000971.tgz", + "integrity": "sha512-TQFYFhRS0O5rdsmSbF1Wn+16latXYsQJat66f7S7lizXW1PVpWJeZw9wqqVLIjuxDRz7s7xRUj13QCfd8hKn6g==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js-compat": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.1.2.tgz", + "integrity": "sha512-X0Ch5f6itrHxhg5HSJucX6nNLNAGr+jq+biBh6nPGc3YAWz2a8p/ZIZY8cUkDzSRNG54omAuu3hoEF8qZbu/6Q==", + "dev": true, + "requires": { + "browserslist": "^4.6.0", + "core-js-pure": "3.1.2", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.0.tgz", + "integrity": "sha512-kCqEOOHoBcFs/2Ccuk4Xarm/KiWRSLEX9CAZF8xkJ6ZPlIoTZ8V5f7J16vYLJqDbR7KrxTJpR2lqjIEm2Qx9cQ==", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.1.2.tgz", + "integrity": "sha512-5ckIdBF26B3ldK9PM177y2ZcATP2oweam9RskHSoqfZCrJ2As6wVg8zJ1zTriFsZf6clj/N1ThDFRGaomMsh9w==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "electron-to-chromium": { + "version": "1.3.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.137.tgz", + "integrity": "sha512-kGi32g42a8vS/WnYE7ELJyejRT7hbr3UeOOu0WeuYuQ29gCpg9Lrf6RdcTQVXSt/v0bjCfnlb/EWOOsiKpTmkw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.0.tgz", + "integrity": "sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "node-releases": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.21.tgz", + "integrity": "sha512-TwnURTCjc8a+ElJUjmDqU6+12jhli1Q61xOQmdZ7ECZVBZuQpN/1UnembiIHDM1wCcfLvh5wrWXUF5H6ufX64Q==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-transform": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.0.tgz", + "integrity": "sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-tree": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.10.tgz", + "integrity": "sha512-K1qVSbcedffwuIslMwpe6vGlj+ZXRnGkvjAtFHfDZZZuEdA/h0dxljAPu9vhUo6Rrx2U2AwJ+nSQ6hK+lrP5MQ==", + "dev": true + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "resolve": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", + "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rollup": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.12.3.tgz", + "integrity": "sha512-ueWhPijWN+GaPgD3l77hXih/gcDXmYph6sWeQegwBYtaqAE834e8u+MC2wT6FKIUsz1DBOyOXAQXUZB+rjWDoQ==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "@types/node": "^12.0.2", + "acorn": "^6.1.1" + } + }, + "rollup-plugin-babel": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.3.2.tgz", + "integrity": "sha512-KfnizE258L/4enADKX61ozfwGHoqYauvoofghFJBhFnpH9Sb9dNPpWg8QHOaAfVASUYV8w0mCx430i9z0LJoJg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "rollup-pluginutils": "^2.3.0" + } + }, + "rollup-plugin-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz", + "integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==", + "dev": true, + "requires": { + "rollup-pluginutils": "^2.5.0" + } + }, + "rollup-plugin-node-resolve": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.0.0.tgz", + "integrity": "sha512-JUFr7DkFps3div9DYwpSg0O+s8zuSSRASUZUVNx6h6zhw2m8vcpToeS68JDPsFbmisMVSMYK0IxftngCRv7M9Q==", + "dev": true, + "requires": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.10.1", + "rollup-pluginutils": "^2.7.0" + } + }, + "rollup-pluginutils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.7.1.tgz", + "integrity": "sha512-3nRf3buQGR9qz/IsSzhZAJyoK663kzseps8itkYHr+Z7ESuaffEPfgRinxbCRA0pf0gzLqkNKkSb8aNVTq75NA==", + "dev": true, + "requires": { + "estree-walker": "^0.6.0", + "micromatch": "^3.1.10" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "uglify-js": { + "version": "3.5.15", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.15.tgz", + "integrity": "sha512-fe7aYFotptIddkwcm6YuA0HmknBZ52ZzOsUxZEdhhkSsz7RfjHDX2QDxwKTiv4JQ5t5NhfmpgAK+J7LiDhKSqg==", + "dev": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 88ee1f22a..671a0009a 100644 --- a/package.json +++ b/package.json @@ -3,18 +3,24 @@ "exportName": "Sortable", "version": "1.9.0", "devDependencies": { - "gulp": "^4.0.0", - "gulp-each": "^0.5.0", - "gulp-rename": "^1.4.0", - "gulp-uglify": "^3.0.1", - "http-server": "^0.9.0", - "pump": "^3.0.0" + "@babel/core": "^7.4.4", + "@babel/plugin-transform-object-assign": "^7.2.0", + "@babel/preset-env": "^7.4.4", + "rollup": "^1.11.3", + "rollup-plugin-babel": "^4.3.2", + "rollup-plugin-json": "^4.0.0", + "rollup-plugin-node-resolve": "^5.0.0", + "uglify-js": "^3.5.12" }, "description": "JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.", - "main": "Sortable.js", + "main": "./Sortable.js", + "module": "modular/sortable.esm.js", "scripts": { - "http-server": "http-server -s ./", - "prepublish": "gulp build" + "build:umd": "set NODE_ENV=umd&& rollup -c build/umd-build.js", + "build:umd:watch": "set NODE_ENV=umd&& rollup -w -c build/umd-build.js", + "build:es": "set NODE_ENV=es&& rollup -c build/esm-build.js", + "minify": "node build/minify.js", + "build": "npm run build:es && npm run build:umd && npm run minify" }, "maintainers": [ "Konstantin Lebedev ", @@ -39,12 +45,5 @@ "vue", "mixin" ], - "license": "MIT", - "spm": { - "main": "Sortable.js", - "ignore": [ - "meteor", - "st" - ] - } + "license": "MIT" } diff --git a/plugins/AutoScroll/AutoScroll.js b/plugins/AutoScroll/AutoScroll.js new file mode 100644 index 000000000..756a712c7 --- /dev/null +++ b/plugins/AutoScroll/AutoScroll.js @@ -0,0 +1,266 @@ +import { + on, + off, + css, + throttle, + cancelThrottle, + scrollBy, + getParentAutoScrollElement, + expando, + getRect, + getWindowScrollingElement +} from '../../src/utils.js'; + +import { Edge, IE11OrLess, Safari } from '../../src/BrowserInfo.js'; + +let autoScrolls = [], + scrollEl, + scrollRootEl, + scrolling = false, + lastAutoScrollX, + lastAutoScrollY, + touchEvt, + pointerElemChangedInterval; + +function AutoScrollPlugin() { + + function AutoScroll() { + this.options = { + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, + bubbleScroll: true + }; + + // Bind all private methods + for (let fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + } + + AutoScroll.prototype = { + dragStarted({ originalEvent }) { + if (this.sortable.nativeDraggable) { + on(document, 'dragover', this._handleAutoScroll); + } else { + if (this.sortable.options.supportPointer) { + on(document, 'pointermove', this._handleFallbackAutoScroll); + } else if (originalEvent.touches) { + on(document, 'touchmove', this._handleFallbackAutoScroll); + } else { + on(document, 'mousemove', this._handleFallbackAutoScroll); + } + } + }, + + dragOverCompleted({ originalEvent }) { + // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached) + if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) { + this._handleAutoScroll(originalEvent); + } + }, + + drop() { + if (this.sortable.nativeDraggable) { + off(document, 'dragover', this._handleAutoScroll); + } else { + off(document, 'pointermove', this._handleFallbackAutoScroll); + off(document, 'touchmove', this._handleFallbackAutoScroll); + off(document, 'mousemove', this._handleFallbackAutoScroll); + } + + clearPointerElemChangedInterval(); + clearAutoScrolls(); + cancelThrottle(); + }, + + nulling() { + touchEvt = + scrollRootEl = + scrollEl = + scrolling = + pointerElemChangedInterval = + lastAutoScrollX = + lastAutoScrollY = null; + + autoScrolls.length = 0; + }, + + _handleFallbackAutoScroll(evt) { + this._handleAutoScroll(evt, true); + }, + + _handleAutoScroll(evt, fallback) { + const x = evt.clientX, + y = evt.clientY, + + elem = document.elementFromPoint(x, y); + + touchEvt = evt; + + // IE does not seem to have native autoscroll, + // Edge's autoscroll seems too conditional, + // MACOS Safari does not have autoscroll, + // Firefox and Chrome are good + if (fallback || Edge || IE11OrLess || Safari) { + autoScroll(evt, this.options, elem, fallback); + + // Listener for pointer element change + let ogElemScroller = getParentAutoScrollElement(elem, true); + if ( + scrolling && + ( + !pointerElemChangedInterval || + x !== lastAutoScrollX || + y !== lastAutoScrollY + ) + ) { + pointerElemChangedInterval && clearPointerElemChangedInterval(); + // Detect for pointer elem change, emulating native DnD behaviour + pointerElemChangedInterval = setInterval(() => { + let newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true); + if (newElem !== ogElemScroller) { + ogElemScroller = newElem; + clearAutoScrolls(); + } + autoScroll(evt, this.options, newElem, fallback); + }, 10); + lastAutoScrollX = x; + lastAutoScrollY = y; + } + } else { + // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll + if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) { + clearAutoScrolls(); + return; + } + autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false); + } + } + }; + + return Object.assign(AutoScroll, { + pluginName: 'scroll', + initializeByDefault: true + }); +} + +function clearAutoScrolls() { + autoScrolls.forEach(function(autoScroll) { + clearInterval(autoScroll.pid); + }); + autoScrolls = []; +} + +function clearPointerElemChangedInterval() { + clearInterval(pointerElemChangedInterval); +} + + +const autoScroll = throttle(function(evt, options, rootEl, isFallback) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + if (!options.scroll) return; + const sens = options.scrollSensitivity, + speed = options.scrollSpeed, + winScroller = getWindowScrollingElement(); + + let scrollThisInstance = false, + scrollCustomFn; + + // New scroll root, set scrollEl + if (scrollRootEl !== rootEl) { + scrollRootEl = rootEl; + + clearAutoScrolls(); + + scrollEl = options.scroll; + scrollCustomFn = options.scrollFn; + + if (scrollEl === true) { + scrollEl = getParentAutoScrollElement(rootEl, true); + } + } + + + let layersOut = 0; + let currentParent = scrollEl; + do { + let el = currentParent, + rect = getRect(el), + + top = rect.top, + bottom = rect.bottom, + left = rect.left, + right = rect.right, + + width = rect.width, + height = rect.height, + + canScrollX, + canScrollY, + + scrollWidth = el.scrollWidth, + scrollHeight = el.scrollHeight, + + elCSS = css(el), + + scrollPosX = el.scrollLeft, + scrollPosY = el.scrollTop; + + + if (el === winScroller) { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible'); + } else { + canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll'); + canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll'); + } + + let vx = canScrollX && (Math.abs(right - evt.clientX) <= sens && (scrollPosX + width) < scrollWidth) - (Math.abs(left - evt.clientX) <= sens && !!scrollPosX); + let vy = canScrollY && (Math.abs(bottom - evt.clientY) <= sens && (scrollPosY + height) < scrollHeight) - (Math.abs(top - evt.clientY) <= sens && !!scrollPosY); + + + if (!autoScrolls[layersOut]) { + for (let i = 0; i <= layersOut; i++) { + if (!autoScrolls[i]) { + autoScrolls[i] = {}; + } + } + } + + if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) { + autoScrolls[layersOut].el = el; + autoScrolls[layersOut].vx = vx; + autoScrolls[layersOut].vy = vy; + + clearInterval(autoScrolls[layersOut].pid); + + if (vx != 0 || vy != 0) { + scrollThisInstance = true; + /* jshint loopfunc:true */ + autoScrolls[layersOut].pid = setInterval((function () { + // emulate drag over during autoscroll (fallback), emulating native DnD behaviour + if (isFallback && this.layer === 0) { + Sortable.active._onTouchMove(touchEvt); // To move ghost if it is positioned absolutely + } + let scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0; + let scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0; + + if (typeof(scrollCustomFn) === 'function') { + if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt, autoScrolls[this.layer].el) !== 'continue') { + return; + } + } + + scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY); + }).bind({layer: layersOut}), 24); + } + } + layersOut++; + } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false))); + scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not +}, 30); + +export default AutoScrollPlugin; diff --git a/plugins/AutoScroll/README.md b/plugins/AutoScroll/README.md new file mode 100644 index 000000000..318570d31 --- /dev/null +++ b/plugins/AutoScroll/README.md @@ -0,0 +1,69 @@ +## AutoScroll +This plugin allows for the page to automatically scroll during dragging near a scrollable element's edge on mobile devices and IE9 (or whenever fallback is enabled), and also enhances most browser's native drag-and-drop autoscrolling. +Demo: + - `window`: https://jsbin.com/dosilir/edit?js,output + - `overflow: hidden`: https://jsbin.com/xecihez/edit?html,js,output + +**This plugin is a default plugin, and is included in the default UMD and ESM builds of Sortable** + + +--- + + +### Options + +```js +new Sortable(el, { + scroll: true, // Enable the plugin. Can be HTMLElement. + scrollFn: function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { ... }, // if you have custom scrollbar scrollFn may be used for autoscrolling + scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling. + scrollSpeed: 10, // px, speed of the scrolling + bubbleScroll: true // apply autoscroll to all parent elements, allowing for easier movement +}); +``` + + +--- + + +#### `scroll` option +Enables the plugin. Defaults to `true`. May also be set to an HTMLElement which will be where autoscrolling is rooted. + +Demo: + - `window`: https://jsbin.com/dosilir/edit?js,output + - `overflow: hidden`: https://jsbin.com/xecihez/edit?html,js,output + + +--- + + +#### `scrollFn` option +Defines function that will be used for autoscrolling. el.scrollTop/el.scrollLeft is used by default. +Useful when you have custom scrollbar with dedicated scroll function. +This function should return `'continue'` if it wishes to allow Sortable's native autoscrolling. + + +--- + + +#### `scrollSensitivity` option +Defines how near the mouse must be to an edge to start scrolling. + + +--- + + +#### `scrollSpeed` option +The speed at which the window should scroll once the mouse pointer gets within the `scrollSensitivity` distance. + + +--- + + +#### `bubbleScroll` option +If set to `true`, the normal `autoscroll` function will also be applied to all parent elements of the element the user is dragging over. + +Demo: https://jsbin.com/kesewor/edit?html,js,output + + +--- diff --git a/plugins/AutoScroll/index.js b/plugins/AutoScroll/index.js new file mode 100644 index 000000000..cc79f7e24 --- /dev/null +++ b/plugins/AutoScroll/index.js @@ -0,0 +1 @@ +export { default } from './AutoScroll.js'; diff --git a/plugins/MultiDrag/MultiDrag.js b/plugins/MultiDrag/MultiDrag.js new file mode 100644 index 000000000..c331d9d29 --- /dev/null +++ b/plugins/MultiDrag/MultiDrag.js @@ -0,0 +1,590 @@ +import { + toggleClass, + getRect, + index, + closest, + on, + off, + clone, + css, + setRect, + unsetRect, + matrix, + expando +} from '../../src/utils.js'; + +import dispatchEvent from '../../src/EventDispatcher.js'; + +let multiDragElements = [], + multiDragClones = [], + lastMultiDragSelect, // for selection with modifier key down (SHIFT) + multiDragSortable, + initialFolding = false, // Initial multi-drag fold when drag started + folding = false, // Folding any other time + dragStarted = false, + dragEl, + clonesFromRect, + clonesHidden; + +function MultiDragPlugin() { + function MultiDrag(sortable) { + // Bind all private methods + for (let fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + if (sortable.options.supportPointer) { + on(document, 'pointerup', this._deselectMultiDrag); + } else { + on(document, 'mouseup', this._deselectMultiDrag); + on(document, 'touchend', this._deselectMultiDrag); + } + + on(document, 'keydown', this._checkKeyDown); + on(document, 'keyup', this._checkKeyUp); + + this.options = { + selectedClass: 'sortable-selected', + multiDragKey: null, + setData(dataTransfer, dragEl) { + let data = ''; + if (multiDragElements.length && multiDragSortable === sortable) { + for (let i in multiDragElements) { + data += (!i ? '' : ', ') + multiDragElements[i].textContent; + } + } else { + data = dragEl.textContent; + } + dataTransfer.setData('Text', data); + } + }; + } + + MultiDrag.prototype = { + multiDragKeyDown: false, + isMultiDrag: false, + + + delayStartGlobal({ dragEl: dragged }) { + dragEl = dragged; + }, + + delayEnded() { + this.isMultiDrag = ~multiDragElements.indexOf(dragEl); + }, + + setupClone({ sortable }) { + if (!this.isMultiDrag) return; + for (let i in multiDragElements) { + multiDragClones.push(clone(multiDragElements[i])); + + multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex; + + multiDragClones[i].draggable = false; + multiDragClones[i].style['will-change'] = ''; + + toggleClass(multiDragClones[i], sortable.options.selectedClass, false); + multiDragElements[i] === dragEl && toggleClass(multiDragClones[i], sortable.options.chosenClass, false); + } + + sortable._hideClone(); + return true; + }, + + clone({ sortable, rootEl, dispatchSortableEvent }) { + if (!this.isMultiDrag) return; + if (!sortable.options.removeCloneOnHide) { + if (multiDragElements.length && multiDragSortable === sortable) { + insertMultiDragClones(true, rootEl); + dispatchSortableEvent('clone'); + + return true; + } + } + }, + + showClone({ cloneNowShown, rootEl }) { + if (!this.isMultiDrag) return; + insertMultiDragClones(false, rootEl); + for (let i in multiDragClones) { + css(multiDragClones[i], 'display', ''); + } + + cloneNowShown(); + clonesHidden = false; + return true; + }, + + hideClone({ sortable, cloneNowHidden }) { + if (!this.isMultiDrag) return; + for (let i in multiDragClones) { + css(multiDragClones[i], 'display', 'none'); + if (sortable.options.removeCloneOnHide && multiDragClones[i].parentNode) { + multiDragClones[i].parentNode.removeChild(multiDragClones[i]); + } + } + cloneNowHidden(); + clonesHidden = true; + return true; + }, + + dragStartGlobal({ sortable }) { + if (!this.isMultiDrag && multiDragSortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + } + + for (let i in multiDragElements) { + multiDragElements[i].sortableIndex = index(multiDragElements[i]); + } + + // Sort multi-drag elements + multiDragElements = multiDragElements.sort(function(a, b) { + return a.sortableIndex - b.sortableIndex; + }); + dragStarted = true; + }, + + dragStarted({ sortable }) { + if (!this.isMultiDrag) return; + if (sortable.options.sort) { + // Capture rects, + // hide multi drag elements (by positioning them absolute), + // set multi drag elements rects to dragRect, + // show multi drag elements, + // animate to rects, + // unset rects & remove from DOM + + sortable.captureAnimationState(); + + if (sortable.options.animation) { + for (let i in multiDragElements) { + if (multiDragElements[i] === dragEl) continue; + css(multiDragElements[i], 'position', 'absolute'); + } + + let dragRect = getRect(dragEl, false, true, true); + + for (let i in multiDragElements) { + if (multiDragElements[i] === dragEl) continue; + setRect(multiDragElements[i], dragRect); + } + + folding = true; + initialFolding = true; + } + } + + sortable.animateAll(function() { + folding = false; + initialFolding = false; + + if (sortable.options.animation) { + for (let i in multiDragElements) { + unsetRect(multiDragElements[i]); + } + } + + // Remove all auxiliary multidrag items from el, if sorting enabled + if (sortable.options.sort) { + removeMultiDragElements(); + } + }); + }, + + dragOver({ target, completed }) { + if (folding && ~multiDragElements.indexOf(target)) { + return completed(false); + } + }, + + revert({ fromSortable, rootEl, sortable, dragRect }) { + if (multiDragElements.length > 1) { + // Setup unfold animation + for (let i in multiDragElements) { + sortable.addAnimationState({ + target: multiDragElements[i], + rect: folding ? getRect(multiDragElements[i]) : dragRect + }); + + unsetRect(multiDragElements[i]); + + multiDragElements[i].fromRect = dragRect; + + fromSortable.removeAnimationState(multiDragElements[i]); + } + folding = false; + insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl); + } + }, + + dragOverCompleted({ sortable, isOwner, insertion, activeSortable, parentEl, putSortable }) { + let options = sortable.options; + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } + + initialFolding = false; + // If leaving sort:false root, or already folding - Fold to new location + if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) { + // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible + let dragRectAbsolute = getRect(dragEl, false, true, true); + + for (let i in multiDragElements) { + if (multiDragElements[i] === dragEl) continue; + setRect(multiDragElements[i], dragRectAbsolute); + + // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted + // while folding, and so that we can capture them again because old sortable will no longer be fromSortable + parentEl.appendChild(multiDragElements[i]); + } + + folding = true; + } + + // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out + if (!isOwner) { + // Only remove if not folding (folding will remove them anyways) + if (!folding) { + removeMultiDragElements(); + } + + if (multiDragElements.length > 1) { + let clonesHiddenBefore = clonesHidden; + activeSortable._showClone(sortable); + + // Unfold animation for clones if showing from hidden + if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) { + for (let i in multiDragClones) { + activeSortable.addAnimationState({ + target: multiDragClones[i], + rect: clonesFromRect + }); + + multiDragClones[i].fromRect = clonesFromRect; + multiDragClones[i].thisAnimationDuration = null; + } + } + } else { + activeSortable._showClone(sortable); + } + } + } + }, + + dragOverAnimationCapture({ dragRect, isOwner, activeSortable }) { + for (let i in multiDragElements) { + multiDragElements[i].thisAnimationDuration = null; + } + + if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) { + clonesFromRect = Object.assign({}, dragRect); + let dragMatrix = matrix(dragEl, true); + clonesFromRect.top -= dragMatrix.f; + clonesFromRect.left -= dragMatrix.e; + } + }, + + dragOverAnimationComplete() { + if (folding) { + folding = false; + removeMultiDragElements(); + } + }, + + drop({ originalEvent: evt, rootEl, parentEl, sortable, dispatchSortableEvent, oldIndex, putSortable }) { + let toSortable = (putSortable || this.sortable); + + if (!evt) return; + + let options = sortable.options, + children = parentEl.children; + + // Multi-drag selection + if (!dragStarted) { + if (options.multiDragKey && !this.multiDragKeyDown) { + this._deselectMultiDrag(); + } + toggleClass(dragEl, options.selectedClass, !~multiDragElements.indexOf(dragEl)); + + if (!~multiDragElements.indexOf(dragEl)) { + multiDragElements.push(dragEl); + dispatchEvent({ + sortable, + rootEl, + name: 'select', + targetEl: dragEl, + originalEvt: evt + }); + + // Modifier activated, select from last to dragEl + if ((!options.multiDragKey || this.multiDragKeyDown) && evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) { + let lastIndex = index(lastMultiDragSelect), + currentIndex = index(dragEl); + + if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) { + // Must include lastMultiDragSelect (select it), in case modified selection from no selection + // (but previous selection existed) + let n, i; + if (currentIndex > lastIndex) { + i = lastIndex; + n = currentIndex; + } else { + i = currentIndex; + n = lastIndex + 1; + } + + for (; i < n; i++) { + if (~multiDragElements.indexOf(children[i])) continue; + toggleClass(children[i], options.selectedClass, true); + multiDragElements.push(children[i]); + + dispatchEvent({ + sortable: sortable, + rootEl, + name: 'select', + targetEl: children[i], + originalEvt: evt + }); + } + } + } else { + lastMultiDragSelect = dragEl; + } + + multiDragSortable = toSortable; + } else { + multiDragElements.splice(multiDragElements.indexOf(dragEl), 1); + lastMultiDragSelect = null; + dispatchEvent({ + sortable, + rootEl, + name: 'deselect', + targetEl: dragEl, + originalEvt: evt + }); + } + } + + // Multi-drag drop + if (dragStarted && this.isMultiDrag) { + // Do not "unfold" after around dragEl if reverted + if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) { + let dragRect = getRect(dragEl), + multiDragIndex = index(dragEl, ':not(.' + Sortable.active.options.selectedClass + ')'); + + if (!initialFolding && options.animation) dragEl.thisAnimationDuration = null; + + toSortable.captureAnimationState(); + + if (!initialFolding) { + if (options.animation) { + dragEl.fromRect = dragRect; + for (let i in multiDragElements) { + multiDragElements[i].thisAnimationDuration = null; + if (multiDragElements[i] !== dragEl) { + let rect = folding ? getRect(multiDragElements[i]) : dragRect; + multiDragElements[i].fromRect = rect; + + // Prepare unfold animation + toSortable.addAnimationState({ + target: multiDragElements[i], + rect: rect + }); + } + } + } + + // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert + // properly they must all be removed + removeMultiDragElements(); + + for (let i in multiDragElements) { + if (children[multiDragIndex]) { + parentEl.insertBefore(multiDragElements[i], children[multiDragIndex]); + } else { + parentEl.appendChild(multiDragElements[i]); + } + multiDragIndex++; + } + + // If initial folding is done, the elements may have changed position because they are now + // unfolding around dragEl, even though dragEl may not have his index changed, so update event + // must be fired here as Sortable will not. + if (oldIndex === index(dragEl)) { + let update = false; + for (let i in multiDragElements) { + if (multiDragElements[i].sortableIndex !== index(multiDragElements[i])) { + update = true; + break; + } + } + + if (update) { + dispatchSortableEvent('update'); + } + } + } + + // Must be done after capturing individual rects (scroll bar) + for (let i in multiDragElements) { + unsetRect(multiDragElements[i]); + } + + toSortable.animateAll(); + } + + multiDragSortable = toSortable; + } + + // Remove clones if necessary + if (rootEl === parentEl || (putSortable && putSortable.lastPutMode !== 'clone')) { + for (let i in multiDragClones) { + multiDragClones[i].parentNode && multiDragClones[i].parentNode.removeChild(multiDragClones[i]); + } + } + }, + + nullingGlobal() { + this.isMultiDrag = + dragStarted = false; + multiDragClones.length = 0; + }, + + destroy() { + this._deselectMultiDrag(); + off(document, 'pointerup', this._deselectMultiDrag); + off(document, 'mouseup', this._deselectMultiDrag); + off(document, 'touchend', this._deselectMultiDrag); + + off(document, 'keydown', this._checkKeyDown); + off(document, 'keyup', this._checkKeyUp); + }, + + _deselectMultiDrag(evt) { + if (dragStarted) return; + + // Only deselect if selection is in this sortable + if (multiDragSortable !== this.sortable) return; + + // Only deselect if target is not item in this sortable + if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return; + + // Only deselect if left click + if (evt && evt.button !== 0) return; + + while (multiDragElements.length) { + let el = multiDragElements[0]; + toggleClass(el, this.sortable.options.selectedClass, false); + multiDragElements.shift(); + dispatchEvent({ + sortable: this.sortable, + rootEl: this.sortable.el, + name: 'deselect', + targetEl: el, + originalEvt: evt + }); + } + }, + + _checkKeyDown(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = true; + } + }, + + _checkKeyUp(evt) { + if (evt.key === this.sortable.options.multiDragKey) { + this.multiDragKeyDown = false; + } + } + }; + + return Object.assign(MultiDrag, { + // Static methods & properties + pluginName: 'multiDrag', + utils: { + /** + * Selects the provided multi-drag item + * @param {HTMLElement} el The element to be selected + */ + select(el) { + let sortable = el.parentNode[expando]; + if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return; + if (multiDragSortable && multiDragSortable !== sortable) { + multiDragSortable.multiDrag._deselectMultiDrag(); + multiDragSortable = sortable; + } + toggleClass(el, sortable.options.selectedClass, true); + multiDragElements.push(el); + }, + /** + * Deselects the provided multi-drag item + * @param {HTMLElement} el The element to be deselected + */ + deselect(el) { + let sortable = el.parentNode[expando], + index = multiDragElements.indexOf(el); + if (!sortable || !sortable.options.multiDrag || !~index) return; + toggleClass(el, sortable.options.selectedClass, false); + multiDragElements.splice(index, 1); + } + }, + eventOptions() { + return { + items: [...multiDragElements], + clones: [...multiDragClones] + }; + }, + optionListeners: { + multiDragKey(key) { + key = key.toLowerCase(); + if (key === 'ctrl') { + key = 'Control'; + } else if (key.length > 1) { + key = key.charAt(0).toUpperCase() + key.substr(1); + } + return key; + } + } + }); +} + +function insertMultiDragElements(clonesInserted, rootEl) { + for (let i in multiDragElements) { + let target = rootEl.children[multiDragElements[i].sortableIndex + (clonesInserted ? Number(i) : 0)]; + if (target) { + rootEl.insertBefore(multiDragElements[i], target); + } else { + rootEl.appendChild(multiDragElements[i]); + } + } +} + +/** + * Insert multi-drag clones + * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted + * @param {HTMLElement} rootEl + */ +function insertMultiDragClones(elementsInserted, rootEl) { + for (let i in multiDragClones) { + let target = rootEl.children[multiDragClones[i].sortableIndex + (elementsInserted ? Number(i) : 0)]; + if (target) { + rootEl.insertBefore(multiDragClones[i], target); + } else { + rootEl.appendChild(multiDragClones[i]); + } + } +} + +function removeMultiDragElements() { + for (let i in multiDragElements) { + if (multiDragElements[i] === dragEl) continue; + multiDragElements[i].parentNode && multiDragElements[i].parentNode.removeChild(multiDragElements[i]); + } +} + +export default MultiDragPlugin; diff --git a/plugins/MultiDrag/README.md b/plugins/MultiDrag/README.md new file mode 100644 index 000000000..205a963f5 --- /dev/null +++ b/plugins/MultiDrag/README.md @@ -0,0 +1,75 @@ +## MultiDrag Plugin +This plugin allows users to select multiple items within a sortable at once, and drag them as one item. +Once placed, the items will unfold into their original order, but all beside eachother at the new position. +[Read More](https://github.com/SortableJS/Sortable/wiki/Dragging-Multiple-Items-in-Sortable) + +Demo: https://jsbin.com/wopavom/edit?js,output + + +--- + + +### Options + +```js +new Sortable(el, { + multiDrag: false, // Enable the plugin + selectedClass: "sortable-selected", // Class name for selected item + multiDragKey: null, // Key that must be down for items to be selected + + // Called when an item is selected + onSelect: function(/**Event*/evt) { + evt.item // The selected item + }, + + // Called when an item is deselected + onDeselect: function(/**Event*/evt) { + evt.item // The deselected item + } +}); +``` + + +--- + + +#### `multiDragKey` option +The key that must be down for multiple items to be selected. The default is `null`, meaning no key must be down. +For special keys, such as the CTRL key, simply specify the option as `'CTRL'` (casing does not matter). + + +--- + + +#### `selectedClass` option +Class name for the selected item(s) if multiDrag is enabled. Defaults to `sortable-selected`. + +```css +.selected { + background-color: #f9c7c8; + border: solid red 1px; +} +``` + +```js +Sortable.create(list, { + multiDrag: true, + selectedClass: "selected" +}); +``` + + +--- + + +### Event Properties + - items:`HTMLElement[]` - Array of selected items, or empty + - clones:`HTMLElement[]` - Array of clones, or empty + + +--- + + +### Sortable.utils +* select(el`:HTMLElement`) — select the given multi-drag item +* deselect(el`:HTMLElement`) — deselect the given multi-drag item diff --git a/plugins/MultiDrag/index.js b/plugins/MultiDrag/index.js new file mode 100644 index 000000000..2507117e0 --- /dev/null +++ b/plugins/MultiDrag/index.js @@ -0,0 +1 @@ +export { default } from './MultiDrag.js'; diff --git a/plugins/OnSpill/OnSpill.js b/plugins/OnSpill/OnSpill.js new file mode 100644 index 000000000..78efc19b1 --- /dev/null +++ b/plugins/OnSpill/OnSpill.js @@ -0,0 +1,71 @@ +import { getChild } from '../../src/utils.js'; + + +const drop = function({ + originalEvent, + putSortable, + dragEl, + activeSortable, + dispatchSortableEvent, + hideGhostForTarget, + unhideGhostForTarget +}) { + let toSortable = putSortable || activeSortable; + hideGhostForTarget(); + let target = document.elementFromPoint(originalEvent.clientX, originalEvent.clientY); + unhideGhostForTarget(); + + if (toSortable && !toSortable.el.contains(target)) { + dispatchSortableEvent('spill'); + this.onSpill(dragEl); + } +}; + +function Revert() {} + +Revert.prototype = { + startIndex: null, + dragStart({ oldDraggableIndex }) { + this.startIndex = oldDraggableIndex; + }, + onSpill(dragEl) { + this.sortable.captureAnimationState(); + let nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options); + + if (nextSibling) { + this.sortable.el.insertBefore(dragEl, nextSibling); + } else { + this.sortable.el.appendChild(dragEl); + } + this.sortable.animateAll(); + }, + drop +}; + +Object.assign(Revert, { + pluginName: 'revertOnSpill' +}); + + +function Remove() {} + +Remove.prototype = { + onSpill(dragEl) { + this.sortable.captureAnimationState(); + dragEl.parentNode && dragEl.parentNode.removeChild(dragEl); + this.sortable.animateAll(); + }, + drop +}; + +Object.assign(Remove, { + pluginName: 'removeOnSpill' +}); + + +export default [Remove, Revert]; + +export { + Remove as RemoveOnSpill, + Revert as RevertOnSpill +}; diff --git a/plugins/OnSpill/README.md b/plugins/OnSpill/README.md new file mode 100644 index 000000000..2c4091fcf --- /dev/null +++ b/plugins/OnSpill/README.md @@ -0,0 +1,41 @@ +# OnSpill Plugins +This file contains two seperate plugins, RemoveOnSpill and RevertOnSpill. They can be imported individually, or the default export (an array of both plugins) can be passed to `Sortable.mount` as well. + +**These plugins are default plugins, and are included in the default UMD and ESM builds of Sortable** + +--- + + +## RevertOnSpill Plugin +This plugin, when enabled, will cause the dragged item to be reverted to it's original position if it is spilled (ie. it is dropped outside of a valid Sortable drop target) + + +--- + + +### Options + +```js +new Sortable(el, { + revertOnSpill: false // Enable plugin +}); +``` + + +--- + + +## RemoveOnSpill Plugin +This plugin, when enabled, will cause the dragged item to be removed from the DOM if it is spilled (ie. it is dropped outside of a valid Sortable drop target) + + +--- + + +### Options + +```js +new Sortable(el, { + removeOnSpill: false // Enable plugin +}); +``` diff --git a/plugins/OnSpill/index.js b/plugins/OnSpill/index.js new file mode 100644 index 000000000..4023b0f60 --- /dev/null +++ b/plugins/OnSpill/index.js @@ -0,0 +1 @@ +export { default, RemoveOnSpill, RevertOnSpill } from './OnSpill.js'; diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 000000000..5d12fcfb4 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,176 @@ +# Creating Sortable Plugins +Sortable plugins are plugins that can be directly mounted to the Sortable class. They are a powerful way of modifying the default behaviour of Sortable beyond what simply using events alone allows. To mount your plugin to Sortable, it must pass a constructor function to the `Sortable.mount` function. This constructor function will be called (with the `new` keyword in front of it) whenever a Sortable instance with your plugin enabled is initialized. The constructor function will be called with the parameters `sortable` and `el`, which is the HTMLElement that the Sortable is being initialized on. This means that there will be a new instance of your plugin each time it is enabled in a Sortable. + + +## Constructor Parameters + +`sortable: Sortable` — The sortable that the plugin is being initialized on + +`el: HTMLElement` — The element that the sortable is being initialized on + + +## Static Properties +The constructor function passed to `Sortable.mount` may contain several static properties and methods. The following static properties may be defined: + +`pluginName: String` (Required) +The name of the option that the user will use in their sortable's options to enable the plugin. Should start with a lower case and be camel-cased. For example: `'multiDrag'`. This is also the property name that the plugin's instance will be under in a sortable instance (ex. `sortableInstance.multiDrag`). + +`utils: Object` +Object containing functions that will be added to the `Sortable.utils` default object on the Sortable class. + +`eventOptions(eventName: String, sortable: Sortable): Function` +A function that is called whenever Sortable fires an event. This function should return an object to be combined with the event object that Sortable will emit. + +`initializeByDefault: Boolean` +Determines whether or not the plugin will always be initialized on every new Sortable instance. If this option is enabled, it does not mean that by default the plugin will be enabled on the Sortable - this must still be done in the options via the plugin's `pluginName`, or it can be enabled by default if your plugin specifies it's pluginName as a default option that is truthy. Since the plugin will already be initialized on every Sortable instance, it can also be enabled dynamically via `sortableInstance.option('pluginName', true)`. +It is a good idea to have this option set to `false` if the plugin modifies the behaviour of Sortable in such a way that enabling or disabling the plugin dynamically could cause it to break. Likewise, this option should be disabled if the plugin should only be instantiated on Sortables in which that plugin is enabled. +This option defaults to `true`. + +`optionListeners: Object` +An object that may contain event listeners that are fired when a specific option is updated. +These listeners are useful because the user's provided options are not necessarily unchanging once the plugin is initialized, and could be changed dynamically via the `option()` method. +The listener will be fired in the context of the instance of the plugin that it is being changed in (ie. the `this` keyword will be the instance of your plugin). +The name of the method should match the name of the option it listens for. The new value of the option will be passed in as an argument, and any returned value will be what the option is stored as. If no value is returned, the option will be stored as the value the user provided. + +Example: + +```js +Plugin.name = 'generateTitle'; +Plugin.optionModifiers = { + // Listen for option 'generateTitle' + generateTitle: function(title) { + // Store the option in all caps + return title.toUpperCase(); + + // OR save it to this instance of your plugin as a private field. + // This way it can be accessed in events, but will not modify the user's options. + this.titleAllCaps = title.toUpperCase(); + } +}; + +``` + +## Plugin Options +Plugins may have custom options or override the defaults of certain options. In order to do this, there must be an `options` object on the initialized plugin. This can be set in the plugin's prototype, or during the initialization of the plugin (when the `el` is available). For example: + +```js +function myPlugin(el) { + this.options = { + color: el.style.backgroundColor + }; +} + +Sortable.mount(myPlugin); +``` + + +## Plugin Events + +### Context +The events will be fired in the context of their own parent object, however the plugin instance's Sortable instance is available under `this.sortable`. + +### Event List +The following table contains details on the events that a plugin may handle in the prototype of the plugin's constructor function. + +| Event Name | Description | Cancelable? | Cancel Behaviour | Event Type | Custom Event Object Properties | +|---------------------------|------------------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------|------------|-------------------------------------------------------------------------| +| filter | Fired when the element is filtered, and dragging is therefore canceled | No | - | Normal | None | +| delayStart | Fired when the delay starts, even if there is no delay | Yes | Cancels sorting | Normal | None | +| delayEnded | Fired when the delay ends, even if there is no delay | Yes | Cancels sorting | Normal | None | +| setupClone | Fired when Sortable clones the dragged element | Yes | Cancels normal clone setup | Normal | None | +| dragStart | Fired when the dragging is first started | Yes | Cancels sorting | Normal | None | +| clone | Fired when the clone is inserted into the DOM (if `removeCloneOnHide: false`). Tick after dragStart. | Yes | Cancels normal clone insertion & hiding | Normal | None | +| dragStarted | Fired tick after dragStart | No | - | Normal | None | +| dragOver | Fired when the user drags over a sortable | Yes | Cancels normal dragover behaviour | DragOver | None | +| dragOverValid | Fired when the user drags over a sortable that the dragged item can be inserted into | Yes | Cancels normal valid dragover behaviour | DragOver | None | +| revert | Fired when the dragged item is reverted to it's original position when entering it's `sort:false` root | Yes | Cancels normal reverting, but is still completed() | DragOver | None | +| dragOverCompleted | Fired when dragOver is completed (ie. bubbling is disabled). To check if inserted, use `inserted` even property. | No | - | DragOver | `insertion: Boolean` — Whether or not the dragged element was inserted | +| dragOverAnimationCapture | Fired right before the animation state is captured in dragOver | No | - | DragOver | None | +| dragOverAnimationComplete | Fired after the animation is completed after a dragOver insertion | No | - | DragOver | None | +| drop | Fired on drop | Yes | Cancels normal drop behavior | Normal | None | +| nulling | Fired when the plugin should preform cleanups, once all drop events have fired | No | - | Normal | None | +| destroy | Fired when Sortable is destroyed | No | - | Normal | None | + +### Global Events +Normally, an event will only be fired in a plugin if the plugin is enabled on the Sortable from which the event is being fired. However, it sometimes may be desirable for a plugin to listen in on an event from Sortables in which it is not enabled on. This is possible with global events. For an event to be global, simply add the suffix 'Global' to the event's name (casing matters) (eg. `dragStartGlobal`). +Please note that your plugin must be initialized on any Sortable from which it expects to recieve events, and that includes global events. In other words, you will want to keep the `initializeByDefault` option as it's default `true` value if your plugin needs to recieve events from Sortables it is not enabled on. +Please also note that if both normal and global event handlers are set, the global event handler will always be fired before the regular one. + +### Event Object +An object with the following properties is passed as an argument to each plugin event when it is fired. + +#### Properties: + +`dragEl: HTMLElement` — The element being dragged + +`parentEl: HTMLElement` — The element that the dragged element is currently in + +`ghostEl: HTMLElement|undefined` — If using fallback, the element dragged under the cursor (undefined until after `dragStarted` plugin event) + +`rootEl: HTMLElement` — The element that the dragged element originated from + +`nextEl: HTMLElement` — The original next sibling of dragEl + +`cloneEl: HTMLElement|undefined` — The clone element (undefined until after `setupClone` plugin event) + +`cloneHidden: Boolean` — Whether or not the clone is hidden + +`dragStarted: Boolean` — Boolean indicating whether or not the dragStart event has fired + +`putSortable: Sortable|undefined` — The element that dragEl is dragged into from it's root, otherwise undefined + +`activeSortable: Sortable` — The active Sortable instance + +`originalEvent: Event` — The original HTML event corresponding to the Sortable event + +`oldIndex: Number` — The old index of dragEl + +`oldDraggableIndex: Number` — The old index of dragEl, only counting draggable elements + +`newIndex: Number` — The new index of dragEl + +`newDraggableIndex: Number` — The new index of dragEl, only counting draggable elements + + +#### Methods: + +`cloneNowHidden()` — Function to be called if the plugin has hidden the clone + +`cloneNowShown()` — Function to be called if the plugin has shown the clone + +`hideGhostForTarget()` — Hides the fallback ghost element if CSS pointer-events are not available. Call this before using document.elementFromPoint at the mouse position. + +`unhideGhostForTarget()` — Unhides the ghost element. To be called after `hideGhostForTarget()`. + +`dispatchSortableEvent(eventName: String)` — Function that can be used to emit an event on the current sortable while sorting, with all usual event properties set (eg. indexes, rootEl, cloneEl, originalEvent, etc.). + + +### DragOverEvent Object +This event is passed to dragover events, and extends the normal event object. + +#### Properties: + +`isOwner: Boolean` — Whether or not the dragged over sortable currently contains the dragged element + +`axis: String` — Direction of the dragged over sortable, `'vertical'` or `'horizontal'` + +`revert: Boolean` — Whether or not the dragged element is being reverted to it's original position from another position + +`dragRect: DOMRect` — DOMRect of the dragged element + +`targetRect: DOMRect` — DOMRect of the target element + +`canSort: Boolean` — Whether or not sorting is enabled in the dragged over sortable + +`fromSortable: Sortable` — The sortable that the dragged element is coming from + +`target: HTMLElement` — The sortable item that is being dragged over + + +#### Methods: + +`onMove(target: HTMLElement, after: Boolean): Boolean|Number` — Calls the `onMove` function the user specified in the options + +`changed()` — Fires the `onChange` event with event properties preconfigured + +`completed(insertion: Boolean)` — Should be called when dragover has "completed", meaning bubbling should be stopped. If `insertion` is `true`, Sortable will treat it as if the dragged element was inserted into the sortable, and hide/show clone, set ghost class, animate, etc. diff --git a/plugins/Swap/README.md b/plugins/Swap/README.md new file mode 100644 index 000000000..07286c1e1 --- /dev/null +++ b/plugins/Swap/README.md @@ -0,0 +1,44 @@ +## Swap Plugin +This plugin modifies the behaviour of Sortable to allow for items to be swapped with eachother rather than sorted. Once dragging starts, the user can drag over other items and there will be no change in the elements. However, the item that the user drops on will be swapped with the originally dragged item. + +Demo: https://jsbin.com/yejehog/edit?html,js,output + + +--- + + +### Options + +```js +new Sortable(el, { + swap: false, // Enable swap mode + swapClass: "sortable-swap-highlight" // Class name for swap item (if swap mode is enabled) +}); +``` + + +--- + + +#### `swapClass` option +Class name for the item to be swapped with, if swap mode is enabled. Defaults to `sortable-swap-highlight`. + +```css +.highlighted { + background-color: #9AB6F1; +} +``` + +```js +Sortable.create(list, { + swap: true, + swapClass: "highlighted" +}); +``` + + +--- + + +### Event Properties + - swapItem:`HTMLElement|undefined` - The element that the dragged element was swapped with diff --git a/plugins/Swap/Swap.js b/plugins/Swap/Swap.js new file mode 100644 index 000000000..c7a026dcf --- /dev/null +++ b/plugins/Swap/Swap.js @@ -0,0 +1,89 @@ +import { + toggleClass, + index +} from '../../src/utils.js'; + +let lastSwapEl; + + +function SwapPlugin() { + function Swap() { + this.options = { + swapClass: 'sortable-swap-highlight' + }; + } + + Swap.prototype = { + dragStart({ dragEl }) { + lastSwapEl = dragEl; + }, + dragOverValid({ completed, target, onMove, activeSortable, changed }) { + if (!activeSortable.options.swap) return; + let el = this.sortable.el, + options = this.sortable.options; + if (target && target !== el) { + let prevSwapEl = lastSwapEl; + if (onMove(target) !== false) { + toggleClass(target, options.swapClass, true); + lastSwapEl = target; + } else { + lastSwapEl = null; + } + + if (prevSwapEl && prevSwapEl !== lastSwapEl) { + toggleClass(prevSwapEl, options.swapClass, false); + } + } + changed(); + + return completed(true); + }, + drop({ activeSortable, putSortable, dragEl }) { + let toSortable = (putSortable || this.sortable); + let options = this.sortable.options; + lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false); + if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) { + if (dragEl !== lastSwapEl) { + toSortable.captureAnimationState(); + if (toSortable !== activeSortable) activeSortable.captureAnimationState(); + swapNodes(dragEl, lastSwapEl); + + toSortable.animateAll(); + if (toSortable !== activeSortable) activeSortable.animateAll(); + } + } + }, + nulling() { + lastSwapEl = null; + } + }; + + return Object.assign(Swap, { + pluginName: 'swap', + eventOptions() { + return { + swapItem: lastSwapEl + }; + } + }); +} + + +function swapNodes(n1, n2) { + let p1 = n1.parentNode, + p2 = n2.parentNode, + i1, i2; + + if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return; + + i1 = index(n1); + i2 = index(n2); + + if (p1.isEqualNode(p2) && i1 < i2) { + i2++; + } + p1.insertBefore(n2, p1.children[i1]); + p2.insertBefore(n1, p2.children[i2]); +} + +export default SwapPlugin; diff --git a/plugins/Swap/index.js b/plugins/Swap/index.js new file mode 100644 index 000000000..9799bc72c --- /dev/null +++ b/plugins/Swap/index.js @@ -0,0 +1 @@ +export { default } from './Swap.js'; diff --git a/src/Animation.js b/src/Animation.js new file mode 100644 index 000000000..eff0110ed --- /dev/null +++ b/src/Animation.js @@ -0,0 +1,198 @@ +import { getRect, css, isScrolledPast, matrix, isRectEqual, indexOfObject } from './utils.js'; +import Sortable from './Sortable.js'; + +export default function AnimationStateManager() { + let animationStates = [], + animationCallbackId; + + return { + captureAnimationState() { + animationStates = []; + if (!this.options.animation) return; + let children = [].slice.call(this.el.children); + + for (let i in children) { + if (css(children[i], 'display') === 'none' || children[i] === Sortable.ghost) continue; + animationStates.push({ + target: children[i], + rect: getRect(children[i]) + }); + let fromRect = getRect(children[i]); + + // If animating: compensate for current animation + if (children[i].thisAnimationDuration) { + let childMatrix = matrix(children[i], true); + if (childMatrix) { + fromRect.top -= childMatrix.f; + fromRect.left -= childMatrix.e; + } + } + + children[i].fromRect = fromRect; + } + }, + + addAnimationState(state) { + animationStates.push(state); + }, + + removeAnimationState(target) { + animationStates.splice(indexOfObject(animationStates, { target }), 1); + }, + + animateAll(callback) { + if (!this.options.animation) { + clearTimeout(animationCallbackId); + if (typeof(callback) === 'function') callback(); + return; + } + + let animating = false, + animationTime = 0; + + for (let i in animationStates) { + let time = 0, + animatingThis = false, + target = animationStates[i].target, + fromRect = target.fromRect, + toRect = getRect(target), + prevFromRect = target.prevFromRect, + prevToRect = target.prevToRect, + animatingRect = animationStates[i].rect, + targetMatrix = matrix(target, true); + + + if (targetMatrix) { + // Compensate for current animation + toRect.top -= targetMatrix.f; + toRect.left -= targetMatrix.e; + } + + target.toRect = toRect; + + // If element is scrolled out of view: Do not animate + if ( + ( + isScrolledPast(target, toRect, 'bottom', 'top') || + isScrolledPast(target, toRect, 'top', 'bottom') || + isScrolledPast(target, toRect, 'right', 'left') || + isScrolledPast(target, toRect, 'left', 'right') + ) && + ( + isScrolledPast(target, animatingRect, 'bottom', 'top') || + isScrolledPast(target, animatingRect, 'top', 'bottom') || + isScrolledPast(target, animatingRect, 'right', 'left') || + isScrolledPast(target, animatingRect, 'left', 'right') + ) && + ( + isScrolledPast(target, fromRect, 'bottom', 'top') || + isScrolledPast(target, fromRect, 'top', 'bottom') || + isScrolledPast(target, fromRect, 'right', 'left') || + isScrolledPast(target, fromRect, 'left', 'right') + ) + ) continue; + + + if (target.thisAnimationDuration) { + // Could also check if animatingRect is between fromRect and toRect + if ( + isRectEqual(prevFromRect, toRect) && + !isRectEqual(fromRect, toRect) && + // Make sure animatingRect is on line between toRect & fromRect + (animatingRect.top - toRect.top) / + (animatingRect.left - toRect.left) === + (fromRect.top - toRect.top) / + (fromRect.left - toRect.left) + ) { + // If returning to same place as started from animation and on same axis + time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options); + } + } + + // if fromRect != toRect: animate + if (!isRectEqual(toRect, fromRect)) { + target.prevFromRect = fromRect; + target.prevToRect = toRect; + + if (!time) { + time = this.options.animation; + } + this.animate( + target, + animatingRect, + time + ); + } + + if (time) { + animating = true; + animationTime = Math.max(animationTime, time); + clearTimeout(target.animationResetTimer); + target.animationResetTimer = setTimeout((function() { + this.animationStates[this.i].target.animationTime = 0; + this.animationStates[this.i].target.prevFromRect = null; + this.animationStates[this.i].target.fromRect = null; + this.animationStates[this.i].target.prevToRect = null; + this.animationStates[this.i].target.thisAnimationDuration = null; + }).bind({ animationStates, i: Number(i) }), time); + target.thisAnimationDuration = time; + } + } + + + clearTimeout(animationCallbackId); + if (!animating) { + if (typeof(callback) === 'function') callback(); + } else { + animationCallbackId = setTimeout(function() { + if (typeof(callback) === 'function') callback(); + }, animationTime); + } + animationStates = []; + }, + + animate(target, prev, duration) { + if (duration) { + css(target, 'transition', ''); + css(target, 'transform', ''); + let currentRect = getRect(target), + elMatrix = matrix(this.el), + scaleX = elMatrix && elMatrix.a, + scaleY = elMatrix && elMatrix.d, + translateX = (prev.left - currentRect.left) / (scaleX || 1), + translateY = (prev.top - currentRect.top) / (scaleY || 1); + + target.animatingX = !!translateX; + target.animatingY = !!translateY; + + css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)'); + + repaint(target); // repaint + + css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : '')); + css(target, 'transform', 'translate3d(0,0,0)'); + (typeof target.animated === 'number') && clearTimeout(target.animated); + target.animated = setTimeout(function () { + css(target, 'transition', ''); + css(target, 'transform', ''); + target.animated = false; + + target.animatingX = false; + target.animatingY = false; + }, duration); + } + } + }; +} + +function repaint(target) { + return target.offsetWidth; +} + + +function calculateRealTime(animatingRect, fromRect, toRect, options) { + return ( + Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / + Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) + ) * options.animation; +} diff --git a/src/BrowserInfo.js b/src/BrowserInfo.js new file mode 100644 index 000000000..b74847456 --- /dev/null +++ b/src/BrowserInfo.js @@ -0,0 +1,17 @@ +function userAgent(pattern) { + return !!navigator.userAgent.match(pattern); +} + +const IE11OrLess = /*@__PURE__*/userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile)/i); +const Edge = /*@__PURE__*/userAgent(/Edge/i); +const FireFox = /*@__PURE__*/userAgent(/firefox/i); +const Safari = /*@__PURE__*/userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i); +const IOS = /*@__PURE__*/userAgent(/iP(ad|od|hone)/i); + +export { + IE11OrLess, + Edge, + FireFox, + Safari, + IOS +}; diff --git a/src/EventDispatcher.js b/src/EventDispatcher.js new file mode 100644 index 000000000..19583f483 --- /dev/null +++ b/src/EventDispatcher.js @@ -0,0 +1,55 @@ +import { IE11OrLess, Edge } from './BrowserInfo.js'; +import { expando } from './utils.js'; +import PluginManager from './PluginManager.js'; + +export default function dispatchEvent( + { + sortable, rootEl, name, + targetEl, cloneEl, toEl, fromEl, + oldIndex, newIndex, + oldDraggableIndex, newDraggableIndex, + originalEvent, putSortable, eventOptions + } +) { + sortable = (sortable || rootEl[expando]); + let evt, + options = sortable.options, + onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); + // Support for new CustomEvent feature + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent(name, { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent(name, true, true); + } + + evt.to = toEl || rootEl; + evt.from = fromEl || rootEl; + evt.item = targetEl || rootEl; + evt.clone = cloneEl; + + evt.oldIndex = oldIndex; + evt.newIndex = newIndex; + + evt.oldDraggableIndex = oldDraggableIndex; + evt.newDraggableIndex = newDraggableIndex; + + evt.originalEvent = originalEvent; + evt.pullMode = putSortable ? putSortable.lastPutMode : undefined; + + let allEventOptions = { ...eventOptions, ...PluginManager.getEventOptions(name, sortable) }; + for (let option in allEventOptions) { + evt[option] = allEventOptions[option]; + } + + if (rootEl) { + rootEl.dispatchEvent(evt); + } + + if (options[onName]) { + options[onName].call(sortable, evt); + } +} diff --git a/src/PluginManager.js b/src/PluginManager.js new file mode 100644 index 000000000..914b1b8c7 --- /dev/null +++ b/src/PluginManager.js @@ -0,0 +1,81 @@ +let plugins = []; + +const defaults = { + initializeByDefault: true +}; + +export default { + mount(plugin) { + // Set default static properties + for (let option in defaults) { + !(option in plugin) && (plugin[option] = defaults[option]); + } + plugins.push(plugin); + }, + pluginEvent(eventName, sortable, evt) { + this.eventCanceled = false; + const eventNameGlobal = eventName + 'Global'; + for (let i in plugins) { + if (!sortable[plugins[i].pluginName]) continue; + // Fire global events if it exists in this sortable + if ( + sortable[plugins[i].pluginName][eventNameGlobal] + ) { + this.eventCanceled = !!sortable[plugins[i].pluginName][eventNameGlobal]({ sortable, ...evt }); + } + + // Only fire plugin event if plugin is enabled in this sortable, + // and plugin has event defined + if ( + sortable.options[plugins[i].pluginName] && + sortable[plugins[i].pluginName][eventName] + ) { + this.eventCanceled = this.eventCanceled || !!sortable[plugins[i].pluginName][eventName]({ sortable, ...evt }); + } + } + }, + initializePlugins(sortable, el, defaults) { + for (let i in plugins) { + const pluginName = plugins[i].pluginName; + if (!sortable.options[pluginName] && !plugins[i].initializeByDefault) continue; + + let initialized = new plugins[i](sortable, el); + initialized.sortable = sortable; + sortable[pluginName] = initialized; + + // Add default options from plugin + Object.assign(defaults, initialized.options); + } + + for (let option in sortable.options) { + let modified = this.modifyOption(sortable, option, sortable.options[option]); + if (typeof(modified) !== 'undefined') { + sortable.options[option] = modified; + } + } + }, + getEventOptions(name, sortable) { + let eventOptions = {}; + for (let i in plugins) { + if (typeof(plugins[i].eventOptions) !== 'function') continue; + eventOptions = { + ...eventOptions, + ...plugins[i].eventOptions(name, sortable) + }; + } + return eventOptions; + }, + modifyOption(sortable, name, value) { + let modifiedValue; + for (let i in plugins) { + // Plugin must exist on the Sortable + if (!sortable[plugins[i].pluginName]) continue; + + // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin + if (plugins[i].optionListeners && typeof(plugins[i].optionListeners[name]) === 'function') { + modifiedValue = plugins[i].optionListeners[name].call(sortable[plugins[i].pluginName], value); + } + } + return modifiedValue; + } +}; diff --git a/src/Sortable.js b/src/Sortable.js new file mode 100644 index 000000000..4b3dc2c88 --- /dev/null +++ b/src/Sortable.js @@ -0,0 +1,1900 @@ +/**! + * Sortable + * @author RubaXa + * @author owenm + * @license MIT + */ + +import { version } from '../package.json'; + +import { IE11OrLess, Edge, FireFox, Safari, IOS } from './BrowserInfo.js'; + +import AnimationStateManager from './Animation.js'; + +import PluginManager from './PluginManager.js'; + +import dispatchEvent from './EventDispatcher.js'; + +import { + on, + off, + closest, + toggleClass, + css, + matrix, + find, + getWindowScrollingElement, + getRect, + isScrolledPast, + getChild, + lastChild, + index, + getRelativeScrollOffset, + extend, + throttle, + scrollBy, + clone, + expando +} from './utils.js'; + + +let pluginEvent = function(eventName, sortable, { evt: originalEvent, ...data } = {}) { + PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, { + dragEl, + parentEl, + ghostEl, + rootEl, + nextEl, + lastDownEl, + cloneEl, + cloneHidden, + dragStarted: moved, + putSortable, + activeSortable: Sortable.active, + originalEvent, + + oldIndex, + oldDraggableIndex, + newIndex, + newDraggableIndex, + + hideGhostForTarget: _hideGhostForTarget, + unhideGhostForTarget: _unhideGhostForTarget, + + + cloneNowHidden() { + cloneHidden = true; + }, + cloneNowShown() { + cloneHidden = false; + }, + + dispatchSortableEvent(name) { + _dispatchEvent({ sortable, name, originalEvent }); + }, + + ...data + }); +}; + +function _dispatchEvent(info) { + dispatchEvent({ + putSortable, + cloneEl, + targetEl: dragEl, + rootEl, + oldIndex, + oldDraggableIndex, + newIndex, + newDraggableIndex, + ...info + }); +} + + +if (typeof window === "undefined" || !window.document) { + throw new Error("Sortable.js requires a window with a document"); +} + +let dragEl, + parentEl, + ghostEl, + rootEl, + nextEl, + lastDownEl, + + cloneEl, + cloneHidden, + + oldIndex, + newIndex, + oldDraggableIndex, + newDraggableIndex, + + activeGroup, + putSortable, + + awaitingDragStarted = false, + ignoreNextClick = false, + sortables = [], + + tapEvt, + touchEvt, + + moved, + + lastTarget, + lastDirection, + pastFirstInvertThresh = false, + isCircumstantialInvert = false, + + targetMoveDistance, + + // For positioning ghost absolutely + ghostRelativeParent, + ghostRelativeParentInitialScroll = [], // (left, top) + + _silent = false, + savedInputChecked = []; + + /** @const */ + const PositionGhostAbsolutely = IOS, + + CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float', + + // This will not pass for IE9, because IE9 DnD only works on anchors + supportDraggable = ('draggable' in document.createElement('div')), + + supportCssPointerEvents = (function() { + // false when <= IE11 + if (IE11OrLess) { + return false; + } + let el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; + })(), + + _detectDirection = function(el, options) { + let elCSS = css(el), + elWidth = parseInt(elCSS.width) + - parseInt(elCSS.paddingLeft) + - parseInt(elCSS.paddingRight) + - parseInt(elCSS.borderLeftWidth) + - parseInt(elCSS.borderRightWidth), + child1 = getChild(el, 0, options), + child2 = getChild(el, 1, options), + firstChildCSS = child1 && css(child1), + secondChildCSS = child2 && css(child2), + firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width, + secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width; + + if (elCSS.display === 'flex') { + return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' + ? 'vertical' : 'horizontal'; + } + + if (elCSS.display === 'grid') { + return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal'; + } + + if (child1 && firstChildCSS.float !== 'none') { + let touchingSideChild2 = firstChildCSS.float === 'left' ? 'left' : 'right'; + + return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? + 'vertical' : 'horizontal'; + } + + return (child1 && + ( + firstChildCSS.display === 'block' || + firstChildCSS.display === 'flex' || + firstChildCSS.display === 'table' || + firstChildCSS.display === 'grid' || + firstChildWidth >= elWidth && + elCSS[CSSFloatProperty] === 'none' || + child2 && + elCSS[CSSFloatProperty] === 'none' && + firstChildWidth + secondChildWidth > elWidth + ) ? + 'vertical' : 'horizontal' + ); + }, + + /** + * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. + * @param {Number} x X position + * @param {Number} y Y position + * @return {HTMLElement} Element of the first found nearest Sortable + */ + _detectNearestEmptySortable = function(x, y) { + for (let i in sortables) { + if (lastChild(sortables[i])) continue; + + let rect = getRect(sortables[i]), + threshold = sortables[i][expando].options.emptyInsertThreshold, + insideHorizontally = x >= (rect.left - threshold) && x <= (rect.right + threshold), + insideVertically = y >= (rect.top - threshold) && y <= (rect.bottom + threshold); + + if (threshold && insideHorizontally && insideVertically) { + return sortables[i]; + } + } + }, + + _prepareGroup = function (options) { + function toFn(value, pull) { + return function(to, from, dragEl, evt) { + let sameGroup = to.options.group.name && + from.options.group.name && + to.options.group.name === from.options.group.name; + + if (value == null && (pull || sameGroup)) { + // Default pull value + // Default pull and put value if same group + return true; + } else if (value == null || value === false) { + return false; + } else if (pull && value === 'clone') { + return value; + } else if (typeof value === 'function') { + return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt); + } else { + let otherGroup = (pull ? to : from).options.group.name; + + return (value === true || + (typeof value === 'string' && value === otherGroup) || + (value.join && value.indexOf(otherGroup) > -1)); + } + }; + } + + let group = {}; + let originalGroup = options.group; + + if (!originalGroup || typeof originalGroup != 'object') { + originalGroup = {name: originalGroup}; + } + + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + group.revertClone = originalGroup.revertClone; + + options.group = group; + }, + + _hideGhostForTarget = function() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', 'none'); + } + }, + + _unhideGhostForTarget = function() { + if (!supportCssPointerEvents && ghostEl) { + css(ghostEl, 'display', ''); + } + }; + + +// #1184 fix - Prevent click event on fallback if dragged but item not changed position +document.addEventListener('click', function(evt) { + if (ignoreNextClick) { + evt.preventDefault(); + evt.stopPropagation && evt.stopPropagation(); + evt.stopImmediatePropagation && evt.stopImmediatePropagation(); + ignoreNextClick = false; + return false; + } +}, true); + +let nearestEmptyInsertDetectEvent = function(evt) { + if (dragEl) { + evt = evt.touches ? evt.touches[0] : evt; + let nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY); + + if (nearest) { + // Create imitation event + let event = {}; + for (let i in evt) { + event[i] = evt[i]; + } + event.target = event.rootEl = nearest; + event.preventDefault = void 0; + event.stopPropagation = void 0; + nearest[expando]._onDragOver(event); + } + } +}; + + +let _checkOutsideTargetEl = function(evt) { + if (dragEl) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); + } +}; + + +/** + * @class Sortable + * @param {HTMLElement} el + * @param {Object} [options] + */ +function Sortable(el, options) { + if (!(el && el.nodeType && el.nodeType === 1)) { + throw `Sortable: \`el\` must be an HTMLElement, not ${ {}.toString.call(el) }`; + } + + this.el = el; // root element + this.options = options = Object.assign({}, options); + + + // Export instance + el[expando] = this; + + let defaults = { + group: null, + sort: true, + disabled: false, + store: null, + handle: null, + draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*', + swapThreshold: 1, // percentage; 0 <= x <= 1 + invertSwap: false, // invert always + invertedSwapThreshold: null, // will be set to same as swapThreshold if default + removeCloneOnHide: true, + direction: function() { + return _detectDirection(el, this.options); + }, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + ignore: 'a, img', + filter: null, + preventOnFilter: true, + animation: 0, + easing: null, + setData: function (dataTransfer, dragEl) { + dataTransfer.setData('Text', dragEl.textContent); + }, + dropBubble: false, + dragoverBubble: false, + dataIdAttr: 'data-id', + delay: 0, + delayOnTouchOnly: false, + touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, + forceFallback: false, + fallbackClass: 'sortable-fallback', + fallbackOnBody: false, + fallbackTolerance: 0, + fallbackOffset: {x: 0, y: 0}, + supportPointer: Sortable.supportPointer !== false && ('PointerEvent' in window), + emptyInsertThreshold: 5 + }; + + PluginManager.initializePlugins(this, el, defaults); + + // Set default options + for (let name in defaults) { + !(name in options) && (options[name] = defaults[name]); + } + + _prepareGroup(options); + + // Bind all private methods + for (let fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + // Setup drag mode + this.nativeDraggable = options.forceFallback ? false : supportDraggable; + + if (this.nativeDraggable) { + // Touch start threshold cannot be greater than the native dragstart threshold + this.options.touchStartThreshold = 1; + } + + // Bind events + if (options.supportPointer) { + on(el, 'pointerdown', this._onTapStart); + } else { + on(el, 'mousedown', this._onTapStart); + on(el, 'touchstart', this._onTapStart); + } + + if (this.nativeDraggable) { + on(el, 'dragover', this); + on(el, 'dragenter', this); + } + + sortables.push(this.el); + + // Restore sorting + options.store && options.store.get && this.sort(options.store.get(this) || []); + + // Add animation state manager + Object.assign(this, AnimationStateManager()); +} + +Sortable.prototype = /** @lends Sortable.prototype */ { + constructor: Sortable, + + _isOutsideThisEl: function(target) { + if (!this.el.contains(target) && target !== this.el) { + lastTarget = null; + } + }, + + _getDirection: function(evt, target) { + return (typeof this.options.direction === 'function') ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction; + }, + + _onTapStart: function (/** Event|TouchEvent */evt) { + if (!evt.cancelable) return; + let _this = this, + el = this.el, + options = this.options, + preventOnFilter = options.preventOnFilter, + type = evt.type, + touch = evt.touches && evt.touches[0], + target = (touch || evt).target, + originalTarget = evt.target.shadowRoot && ((evt.path && evt.path[0]) || (evt.composedPath && evt.composedPath()[0])) || target, + filter = options.filter; + + _saveInputCheckedState(el); + + + // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. + if (dragEl) { + return; + } + + if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { + return; // only left button and enabled + } + + // cancel dnd if original target is content editable + if (originalTarget.isContentEditable) { + return; + } + + target = closest(target, options.draggable, el, false); + + + if (target && target.animated) { + return; + } + + if (lastDownEl === target) { + // Ignoring duplicate `down` + return; + } + + // Get the index of the dragged element within its parent + oldIndex = index(target); + oldDraggableIndex = index(target, options.draggable); + + // Check filter + if (typeof filter === 'function') { + if (filter.call(this, evt, target, this)) { + _dispatchEvent({ + sortable: _this, + rootEl: originalTarget, + name: 'filter', + targetEl: target, + toEl: el, + fromEl: el + }); + pluginEvent('filter', _this, { evt }); + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } + else if (filter) { + filter = filter.split(',').some(function (criteria) { + criteria = closest(originalTarget, criteria.trim(), el, false); + + if (criteria) { + _dispatchEvent({ + sortable: _this, + rootEl: criteria, + name: 'filter', + targetEl: target, + fromEl: el, + toEl: el + }); + pluginEvent('filter', _this, { evt }); + return true; + } + }); + + if (filter) { + preventOnFilter && evt.cancelable && evt.preventDefault(); + return; // cancel dnd + } + } + + if (options.handle && !closest(originalTarget, options.handle, el, false)) { + return; + } + + // Prepare `dragstart` + this._prepareDragStart(evt, touch, target); + }, + + _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target) { + let _this = this, + el = _this.el, + options = _this.options, + ownerDocument = el.ownerDocument, + dragStartFn; + + if (target && !dragEl && (target.parentNode === el)) { + rootEl = el; + dragEl = target; + parentEl = dragEl.parentNode; + nextEl = dragEl.nextSibling; + lastDownEl = target; + activeGroup = options.group; + + Sortable.dragged = dragEl; + + tapEvt = { + target: dragEl, + clientX: (touch || evt).clientX, + clientY: (touch || evt).clientY + }; + + this._lastX = (touch || evt).clientX; + this._lastY = (touch || evt).clientY; + + dragEl.style['will-change'] = 'all'; + + dragStartFn = function () { + pluginEvent('delayEnded', _this, { evt }); + if (Sortable.eventCanceled) { + _this._onDrop(); + return; + } + // Delayed drag has been triggered + // we can re-enable the events: touchmove/mousemove + _this._disableDelayedDragEvents(); + + if (!FireFox && _this.nativeDraggable) { + dragEl.draggable = true; + } + + // Bind the events: dragstart/dragend + _this._triggerDragStart(evt, touch); + + // Drag start event + _dispatchEvent({ + sortable: _this, + name: 'choose', + originalEvent: evt + }); + + // Chosen item + toggleClass(dragEl, options.chosenClass, true); + }; + + // Disable "draggable" + options.ignore.split(',').forEach(function (criteria) { + find(dragEl, criteria.trim(), _disableDraggable); + }); + + on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent); + on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent); + + on(ownerDocument, 'mouseup', _this._onDrop); + on(ownerDocument, 'touchend', _this._onDrop); + on(ownerDocument, 'touchcancel', _this._onDrop); + + // Make dragEl draggable (must be before delay for FireFox) + if (FireFox && this.nativeDraggable) { + this.options.touchStartThreshold = 4; + dragEl.draggable = true; + } + + pluginEvent('delayStart', this, { evt }); + + // Delay is impossible for native DnD in Edge or IE + if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) { + if (Sortable.eventCanceled) { + this._onDrop(); + return; + } + // If the user moves the pointer or let go the click or touch + // before the delay has been reached: + // disable the delayed drag + on(ownerDocument, 'mouseup', _this._disableDelayedDrag); + on(ownerDocument, 'touchend', _this._disableDelayedDrag); + on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); + on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler); + on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler); + options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler); + + _this._dragStartTimer = setTimeout(dragStartFn, options.delay); + } else { + dragStartFn(); + } + } + }, + + _delayedDragTouchMoveHandler: function (/** TouchEvent|PointerEvent **/e) { + let touch = e.touches ? e.touches[0] : e; + if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) + >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1)) + ) { + this._disableDelayedDrag(); + } + }, + + _disableDelayedDrag: function () { + dragEl && _disableDraggable(dragEl); + clearTimeout(this._dragStartTimer); + + this._disableDelayedDragEvents(); + }, + + _disableDelayedDragEvents: function () { + let ownerDocument = this.el.ownerDocument; + off(ownerDocument, 'mouseup', this._disableDelayedDrag); + off(ownerDocument, 'touchend', this._disableDelayedDrag); + off(ownerDocument, 'touchcancel', this._disableDelayedDrag); + off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler); + off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler); + }, + + _triggerDragStart: function (/** Event */evt, /** Touch */touch) { + touch = touch || (evt.pointerType == 'touch' ? evt : null); + + if (!this.nativeDraggable || touch) { + if (this.options.supportPointer) { + on(document, 'pointermove', this._onTouchMove); + } else if (touch) { + on(document, 'touchmove', this._onTouchMove); + } else { + on(document, 'mousemove', this._onTouchMove); + } + } else { + on(dragEl, 'dragend', this); + on(rootEl, 'dragstart', this._onDragStart); + } + + try { + if (document.selection) { + // Timeout neccessary for IE9 + _nextTick(function () { + document.selection.empty(); + }); + } else { + window.getSelection().removeAllRanges(); + } + } catch (err) { + } + }, + + _dragStarted: function (fallback, evt) { + let _this = this; + awaitingDragStarted = false; + if (rootEl && dragEl) { + pluginEvent('dragStarted', this, { evt }); + + if (this.nativeDraggable) { + on(document, 'dragover', _checkOutsideTargetEl); + } + let options = this.options; + + // Apply effect + !fallback && toggleClass(dragEl, options.dragClass, false); + toggleClass(dragEl, options.ghostClass, true); + + Sortable.active = this; + + fallback && this._appendGhost(); + + // Drag start event + _dispatchEvent({ + sortable: this, + name: 'start', + originalEvent: evt + }); + } else { + this._nulling(); + } + }, + + _emulateDragOver: function () { + if (touchEvt) { + this._lastX = touchEvt.clientX; + this._lastY = touchEvt.clientY; + + _hideGhostForTarget(); + + let target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + let parent = target; + + while (target && target.shadowRoot) { + target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + if (target === parent) break; + parent = target; + } + + dragEl.parentNode[expando]._isOutsideThisEl(target); + + if (parent) { + do { + if (parent[expando]) { + let inserted; + + inserted = parent[expando]._onDragOver({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); + + if (inserted && !this.options.dragoverBubble) { + break; + } + } + + target = parent; // store last element + } + /* jshint boss:true */ + while (parent = parent.parentNode); + } + + _unhideGhostForTarget(); + } + }, + + + _onTouchMove: function (/**TouchEvent*/evt) { + if (tapEvt) { + let options = this.options, + fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, + touch = evt.touches ? evt.touches[0] : evt, + ghostMatrix = ghostEl && matrix(ghostEl), + scaleX = ghostEl && ghostMatrix && ghostMatrix.a, + scaleY = ghostEl && ghostMatrix && ghostMatrix.d, + relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent), + dx = ((touch.clientX - tapEvt.clientX) + + fallbackOffset.x) / (scaleX || 1) + + (relativeScrollOffset ? (relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0]) : 0) / (scaleX || 1), + dy = ((touch.clientY - tapEvt.clientY) + + fallbackOffset.y) / (scaleY || 1) + + (relativeScrollOffset ? (relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1]) : 0) / (scaleY || 1), + translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; + + // only set the status to dragging, when we are actually dragging + if (!Sortable.active && !awaitingDragStarted) { + if (fallbackTolerance && + Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance + ) { + return; + } + this._onDragStart(evt, true); + } + + touchEvt = touch; + + css(ghostEl, 'webkitTransform', translate3d); + css(ghostEl, 'mozTransform', translate3d); + css(ghostEl, 'msTransform', translate3d); + css(ghostEl, 'transform', translate3d); + + evt.cancelable && evt.preventDefault(); + } + }, + + _appendGhost: function () { + // Bug if using scale(): https://stackoverflow.com/questions/2637058 + // Not being adjusted for + if (!ghostEl) { + let container = this.options.fallbackOnBody ? document.body : rootEl, + rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container), + options = this.options; + + // Position absolutely + if (PositionGhostAbsolutely) { + // Get relatively positioned parent + ghostRelativeParent = container; + + while ( + css(ghostRelativeParent, 'position') === 'static' && + css(ghostRelativeParent, 'transform') === 'none' && + ghostRelativeParent !== document + ) { + ghostRelativeParent = ghostRelativeParent.parentNode; + } + + if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) { + if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement(); + + rect.top += ghostRelativeParent.scrollTop; + rect.left += ghostRelativeParent.scrollLeft; + } else { + ghostRelativeParent = getWindowScrollingElement(); + } + ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent); + } + + + ghostEl = dragEl.cloneNode(true); + + toggleClass(ghostEl, options.ghostClass, false); + toggleClass(ghostEl, options.fallbackClass, true); + toggleClass(ghostEl, options.dragClass, true); + + css(ghostEl, 'transition', ''); + css(ghostEl, 'transform', ''); + + css(ghostEl, 'box-sizing', 'border-box'); + css(ghostEl, 'margin', 0); + css(ghostEl, 'top', rect.top); + css(ghostEl, 'left', rect.left); + css(ghostEl, 'width', rect.width); + css(ghostEl, 'height', rect.height); + css(ghostEl, 'opacity', '0.8'); + css(ghostEl, 'position', (PositionGhostAbsolutely ? 'absolute' : 'fixed')); + css(ghostEl, 'zIndex', '100000'); + css(ghostEl, 'pointerEvents', 'none'); + + Sortable.ghost = ghostEl; + + container.appendChild(ghostEl); + } + }, + + _onDragStart: function (/**Event*/evt, /**boolean*/fallback) { + let _this = this; + let dataTransfer = evt.dataTransfer; + let options = _this.options; + + pluginEvent('dragStart', this, { evt }); + if (Sortable.eventCanceled) { + this._onDrop(); + return; + } + + pluginEvent('setupClone', this); + if (!Sortable.eventCanceled) { + cloneEl = clone(dragEl); + + cloneEl.draggable = false; + cloneEl.style['will-change'] = ''; + + this._hideClone(); + + toggleClass(cloneEl, this.options.chosenClass, false); + Sortable.clone = cloneEl; + } + + + // #1143: IFrame support workaround + _this.cloneId = _nextTick(function() { + pluginEvent('clone', _this); + if (Sortable.eventCanceled) return; + + if (!_this.options.removeCloneOnHide) { + rootEl.insertBefore(cloneEl, dragEl); + } + _this._hideClone(); + + _dispatchEvent({ + sortable: _this, + name: 'clone' + }); + }); + + + !fallback && toggleClass(dragEl, options.dragClass, true); + + // Set proper drop events + if (fallback) { + ignoreNextClick = true; + _this._loopId = setInterval(_this._emulateDragOver, 50); + } else { + // Undo what was set in _prepareDragStart before drag started + off(document, 'mouseup', _this._onDrop); + off(document, 'touchend', _this._onDrop); + off(document, 'touchcancel', _this._onDrop); + + if (dataTransfer) { + dataTransfer.effectAllowed = 'move'; + options.setData && options.setData.call(_this, dataTransfer, dragEl); + } + + on(document, 'drop', _this); + + // #1276 fix: + css(dragEl, 'transform', 'translateZ(0)'); + } + + awaitingDragStarted = true; + + _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt)); + on(document, 'selectstart', _this); + + moved = true; + + if (Safari) { + css(document.body, 'user-select', 'none'); + } + }, + + + // Returns true - if no further action is needed (either inserted or another condition) + _onDragOver: function (/**Event*/evt) { + let el = this.el, + target = evt.target, + dragRect, + targetRect, + revert, + options = this.options, + group = options.group, + activeSortable = Sortable.active, + isOwner = (activeGroup === group), + canSort = options.sort, + fromSortable = (putSortable || activeSortable), + vertical, + _this = this, + completedFired = false; + + if (_silent) return; + + function dragOverEvent(name, extra) { + pluginEvent(name, _this, { + evt, + isOwner, + axis: vertical ? 'vertical' : 'horizontal', + revert, + dragRect, + targetRect, + canSort, + fromSortable, + target, + completed, + onMove(target, after) { + onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after); + }, + changed, + ...extra + }); + } + + // Capture animation state + function capture() { + dragOverEvent('dragOverAnimationCapture'); + + _this.captureAnimationState(); + if (_this !== fromSortable) { + fromSortable.captureAnimationState(); + } + } + + // Return invocation when dragEl is inserted (or completed) + function completed(insertion) { + dragOverEvent('dragOverCompleted', { insertion }); + + if (insertion) { + // Clones must be hidden before folding animation to capture dragRectAbsolute properly + if (isOwner) { + activeSortable._hideClone(); + } else { + activeSortable._showClone(_this); + } + + if (_this !== fromSortable) { + // Set ghost class to new sortable's ghost class + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false); + toggleClass(dragEl, options.ghostClass, true); + } + + if (putSortable !== _this && _this !== Sortable.active) { + putSortable = _this; + } else if (_this === Sortable.active && putSortable) { + putSortable = null; + } + + // Animation + if (fromSortable === _this) { + _this._ignoreWhileAnimating = target; + } + _this.animateAll(function() { + dragOverEvent('dragOverAnimationComplete'); + _this._ignoreWhileAnimating = null; + }); + if (_this !== fromSortable) { + fromSortable.animateAll(); + fromSortable._ignoreWhileAnimating = null; + } + } + + + // Null lastTarget if it is not inside a previously swapped element + if ((target === dragEl && !dragEl.animated) || (target === el && !target.animated)) { + lastTarget = null; + } + + // no bubbling and not fallback + if (!options.dragoverBubble && !evt.rootEl && target !== document) { + dragEl.parentNode[expando]._isOutsideThisEl(evt.target); + + // Do not detect for empty insert if already inserted + !insertion && nearestEmptyInsertDetectEvent(evt); + } + + !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation(); + + return (completedFired = true); + } + + // Call when dragEl has been inserted + function changed() { + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + _dispatchEvent({ + sortable: _this, + name: 'change', + toEl: el, + newIndex, + newDraggableIndex, + originalEvent: evt + }); + } + + + if (evt.preventDefault !== void 0) { + evt.cancelable && evt.preventDefault(); + } + + + target = closest(target, options.draggable, el, true); + + dragOverEvent('dragOver'); + if (Sortable.eventCanceled) return completedFired; + + if ( + dragEl.contains(evt.target) || + target.animated && target.animatingX && target.animatingY || + _this._ignoreWhileAnimating === target + ) { + return completed(false); + } + + ignoreNextClick = false; + + if (activeSortable && !options.disabled && + (isOwner + ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list + : ( + putSortable === this || + ( + (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && + group.checkPut(this, activeSortable, dragEl, evt) + ) + ) + ) + ) { + vertical = this._getDirection(evt, target) === 'vertical'; + + dragRect = getRect(dragEl); + + dragOverEvent('dragOverValid'); + if (Sortable.eventCanceled) return completedFired; + + if (revert) { + parentEl = rootEl; // actualization + capture(); + + this._hideClone(); + + dragOverEvent('revert'); + + if (!Sortable.eventCanceled) { + if (nextEl) { + rootEl.insertBefore(dragEl, nextEl); + } else { + rootEl.appendChild(dragEl); + } + } + + return completed(true); + } + + let elLastChild = lastChild(el, options.draggable); + + if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) { + // If already at end of list: Do not insert + if (elLastChild === dragEl) { + return completed(false); + } + + // assign target only if condition is true + if (elLastChild && el === evt.target) { + target = elLastChild; + } + + if (target) { + targetRect = getRect(target); + } + + if (onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) { + capture(); + el.appendChild(dragEl); + parentEl = el; // actualization + + changed(); + return completed(true); + } + } + else if (target.parentNode === el) { + let direction = 0, + targetBeforeFirstSwap, + differentLevel = dragEl.parentNode !== el, + side1 = vertical ? 'top' : 'left', + scrolledPastTop = isScrolledPast(target, null, 'top', 'top') || isScrolledPast(dragEl, null, 'top', 'top'), + scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0; + + + if (lastTarget !== target) { + targetBeforeFirstSwap = getRect(target)[side1]; + pastFirstInvertThresh = false; + isCircumstantialInvert = options.invertSwap || differentLevel; + } + + direction = _getSwapDirection( + evt, target, vertical, + options.swapThreshold, + options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, + isCircumstantialInvert, + lastTarget === target + ); + + let sibling; + + if (direction !== 0) { + // Check if target is beside dragEl in respective direction (ignoring hidden elements) + let dragIndex = index(dragEl); + + do { + dragIndex -= direction; + sibling = parentEl.children[dragIndex]; + } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl)); + } + // If dragEl is already beside target: Do not insert + if ( + direction === 0 || + sibling === target + ) { + return completed(false); + } + + lastTarget = target; + + lastDirection = direction; + + targetRect = getRect(target); + + let nextSibling = target.nextElementSibling, + after = false; + + after = direction === 1; + + let moveVector = onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); + + if (moveVector !== false) { + if (moveVector === 1 || moveVector === -1) { + after = (moveVector === 1); + } + + _silent = true; + setTimeout(_unsilent, 30); + + capture(); + + if (after && !nextSibling) { + el.appendChild(dragEl); + } else { + target.parentNode.insertBefore(dragEl, after ? nextSibling : target); + } + + // Undo chrome's scroll adjustment (has no effect on other browsers) + if (scrolledPastTop) { + scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop); + } + + parentEl = dragEl.parentNode; // actualization + + // must be done before animation + if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) { + targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]); + } + changed(); + + return completed(true); + } + } + + if (el.contains(dragEl)) { + return completed(false); + } + } + + return false; + }, + + _ignoreWhileAnimating: null, + + _offMoveEvents: function() { + off(document, 'mousemove', this._onTouchMove); + off(document, 'touchmove', this._onTouchMove); + off(document, 'pointermove', this._onTouchMove); + off(document, 'dragover', nearestEmptyInsertDetectEvent); + off(document, 'mousemove', nearestEmptyInsertDetectEvent); + off(document, 'touchmove', nearestEmptyInsertDetectEvent); + }, + + _offUpEvents: function () { + let ownerDocument = this.el.ownerDocument; + + off(ownerDocument, 'mouseup', this._onDrop); + off(ownerDocument, 'touchend', this._onDrop); + off(ownerDocument, 'pointerup', this._onDrop); + off(ownerDocument, 'touchcancel', this._onDrop); + off(document, 'selectstart', this); + }, + + _onDrop: function (/**Event*/evt) { + let el = this.el, + options = this.options; + + // Get the index of the dragged element within its parent + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + pluginEvent('drop', this, { + evt + }); + + // Get again after plugin event + newIndex = index(dragEl); + newDraggableIndex = index(dragEl, options.draggable); + + if (Sortable.eventCanceled) { + this._nulling(); + return; + } + + awaitingDragStarted = false; + isCircumstantialInvert = false; + pastFirstInvertThresh = false; + + clearInterval(this._loopId); + + clearTimeout(this._dragStartTimer); + + _cancelNextTick(this.cloneId); + _cancelNextTick(this._dragStartId); + + // Unbind events + if (this.nativeDraggable) { + off(document, 'drop', this); + off(el, 'dragstart', this._onDragStart); + } + this._offMoveEvents(); + this._offUpEvents(); + + + if (Safari) { + css(document.body, 'user-select', ''); + } + + + if (evt) { + if (moved) { + evt.cancelable && evt.preventDefault(); + !options.dropBubble && evt.stopPropagation(); + } + + ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); + + if (rootEl === parentEl || (putSortable && putSortable.lastPutMode !== 'clone')) { + // Remove clone(s) + cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); + } + + if (dragEl) { + if (this.nativeDraggable) { + off(dragEl, 'dragend', this); + } + + _disableDraggable(dragEl); + dragEl.style['will-change'] = ''; + + // Remove classes + // ghostClass is added in dragStarted + if (moved && !awaitingDragStarted) { + toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false); + } + toggleClass(dragEl, this.options.chosenClass, false); + + // Drag stop event + _dispatchEvent({ + sortable: this, + name: 'unchoose', + toEl: parentEl, + newIndex: null, + newDraggableIndex: null, + originalEvent: evt + }); + + + if (rootEl !== parentEl) { + + if (newIndex >= 0) { + // Add event + _dispatchEvent({ + rootEl: parentEl, + name: 'add', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); + + // Remove event + _dispatchEvent({ + sortable: this, + name: 'remove', + toEl: parentEl, + originalEvent: evt + }); + + // drag from one list and drop into another + _dispatchEvent({ + rootEl: parentEl, + name: 'sort', + toEl: parentEl, + fromEl: rootEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + + putSortable && putSortable.save(); + } else { + if (newIndex !== oldIndex) { + if (newIndex >= 0) { + // drag & drop within the same list + _dispatchEvent({ + sortable: this, + name: 'update', + toEl: parentEl, + originalEvent: evt + }); + + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + originalEvent: evt + }); + } + } + } + + if (Sortable.active) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { + newIndex = oldIndex; + newDraggableIndex = oldDraggableIndex; + } + + _dispatchEvent({ + sortable: this, + name: 'end', + toEl: parentEl, + originalEvent: evt + }); + + // Save sorting + this.save(); + } + } + + } + this._nulling(); + }, + + _nulling: function() { + pluginEvent('nulling', this); + + rootEl = + dragEl = + parentEl = + ghostEl = + nextEl = + cloneEl = + lastDownEl = + cloneHidden = + + tapEvt = + touchEvt = + + moved = + newIndex = + newDraggableIndex = + oldIndex = + oldDraggableIndex = + + lastTarget = + lastDirection = + + putSortable = + activeGroup = + Sortable.dragged = + Sortable.ghost = + Sortable.clone = + Sortable.active = null; + + savedInputChecked.forEach(function (el) { + el.checked = true; + }); + + savedInputChecked.length = 0; + }, + + handleEvent: function (/**Event*/evt) { + switch (evt.type) { + case 'drop': + case 'dragend': + this._onDrop(evt); + break; + + case 'dragenter': + case 'dragover': + if (dragEl) { + this._onDragOver(evt); + _globalDragOver(evt); + } + break; + + case 'selectstart': + evt.preventDefault(); + break; + } + }, + + + /** + * Serializes the item into an array of string. + * @returns {String[]} + */ + toArray: function () { + let order = [], + el, + children = this.el.children, + i = 0, + n = children.length, + options = this.options; + + for (; i < n; i++) { + el = children[i]; + if (closest(el, options.draggable, this.el, false)) { + order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); + } + } + + return order; + }, + + + /** + * Sorts the elements according to the array. + * @param {String[]} order order of the items + */ + sort: function (order) { + let items = {}, rootEl = this.el; + + this.toArray().forEach(function (id, i) { + let el = rootEl.children[i]; + + if (closest(el, this.options.draggable, rootEl, false)) { + items[id] = el; + } + }, this); + + order.forEach(function (id) { + if (items[id]) { + rootEl.removeChild(items[id]); + rootEl.appendChild(items[id]); + } + }); + }, + + + /** + * Save the current sorting + */ + save: function () { + let store = this.options.store; + store && store.set && store.set(this); + }, + + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * @param {HTMLElement} el + * @param {String} [selector] default: `options.draggable` + * @returns {HTMLElement|null} + */ + closest: function (el, selector) { + return closest(el, selector || this.options.draggable, this.el, false); + }, + + + /** + * Set/get option + * @param {string} name + * @param {*} [value] + * @returns {*} + */ + option: function (name, value) { + let options = this.options; + + if (value === void 0) { + return options[name]; + } else { + let modifiedValue = PluginManager.modifyOption(this, name, value); + if (typeof(modifiedValue) !== 'undefined') { + options[name] = modifiedValue; + } else { + options[name] = value; + } + + if (name === 'group') { + _prepareGroup(options); + } + } + }, + + + /** + * Destroy + */ + destroy: function () { + pluginEvent('destroy', this); + let el = this.el; + + el[expando] = null; + + off(el, 'mousedown', this._onTapStart); + off(el, 'touchstart', this._onTapStart); + off(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + off(el, 'dragover', this); + off(el, 'dragenter', this); + } + // Remove draggable attributes + Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { + el.removeAttribute('draggable'); + }); + + this._onDrop(); + + sortables.splice(sortables.indexOf(this.el), 1); + + this.el = el = null; + }, + + _hideClone: function() { + if (!cloneHidden) { + pluginEvent('hideClone', this); + if (Sortable.eventCanceled) return; + + + css(cloneEl, 'display', 'none'); + if (this.options.removeCloneOnHide && cloneEl.parentNode) { + cloneEl.parentNode.removeChild(cloneEl); + } + cloneHidden = true; + } + }, + + _showClone: function(putSortable) { + if (putSortable.lastPutMode !== 'clone') { + this._hideClone(); + return; + } + + + if (cloneHidden) { + pluginEvent('showClone', this); + if (Sortable.eventCanceled) return; + + // show clone at dragEl or original position + if (rootEl.contains(dragEl) && !this.options.group.revertClone) { + rootEl.insertBefore(cloneEl, dragEl); + } else if (nextEl) { + rootEl.insertBefore(cloneEl, nextEl); + } else { + rootEl.appendChild(cloneEl); + } + + if (this.options.group.revertClone) { + this._animate(dragEl, cloneEl); + } + + css(cloneEl, 'display', ''); + cloneHidden = false; + } + } +}; + +function _globalDragOver(/**Event*/evt) { + if (evt.dataTransfer) { + evt.dataTransfer.dropEffect = 'move'; + } + evt.cancelable && evt.preventDefault(); +} + +function onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) { + let evt, + sortable = fromEl[expando], + onMoveFn = sortable.options.onMove, + retVal; + // Support for new CustomEvent feature + if (window.CustomEvent && !IE11OrLess && !Edge) { + evt = new CustomEvent('move', { + bubbles: true, + cancelable: true + }); + } else { + evt = document.createEvent('Event'); + evt.initEvent('move', true, true); + } + + evt.to = toEl; + evt.from = fromEl; + evt.dragged = dragEl; + evt.draggedRect = dragRect; + evt.related = targetEl || toEl; + evt.relatedRect = targetRect || getRect(toEl); + evt.willInsertAfter = willInsertAfter; + + evt.originalEvent = originalEvent; + + fromEl.dispatchEvent(evt); + + if (onMoveFn) { + retVal = onMoveFn.call(sortable, evt, originalEvent); + } + + return retVal; +} + +function _disableDraggable(el) { + el.draggable = false; +} + +function _unsilent() { + _silent = false; +} + + +function _ghostIsLast(evt, vertical, sortable) { + let elRect = getRect(lastChild(sortable.el, sortable.options.draggable)), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + mouseOnOppAxis = vertical ? evt.clientX : evt.clientY, + targetS2 = vertical ? elRect.bottom : elRect.right, + targetS1Opp = vertical ? elRect.left : elRect.top, + targetS2Opp = vertical ? elRect.right : elRect.bottom; + + return (mouseOnAxis > targetS2 && mouseOnOppAxis > targetS1Opp && mouseOnOppAxis < targetS2Opp); +} + +function _getSwapDirection(evt, target, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) { + let targetRect = getRect(target), + mouseOnAxis = vertical ? evt.clientY : evt.clientX, + targetLength = vertical ? targetRect.height : targetRect.width, + targetS1 = vertical ? targetRect.top : targetRect.left, + targetS2 = vertical ? targetRect.bottom : targetRect.right, + invert = false; + + + if (!invertSwap) { + // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold + if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2 + // check if past first invert threshold on side opposite of lastDirection + if (!pastFirstInvertThresh && + (lastDirection === 1 ? + ( + mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 + ) : + ( + mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2 + ) + ) + ) + { + // past first invert threshold, do not restrict inverted threshold to dragEl shadow + pastFirstInvertThresh = true; + } + + if (!pastFirstInvertThresh) { + // dragEl shadow (target move distance shadow) + if ( + lastDirection === 1 ? + ( + mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow + ) : + ( + mouseOnAxis > targetS2 - targetMoveDistance + ) + ) + { + return -lastDirection; + } + } else { + invert = true; + } + } else { + // Regular + if ( + mouseOnAxis > targetS1 + (targetLength * (1 - swapThreshold) / 2) && + mouseOnAxis < targetS2 - (targetLength * (1 - swapThreshold) / 2) + ) { + return _getInsertDirection(target); + } + } + } + + invert = invert || invertSwap; + + if (invert) { + // Invert of regular + if ( + mouseOnAxis < targetS1 + (targetLength * invertedSwapThreshold / 2) || + mouseOnAxis > targetS2 - (targetLength * invertedSwapThreshold / 2) + ) + { + return ((mouseOnAxis > targetS1 + targetLength / 2) ? 1 : -1); + } + } + + return 0; +} + +/** + * Gets the direction dragEl must be swapped relative to target in order to make it + * seem that dragEl has been "inserted" into that element's position + * @param {HTMLElement} target The target whose position dragEl is being inserted at + * @return {Number} Direction dragEl must be swapped + */ +function _getInsertDirection(target) { + if (index(dragEl) < index(target)) { + return 1; + } else { + return -1; + } +} + + +/** + * Generate id + * @param {HTMLElement} el + * @returns {String} + * @private + */ +function _generateId(el) { + let str = el.tagName + el.className + el.src + el.href + el.textContent, + i = str.length, + sum = 0; + + while (i--) { + sum += str.charCodeAt(i); + } + + return sum.toString(36); +} + +function _saveInputCheckedState(root) { + savedInputChecked.length = 0; + + let inputs = root.getElementsByTagName('input'); + let idx = inputs.length; + + while (idx--) { + let el = inputs[idx]; + el.checked && savedInputChecked.push(el); + } +} + +function _nextTick(fn) { + return setTimeout(fn, 0); +} + +function _cancelNextTick(id) { + return clearTimeout(id); +} + +// Fixed #973: +on(document, 'touchmove', function(evt) { + if ((Sortable.active || awaitingDragStarted) && evt.cancelable) { + evt.preventDefault(); + } +}); + + +// Export utils +Sortable.utils = { + on: on, + off: off, + css: css, + find: find, + is: function (el, selector) { + return !!closest(el, selector, el, false); + }, + extend: extend, + throttle: throttle, + closest: closest, + toggleClass: toggleClass, + clone: clone, + index: index, + nextTick: _nextTick, + cancelNextTick: _cancelNextTick, + detectDirection: _detectDirection, + getChild: getChild +}; + + +/** + * Mount a plugin to Sortable + * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted + */ +Sortable.mount = function(...plugins) { + if (plugins[0].constructor === Array) plugins = plugins[0]; + + for (let i in plugins) { + let plugin = plugins[i]; + if (!plugin.prototype || !plugin.prototype.constructor) { + throw `Sortable: Mounted plugin must be a constructor function, not ${ {}.toString.call(el) }`; + } + if (plugin.utils) Sortable.utils = { ...Sortable.utils, ...plugin.utils }; + + PluginManager.mount(plugin); + } +}; + + + +/** + * Create sortable instance + * @param {HTMLElement} el + * @param {Object} [options] + */ +Sortable.create = function (el, options) { + return new Sortable(el, options); +}; + + +// Export +Sortable.version = version; + + +export default Sortable; diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 000000000..c2d04a23a --- /dev/null +++ b/src/utils.js @@ -0,0 +1,550 @@ +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 = ''; + 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; + /*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() { + if (IE11OrLess) { + return document.documentElement; + } else { + return document.scrollingElement; + } +} + + +/** + * 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 {[DOMRect]} rect Optional rect of `el` to use + * @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, rect, elSide, parentSide) { + let parent = getParentAutoScrollElement(el, true), + elSideVal = (rect ? rect : 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) { + for (let key in obj) { + if (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 +};