1/**!
2 * Sortable 1.10.2
3 * @author	RubaXa   <trash@rubaxa.org>
4 * @author	owenm    <owen23355@gmail.com>
5 * @license MIT
6 */
7function _typeof(obj) {
8  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
9    _typeof = function (obj) {
10      return typeof obj;
11    };
12  } else {
13    _typeof = function (obj) {
14      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
15    };
16  }
17
18  return _typeof(obj);
19}
20
21function _defineProperty(obj, key, value) {
22  if (key in obj) {
23    Object.defineProperty(obj, key, {
24      value: value,
25      enumerable: true,
26      configurable: true,
27      writable: true
28    });
29  } else {
30    obj[key] = value;
31  }
32
33  return obj;
34}
35
36function _extends() {
37  _extends = Object.assign || function (target) {
38    for (var i = 1; i < arguments.length; i++) {
39      var source = arguments[i];
40
41      for (var key in source) {
42        if (Object.prototype.hasOwnProperty.call(source, key)) {
43          target[key] = source[key];
44        }
45      }
46    }
47
48    return target;
49  };
50
51  return _extends.apply(this, arguments);
52}
53
54function _objectSpread(target) {
55  for (var i = 1; i < arguments.length; i++) {
56    var source = arguments[i] != null ? arguments[i] : {};
57    var ownKeys = Object.keys(source);
58
59    if (typeof Object.getOwnPropertySymbols === 'function') {
60      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
61        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
62      }));
63    }
64
65    ownKeys.forEach(function (key) {
66      _defineProperty(target, key, source[key]);
67    });
68  }
69
70  return target;
71}
72
73function _objectWithoutPropertiesLoose(source, excluded) {
74  if (source == null) return {};
75  var target = {};
76  var sourceKeys = Object.keys(source);
77  var key, i;
78
79  for (i = 0; i < sourceKeys.length; i++) {
80    key = sourceKeys[i];
81    if (excluded.indexOf(key) >= 0) continue;
82    target[key] = source[key];
83  }
84
85  return target;
86}
87
88function _objectWithoutProperties(source, excluded) {
89  if (source == null) return {};
90
91  var target = _objectWithoutPropertiesLoose(source, excluded);
92
93  var key, i;
94
95  if (Object.getOwnPropertySymbols) {
96    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
97
98    for (i = 0; i < sourceSymbolKeys.length; i++) {
99      key = sourceSymbolKeys[i];
100      if (excluded.indexOf(key) >= 0) continue;
101      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
102      target[key] = source[key];
103    }
104  }
105
106  return target;
107}
108
109function _toConsumableArray(arr) {
110  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
111}
112
113function _arrayWithoutHoles(arr) {
114  if (Array.isArray(arr)) {
115    for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
116
117    return arr2;
118  }
119}
120
121function _iterableToArray(iter) {
122  if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
123}
124
125function _nonIterableSpread() {
126  throw new TypeError("Invalid attempt to spread non-iterable instance");
127}
128
129var version = "1.10.2";
130
131function userAgent(pattern) {
132  if (typeof window !== 'undefined' && window.navigator) {
133    return !!
134    /*@__PURE__*/
135    navigator.userAgent.match(pattern);
136  }
137}
138
139var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
140var Edge = userAgent(/Edge/i);
141var FireFox = userAgent(/firefox/i);
142var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
143var IOS = userAgent(/iP(ad|od|hone)/i);
144var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
145
146var captureMode = {
147  capture: false,
148  passive: false
149};
150
151function on(el, event, fn) {
152  el.addEventListener(event, fn, !IE11OrLess && captureMode);
153}
154
155function off(el, event, fn) {
156  el.removeEventListener(event, fn, !IE11OrLess && captureMode);
157}
158
159function matches(
160/**HTMLElement*/
161el,
162/**String*/
163selector) {
164  if (!selector) return;
165  selector[0] === '>' && (selector = selector.substring(1));
166
167  if (el) {
168    try {
169      if (el.matches) {
170        return el.matches(selector);
171      } else if (el.msMatchesSelector) {
172        return el.msMatchesSelector(selector);
173      } else if (el.webkitMatchesSelector) {
174        return el.webkitMatchesSelector(selector);
175      }
176    } catch (_) {
177      return false;
178    }
179  }
180
181  return false;
182}
183
184function getParentOrHost(el) {
185  return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
186}
187
188function closest(
189/**HTMLElement*/
190el,
191/**String*/
192selector,
193/**HTMLElement*/
194ctx, includeCTX) {
195  if (el) {
196    ctx = ctx || document;
197
198    do {
199      if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
200        return el;
201      }
202
203      if (el === ctx) break;
204      /* jshint boss:true */
205    } while (el = getParentOrHost(el));
206  }
207
208  return null;
209}
210
211var R_SPACE = /\s+/g;
212
213function toggleClass(el, name, state) {
214  if (el && name) {
215    if (el.classList) {
216      el.classList[state ? 'add' : 'remove'](name);
217    } else {
218      var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
219      el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
220    }
221  }
222}
223
224function css(el, prop, val) {
225  var style = el && el.style;
226
227  if (style) {
228    if (val === void 0) {
229      if (document.defaultView && document.defaultView.getComputedStyle) {
230        val = document.defaultView.getComputedStyle(el, '');
231      } else if (el.currentStyle) {
232        val = el.currentStyle;
233      }
234
235      return prop === void 0 ? val : val[prop];
236    } else {
237      if (!(prop in style) && prop.indexOf('webkit') === -1) {
238        prop = '-webkit-' + prop;
239      }
240
241      style[prop] = val + (typeof val === 'string' ? '' : 'px');
242    }
243  }
244}
245
246function matrix(el, selfOnly) {
247  var appliedTransforms = '';
248
249  if (typeof el === 'string') {
250    appliedTransforms = el;
251  } else {
252    do {
253      var transform = css(el, 'transform');
254
255      if (transform && transform !== 'none') {
256        appliedTransforms = transform + ' ' + appliedTransforms;
257      }
258      /* jshint boss:true */
259
260    } while (!selfOnly && (el = el.parentNode));
261  }
262
263  var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
264  /*jshint -W056 */
265
266  return matrixFn && new matrixFn(appliedTransforms);
267}
268
269function find(ctx, tagName, iterator) {
270  if (ctx) {
271    var list = ctx.getElementsByTagName(tagName),
272        i = 0,
273        n = list.length;
274
275    if (iterator) {
276      for (; i < n; i++) {
277        iterator(list[i], i);
278      }
279    }
280
281    return list;
282  }
283
284  return [];
285}
286
287function getWindowScrollingElement() {
288  var scrollingElement = document.scrollingElement;
289
290  if (scrollingElement) {
291    return scrollingElement;
292  } else {
293    return document.documentElement;
294  }
295}
296/**
297 * Returns the "bounding client rect" of given element
298 * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
299 * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
300 * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
301 * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
302 * @param  {[HTMLElement]} container              The parent the element will be placed in
303 * @return {Object}                               The boundingClientRect of el, with specified adjustments
304 */
305
306
307function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
308  if (!el.getBoundingClientRect && el !== window) return;
309  var elRect, top, left, bottom, right, height, width;
310
311  if (el !== window && el !== getWindowScrollingElement()) {
312    elRect = el.getBoundingClientRect();
313    top = elRect.top;
314    left = elRect.left;
315    bottom = elRect.bottom;
316    right = elRect.right;
317    height = elRect.height;
318    width = elRect.width;
319  } else {
320    top = 0;
321    left = 0;
322    bottom = window.innerHeight;
323    right = window.innerWidth;
324    height = window.innerHeight;
325    width = window.innerWidth;
326  }
327
328  if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
329    // Adjust for translate()
330    container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
331    // Not needed on <= IE11
332
333    if (!IE11OrLess) {
334      do {
335        if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
336          var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
337
338          top -= containerRect.top + parseInt(css(container, 'border-top-width'));
339          left -= containerRect.left + parseInt(css(container, 'border-left-width'));
340          bottom = top + elRect.height;
341          right = left + elRect.width;
342          break;
343        }
344        /* jshint boss:true */
345
346      } while (container = container.parentNode);
347    }
348  }
349
350  if (undoScale && el !== window) {
351    // Adjust for scale()
352    var elMatrix = matrix(container || el),
353        scaleX = elMatrix && elMatrix.a,
354        scaleY = elMatrix && elMatrix.d;
355
356    if (elMatrix) {
357      top /= scaleY;
358      left /= scaleX;
359      width /= scaleX;
360      height /= scaleY;
361      bottom = top + height;
362      right = left + width;
363    }
364  }
365
366  return {
367    top: top,
368    left: left,
369    bottom: bottom,
370    right: right,
371    width: width,
372    height: height
373  };
374}
375/**
376 * Checks if a side of an element is scrolled past a side of its parents
377 * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
378 * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
379 * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
380 * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
381 */
382
383
384function isScrolledPast(el, elSide, parentSide) {
385  var parent = getParentAutoScrollElement(el, true),
386      elSideVal = getRect(el)[elSide];
387  /* jshint boss:true */
388
389  while (parent) {
390    var parentSideVal = getRect(parent)[parentSide],
391        visible = void 0;
392
393    if (parentSide === 'top' || parentSide === 'left') {
394      visible = elSideVal >= parentSideVal;
395    } else {
396      visible = elSideVal <= parentSideVal;
397    }
398
399    if (!visible) return parent;
400    if (parent === getWindowScrollingElement()) break;
401    parent = getParentAutoScrollElement(parent, false);
402  }
403
404  return false;
405}
406/**
407 * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
408 * and non-draggable elements
409 * @param  {HTMLElement} el       The parent element
410 * @param  {Number} childNum      The index of the child
411 * @param  {Object} options       Parent Sortable's options
412 * @return {HTMLElement}          The child at index childNum, or null if not found
413 */
414
415
416function getChild(el, childNum, options) {
417  var currentChild = 0,
418      i = 0,
419      children = el.children;
420
421  while (i < children.length) {
422    if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && children[i] !== Sortable.dragged && closest(children[i], options.draggable, el, false)) {
423      if (currentChild === childNum) {
424        return children[i];
425      }
426
427      currentChild++;
428    }
429
430    i++;
431  }
432
433  return null;
434}
435/**
436 * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
437 * @param  {HTMLElement} el       Parent element
438 * @param  {selector} selector    Any other elements that should be ignored
439 * @return {HTMLElement}          The last child, ignoring ghostEl
440 */
441
442
443function lastChild(el, selector) {
444  var last = el.lastElementChild;
445
446  while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
447    last = last.previousElementSibling;
448  }
449
450  return last || null;
451}
452/**
453 * Returns the index of an element within its parent for a selected set of
454 * elements
455 * @param  {HTMLElement} el
456 * @param  {selector} selector
457 * @return {number}
458 */
459
460
461function index(el, selector) {
462  var index = 0;
463
464  if (!el || !el.parentNode) {
465    return -1;
466  }
467  /* jshint boss:true */
468
469
470  while (el = el.previousElementSibling) {
471    if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
472      index++;
473    }
474  }
475
476  return index;
477}
478/**
479 * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
480 * The value is returned in real pixels.
481 * @param  {HTMLElement} el
482 * @return {Array}             Offsets in the format of [left, top]
483 */
484
485
486function getRelativeScrollOffset(el) {
487  var offsetLeft = 0,
488      offsetTop = 0,
489      winScroller = getWindowScrollingElement();
490
491  if (el) {
492    do {
493      var elMatrix = matrix(el),
494          scaleX = elMatrix.a,
495          scaleY = elMatrix.d;
496      offsetLeft += el.scrollLeft * scaleX;
497      offsetTop += el.scrollTop * scaleY;
498    } while (el !== winScroller && (el = el.parentNode));
499  }
500
501  return [offsetLeft, offsetTop];
502}
503/**
504 * Returns the index of the object within the given array
505 * @param  {Array} arr   Array that may or may not hold the object
506 * @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
507 * @return {Number}      The index of the object in the array, or -1
508 */
509
510
511function indexOfObject(arr, obj) {
512  for (var i in arr) {
513    if (!arr.hasOwnProperty(i)) continue;
514
515    for (var key in obj) {
516      if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
517    }
518  }
519
520  return -1;
521}
522
523function getParentAutoScrollElement(el, includeSelf) {
524  // skip to window
525  if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
526  var elem = el;
527  var gotSelf = false;
528
529  do {
530    // we don't need to get elem css if it isn't even overflowing in the first place (performance)
531    if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
532      var elemCSS = css(elem);
533
534      if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
535        if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
536        if (gotSelf || includeSelf) return elem;
537        gotSelf = true;
538      }
539    }
540    /* jshint boss:true */
541
542  } while (elem = elem.parentNode);
543
544  return getWindowScrollingElement();
545}
546
547function extend(dst, src) {
548  if (dst && src) {
549    for (var key in src) {
550      if (src.hasOwnProperty(key)) {
551        dst[key] = src[key];
552      }
553    }
554  }
555
556  return dst;
557}
558
559function isRectEqual(rect1, rect2) {
560  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);
561}
562
563var _throttleTimeout;
564
565function throttle(callback, ms) {
566  return function () {
567    if (!_throttleTimeout) {
568      var args = arguments,
569          _this = this;
570
571      if (args.length === 1) {
572        callback.call(_this, args[0]);
573      } else {
574        callback.apply(_this, args);
575      }
576
577      _throttleTimeout = setTimeout(function () {
578        _throttleTimeout = void 0;
579      }, ms);
580    }
581  };
582}
583
584function cancelThrottle() {
585  clearTimeout(_throttleTimeout);
586  _throttleTimeout = void 0;
587}
588
589function scrollBy(el, x, y) {
590  el.scrollLeft += x;
591  el.scrollTop += y;
592}
593
594function clone(el) {
595  var Polymer = window.Polymer;
596  var $ = window.jQuery || window.Zepto;
597
598  if (Polymer && Polymer.dom) {
599    return Polymer.dom(el).cloneNode(true);
600  } else if ($) {
601    return $(el).clone(true)[0];
602  } else {
603    return el.cloneNode(true);
604  }
605}
606
607function setRect(el, rect) {
608  css(el, 'position', 'absolute');
609  css(el, 'top', rect.top);
610  css(el, 'left', rect.left);
611  css(el, 'width', rect.width);
612  css(el, 'height', rect.height);
613}
614
615function unsetRect(el) {
616  css(el, 'position', '');
617  css(el, 'top', '');
618  css(el, 'left', '');
619  css(el, 'width', '');
620  css(el, 'height', '');
621}
622
623var expando = 'Sortable' + new Date().getTime();
624
625function AnimationStateManager() {
626  var animationStates = [],
627      animationCallbackId;
628  return {
629    captureAnimationState: function captureAnimationState() {
630      animationStates = [];
631      if (!this.options.animation) return;
632      var children = [].slice.call(this.el.children);
633      children.forEach(function (child) {
634        if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
635        animationStates.push({
636          target: child,
637          rect: getRect(child)
638        });
639
640        var fromRect = _objectSpread({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation
641
642
643        if (child.thisAnimationDuration) {
644          var childMatrix = matrix(child, true);
645
646          if (childMatrix) {
647            fromRect.top -= childMatrix.f;
648            fromRect.left -= childMatrix.e;
649          }
650        }
651
652        child.fromRect = fromRect;
653      });
654    },
655    addAnimationState: function addAnimationState(state) {
656      animationStates.push(state);
657    },
658    removeAnimationState: function removeAnimationState(target) {
659      animationStates.splice(indexOfObject(animationStates, {
660        target: target
661      }), 1);
662    },
663    animateAll: function animateAll(callback) {
664      var _this = this;
665
666      if (!this.options.animation) {
667        clearTimeout(animationCallbackId);
668        if (typeof callback === 'function') callback();
669        return;
670      }
671
672      var animating = false,
673          animationTime = 0;
674      animationStates.forEach(function (state) {
675        var time = 0,
676            target = state.target,
677            fromRect = target.fromRect,
678            toRect = getRect(target),
679            prevFromRect = target.prevFromRect,
680            prevToRect = target.prevToRect,
681            animatingRect = state.rect,
682            targetMatrix = matrix(target, true);
683
684        if (targetMatrix) {
685          // Compensate for current animation
686          toRect.top -= targetMatrix.f;
687          toRect.left -= targetMatrix.e;
688        }
689
690        target.toRect = toRect;
691
692        if (target.thisAnimationDuration) {
693          // Could also check if animatingRect is between fromRect and toRect
694          if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
695          (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
696            // If returning to same place as started from animation and on same axis
697            time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
698          }
699        } // if fromRect != toRect: animate
700
701
702        if (!isRectEqual(toRect, fromRect)) {
703          target.prevFromRect = fromRect;
704          target.prevToRect = toRect;
705
706          if (!time) {
707            time = _this.options.animation;
708          }
709
710          _this.animate(target, animatingRect, toRect, time);
711        }
712
713        if (time) {
714          animating = true;
715          animationTime = Math.max(animationTime, time);
716          clearTimeout(target.animationResetTimer);
717          target.animationResetTimer = setTimeout(function () {
718            target.animationTime = 0;
719            target.prevFromRect = null;
720            target.fromRect = null;
721            target.prevToRect = null;
722            target.thisAnimationDuration = null;
723          }, time);
724          target.thisAnimationDuration = time;
725        }
726      });
727      clearTimeout(animationCallbackId);
728
729      if (!animating) {
730        if (typeof callback === 'function') callback();
731      } else {
732        animationCallbackId = setTimeout(function () {
733          if (typeof callback === 'function') callback();
734        }, animationTime);
735      }
736
737      animationStates = [];
738    },
739    animate: function animate(target, currentRect, toRect, duration) {
740      if (duration) {
741        css(target, 'transition', '');
742        css(target, 'transform', '');
743        var elMatrix = matrix(this.el),
744            scaleX = elMatrix && elMatrix.a,
745            scaleY = elMatrix && elMatrix.d,
746            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
747            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
748        target.animatingX = !!translateX;
749        target.animatingY = !!translateY;
750        css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
751        repaint(target); // repaint
752
753        css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
754        css(target, 'transform', 'translate3d(0,0,0)');
755        typeof target.animated === 'number' && clearTimeout(target.animated);
756        target.animated = setTimeout(function () {
757          css(target, 'transition', '');
758          css(target, 'transform', '');
759          target.animated = false;
760          target.animatingX = false;
761          target.animatingY = false;
762        }, duration);
763      }
764    }
765  };
766}
767
768function repaint(target) {
769  return target.offsetWidth;
770}
771
772function calculateRealTime(animatingRect, fromRect, toRect, options) {
773  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;
774}
775
776var plugins = [];
777var defaults = {
778  initializeByDefault: true
779};
780var PluginManager = {
781  mount: function mount(plugin) {
782    // Set default static properties
783    for (var option in defaults) {
784      if (defaults.hasOwnProperty(option) && !(option in plugin)) {
785        plugin[option] = defaults[option];
786      }
787    }
788
789    plugins.push(plugin);
790  },
791  pluginEvent: function pluginEvent(eventName, sortable, evt) {
792    var _this = this;
793
794    this.eventCanceled = false;
795
796    evt.cancel = function () {
797      _this.eventCanceled = true;
798    };
799
800    var eventNameGlobal = eventName + 'Global';
801    plugins.forEach(function (plugin) {
802      if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
803
804      if (sortable[plugin.pluginName][eventNameGlobal]) {
805        sortable[plugin.pluginName][eventNameGlobal](_objectSpread({
806          sortable: sortable
807        }, evt));
808      } // Only fire plugin event if plugin is enabled in this sortable,
809      // and plugin has event defined
810
811
812      if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
813        sortable[plugin.pluginName][eventName](_objectSpread({
814          sortable: sortable
815        }, evt));
816      }
817    });
818  },
819  initializePlugins: function initializePlugins(sortable, el, defaults, options) {
820    plugins.forEach(function (plugin) {
821      var pluginName = plugin.pluginName;
822      if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
823      var initialized = new plugin(sortable, el, sortable.options);
824      initialized.sortable = sortable;
825      initialized.options = sortable.options;
826      sortable[pluginName] = initialized; // Add default options from plugin
827
828      _extends(defaults, initialized.defaults);
829    });
830
831    for (var option in sortable.options) {
832      if (!sortable.options.hasOwnProperty(option)) continue;
833      var modified = this.modifyOption(sortable, option, sortable.options[option]);
834
835      if (typeof modified !== 'undefined') {
836        sortable.options[option] = modified;
837      }
838    }
839  },
840  getEventProperties: function getEventProperties(name, sortable) {
841    var eventProperties = {};
842    plugins.forEach(function (plugin) {
843      if (typeof plugin.eventProperties !== 'function') return;
844
845      _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
846    });
847    return eventProperties;
848  },
849  modifyOption: function modifyOption(sortable, name, value) {
850    var modifiedValue;
851    plugins.forEach(function (plugin) {
852      // Plugin must exist on the Sortable
853      if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
854
855      if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
856        modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
857      }
858    });
859    return modifiedValue;
860  }
861};
862
863function dispatchEvent(_ref) {
864  var sortable = _ref.sortable,
865      rootEl = _ref.rootEl,
866      name = _ref.name,
867      targetEl = _ref.targetEl,
868      cloneEl = _ref.cloneEl,
869      toEl = _ref.toEl,
870      fromEl = _ref.fromEl,
871      oldIndex = _ref.oldIndex,
872      newIndex = _ref.newIndex,
873      oldDraggableIndex = _ref.oldDraggableIndex,
874      newDraggableIndex = _ref.newDraggableIndex,
875      originalEvent = _ref.originalEvent,
876      putSortable = _ref.putSortable,
877      extraEventProperties = _ref.extraEventProperties;
878  sortable = sortable || rootEl && rootEl[expando];
879  if (!sortable) return;
880  var evt,
881      options = sortable.options,
882      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
883
884  if (window.CustomEvent && !IE11OrLess && !Edge) {
885    evt = new CustomEvent(name, {
886      bubbles: true,
887      cancelable: true
888    });
889  } else {
890    evt = document.createEvent('Event');
891    evt.initEvent(name, true, true);
892  }
893
894  evt.to = toEl || rootEl;
895  evt.from = fromEl || rootEl;
896  evt.item = targetEl || rootEl;
897  evt.clone = cloneEl;
898  evt.oldIndex = oldIndex;
899  evt.newIndex = newIndex;
900  evt.oldDraggableIndex = oldDraggableIndex;
901  evt.newDraggableIndex = newDraggableIndex;
902  evt.originalEvent = originalEvent;
903  evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
904
905  var allEventProperties = _objectSpread({}, extraEventProperties, PluginManager.getEventProperties(name, sortable));
906
907  for (var option in allEventProperties) {
908    evt[option] = allEventProperties[option];
909  }
910
911  if (rootEl) {
912    rootEl.dispatchEvent(evt);
913  }
914
915  if (options[onName]) {
916    options[onName].call(sortable, evt);
917  }
918}
919
920var pluginEvent = function pluginEvent(eventName, sortable) {
921  var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
922      originalEvent = _ref.evt,
923      data = _objectWithoutProperties(_ref, ["evt"]);
924
925  PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread({
926    dragEl: dragEl,
927    parentEl: parentEl,
928    ghostEl: ghostEl,
929    rootEl: rootEl,
930    nextEl: nextEl,
931    lastDownEl: lastDownEl,
932    cloneEl: cloneEl,
933    cloneHidden: cloneHidden,
934    dragStarted: moved,
935    putSortable: putSortable,
936    activeSortable: Sortable.active,
937    originalEvent: originalEvent,
938    oldIndex: oldIndex,
939    oldDraggableIndex: oldDraggableIndex,
940    newIndex: newIndex,
941    newDraggableIndex: newDraggableIndex,
942    hideGhostForTarget: _hideGhostForTarget,
943    unhideGhostForTarget: _unhideGhostForTarget,
944    cloneNowHidden: function cloneNowHidden() {
945      cloneHidden = true;
946    },
947    cloneNowShown: function cloneNowShown() {
948      cloneHidden = false;
949    },
950    dispatchSortableEvent: function dispatchSortableEvent(name) {
951      _dispatchEvent({
952        sortable: sortable,
953        name: name,
954        originalEvent: originalEvent
955      });
956    }
957  }, data));
958};
959
960function _dispatchEvent(info) {
961  dispatchEvent(_objectSpread({
962    putSortable: putSortable,
963    cloneEl: cloneEl,
964    targetEl: dragEl,
965    rootEl: rootEl,
966    oldIndex: oldIndex,
967    oldDraggableIndex: oldDraggableIndex,
968    newIndex: newIndex,
969    newDraggableIndex: newDraggableIndex
970  }, info));
971}
972
973var dragEl,
974    parentEl,
975    ghostEl,
976    rootEl,
977    nextEl,
978    lastDownEl,
979    cloneEl,
980    cloneHidden,
981    oldIndex,
982    newIndex,
983    oldDraggableIndex,
984    newDraggableIndex,
985    activeGroup,
986    putSortable,
987    awaitingDragStarted = false,
988    ignoreNextClick = false,
989    sortables = [],
990    tapEvt,
991    touchEvt,
992    lastDx,
993    lastDy,
994    tapDistanceLeft,
995    tapDistanceTop,
996    moved,
997    lastTarget,
998    lastDirection,
999    pastFirstInvertThresh = false,
1000    isCircumstantialInvert = false,
1001    targetMoveDistance,
1002    // For positioning ghost absolutely
1003ghostRelativeParent,
1004    ghostRelativeParentInitialScroll = [],
1005    // (left, top)
1006_silent = false,
1007    savedInputChecked = [];
1008/** @const */
1009
1010var documentExists = typeof document !== 'undefined',
1011    PositionGhostAbsolutely = IOS,
1012    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
1013    // This will not pass for IE9, because IE9 DnD only works on anchors
1014supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
1015    supportCssPointerEvents = function () {
1016  if (!documentExists) return; // false when <= IE11
1017
1018  if (IE11OrLess) {
1019    return false;
1020  }
1021
1022  var el = document.createElement('x');
1023  el.style.cssText = 'pointer-events:auto';
1024  return el.style.pointerEvents === 'auto';
1025}(),
1026    _detectDirection = function _detectDirection(el, options) {
1027  var elCSS = css(el),
1028      elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
1029      child1 = getChild(el, 0, options),
1030      child2 = getChild(el, 1, options),
1031      firstChildCSS = child1 && css(child1),
1032      secondChildCSS = child2 && css(child2),
1033      firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
1034      secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
1035
1036  if (elCSS.display === 'flex') {
1037    return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
1038  }
1039
1040  if (elCSS.display === 'grid') {
1041    return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
1042  }
1043
1044  if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
1045    var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
1046    return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
1047  }
1048
1049  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';
1050},
1051    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
1052  var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
1053      dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
1054      dragElOppLength = vertical ? dragRect.width : dragRect.height,
1055      targetS1Opp = vertical ? targetRect.left : targetRect.top,
1056      targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
1057      targetOppLength = vertical ? targetRect.width : targetRect.height;
1058  return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
1059},
1060
1061/**
1062 * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
1063 * @param  {Number} x      X position
1064 * @param  {Number} y      Y position
1065 * @return {HTMLElement}   Element of the first found nearest Sortable
1066 */
1067_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
1068  var ret;
1069  sortables.some(function (sortable) {
1070    if (lastChild(sortable)) return;
1071    var rect = getRect(sortable),
1072        threshold = sortable[expando].options.emptyInsertThreshold,
1073        insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
1074        insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
1075
1076    if (threshold && insideHorizontally && insideVertically) {
1077      return ret = sortable;
1078    }
1079  });
1080  return ret;
1081},
1082    _prepareGroup = function _prepareGroup(options) {
1083  function toFn(value, pull) {
1084    return function (to, from, dragEl, evt) {
1085      var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
1086
1087      if (value == null && (pull || sameGroup)) {
1088        // Default pull value
1089        // Default pull and put value if same group
1090        return true;
1091      } else if (value == null || value === false) {
1092        return false;
1093      } else if (pull && value === 'clone') {
1094        return value;
1095      } else if (typeof value === 'function') {
1096        return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
1097      } else {
1098        var otherGroup = (pull ? to : from).options.group.name;
1099        return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
1100      }
1101    };
1102  }
1103
1104  var group = {};
1105  var originalGroup = options.group;
1106
1107  if (!originalGroup || _typeof(originalGroup) != 'object') {
1108    originalGroup = {
1109      name: originalGroup
1110    };
1111  }
1112
1113  group.name = originalGroup.name;
1114  group.checkPull = toFn(originalGroup.pull, true);
1115  group.checkPut = toFn(originalGroup.put);
1116  group.revertClone = originalGroup.revertClone;
1117  options.group = group;
1118},
1119    _hideGhostForTarget = function _hideGhostForTarget() {
1120  if (!supportCssPointerEvents && ghostEl) {
1121    css(ghostEl, 'display', 'none');
1122  }
1123},
1124    _unhideGhostForTarget = function _unhideGhostForTarget() {
1125  if (!supportCssPointerEvents && ghostEl) {
1126    css(ghostEl, 'display', '');
1127  }
1128}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
1129
1130
1131if (documentExists) {
1132  document.addEventListener('click', function (evt) {
1133    if (ignoreNextClick) {
1134      evt.preventDefault();
1135      evt.stopPropagation && evt.stopPropagation();
1136      evt.stopImmediatePropagation && evt.stopImmediatePropagation();
1137      ignoreNextClick = false;
1138      return false;
1139    }
1140  }, true);
1141}
1142
1143var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
1144  if (dragEl) {
1145    evt = evt.touches ? evt.touches[0] : evt;
1146
1147    var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
1148
1149    if (nearest) {
1150      // Create imitation event
1151      var event = {};
1152
1153      for (var i in evt) {
1154        if (evt.hasOwnProperty(i)) {
1155          event[i] = evt[i];
1156        }
1157      }
1158
1159      event.target = event.rootEl = nearest;
1160      event.preventDefault = void 0;
1161      event.stopPropagation = void 0;
1162
1163      nearest[expando]._onDragOver(event);
1164    }
1165  }
1166};
1167
1168var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
1169  if (dragEl) {
1170    dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
1171  }
1172};
1173/**
1174 * @class  Sortable
1175 * @param  {HTMLElement}  el
1176 * @param  {Object}       [options]
1177 */
1178
1179
1180function Sortable(el, options) {
1181  if (!(el && el.nodeType && el.nodeType === 1)) {
1182    throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
1183  }
1184
1185  this.el = el; // root element
1186
1187  this.options = options = _extends({}, options); // Export instance
1188
1189  el[expando] = this;
1190  var defaults = {
1191    group: null,
1192    sort: true,
1193    disabled: false,
1194    store: null,
1195    handle: null,
1196    draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
1197    swapThreshold: 1,
1198    // percentage; 0 <= x <= 1
1199    invertSwap: false,
1200    // invert always
1201    invertedSwapThreshold: null,
1202    // will be set to same as swapThreshold if default
1203    removeCloneOnHide: true,
1204    direction: function direction() {
1205      return _detectDirection(el, this.options);
1206    },
1207    ghostClass: 'sortable-ghost',
1208    chosenClass: 'sortable-chosen',
1209    dragClass: 'sortable-drag',
1210    ignore: 'a, img',
1211    filter: null,
1212    preventOnFilter: true,
1213    animation: 0,
1214    easing: null,
1215    setData: function setData(dataTransfer, dragEl) {
1216      dataTransfer.setData('Text', dragEl.textContent);
1217    },
1218    dropBubble: false,
1219    dragoverBubble: false,
1220    dataIdAttr: 'data-id',
1221    delay: 0,
1222    delayOnTouchOnly: false,
1223    touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
1224    forceFallback: false,
1225    fallbackClass: 'sortable-fallback',
1226    fallbackOnBody: false,
1227    fallbackTolerance: 0,
1228    fallbackOffset: {
1229      x: 0,
1230      y: 0
1231    },
1232    supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window,
1233    emptyInsertThreshold: 5
1234  };
1235  PluginManager.initializePlugins(this, el, defaults); // Set default options
1236
1237  for (var name in defaults) {
1238    !(name in options) && (options[name] = defaults[name]);
1239  }
1240
1241  _prepareGroup(options); // Bind all private methods
1242
1243
1244  for (var fn in this) {
1245    if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
1246      this[fn] = this[fn].bind(this);
1247    }
1248  } // Setup drag mode
1249
1250
1251  this.nativeDraggable = options.forceFallback ? false : supportDraggable;
1252
1253  if (this.nativeDraggable) {
1254    // Touch start threshold cannot be greater than the native dragstart threshold
1255    this.options.touchStartThreshold = 1;
1256  } // Bind events
1257
1258
1259  if (options.supportPointer) {
1260    on(el, 'pointerdown', this._onTapStart);
1261  } else {
1262    on(el, 'mousedown', this._onTapStart);
1263    on(el, 'touchstart', this._onTapStart);
1264  }
1265
1266  if (this.nativeDraggable) {
1267    on(el, 'dragover', this);
1268    on(el, 'dragenter', this);
1269  }
1270
1271  sortables.push(this.el); // Restore sorting
1272
1273  options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
1274
1275  _extends(this, AnimationStateManager());
1276}
1277
1278Sortable.prototype =
1279/** @lends Sortable.prototype */
1280{
1281  constructor: Sortable,
1282  _isOutsideThisEl: function _isOutsideThisEl(target) {
1283    if (!this.el.contains(target) && target !== this.el) {
1284      lastTarget = null;
1285    }
1286  },
1287  _getDirection: function _getDirection(evt, target) {
1288    return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
1289  },
1290  _onTapStart: function _onTapStart(
1291  /** Event|TouchEvent */
1292  evt) {
1293    if (!evt.cancelable) return;
1294
1295    var _this = this,
1296        el = this.el,
1297        options = this.options,
1298        preventOnFilter = options.preventOnFilter,
1299        type = evt.type,
1300        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
1301        target = (touch || evt).target,
1302        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
1303        filter = options.filter;
1304
1305    _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
1306
1307
1308    if (dragEl) {
1309      return;
1310    }
1311
1312    if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
1313      return; // only left button and enabled
1314    } // cancel dnd if original target is content editable
1315
1316
1317    if (originalTarget.isContentEditable) {
1318      return;
1319    }
1320
1321    target = closest(target, options.draggable, el, false);
1322
1323    if (target && target.animated) {
1324      return;
1325    }
1326
1327    if (lastDownEl === target) {
1328      // Ignoring duplicate `down`
1329      return;
1330    } // Get the index of the dragged element within its parent
1331
1332
1333    oldIndex = index(target);
1334    oldDraggableIndex = index(target, options.draggable); // Check filter
1335
1336    if (typeof filter === 'function') {
1337      if (filter.call(this, evt, target, this)) {
1338        _dispatchEvent({
1339          sortable: _this,
1340          rootEl: originalTarget,
1341          name: 'filter',
1342          targetEl: target,
1343          toEl: el,
1344          fromEl: el
1345        });
1346
1347        pluginEvent('filter', _this, {
1348          evt: evt
1349        });
1350        preventOnFilter && evt.cancelable && evt.preventDefault();
1351        return; // cancel dnd
1352      }
1353    } else if (filter) {
1354      filter = filter.split(',').some(function (criteria) {
1355        criteria = closest(originalTarget, criteria.trim(), el, false);
1356
1357        if (criteria) {
1358          _dispatchEvent({
1359            sortable: _this,
1360            rootEl: criteria,
1361            name: 'filter',
1362            targetEl: target,
1363            fromEl: el,
1364            toEl: el
1365          });
1366
1367          pluginEvent('filter', _this, {
1368            evt: evt
1369          });
1370          return true;
1371        }
1372      });
1373
1374      if (filter) {
1375        preventOnFilter && evt.cancelable && evt.preventDefault();
1376        return; // cancel dnd
1377      }
1378    }
1379
1380    if (options.handle && !closest(originalTarget, options.handle, el, false)) {
1381      return;
1382    } // Prepare `dragstart`
1383
1384
1385    this._prepareDragStart(evt, touch, target);
1386  },
1387  _prepareDragStart: function _prepareDragStart(
1388  /** Event */
1389  evt,
1390  /** Touch */
1391  touch,
1392  /** HTMLElement */
1393  target) {
1394    var _this = this,
1395        el = _this.el,
1396        options = _this.options,
1397        ownerDocument = el.ownerDocument,
1398        dragStartFn;
1399
1400    if (target && !dragEl && target.parentNode === el) {
1401      var dragRect = getRect(target);
1402      rootEl = el;
1403      dragEl = target;
1404      parentEl = dragEl.parentNode;
1405      nextEl = dragEl.nextSibling;
1406      lastDownEl = target;
1407      activeGroup = options.group;
1408      Sortable.dragged = dragEl;
1409      tapEvt = {
1410        target: dragEl,
1411        clientX: (touch || evt).clientX,
1412        clientY: (touch || evt).clientY
1413      };
1414      tapDistanceLeft = tapEvt.clientX - dragRect.left;
1415      tapDistanceTop = tapEvt.clientY - dragRect.top;
1416      this._lastX = (touch || evt).clientX;
1417      this._lastY = (touch || evt).clientY;
1418      dragEl.style['will-change'] = 'all';
1419
1420      dragStartFn = function dragStartFn() {
1421        pluginEvent('delayEnded', _this, {
1422          evt: evt
1423        });
1424
1425        if (Sortable.eventCanceled) {
1426          _this._onDrop();
1427
1428          return;
1429        } // Delayed drag has been triggered
1430        // we can re-enable the events: touchmove/mousemove
1431
1432
1433        _this._disableDelayedDragEvents();
1434
1435        if (!FireFox && _this.nativeDraggable) {
1436          dragEl.draggable = true;
1437        } // Bind the events: dragstart/dragend
1438
1439
1440        _this._triggerDragStart(evt, touch); // Drag start event
1441
1442
1443        _dispatchEvent({
1444          sortable: _this,
1445          name: 'choose',
1446          originalEvent: evt
1447        }); // Chosen item
1448
1449
1450        toggleClass(dragEl, options.chosenClass, true);
1451      }; // Disable "draggable"
1452
1453
1454      options.ignore.split(',').forEach(function (criteria) {
1455        find(dragEl, criteria.trim(), _disableDraggable);
1456      });
1457      on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
1458      on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
1459      on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
1460      on(ownerDocument, 'mouseup', _this._onDrop);
1461      on(ownerDocument, 'touchend', _this._onDrop);
1462      on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
1463
1464      if (FireFox && this.nativeDraggable) {
1465        this.options.touchStartThreshold = 4;
1466        dragEl.draggable = true;
1467      }
1468
1469      pluginEvent('delayStart', this, {
1470        evt: evt
1471      }); // Delay is impossible for native DnD in Edge or IE
1472
1473      if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
1474        if (Sortable.eventCanceled) {
1475          this._onDrop();
1476
1477          return;
1478        } // If the user moves the pointer or let go the click or touch
1479        // before the delay has been reached:
1480        // disable the delayed drag
1481
1482
1483        on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
1484        on(ownerDocument, 'touchend', _this._disableDelayedDrag);
1485        on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
1486        on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
1487        on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
1488        options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
1489        _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
1490      } else {
1491        dragStartFn();
1492      }
1493    }
1494  },
1495  _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
1496  /** TouchEvent|PointerEvent **/
1497  e) {
1498    var touch = e.touches ? e.touches[0] : e;
1499
1500    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))) {
1501      this._disableDelayedDrag();
1502    }
1503  },
1504  _disableDelayedDrag: function _disableDelayedDrag() {
1505    dragEl && _disableDraggable(dragEl);
1506    clearTimeout(this._dragStartTimer);
1507
1508    this._disableDelayedDragEvents();
1509  },
1510  _disableDelayedDragEvents: function _disableDelayedDragEvents() {
1511    var ownerDocument = this.el.ownerDocument;
1512    off(ownerDocument, 'mouseup', this._disableDelayedDrag);
1513    off(ownerDocument, 'touchend', this._disableDelayedDrag);
1514    off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
1515    off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
1516    off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
1517    off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
1518  },
1519  _triggerDragStart: function _triggerDragStart(
1520  /** Event */
1521  evt,
1522  /** Touch */
1523  touch) {
1524    touch = touch || evt.pointerType == 'touch' && evt;
1525
1526    if (!this.nativeDraggable || touch) {
1527      if (this.options.supportPointer) {
1528        on(document, 'pointermove', this._onTouchMove);
1529      } else if (touch) {
1530        on(document, 'touchmove', this._onTouchMove);
1531      } else {
1532        on(document, 'mousemove', this._onTouchMove);
1533      }
1534    } else {
1535      on(dragEl, 'dragend', this);
1536      on(rootEl, 'dragstart', this._onDragStart);
1537    }
1538
1539    try {
1540      if (document.selection) {
1541        // Timeout neccessary for IE9
1542        _nextTick(function () {
1543          document.selection.empty();
1544        });
1545      } else {
1546        window.getSelection().removeAllRanges();
1547      }
1548    } catch (err) {}
1549  },
1550  _dragStarted: function _dragStarted(fallback, evt) {
1551
1552    awaitingDragStarted = false;
1553
1554    if (rootEl && dragEl) {
1555      pluginEvent('dragStarted', this, {
1556        evt: evt
1557      });
1558
1559      if (this.nativeDraggable) {
1560        on(document, 'dragover', _checkOutsideTargetEl);
1561      }
1562
1563      var options = this.options; // Apply effect
1564
1565      !fallback && toggleClass(dragEl, options.dragClass, false);
1566      toggleClass(dragEl, options.ghostClass, true);
1567      Sortable.active = this;
1568      fallback && this._appendGhost(); // Drag start event
1569
1570      _dispatchEvent({
1571        sortable: this,
1572        name: 'start',
1573        originalEvent: evt
1574      });
1575    } else {
1576      this._nulling();
1577    }
1578  },
1579  _emulateDragOver: function _emulateDragOver() {
1580    if (touchEvt) {
1581      this._lastX = touchEvt.clientX;
1582      this._lastY = touchEvt.clientY;
1583
1584      _hideGhostForTarget();
1585
1586      var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
1587      var parent = target;
1588
1589      while (target && target.shadowRoot) {
1590        target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
1591        if (target === parent) break;
1592        parent = target;
1593      }
1594
1595      dragEl.parentNode[expando]._isOutsideThisEl(target);
1596
1597      if (parent) {
1598        do {
1599          if (parent[expando]) {
1600            var inserted = void 0;
1601            inserted = parent[expando]._onDragOver({
1602              clientX: touchEvt.clientX,
1603              clientY: touchEvt.clientY,
1604              target: target,
1605              rootEl: parent
1606            });
1607
1608            if (inserted && !this.options.dragoverBubble) {
1609              break;
1610            }
1611          }
1612
1613          target = parent; // store last element
1614        }
1615        /* jshint boss:true */
1616        while (parent = parent.parentNode);
1617      }
1618
1619      _unhideGhostForTarget();
1620    }
1621  },
1622  _onTouchMove: function _onTouchMove(
1623  /**TouchEvent*/
1624  evt) {
1625    if (tapEvt) {
1626      var options = this.options,
1627          fallbackTolerance = options.fallbackTolerance,
1628          fallbackOffset = options.fallbackOffset,
1629          touch = evt.touches ? evt.touches[0] : evt,
1630          ghostMatrix = ghostEl && matrix(ghostEl, true),
1631          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
1632          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
1633          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
1634          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
1635          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging
1636
1637      if (!Sortable.active && !awaitingDragStarted) {
1638        if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
1639          return;
1640        }
1641
1642        this._onDragStart(evt, true);
1643      }
1644
1645      if (ghostEl) {
1646        if (ghostMatrix) {
1647          ghostMatrix.e += dx - (lastDx || 0);
1648          ghostMatrix.f += dy - (lastDy || 0);
1649        } else {
1650          ghostMatrix = {
1651            a: 1,
1652            b: 0,
1653            c: 0,
1654            d: 1,
1655            e: dx,
1656            f: dy
1657          };
1658        }
1659
1660        var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
1661        css(ghostEl, 'webkitTransform', cssMatrix);
1662        css(ghostEl, 'mozTransform', cssMatrix);
1663        css(ghostEl, 'msTransform', cssMatrix);
1664        css(ghostEl, 'transform', cssMatrix);
1665        lastDx = dx;
1666        lastDy = dy;
1667        touchEvt = touch;
1668      }
1669
1670      evt.cancelable && evt.preventDefault();
1671    }
1672  },
1673  _appendGhost: function _appendGhost() {
1674    // Bug if using scale(): https://stackoverflow.com/questions/2637058
1675    // Not being adjusted for
1676    if (!ghostEl) {
1677      var container = this.options.fallbackOnBody ? document.body : rootEl,
1678          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
1679          options = this.options; // Position absolutely
1680
1681      if (PositionGhostAbsolutely) {
1682        // Get relatively positioned parent
1683        ghostRelativeParent = container;
1684
1685        while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
1686          ghostRelativeParent = ghostRelativeParent.parentNode;
1687        }
1688
1689        if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
1690          if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
1691          rect.top += ghostRelativeParent.scrollTop;
1692          rect.left += ghostRelativeParent.scrollLeft;
1693        } else {
1694          ghostRelativeParent = getWindowScrollingElement();
1695        }
1696
1697        ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
1698      }
1699
1700      ghostEl = dragEl.cloneNode(true);
1701      toggleClass(ghostEl, options.ghostClass, false);
1702      toggleClass(ghostEl, options.fallbackClass, true);
1703      toggleClass(ghostEl, options.dragClass, true);
1704      css(ghostEl, 'transition', '');
1705      css(ghostEl, 'transform', '');
1706      css(ghostEl, 'box-sizing', 'border-box');
1707      css(ghostEl, 'margin', 0);
1708      css(ghostEl, 'top', rect.top);
1709      css(ghostEl, 'left', rect.left);
1710      css(ghostEl, 'width', rect.width);
1711      css(ghostEl, 'height', rect.height);
1712      css(ghostEl, 'opacity', '0.8');
1713      css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
1714      css(ghostEl, 'zIndex', '100000');
1715      css(ghostEl, 'pointerEvents', 'none');
1716      Sortable.ghost = ghostEl;
1717      container.appendChild(ghostEl); // Set transform-origin
1718
1719      css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
1720    }
1721  },
1722  _onDragStart: function _onDragStart(
1723  /**Event*/
1724  evt,
1725  /**boolean*/
1726  fallback) {
1727    var _this = this;
1728
1729    var dataTransfer = evt.dataTransfer;
1730    var options = _this.options;
1731    pluginEvent('dragStart', this, {
1732      evt: evt
1733    });
1734
1735    if (Sortable.eventCanceled) {
1736      this._onDrop();
1737
1738      return;
1739    }
1740
1741    pluginEvent('setupClone', this);
1742
1743    if (!Sortable.eventCanceled) {
1744      cloneEl = clone(dragEl);
1745      cloneEl.draggable = false;
1746      cloneEl.style['will-change'] = '';
1747
1748      this._hideClone();
1749
1750      toggleClass(cloneEl, this.options.chosenClass, false);
1751      Sortable.clone = cloneEl;
1752    } // #1143: IFrame support workaround
1753
1754
1755    _this.cloneId = _nextTick(function () {
1756      pluginEvent('clone', _this);
1757      if (Sortable.eventCanceled) return;
1758
1759      if (!_this.options.removeCloneOnHide) {
1760        rootEl.insertBefore(cloneEl, dragEl);
1761      }
1762
1763      _this._hideClone();
1764
1765      _dispatchEvent({
1766        sortable: _this,
1767        name: 'clone'
1768      });
1769    });
1770    !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
1771
1772    if (fallback) {
1773      ignoreNextClick = true;
1774      _this._loopId = setInterval(_this._emulateDragOver, 50);
1775    } else {
1776      // Undo what was set in _prepareDragStart before drag started
1777      off(document, 'mouseup', _this._onDrop);
1778      off(document, 'touchend', _this._onDrop);
1779      off(document, 'touchcancel', _this._onDrop);
1780
1781      if (dataTransfer) {
1782        dataTransfer.effectAllowed = 'move';
1783        options.setData && options.setData.call(_this, dataTransfer, dragEl);
1784      }
1785
1786      on(document, 'drop', _this); // #1276 fix:
1787
1788      css(dragEl, 'transform', 'translateZ(0)');
1789    }
1790
1791    awaitingDragStarted = true;
1792    _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
1793    on(document, 'selectstart', _this);
1794    moved = true;
1795
1796    if (Safari) {
1797      css(document.body, 'user-select', 'none');
1798    }
1799  },
1800  // Returns true - if no further action is needed (either inserted or another condition)
1801  _onDragOver: function _onDragOver(
1802  /**Event*/
1803  evt) {
1804    var el = this.el,
1805        target = evt.target,
1806        dragRect,
1807        targetRect,
1808        revert,
1809        options = this.options,
1810        group = options.group,
1811        activeSortable = Sortable.active,
1812        isOwner = activeGroup === group,
1813        canSort = options.sort,
1814        fromSortable = putSortable || activeSortable,
1815        vertical,
1816        _this = this,
1817        completedFired = false;
1818
1819    if (_silent) return;
1820
1821    function dragOverEvent(name, extra) {
1822      pluginEvent(name, _this, _objectSpread({
1823        evt: evt,
1824        isOwner: isOwner,
1825        axis: vertical ? 'vertical' : 'horizontal',
1826        revert: revert,
1827        dragRect: dragRect,
1828        targetRect: targetRect,
1829        canSort: canSort,
1830        fromSortable: fromSortable,
1831        target: target,
1832        completed: completed,
1833        onMove: function onMove(target, after) {
1834          return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
1835        },
1836        changed: changed
1837      }, extra));
1838    } // Capture animation state
1839
1840
1841    function capture() {
1842      dragOverEvent('dragOverAnimationCapture');
1843
1844      _this.captureAnimationState();
1845
1846      if (_this !== fromSortable) {
1847        fromSortable.captureAnimationState();
1848      }
1849    } // Return invocation when dragEl is inserted (or completed)
1850
1851
1852    function completed(insertion) {
1853      dragOverEvent('dragOverCompleted', {
1854        insertion: insertion
1855      });
1856
1857      if (insertion) {
1858        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
1859        if (isOwner) {
1860          activeSortable._hideClone();
1861        } else {
1862          activeSortable._showClone(_this);
1863        }
1864
1865        if (_this !== fromSortable) {
1866          // Set ghost class to new sortable's ghost class
1867          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
1868          toggleClass(dragEl, options.ghostClass, true);
1869        }
1870
1871        if (putSortable !== _this && _this !== Sortable.active) {
1872          putSortable = _this;
1873        } else if (_this === Sortable.active && putSortable) {
1874          putSortable = null;
1875        } // Animation
1876
1877
1878        if (fromSortable === _this) {
1879          _this._ignoreWhileAnimating = target;
1880        }
1881
1882        _this.animateAll(function () {
1883          dragOverEvent('dragOverAnimationComplete');
1884          _this._ignoreWhileAnimating = null;
1885        });
1886
1887        if (_this !== fromSortable) {
1888          fromSortable.animateAll();
1889          fromSortable._ignoreWhileAnimating = null;
1890        }
1891      } // Null lastTarget if it is not inside a previously swapped element
1892
1893
1894      if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
1895        lastTarget = null;
1896      } // no bubbling and not fallback
1897
1898
1899      if (!options.dragoverBubble && !evt.rootEl && target !== document) {
1900        dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
1901
1902
1903        !insertion && nearestEmptyInsertDetectEvent(evt);
1904      }
1905
1906      !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
1907      return completedFired = true;
1908    } // Call when dragEl has been inserted
1909
1910
1911    function changed() {
1912      newIndex = index(dragEl);
1913      newDraggableIndex = index(dragEl, options.draggable);
1914
1915      _dispatchEvent({
1916        sortable: _this,
1917        name: 'change',
1918        toEl: el,
1919        newIndex: newIndex,
1920        newDraggableIndex: newDraggableIndex,
1921        originalEvent: evt
1922      });
1923    }
1924
1925    if (evt.preventDefault !== void 0) {
1926      evt.cancelable && evt.preventDefault();
1927    }
1928
1929    target = closest(target, options.draggable, el, true);
1930    dragOverEvent('dragOver');
1931    if (Sortable.eventCanceled) return completedFired;
1932
1933    if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
1934      return completed(false);
1935    }
1936
1937    ignoreNextClick = false;
1938
1939    if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
1940    : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
1941      vertical = this._getDirection(evt, target) === 'vertical';
1942      dragRect = getRect(dragEl);
1943      dragOverEvent('dragOverValid');
1944      if (Sortable.eventCanceled) return completedFired;
1945
1946      if (revert) {
1947        parentEl = rootEl; // actualization
1948
1949        capture();
1950
1951        this._hideClone();
1952
1953        dragOverEvent('revert');
1954
1955        if (!Sortable.eventCanceled) {
1956          if (nextEl) {
1957            rootEl.insertBefore(dragEl, nextEl);
1958          } else {
1959            rootEl.appendChild(dragEl);
1960          }
1961        }
1962
1963        return completed(true);
1964      }
1965
1966      var elLastChild = lastChild(el, options.draggable);
1967
1968      if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
1969        // If already at end of list: Do not insert
1970        if (elLastChild === dragEl) {
1971          return completed(false);
1972        } // assign target only if condition is true
1973
1974
1975        if (elLastChild && el === evt.target) {
1976          target = elLastChild;
1977        }
1978
1979        if (target) {
1980          targetRect = getRect(target);
1981        }
1982
1983        if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
1984          capture();
1985          el.appendChild(dragEl);
1986          parentEl = el; // actualization
1987
1988          changed();
1989          return completed(true);
1990        }
1991      } else if (target.parentNode === el) {
1992        targetRect = getRect(target);
1993        var direction = 0,
1994            targetBeforeFirstSwap,
1995            differentLevel = dragEl.parentNode !== el,
1996            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
1997            side1 = vertical ? 'top' : 'left',
1998            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
1999            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
2000
2001        if (lastTarget !== target) {
2002          targetBeforeFirstSwap = targetRect[side1];
2003          pastFirstInvertThresh = false;
2004          isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
2005        }
2006
2007        direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
2008        var sibling;
2009
2010        if (direction !== 0) {
2011          // Check if target is beside dragEl in respective direction (ignoring hidden elements)
2012          var dragIndex = index(dragEl);
2013
2014          do {
2015            dragIndex -= direction;
2016            sibling = parentEl.children[dragIndex];
2017          } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
2018        } // If dragEl is already beside target: Do not insert
2019
2020
2021        if (direction === 0 || sibling === target) {
2022          return completed(false);
2023        }
2024
2025        lastTarget = target;
2026        lastDirection = direction;
2027        var nextSibling = target.nextElementSibling,
2028            after = false;
2029        after = direction === 1;
2030
2031        var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
2032
2033        if (moveVector !== false) {
2034          if (moveVector === 1 || moveVector === -1) {
2035            after = moveVector === 1;
2036          }
2037
2038          _silent = true;
2039          setTimeout(_unsilent, 30);
2040          capture();
2041
2042          if (after && !nextSibling) {
2043            el.appendChild(dragEl);
2044          } else {
2045            target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
2046          } // Undo chrome's scroll adjustment (has no effect on other browsers)
2047
2048
2049          if (scrolledPastTop) {
2050            scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
2051          }
2052
2053          parentEl = dragEl.parentNode; // actualization
2054          // must be done before animation
2055
2056          if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
2057            targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
2058          }
2059
2060          changed();
2061          return completed(true);
2062        }
2063      }
2064
2065      if (el.contains(dragEl)) {
2066        return completed(false);
2067      }
2068    }
2069
2070    return false;
2071  },
2072  _ignoreWhileAnimating: null,
2073  _offMoveEvents: function _offMoveEvents() {
2074    off(document, 'mousemove', this._onTouchMove);
2075    off(document, 'touchmove', this._onTouchMove);
2076    off(document, 'pointermove', this._onTouchMove);
2077    off(document, 'dragover', nearestEmptyInsertDetectEvent);
2078    off(document, 'mousemove', nearestEmptyInsertDetectEvent);
2079    off(document, 'touchmove', nearestEmptyInsertDetectEvent);
2080  },
2081  _offUpEvents: function _offUpEvents() {
2082    var ownerDocument = this.el.ownerDocument;
2083    off(ownerDocument, 'mouseup', this._onDrop);
2084    off(ownerDocument, 'touchend', this._onDrop);
2085    off(ownerDocument, 'pointerup', this._onDrop);
2086    off(ownerDocument, 'touchcancel', this._onDrop);
2087    off(document, 'selectstart', this);
2088  },
2089  _onDrop: function _onDrop(
2090  /**Event*/
2091  evt) {
2092    var el = this.el,
2093        options = this.options; // Get the index of the dragged element within its parent
2094
2095    newIndex = index(dragEl);
2096    newDraggableIndex = index(dragEl, options.draggable);
2097    pluginEvent('drop', this, {
2098      evt: evt
2099    });
2100    parentEl = dragEl && dragEl.parentNode; // Get again after plugin event
2101
2102    newIndex = index(dragEl);
2103    newDraggableIndex = index(dragEl, options.draggable);
2104
2105    if (Sortable.eventCanceled) {
2106      this._nulling();
2107
2108      return;
2109    }
2110
2111    awaitingDragStarted = false;
2112    isCircumstantialInvert = false;
2113    pastFirstInvertThresh = false;
2114    clearInterval(this._loopId);
2115    clearTimeout(this._dragStartTimer);
2116
2117    _cancelNextTick(this.cloneId);
2118
2119    _cancelNextTick(this._dragStartId); // Unbind events
2120
2121
2122    if (this.nativeDraggable) {
2123      off(document, 'drop', this);
2124      off(el, 'dragstart', this._onDragStart);
2125    }
2126
2127    this._offMoveEvents();
2128
2129    this._offUpEvents();
2130
2131    if (Safari) {
2132      css(document.body, 'user-select', '');
2133    }
2134
2135    css(dragEl, 'transform', '');
2136
2137    if (evt) {
2138      if (moved) {
2139        evt.cancelable && evt.preventDefault();
2140        !options.dropBubble && evt.stopPropagation();
2141      }
2142
2143      ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
2144
2145      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
2146        // Remove clone(s)
2147        cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
2148      }
2149
2150      if (dragEl) {
2151        if (this.nativeDraggable) {
2152          off(dragEl, 'dragend', this);
2153        }
2154
2155        _disableDraggable(dragEl);
2156
2157        dragEl.style['will-change'] = ''; // Remove classes
2158        // ghostClass is added in dragStarted
2159
2160        if (moved && !awaitingDragStarted) {
2161          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
2162        }
2163
2164        toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
2165
2166        _dispatchEvent({
2167          sortable: this,
2168          name: 'unchoose',
2169          toEl: parentEl,
2170          newIndex: null,
2171          newDraggableIndex: null,
2172          originalEvent: evt
2173        });
2174
2175        if (rootEl !== parentEl) {
2176          if (newIndex >= 0) {
2177            // Add event
2178            _dispatchEvent({
2179              rootEl: parentEl,
2180              name: 'add',
2181              toEl: parentEl,
2182              fromEl: rootEl,
2183              originalEvent: evt
2184            }); // Remove event
2185
2186
2187            _dispatchEvent({
2188              sortable: this,
2189              name: 'remove',
2190              toEl: parentEl,
2191              originalEvent: evt
2192            }); // drag from one list and drop into another
2193
2194
2195            _dispatchEvent({
2196              rootEl: parentEl,
2197              name: 'sort',
2198              toEl: parentEl,
2199              fromEl: rootEl,
2200              originalEvent: evt
2201            });
2202
2203            _dispatchEvent({
2204              sortable: this,
2205              name: 'sort',
2206              toEl: parentEl,
2207              originalEvent: evt
2208            });
2209          }
2210
2211          putSortable && putSortable.save();
2212        } else {
2213          if (newIndex !== oldIndex) {
2214            if (newIndex >= 0) {
2215              // drag & drop within the same list
2216              _dispatchEvent({
2217                sortable: this,
2218                name: 'update',
2219                toEl: parentEl,
2220                originalEvent: evt
2221              });
2222
2223              _dispatchEvent({
2224                sortable: this,
2225                name: 'sort',
2226                toEl: parentEl,
2227                originalEvent: evt
2228              });
2229            }
2230          }
2231        }
2232
2233        if (Sortable.active) {
2234          /* jshint eqnull:true */
2235          if (newIndex == null || newIndex === -1) {
2236            newIndex = oldIndex;
2237            newDraggableIndex = oldDraggableIndex;
2238          }
2239
2240          _dispatchEvent({
2241            sortable: this,
2242            name: 'end',
2243            toEl: parentEl,
2244            originalEvent: evt
2245          }); // Save sorting
2246
2247
2248          this.save();
2249        }
2250      }
2251    }
2252
2253    this._nulling();
2254  },
2255  _nulling: function _nulling() {
2256    pluginEvent('nulling', this);
2257    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;
2258    savedInputChecked.forEach(function (el) {
2259      el.checked = true;
2260    });
2261    savedInputChecked.length = lastDx = lastDy = 0;
2262  },
2263  handleEvent: function handleEvent(
2264  /**Event*/
2265  evt) {
2266    switch (evt.type) {
2267      case 'drop':
2268      case 'dragend':
2269        this._onDrop(evt);
2270
2271        break;
2272
2273      case 'dragenter':
2274      case 'dragover':
2275        if (dragEl) {
2276          this._onDragOver(evt);
2277
2278          _globalDragOver(evt);
2279        }
2280
2281        break;
2282
2283      case 'selectstart':
2284        evt.preventDefault();
2285        break;
2286    }
2287  },
2288
2289  /**
2290   * Serializes the item into an array of string.
2291   * @returns {String[]}
2292   */
2293  toArray: function toArray() {
2294    var order = [],
2295        el,
2296        children = this.el.children,
2297        i = 0,
2298        n = children.length,
2299        options = this.options;
2300
2301    for (; i < n; i++) {
2302      el = children[i];
2303
2304      if (closest(el, options.draggable, this.el, false)) {
2305        order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
2306      }
2307    }
2308
2309    return order;
2310  },
2311
2312  /**
2313   * Sorts the elements according to the array.
2314   * @param  {String[]}  order  order of the items
2315   */
2316  sort: function sort(order) {
2317    var items = {},
2318        rootEl = this.el;
2319    this.toArray().forEach(function (id, i) {
2320      var el = rootEl.children[i];
2321
2322      if (closest(el, this.options.draggable, rootEl, false)) {
2323        items[id] = el;
2324      }
2325    }, this);
2326    order.forEach(function (id) {
2327      if (items[id]) {
2328        rootEl.removeChild(items[id]);
2329        rootEl.appendChild(items[id]);
2330      }
2331    });
2332  },
2333
2334  /**
2335   * Save the current sorting
2336   */
2337  save: function save() {
2338    var store = this.options.store;
2339    store && store.set && store.set(this);
2340  },
2341
2342  /**
2343   * 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.
2344   * @param   {HTMLElement}  el
2345   * @param   {String}       [selector]  default: `options.draggable`
2346   * @returns {HTMLElement|null}
2347   */
2348  closest: function closest$1(el, selector) {
2349    return closest(el, selector || this.options.draggable, this.el, false);
2350  },
2351
2352  /**
2353   * Set/get option
2354   * @param   {string} name
2355   * @param   {*}      [value]
2356   * @returns {*}
2357   */
2358  option: function option(name, value) {
2359    var options = this.options;
2360
2361    if (value === void 0) {
2362      return options[name];
2363    } else {
2364      var modifiedValue = PluginManager.modifyOption(this, name, value);
2365
2366      if (typeof modifiedValue !== 'undefined') {
2367        options[name] = modifiedValue;
2368      } else {
2369        options[name] = value;
2370      }
2371
2372      if (name === 'group') {
2373        _prepareGroup(options);
2374      }
2375    }
2376  },
2377
2378  /**
2379   * Destroy
2380   */
2381  destroy: function destroy() {
2382    pluginEvent('destroy', this);
2383    var el = this.el;
2384    el[expando] = null;
2385    off(el, 'mousedown', this._onTapStart);
2386    off(el, 'touchstart', this._onTapStart);
2387    off(el, 'pointerdown', this._onTapStart);
2388
2389    if (this.nativeDraggable) {
2390      off(el, 'dragover', this);
2391      off(el, 'dragenter', this);
2392    } // Remove draggable attributes
2393
2394
2395    Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
2396      el.removeAttribute('draggable');
2397    });
2398
2399    this._onDrop();
2400
2401    this._disableDelayedDragEvents();
2402
2403    sortables.splice(sortables.indexOf(this.el), 1);
2404    this.el = el = null;
2405  },
2406  _hideClone: function _hideClone() {
2407    if (!cloneHidden) {
2408      pluginEvent('hideClone', this);
2409      if (Sortable.eventCanceled) return;
2410      css(cloneEl, 'display', 'none');
2411
2412      if (this.options.removeCloneOnHide && cloneEl.parentNode) {
2413        cloneEl.parentNode.removeChild(cloneEl);
2414      }
2415
2416      cloneHidden = true;
2417    }
2418  },
2419  _showClone: function _showClone(putSortable) {
2420    if (putSortable.lastPutMode !== 'clone') {
2421      this._hideClone();
2422
2423      return;
2424    }
2425
2426    if (cloneHidden) {
2427      pluginEvent('showClone', this);
2428      if (Sortable.eventCanceled) return; // show clone at dragEl or original position
2429
2430      if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
2431        rootEl.insertBefore(cloneEl, dragEl);
2432      } else if (nextEl) {
2433        rootEl.insertBefore(cloneEl, nextEl);
2434      } else {
2435        rootEl.appendChild(cloneEl);
2436      }
2437
2438      if (this.options.group.revertClone) {
2439        this.animate(dragEl, cloneEl);
2440      }
2441
2442      css(cloneEl, 'display', '');
2443      cloneHidden = false;
2444    }
2445  }
2446};
2447
2448function _globalDragOver(
2449/**Event*/
2450evt) {
2451  if (evt.dataTransfer) {
2452    evt.dataTransfer.dropEffect = 'move';
2453  }
2454
2455  evt.cancelable && evt.preventDefault();
2456}
2457
2458function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
2459  var evt,
2460      sortable = fromEl[expando],
2461      onMoveFn = sortable.options.onMove,
2462      retVal; // Support for new CustomEvent feature
2463
2464  if (window.CustomEvent && !IE11OrLess && !Edge) {
2465    evt = new CustomEvent('move', {
2466      bubbles: true,
2467      cancelable: true
2468    });
2469  } else {
2470    evt = document.createEvent('Event');
2471    evt.initEvent('move', true, true);
2472  }
2473
2474  evt.to = toEl;
2475  evt.from = fromEl;
2476  evt.dragged = dragEl;
2477  evt.draggedRect = dragRect;
2478  evt.related = targetEl || toEl;
2479  evt.relatedRect = targetRect || getRect(toEl);
2480  evt.willInsertAfter = willInsertAfter;
2481  evt.originalEvent = originalEvent;
2482  fromEl.dispatchEvent(evt);
2483
2484  if (onMoveFn) {
2485    retVal = onMoveFn.call(sortable, evt, originalEvent);
2486  }
2487
2488  return retVal;
2489}
2490
2491function _disableDraggable(el) {
2492  el.draggable = false;
2493}
2494
2495function _unsilent() {
2496  _silent = false;
2497}
2498
2499function _ghostIsLast(evt, vertical, sortable) {
2500  var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
2501  var spacer = 10;
2502  return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
2503}
2504
2505function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
2506  var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
2507      targetLength = vertical ? targetRect.height : targetRect.width,
2508      targetS1 = vertical ? targetRect.top : targetRect.left,
2509      targetS2 = vertical ? targetRect.bottom : targetRect.right,
2510      invert = false;
2511
2512  if (!invertSwap) {
2513    // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
2514    if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
2515      // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
2516      // check if past first invert threshold on side opposite of lastDirection
2517      if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
2518        // past first invert threshold, do not restrict inverted threshold to dragEl shadow
2519        pastFirstInvertThresh = true;
2520      }
2521
2522      if (!pastFirstInvertThresh) {
2523        // dragEl shadow (target move distance shadow)
2524        if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
2525        : mouseOnAxis > targetS2 - targetMoveDistance) {
2526          return -lastDirection;
2527        }
2528      } else {
2529        invert = true;
2530      }
2531    } else {
2532      // Regular
2533      if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
2534        return _getInsertDirection(target);
2535      }
2536    }
2537  }
2538
2539  invert = invert || invertSwap;
2540
2541  if (invert) {
2542    // Invert of regular
2543    if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
2544      return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
2545    }
2546  }
2547
2548  return 0;
2549}
2550/**
2551 * Gets the direction dragEl must be swapped relative to target in order to make it
2552 * seem that dragEl has been "inserted" into that element's position
2553 * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
2554 * @return {Number}                   Direction dragEl must be swapped
2555 */
2556
2557
2558function _getInsertDirection(target) {
2559  if (index(dragEl) < index(target)) {
2560    return 1;
2561  } else {
2562    return -1;
2563  }
2564}
2565/**
2566 * Generate id
2567 * @param   {HTMLElement} el
2568 * @returns {String}
2569 * @private
2570 */
2571
2572
2573function _generateId(el) {
2574  var str = el.tagName + el.className + el.src + el.href + el.textContent,
2575      i = str.length,
2576      sum = 0;
2577
2578  while (i--) {
2579    sum += str.charCodeAt(i);
2580  }
2581
2582  return sum.toString(36);
2583}
2584
2585function _saveInputCheckedState(root) {
2586  savedInputChecked.length = 0;
2587  var inputs = root.getElementsByTagName('input');
2588  var idx = inputs.length;
2589
2590  while (idx--) {
2591    var el = inputs[idx];
2592    el.checked && savedInputChecked.push(el);
2593  }
2594}
2595
2596function _nextTick(fn) {
2597  return setTimeout(fn, 0);
2598}
2599
2600function _cancelNextTick(id) {
2601  return clearTimeout(id);
2602} // Fixed #973:
2603
2604
2605if (documentExists) {
2606  on(document, 'touchmove', function (evt) {
2607    if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
2608      evt.preventDefault();
2609    }
2610  });
2611} // Export utils
2612
2613
2614Sortable.utils = {
2615  on: on,
2616  off: off,
2617  css: css,
2618  find: find,
2619  is: function is(el, selector) {
2620    return !!closest(el, selector, el, false);
2621  },
2622  extend: extend,
2623  throttle: throttle,
2624  closest: closest,
2625  toggleClass: toggleClass,
2626  clone: clone,
2627  index: index,
2628  nextTick: _nextTick,
2629  cancelNextTick: _cancelNextTick,
2630  detectDirection: _detectDirection,
2631  getChild: getChild
2632};
2633/**
2634 * Get the Sortable instance of an element
2635 * @param  {HTMLElement} element The element
2636 * @return {Sortable|undefined}         The instance of Sortable
2637 */
2638
2639Sortable.get = function (element) {
2640  return element[expando];
2641};
2642/**
2643 * Mount a plugin to Sortable
2644 * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
2645 */
2646
2647
2648Sortable.mount = function () {
2649  for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
2650    plugins[_key] = arguments[_key];
2651  }
2652
2653  if (plugins[0].constructor === Array) plugins = plugins[0];
2654  plugins.forEach(function (plugin) {
2655    if (!plugin.prototype || !plugin.prototype.constructor) {
2656      throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
2657    }
2658
2659    if (plugin.utils) Sortable.utils = _objectSpread({}, Sortable.utils, plugin.utils);
2660    PluginManager.mount(plugin);
2661  });
2662};
2663/**
2664 * Create sortable instance
2665 * @param {HTMLElement}  el
2666 * @param {Object}      [options]
2667 */
2668
2669
2670Sortable.create = function (el, options) {
2671  return new Sortable(el, options);
2672}; // Export
2673
2674
2675Sortable.version = version;
2676
2677var autoScrolls = [],
2678    scrollEl,
2679    scrollRootEl,
2680    scrolling = false,
2681    lastAutoScrollX,
2682    lastAutoScrollY,
2683    touchEvt$1,
2684    pointerElemChangedInterval;
2685
2686function AutoScrollPlugin() {
2687  function AutoScroll() {
2688    this.defaults = {
2689      scroll: true,
2690      scrollSensitivity: 30,
2691      scrollSpeed: 10,
2692      bubbleScroll: true
2693    }; // Bind all private methods
2694
2695    for (var fn in this) {
2696      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
2697        this[fn] = this[fn].bind(this);
2698      }
2699    }
2700  }
2701
2702  AutoScroll.prototype = {
2703    dragStarted: function dragStarted(_ref) {
2704      var originalEvent = _ref.originalEvent;
2705
2706      if (this.sortable.nativeDraggable) {
2707        on(document, 'dragover', this._handleAutoScroll);
2708      } else {
2709        if (this.options.supportPointer) {
2710          on(document, 'pointermove', this._handleFallbackAutoScroll);
2711        } else if (originalEvent.touches) {
2712          on(document, 'touchmove', this._handleFallbackAutoScroll);
2713        } else {
2714          on(document, 'mousemove', this._handleFallbackAutoScroll);
2715        }
2716      }
2717    },
2718    dragOverCompleted: function dragOverCompleted(_ref2) {
2719      var originalEvent = _ref2.originalEvent;
2720
2721      // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
2722      if (!this.options.dragOverBubble && !originalEvent.rootEl) {
2723        this._handleAutoScroll(originalEvent);
2724      }
2725    },
2726    drop: function drop() {
2727      if (this.sortable.nativeDraggable) {
2728        off(document, 'dragover', this._handleAutoScroll);
2729      } else {
2730        off(document, 'pointermove', this._handleFallbackAutoScroll);
2731        off(document, 'touchmove', this._handleFallbackAutoScroll);
2732        off(document, 'mousemove', this._handleFallbackAutoScroll);
2733      }
2734
2735      clearPointerElemChangedInterval();
2736      clearAutoScrolls();
2737      cancelThrottle();
2738    },
2739    nulling: function nulling() {
2740      touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
2741      autoScrolls.length = 0;
2742    },
2743    _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
2744      this._handleAutoScroll(evt, true);
2745    },
2746    _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
2747      var _this = this;
2748
2749      var x = (evt.touches ? evt.touches[0] : evt).clientX,
2750          y = (evt.touches ? evt.touches[0] : evt).clientY,
2751          elem = document.elementFromPoint(x, y);
2752      touchEvt$1 = evt; // IE does not seem to have native autoscroll,
2753      // Edge's autoscroll seems too conditional,
2754      // MACOS Safari does not have autoscroll,
2755      // Firefox and Chrome are good
2756
2757      if (fallback || Edge || IE11OrLess || Safari) {
2758        autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
2759
2760        var ogElemScroller = getParentAutoScrollElement(elem, true);
2761
2762        if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
2763          pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
2764
2765          pointerElemChangedInterval = setInterval(function () {
2766            var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
2767
2768            if (newElem !== ogElemScroller) {
2769              ogElemScroller = newElem;
2770              clearAutoScrolls();
2771            }
2772
2773            autoScroll(evt, _this.options, newElem, fallback);
2774          }, 10);
2775          lastAutoScrollX = x;
2776          lastAutoScrollY = y;
2777        }
2778      } else {
2779        // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
2780        if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
2781          clearAutoScrolls();
2782          return;
2783        }
2784
2785        autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
2786      }
2787    }
2788  };
2789  return _extends(AutoScroll, {
2790    pluginName: 'scroll',
2791    initializeByDefault: true
2792  });
2793}
2794
2795function clearAutoScrolls() {
2796  autoScrolls.forEach(function (autoScroll) {
2797    clearInterval(autoScroll.pid);
2798  });
2799  autoScrolls = [];
2800}
2801
2802function clearPointerElemChangedInterval() {
2803  clearInterval(pointerElemChangedInterval);
2804}
2805
2806var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
2807  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
2808  if (!options.scroll) return;
2809  var x = (evt.touches ? evt.touches[0] : evt).clientX,
2810      y = (evt.touches ? evt.touches[0] : evt).clientY,
2811      sens = options.scrollSensitivity,
2812      speed = options.scrollSpeed,
2813      winScroller = getWindowScrollingElement();
2814  var scrollThisInstance = false,
2815      scrollCustomFn; // New scroll root, set scrollEl
2816
2817  if (scrollRootEl !== rootEl) {
2818    scrollRootEl = rootEl;
2819    clearAutoScrolls();
2820    scrollEl = options.scroll;
2821    scrollCustomFn = options.scrollFn;
2822
2823    if (scrollEl === true) {
2824      scrollEl = getParentAutoScrollElement(rootEl, true);
2825    }
2826  }
2827
2828  var layersOut = 0;
2829  var currentParent = scrollEl;
2830
2831  do {
2832    var el = currentParent,
2833        rect = getRect(el),
2834        top = rect.top,
2835        bottom = rect.bottom,
2836        left = rect.left,
2837        right = rect.right,
2838        width = rect.width,
2839        height = rect.height,
2840        canScrollX = void 0,
2841        canScrollY = void 0,
2842        scrollWidth = el.scrollWidth,
2843        scrollHeight = el.scrollHeight,
2844        elCSS = css(el),
2845        scrollPosX = el.scrollLeft,
2846        scrollPosY = el.scrollTop;
2847
2848    if (el === winScroller) {
2849      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
2850      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
2851    } else {
2852      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
2853      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
2854    }
2855
2856    var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
2857    var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
2858
2859    if (!autoScrolls[layersOut]) {
2860      for (var i = 0; i <= layersOut; i++) {
2861        if (!autoScrolls[i]) {
2862          autoScrolls[i] = {};
2863        }
2864      }
2865    }
2866
2867    if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
2868      autoScrolls[layersOut].el = el;
2869      autoScrolls[layersOut].vx = vx;
2870      autoScrolls[layersOut].vy = vy;
2871      clearInterval(autoScrolls[layersOut].pid);
2872
2873      if (vx != 0 || vy != 0) {
2874        scrollThisInstance = true;
2875        /* jshint loopfunc:true */
2876
2877        autoScrolls[layersOut].pid = setInterval(function () {
2878          // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
2879          if (isFallback && this.layer === 0) {
2880            Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
2881
2882          }
2883
2884          var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
2885          var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
2886
2887          if (typeof scrollCustomFn === 'function') {
2888            if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
2889              return;
2890            }
2891          }
2892
2893          scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
2894        }.bind({
2895          layer: layersOut
2896        }), 24);
2897      }
2898    }
2899
2900    layersOut++;
2901  } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
2902
2903  scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
2904}, 30);
2905
2906var drop = function drop(_ref) {
2907  var originalEvent = _ref.originalEvent,
2908      putSortable = _ref.putSortable,
2909      dragEl = _ref.dragEl,
2910      activeSortable = _ref.activeSortable,
2911      dispatchSortableEvent = _ref.dispatchSortableEvent,
2912      hideGhostForTarget = _ref.hideGhostForTarget,
2913      unhideGhostForTarget = _ref.unhideGhostForTarget;
2914  if (!originalEvent) return;
2915  var toSortable = putSortable || activeSortable;
2916  hideGhostForTarget();
2917  var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
2918  var target = document.elementFromPoint(touch.clientX, touch.clientY);
2919  unhideGhostForTarget();
2920
2921  if (toSortable && !toSortable.el.contains(target)) {
2922    dispatchSortableEvent('spill');
2923    this.onSpill({
2924      dragEl: dragEl,
2925      putSortable: putSortable
2926    });
2927  }
2928};
2929
2930function Revert() {}
2931
2932Revert.prototype = {
2933  startIndex: null,
2934  dragStart: function dragStart(_ref2) {
2935    var oldDraggableIndex = _ref2.oldDraggableIndex;
2936    this.startIndex = oldDraggableIndex;
2937  },
2938  onSpill: function onSpill(_ref3) {
2939    var dragEl = _ref3.dragEl,
2940        putSortable = _ref3.putSortable;
2941    this.sortable.captureAnimationState();
2942
2943    if (putSortable) {
2944      putSortable.captureAnimationState();
2945    }
2946
2947    var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
2948
2949    if (nextSibling) {
2950      this.sortable.el.insertBefore(dragEl, nextSibling);
2951    } else {
2952      this.sortable.el.appendChild(dragEl);
2953    }
2954
2955    this.sortable.animateAll();
2956
2957    if (putSortable) {
2958      putSortable.animateAll();
2959    }
2960  },
2961  drop: drop
2962};
2963
2964_extends(Revert, {
2965  pluginName: 'revertOnSpill'
2966});
2967
2968function Remove() {}
2969
2970Remove.prototype = {
2971  onSpill: function onSpill(_ref4) {
2972    var dragEl = _ref4.dragEl,
2973        putSortable = _ref4.putSortable;
2974    var parentSortable = putSortable || this.sortable;
2975    parentSortable.captureAnimationState();
2976    dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
2977    parentSortable.animateAll();
2978  },
2979  drop: drop
2980};
2981
2982_extends(Remove, {
2983  pluginName: 'removeOnSpill'
2984});
2985
2986var lastSwapEl;
2987
2988function SwapPlugin() {
2989  function Swap() {
2990    this.defaults = {
2991      swapClass: 'sortable-swap-highlight'
2992    };
2993  }
2994
2995  Swap.prototype = {
2996    dragStart: function dragStart(_ref) {
2997      var dragEl = _ref.dragEl;
2998      lastSwapEl = dragEl;
2999    },
3000    dragOverValid: function dragOverValid(_ref2) {
3001      var completed = _ref2.completed,
3002          target = _ref2.target,
3003          onMove = _ref2.onMove,
3004          activeSortable = _ref2.activeSortable,
3005          changed = _ref2.changed,
3006          cancel = _ref2.cancel;
3007      if (!activeSortable.options.swap) return;
3008      var el = this.sortable.el,
3009          options = this.options;
3010
3011      if (target && target !== el) {
3012        var prevSwapEl = lastSwapEl;
3013
3014        if (onMove(target) !== false) {
3015          toggleClass(target, options.swapClass, true);
3016          lastSwapEl = target;
3017        } else {
3018          lastSwapEl = null;
3019        }
3020
3021        if (prevSwapEl && prevSwapEl !== lastSwapEl) {
3022          toggleClass(prevSwapEl, options.swapClass, false);
3023        }
3024      }
3025
3026      changed();
3027      completed(true);
3028      cancel();
3029    },
3030    drop: function drop(_ref3) {
3031      var activeSortable = _ref3.activeSortable,
3032          putSortable = _ref3.putSortable,
3033          dragEl = _ref3.dragEl;
3034      var toSortable = putSortable || this.sortable;
3035      var options = this.options;
3036      lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
3037
3038      if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
3039        if (dragEl !== lastSwapEl) {
3040          toSortable.captureAnimationState();
3041          if (toSortable !== activeSortable) activeSortable.captureAnimationState();
3042          swapNodes(dragEl, lastSwapEl);
3043          toSortable.animateAll();
3044          if (toSortable !== activeSortable) activeSortable.animateAll();
3045        }
3046      }
3047    },
3048    nulling: function nulling() {
3049      lastSwapEl = null;
3050    }
3051  };
3052  return _extends(Swap, {
3053    pluginName: 'swap',
3054    eventProperties: function eventProperties() {
3055      return {
3056        swapItem: lastSwapEl
3057      };
3058    }
3059  });
3060}
3061
3062function swapNodes(n1, n2) {
3063  var p1 = n1.parentNode,
3064      p2 = n2.parentNode,
3065      i1,
3066      i2;
3067  if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
3068  i1 = index(n1);
3069  i2 = index(n2);
3070
3071  if (p1.isEqualNode(p2) && i1 < i2) {
3072    i2++;
3073  }
3074
3075  p1.insertBefore(n2, p1.children[i1]);
3076  p2.insertBefore(n1, p2.children[i2]);
3077}
3078
3079var multiDragElements = [],
3080    multiDragClones = [],
3081    lastMultiDragSelect,
3082    // for selection with modifier key down (SHIFT)
3083multiDragSortable,
3084    initialFolding = false,
3085    // Initial multi-drag fold when drag started
3086folding = false,
3087    // Folding any other time
3088dragStarted = false,
3089    dragEl$1,
3090    clonesFromRect,
3091    clonesHidden;
3092
3093function MultiDragPlugin() {
3094  function MultiDrag(sortable) {
3095    // Bind all private methods
3096    for (var fn in this) {
3097      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
3098        this[fn] = this[fn].bind(this);
3099      }
3100    }
3101
3102    if (sortable.options.supportPointer) {
3103      on(document, 'pointerup', this._deselectMultiDrag);
3104    } else {
3105      on(document, 'mouseup', this._deselectMultiDrag);
3106      on(document, 'touchend', this._deselectMultiDrag);
3107    }
3108
3109    on(document, 'keydown', this._checkKeyDown);
3110    on(document, 'keyup', this._checkKeyUp);
3111    this.defaults = {
3112      selectedClass: 'sortable-selected',
3113      multiDragKey: null,
3114      setData: function setData(dataTransfer, dragEl) {
3115        var data = '';
3116
3117        if (multiDragElements.length && multiDragSortable === sortable) {
3118          multiDragElements.forEach(function (multiDragElement, i) {
3119            data += (!i ? '' : ', ') + multiDragElement.textContent;
3120          });
3121        } else {
3122          data = dragEl.textContent;
3123        }
3124
3125        dataTransfer.setData('Text', data);
3126      }
3127    };
3128  }
3129
3130  MultiDrag.prototype = {
3131    multiDragKeyDown: false,
3132    isMultiDrag: false,
3133    delayStartGlobal: function delayStartGlobal(_ref) {
3134      var dragged = _ref.dragEl;
3135      dragEl$1 = dragged;
3136    },
3137    delayEnded: function delayEnded() {
3138      this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
3139    },
3140    setupClone: function setupClone(_ref2) {
3141      var sortable = _ref2.sortable,
3142          cancel = _ref2.cancel;
3143      if (!this.isMultiDrag) return;
3144
3145      for (var i = 0; i < multiDragElements.length; i++) {
3146        multiDragClones.push(clone(multiDragElements[i]));
3147        multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
3148        multiDragClones[i].draggable = false;
3149        multiDragClones[i].style['will-change'] = '';
3150        toggleClass(multiDragClones[i], this.options.selectedClass, false);
3151        multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
3152      }
3153
3154      sortable._hideClone();
3155
3156      cancel();
3157    },
3158    clone: function clone(_ref3) {
3159      var sortable = _ref3.sortable,
3160          rootEl = _ref3.rootEl,
3161          dispatchSortableEvent = _ref3.dispatchSortableEvent,
3162          cancel = _ref3.cancel;
3163      if (!this.isMultiDrag) return;
3164
3165      if (!this.options.removeCloneOnHide) {
3166        if (multiDragElements.length && multiDragSortable === sortable) {
3167          insertMultiDragClones(true, rootEl);
3168          dispatchSortableEvent('clone');
3169          cancel();
3170        }
3171      }
3172    },
3173    showClone: function showClone(_ref4) {
3174      var cloneNowShown = _ref4.cloneNowShown,
3175          rootEl = _ref4.rootEl,
3176          cancel = _ref4.cancel;
3177      if (!this.isMultiDrag) return;
3178      insertMultiDragClones(false, rootEl);
3179      multiDragClones.forEach(function (clone) {
3180        css(clone, 'display', '');
3181      });
3182      cloneNowShown();
3183      clonesHidden = false;
3184      cancel();
3185    },
3186    hideClone: function hideClone(_ref5) {
3187      var _this = this;
3188
3189      var sortable = _ref5.sortable,
3190          cloneNowHidden = _ref5.cloneNowHidden,
3191          cancel = _ref5.cancel;
3192      if (!this.isMultiDrag) return;
3193      multiDragClones.forEach(function (clone) {
3194        css(clone, 'display', 'none');
3195
3196        if (_this.options.removeCloneOnHide && clone.parentNode) {
3197          clone.parentNode.removeChild(clone);
3198        }
3199      });
3200      cloneNowHidden();
3201      clonesHidden = true;
3202      cancel();
3203    },
3204    dragStartGlobal: function dragStartGlobal(_ref6) {
3205      var sortable = _ref6.sortable;
3206
3207      if (!this.isMultiDrag && multiDragSortable) {
3208        multiDragSortable.multiDrag._deselectMultiDrag();
3209      }
3210
3211      multiDragElements.forEach(function (multiDragElement) {
3212        multiDragElement.sortableIndex = index(multiDragElement);
3213      }); // Sort multi-drag elements
3214
3215      multiDragElements = multiDragElements.sort(function (a, b) {
3216        return a.sortableIndex - b.sortableIndex;
3217      });
3218      dragStarted = true;
3219    },
3220    dragStarted: function dragStarted(_ref7) {
3221      var _this2 = this;
3222
3223      var sortable = _ref7.sortable;
3224      if (!this.isMultiDrag) return;
3225
3226      if (this.options.sort) {
3227        // Capture rects,
3228        // hide multi drag elements (by positioning them absolute),
3229        // set multi drag elements rects to dragRect,
3230        // show multi drag elements,
3231        // animate to rects,
3232        // unset rects & remove from DOM
3233        sortable.captureAnimationState();
3234
3235        if (this.options.animation) {
3236          multiDragElements.forEach(function (multiDragElement) {
3237            if (multiDragElement === dragEl$1) return;
3238            css(multiDragElement, 'position', 'absolute');
3239          });
3240          var dragRect = getRect(dragEl$1, false, true, true);
3241          multiDragElements.forEach(function (multiDragElement) {
3242            if (multiDragElement === dragEl$1) return;
3243            setRect(multiDragElement, dragRect);
3244          });
3245          folding = true;
3246          initialFolding = true;
3247        }
3248      }
3249
3250      sortable.animateAll(function () {
3251        folding = false;
3252        initialFolding = false;
3253
3254        if (_this2.options.animation) {
3255          multiDragElements.forEach(function (multiDragElement) {
3256            unsetRect(multiDragElement);
3257          });
3258        } // Remove all auxiliary multidrag items from el, if sorting enabled
3259
3260
3261        if (_this2.options.sort) {
3262          removeMultiDragElements();
3263        }
3264      });
3265    },
3266    dragOver: function dragOver(_ref8) {
3267      var target = _ref8.target,
3268          completed = _ref8.completed,
3269          cancel = _ref8.cancel;
3270
3271      if (folding && ~multiDragElements.indexOf(target)) {
3272        completed(false);
3273        cancel();
3274      }
3275    },
3276    revert: function revert(_ref9) {
3277      var fromSortable = _ref9.fromSortable,
3278          rootEl = _ref9.rootEl,
3279          sortable = _ref9.sortable,
3280          dragRect = _ref9.dragRect;
3281
3282      if (multiDragElements.length > 1) {
3283        // Setup unfold animation
3284        multiDragElements.forEach(function (multiDragElement) {
3285          sortable.addAnimationState({
3286            target: multiDragElement,
3287            rect: folding ? getRect(multiDragElement) : dragRect
3288          });
3289          unsetRect(multiDragElement);
3290          multiDragElement.fromRect = dragRect;
3291          fromSortable.removeAnimationState(multiDragElement);
3292        });
3293        folding = false;
3294        insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
3295      }
3296    },
3297    dragOverCompleted: function dragOverCompleted(_ref10) {
3298      var sortable = _ref10.sortable,
3299          isOwner = _ref10.isOwner,
3300          insertion = _ref10.insertion,
3301          activeSortable = _ref10.activeSortable,
3302          parentEl = _ref10.parentEl,
3303          putSortable = _ref10.putSortable;
3304      var options = this.options;
3305
3306      if (insertion) {
3307        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
3308        if (isOwner) {
3309          activeSortable._hideClone();
3310        }
3311
3312        initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location
3313
3314        if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
3315          // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
3316          var dragRectAbsolute = getRect(dragEl$1, false, true, true);
3317          multiDragElements.forEach(function (multiDragElement) {
3318            if (multiDragElement === dragEl$1) return;
3319            setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
3320            // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
3321
3322            parentEl.appendChild(multiDragElement);
3323          });
3324          folding = true;
3325        } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
3326
3327
3328        if (!isOwner) {
3329          // Only remove if not folding (folding will remove them anyways)
3330          if (!folding) {
3331            removeMultiDragElements();
3332          }
3333
3334          if (multiDragElements.length > 1) {
3335            var clonesHiddenBefore = clonesHidden;
3336
3337            activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden
3338
3339
3340            if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
3341              multiDragClones.forEach(function (clone) {
3342                activeSortable.addAnimationState({
3343                  target: clone,
3344                  rect: clonesFromRect
3345                });
3346                clone.fromRect = clonesFromRect;
3347                clone.thisAnimationDuration = null;
3348              });
3349            }
3350          } else {
3351            activeSortable._showClone(sortable);
3352          }
3353        }
3354      }
3355    },
3356    dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
3357      var dragRect = _ref11.dragRect,
3358          isOwner = _ref11.isOwner,
3359          activeSortable = _ref11.activeSortable;
3360      multiDragElements.forEach(function (multiDragElement) {
3361        multiDragElement.thisAnimationDuration = null;
3362      });
3363
3364      if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
3365        clonesFromRect = _extends({}, dragRect);
3366        var dragMatrix = matrix(dragEl$1, true);
3367        clonesFromRect.top -= dragMatrix.f;
3368        clonesFromRect.left -= dragMatrix.e;
3369      }
3370    },
3371    dragOverAnimationComplete: function dragOverAnimationComplete() {
3372      if (folding) {
3373        folding = false;
3374        removeMultiDragElements();
3375      }
3376    },
3377    drop: function drop(_ref12) {
3378      var evt = _ref12.originalEvent,
3379          rootEl = _ref12.rootEl,
3380          parentEl = _ref12.parentEl,
3381          sortable = _ref12.sortable,
3382          dispatchSortableEvent = _ref12.dispatchSortableEvent,
3383          oldIndex = _ref12.oldIndex,
3384          putSortable = _ref12.putSortable;
3385      var toSortable = putSortable || this.sortable;
3386      if (!evt) return;
3387      var options = this.options,
3388          children = parentEl.children; // Multi-drag selection
3389
3390      if (!dragStarted) {
3391        if (options.multiDragKey && !this.multiDragKeyDown) {
3392          this._deselectMultiDrag();
3393        }
3394
3395        toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
3396
3397        if (!~multiDragElements.indexOf(dragEl$1)) {
3398          multiDragElements.push(dragEl$1);
3399          dispatchEvent({
3400            sortable: sortable,
3401            rootEl: rootEl,
3402            name: 'select',
3403            targetEl: dragEl$1,
3404            originalEvt: evt
3405          }); // Modifier activated, select from last to dragEl
3406
3407          if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
3408            var lastIndex = index(lastMultiDragSelect),
3409                currentIndex = index(dragEl$1);
3410
3411            if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
3412              // Must include lastMultiDragSelect (select it), in case modified selection from no selection
3413              // (but previous selection existed)
3414              var n, i;
3415
3416              if (currentIndex > lastIndex) {
3417                i = lastIndex;
3418                n = currentIndex;
3419              } else {
3420                i = currentIndex;
3421                n = lastIndex + 1;
3422              }
3423
3424              for (; i < n; i++) {
3425                if (~multiDragElements.indexOf(children[i])) continue;
3426                toggleClass(children[i], options.selectedClass, true);
3427                multiDragElements.push(children[i]);
3428                dispatchEvent({
3429                  sortable: sortable,
3430                  rootEl: rootEl,
3431                  name: 'select',
3432                  targetEl: children[i],
3433                  originalEvt: evt
3434                });
3435              }
3436            }
3437          } else {
3438            lastMultiDragSelect = dragEl$1;
3439          }
3440
3441          multiDragSortable = toSortable;
3442        } else {
3443          multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
3444          lastMultiDragSelect = null;
3445          dispatchEvent({
3446            sortable: sortable,
3447            rootEl: rootEl,
3448            name: 'deselect',
3449            targetEl: dragEl$1,
3450            originalEvt: evt
3451          });
3452        }
3453      } // Multi-drag drop
3454
3455
3456      if (dragStarted && this.isMultiDrag) {
3457        // Do not "unfold" after around dragEl if reverted
3458        if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
3459          var dragRect = getRect(dragEl$1),
3460              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
3461          if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
3462          toSortable.captureAnimationState();
3463
3464          if (!initialFolding) {
3465            if (options.animation) {
3466              dragEl$1.fromRect = dragRect;
3467              multiDragElements.forEach(function (multiDragElement) {
3468                multiDragElement.thisAnimationDuration = null;
3469
3470                if (multiDragElement !== dragEl$1) {
3471                  var rect = folding ? getRect(multiDragElement) : dragRect;
3472                  multiDragElement.fromRect = rect; // Prepare unfold animation
3473
3474                  toSortable.addAnimationState({
3475                    target: multiDragElement,
3476                    rect: rect
3477                  });
3478                }
3479              });
3480            } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
3481            // properly they must all be removed
3482
3483
3484            removeMultiDragElements();
3485            multiDragElements.forEach(function (multiDragElement) {
3486              if (children[multiDragIndex]) {
3487                parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
3488              } else {
3489                parentEl.appendChild(multiDragElement);
3490              }
3491
3492              multiDragIndex++;
3493            }); // If initial folding is done, the elements may have changed position because they are now
3494            // unfolding around dragEl, even though dragEl may not have his index changed, so update event
3495            // must be fired here as Sortable will not.
3496
3497            if (oldIndex === index(dragEl$1)) {
3498              var update = false;
3499              multiDragElements.forEach(function (multiDragElement) {
3500                if (multiDragElement.sortableIndex !== index(multiDragElement)) {
3501                  update = true;
3502                  return;
3503                }
3504              });
3505
3506              if (update) {
3507                dispatchSortableEvent('update');
3508              }
3509            }
3510          } // Must be done after capturing individual rects (scroll bar)
3511
3512
3513          multiDragElements.forEach(function (multiDragElement) {
3514            unsetRect(multiDragElement);
3515          });
3516          toSortable.animateAll();
3517        }
3518
3519        multiDragSortable = toSortable;
3520      } // Remove clones if necessary
3521
3522
3523      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
3524        multiDragClones.forEach(function (clone) {
3525          clone.parentNode && clone.parentNode.removeChild(clone);
3526        });
3527      }
3528    },
3529    nullingGlobal: function nullingGlobal() {
3530      this.isMultiDrag = dragStarted = false;
3531      multiDragClones.length = 0;
3532    },
3533    destroyGlobal: function destroyGlobal() {
3534      this._deselectMultiDrag();
3535
3536      off(document, 'pointerup', this._deselectMultiDrag);
3537      off(document, 'mouseup', this._deselectMultiDrag);
3538      off(document, 'touchend', this._deselectMultiDrag);
3539      off(document, 'keydown', this._checkKeyDown);
3540      off(document, 'keyup', this._checkKeyUp);
3541    },
3542    _deselectMultiDrag: function _deselectMultiDrag(evt) {
3543      if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable
3544
3545      if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable
3546
3547      if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click
3548
3549      if (evt && evt.button !== 0) return;
3550
3551      while (multiDragElements.length) {
3552        var el = multiDragElements[0];
3553        toggleClass(el, this.options.selectedClass, false);
3554        multiDragElements.shift();
3555        dispatchEvent({
3556          sortable: this.sortable,
3557          rootEl: this.sortable.el,
3558          name: 'deselect',
3559          targetEl: el,
3560          originalEvt: evt
3561        });
3562      }
3563    },
3564    _checkKeyDown: function _checkKeyDown(evt) {
3565      if (evt.key === this.options.multiDragKey) {
3566        this.multiDragKeyDown = true;
3567      }
3568    },
3569    _checkKeyUp: function _checkKeyUp(evt) {
3570      if (evt.key === this.options.multiDragKey) {
3571        this.multiDragKeyDown = false;
3572      }
3573    }
3574  };
3575  return _extends(MultiDrag, {
3576    // Static methods & properties
3577    pluginName: 'multiDrag',
3578    utils: {
3579      /**
3580       * Selects the provided multi-drag item
3581       * @param  {HTMLElement} el    The element to be selected
3582       */
3583      select: function select(el) {
3584        var sortable = el.parentNode[expando];
3585        if (!sortable || !sortable.options.multiDrag || ~multiDragElements.