para 0.8.7 → 0.8.8

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