svelte-dnd-action 0.9.78 → 0.9.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +535 -295
- package/dist/index.mjs +535 -295
- package/package.json +1 -1
- package/src/constants.js +1 -0
- package/src/helpers/aria.js +50 -28
- package/src/helpers/dispatcher.js +12 -8
- package/src/helpers/intersection.js +19 -14
- package/src/helpers/multiScroller.js +8 -10
- package/src/helpers/observer.js +14 -4
- package/src/helpers/scroller.js +5 -4
- package/src/helpers/styler.js +9 -6
- package/src/helpers/util.js +31 -0
- package/src/keyboardAction.js +201 -84
- package/src/pointerAction.js +109 -79
- package/src/wrappers/withDragHandles.js +11 -5
package/dist/index.js
CHANGED
|
@@ -184,6 +184,105 @@
|
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* The window an element lives in. A drop zone can live in another window than the one that
|
|
189
|
+
* loaded this module, for example a same-origin iframe or a popup opened with window.open.
|
|
190
|
+
* @param {Node} el
|
|
191
|
+
* @return {Window}
|
|
192
|
+
*/
|
|
193
|
+
function getWindowOf(el) {
|
|
194
|
+
// eslint-disable-next-line no-restricted-globals -- for a document without a window, e.g. after its window closed
|
|
195
|
+
return el.ownerDocument.defaultView || window;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Schedules a timeout on the given window. Work for a zone runs on the zone's window: the browser throttles
|
|
200
|
+
* or stops the timers of a hidden window, and the loading window can be hidden while the zone's is not.
|
|
201
|
+
* @param {Window} win
|
|
202
|
+
* @param {function} callback
|
|
203
|
+
* @param {number} ms
|
|
204
|
+
* @return {{win: Window, id: number}} - pass it to clearTimeoutIn
|
|
205
|
+
*/
|
|
206
|
+
function setTimeoutIn(win, callback, ms) {
|
|
207
|
+
return {
|
|
208
|
+
win: win,
|
|
209
|
+
id: win.setTimeout(callback, ms)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Cancels a timeout through the window that scheduled it
|
|
215
|
+
* @param {{win: Window, id: number}} [timeout] - from setTimeoutIn
|
|
216
|
+
*/
|
|
217
|
+
function clearTimeoutIn(timeout) {
|
|
218
|
+
if (timeout) timeout.win.clearTimeout(timeout.id);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @param {Object} object
|
|
223
|
+
* @return {string}
|
|
224
|
+
*/
|
|
225
|
+
function toString(object) {
|
|
226
|
+
return JSON.stringify(object, null, 2);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Finds the depth of the given node in the DOM tree
|
|
231
|
+
* @param {HTMLElement} node
|
|
232
|
+
* @return {number} - the depth of the node
|
|
233
|
+
*/
|
|
234
|
+
function getDepth(node) {
|
|
235
|
+
if (!node) {
|
|
236
|
+
throw new Error("cannot get depth of a falsy node");
|
|
237
|
+
}
|
|
238
|
+
return _getDepth(node, 0);
|
|
239
|
+
}
|
|
240
|
+
function _getDepth(node) {
|
|
241
|
+
var countSoFar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
242
|
+
if (!node.parentElement) {
|
|
243
|
+
return countSoFar - 1;
|
|
244
|
+
}
|
|
245
|
+
return _getDepth(node.parentElement, countSoFar + 1);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* A simple util to shallow compare objects quickly, it doesn't validate the arguments so pass objects in
|
|
250
|
+
* @param {Object} objA
|
|
251
|
+
* @param {Object} objB
|
|
252
|
+
* @return {boolean} - true if objA and objB are shallow equal
|
|
253
|
+
*/
|
|
254
|
+
function areObjectsShallowEqual(objA, objB) {
|
|
255
|
+
if (Object.keys(objA).length !== Object.keys(objB).length) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
for (var keyA in objA) {
|
|
259
|
+
if (!{}.hasOwnProperty.call(objB, keyA) || objB[keyA] !== objA[keyA]) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Shallow compares two arrays
|
|
268
|
+
* @param arrA
|
|
269
|
+
* @param arrB
|
|
270
|
+
* @return {boolean} - whether the arrays are shallow equal
|
|
271
|
+
*/
|
|
272
|
+
function areArraysShallowEqualSameOrder(arrA, arrB) {
|
|
273
|
+
if (arrA.length !== arrB.length) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
for (var i = 0; i < arrA.length; i++) {
|
|
277
|
+
if (arrA[i] !== arrB[i]) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Events are created in the window of the element they are dispatched on, so a listener in that window sees an
|
|
285
|
+
// instance of its own CustomEvent.
|
|
187
286
|
// external events
|
|
188
287
|
var FINALIZE_EVENT_NAME = "finalize";
|
|
189
288
|
var CONSIDER_EVENT_NAME = "consider";
|
|
@@ -198,7 +297,7 @@
|
|
|
198
297
|
* @param {Info} info
|
|
199
298
|
*/
|
|
200
299
|
function dispatchFinalizeEvent(el, items, info) {
|
|
201
|
-
el.dispatchEvent(new CustomEvent(FINALIZE_EVENT_NAME, {
|
|
300
|
+
el.dispatchEvent(new (getWindowOf(el).CustomEvent)(FINALIZE_EVENT_NAME, {
|
|
202
301
|
detail: {
|
|
203
302
|
items: items,
|
|
204
303
|
info: info
|
|
@@ -213,7 +312,7 @@
|
|
|
213
312
|
* @param {Info} info
|
|
214
313
|
*/
|
|
215
314
|
function dispatchConsiderEvent(el, items, info) {
|
|
216
|
-
el.dispatchEvent(new CustomEvent(CONSIDER_EVENT_NAME, {
|
|
315
|
+
el.dispatchEvent(new (getWindowOf(el).CustomEvent)(CONSIDER_EVENT_NAME, {
|
|
217
316
|
detail: {
|
|
218
317
|
items: items,
|
|
219
318
|
info: info
|
|
@@ -231,7 +330,7 @@
|
|
|
231
330
|
OUTSIDE_OF_ANY: "outsideOfAny"
|
|
232
331
|
};
|
|
233
332
|
function dispatchDraggedElementEnteredContainer(containerEl, indexObj, draggedEl) {
|
|
234
|
-
containerEl.dispatchEvent(new CustomEvent(DRAGGED_ENTERED_EVENT_NAME, {
|
|
333
|
+
containerEl.dispatchEvent(new (getWindowOf(containerEl).CustomEvent)(DRAGGED_ENTERED_EVENT_NAME, {
|
|
235
334
|
detail: {
|
|
236
335
|
indexObj: indexObj,
|
|
237
336
|
draggedEl: draggedEl
|
|
@@ -245,7 +344,7 @@
|
|
|
245
344
|
* @param theOtherDz - the new dropzone the element entered
|
|
246
345
|
*/
|
|
247
346
|
function dispatchDraggedElementLeftContainerForAnother(containerEl, draggedEl, theOtherDz) {
|
|
248
|
-
containerEl.dispatchEvent(new CustomEvent(DRAGGED_LEFT_EVENT_NAME, {
|
|
347
|
+
containerEl.dispatchEvent(new (getWindowOf(containerEl).CustomEvent)(DRAGGED_LEFT_EVENT_NAME, {
|
|
249
348
|
detail: {
|
|
250
349
|
draggedEl: draggedEl,
|
|
251
350
|
type: DRAGGED_LEFT_TYPES.LEFT_FOR_ANOTHER,
|
|
@@ -254,7 +353,7 @@
|
|
|
254
353
|
}));
|
|
255
354
|
}
|
|
256
355
|
function dispatchDraggedElementLeftContainerForNone(containerEl, draggedEl) {
|
|
257
|
-
containerEl.dispatchEvent(new CustomEvent(DRAGGED_LEFT_EVENT_NAME, {
|
|
356
|
+
containerEl.dispatchEvent(new (getWindowOf(containerEl).CustomEvent)(DRAGGED_LEFT_EVENT_NAME, {
|
|
258
357
|
detail: {
|
|
259
358
|
draggedEl: draggedEl,
|
|
260
359
|
type: DRAGGED_LEFT_TYPES.OUTSIDE_OF_ANY
|
|
@@ -262,7 +361,7 @@
|
|
|
262
361
|
}));
|
|
263
362
|
}
|
|
264
363
|
function dispatchDraggedElementIsOverIndex(containerEl, indexObj, draggedEl) {
|
|
265
|
-
containerEl.dispatchEvent(new CustomEvent(DRAGGED_OVER_INDEX_EVENT_NAME, {
|
|
364
|
+
containerEl.dispatchEvent(new (getWindowOf(containerEl).CustomEvent)(DRAGGED_OVER_INDEX_EVENT_NAME, {
|
|
266
365
|
detail: {
|
|
267
366
|
indexObj: indexObj,
|
|
268
367
|
draggedEl: draggedEl
|
|
@@ -270,7 +369,8 @@
|
|
|
270
369
|
}));
|
|
271
370
|
}
|
|
272
371
|
function dispatchDraggedLeftDocument(draggedEl) {
|
|
273
|
-
|
|
372
|
+
var win = getWindowOf(draggedEl);
|
|
373
|
+
win.dispatchEvent(new win.CustomEvent(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, {
|
|
274
374
|
detail: {
|
|
275
375
|
draggedEl: draggedEl
|
|
276
376
|
}
|
|
@@ -346,6 +446,8 @@
|
|
|
346
446
|
});
|
|
347
447
|
ITEM_ID_KEY = newKeyName;
|
|
348
448
|
}
|
|
449
|
+
|
|
450
|
+
// eslint-disable-next-line no-restricted-globals -- detects server-side rendering
|
|
349
451
|
var isOnServer = typeof window === "undefined";
|
|
350
452
|
var printDebug = function printDebug() {};
|
|
351
453
|
|
|
@@ -381,7 +483,7 @@
|
|
|
381
483
|
var onlyVisible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
382
484
|
var ta;
|
|
383
485
|
var rect = onlyVisible ? getVisibleRectRecursive(el) : el.getBoundingClientRect();
|
|
384
|
-
var style = getComputedStyle(el);
|
|
486
|
+
var style = getWindowOf(el).getComputedStyle(el);
|
|
385
487
|
var tx = style.transform;
|
|
386
488
|
if (tx) {
|
|
387
489
|
var sx, sy, dx, dy;
|
|
@@ -401,8 +503,8 @@
|
|
|
401
503
|
return rect;
|
|
402
504
|
}
|
|
403
505
|
var to = style.transformOrigin;
|
|
404
|
-
var x = rect.
|
|
405
|
-
var y = rect.
|
|
506
|
+
var x = rect.left - dx - (1 - sx) * parseFloat(to);
|
|
507
|
+
var y = rect.top - dy - (1 - sy) * parseFloat(to.slice(to.indexOf(" ") + 1));
|
|
406
508
|
var w = sx ? rect.width / sx : el.offsetWidth;
|
|
407
509
|
var h = sy ? rect.height / sy : el.offsetHeight;
|
|
408
510
|
return {
|
|
@@ -427,11 +529,12 @@
|
|
|
427
529
|
*/
|
|
428
530
|
function getAbsoluteRectNoTransforms(el) {
|
|
429
531
|
var rect = getBoundingRectNoTransforms(el);
|
|
532
|
+
var win = getWindowOf(el);
|
|
430
533
|
return {
|
|
431
|
-
top: rect.top +
|
|
432
|
-
bottom: rect.bottom +
|
|
433
|
-
left: rect.left +
|
|
434
|
-
right: rect.right +
|
|
534
|
+
top: rect.top + win.scrollY,
|
|
535
|
+
bottom: rect.bottom + win.scrollY,
|
|
536
|
+
left: rect.left + win.scrollX,
|
|
537
|
+
right: rect.right + win.scrollX
|
|
435
538
|
};
|
|
436
539
|
}
|
|
437
540
|
|
|
@@ -442,11 +545,12 @@
|
|
|
442
545
|
*/
|
|
443
546
|
function getAbsoluteRect(el) {
|
|
444
547
|
var rect = el.getBoundingClientRect();
|
|
548
|
+
var win = getWindowOf(el);
|
|
445
549
|
return {
|
|
446
|
-
top: rect.top +
|
|
447
|
-
bottom: rect.bottom +
|
|
448
|
-
left: rect.left +
|
|
449
|
-
right: rect.right +
|
|
550
|
+
top: rect.top + win.scrollY,
|
|
551
|
+
bottom: rect.bottom + win.scrollY,
|
|
552
|
+
left: rect.left + win.scrollX,
|
|
553
|
+
right: rect.right + win.scrollX
|
|
450
554
|
};
|
|
451
555
|
}
|
|
452
556
|
|
|
@@ -514,7 +618,8 @@
|
|
|
514
618
|
*/
|
|
515
619
|
function isElementOffDocument(el) {
|
|
516
620
|
var rect = getAbsoluteRect(el);
|
|
517
|
-
|
|
621
|
+
var documentElement = el.ownerDocument.documentElement;
|
|
622
|
+
return rect.right < 0 || rect.left > documentElement.scrollWidth || rect.bottom < 0 || rect.top > documentElement.scrollHeight;
|
|
518
623
|
}
|
|
519
624
|
|
|
520
625
|
/**
|
|
@@ -547,8 +652,8 @@
|
|
|
547
652
|
|
|
548
653
|
// walk up and clip ONLY by scrollable ancestors
|
|
549
654
|
var parent = element.parentElement;
|
|
550
|
-
while (parent && parent !==
|
|
551
|
-
var style =
|
|
655
|
+
while (parent && parent !== element.ownerDocument.body) {
|
|
656
|
+
var style = getWindowOf(parent).getComputedStyle(parent);
|
|
552
657
|
var overflowY = style.overflowY;
|
|
553
658
|
var overflowX = style.overflowX;
|
|
554
659
|
var isScrollableY = overflowY === "scroll" || overflowY === "auto";
|
|
@@ -727,72 +832,12 @@
|
|
|
727
832
|
};
|
|
728
833
|
}
|
|
729
834
|
|
|
730
|
-
/**
|
|
731
|
-
* @param {Object} object
|
|
732
|
-
* @return {string}
|
|
733
|
-
*/
|
|
734
|
-
function toString(object) {
|
|
735
|
-
return JSON.stringify(object, null, 2);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* Finds the depth of the given node in the DOM tree
|
|
740
|
-
* @param {HTMLElement} node
|
|
741
|
-
* @return {number} - the depth of the node
|
|
742
|
-
*/
|
|
743
|
-
function getDepth(node) {
|
|
744
|
-
if (!node) {
|
|
745
|
-
throw new Error("cannot get depth of a falsy node");
|
|
746
|
-
}
|
|
747
|
-
return _getDepth(node, 0);
|
|
748
|
-
}
|
|
749
|
-
function _getDepth(node) {
|
|
750
|
-
var countSoFar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
751
|
-
if (!node.parentElement) {
|
|
752
|
-
return countSoFar - 1;
|
|
753
|
-
}
|
|
754
|
-
return _getDepth(node.parentElement, countSoFar + 1);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
/**
|
|
758
|
-
* A simple util to shallow compare objects quickly, it doesn't validate the arguments so pass objects in
|
|
759
|
-
* @param {Object} objA
|
|
760
|
-
* @param {Object} objB
|
|
761
|
-
* @return {boolean} - true if objA and objB are shallow equal
|
|
762
|
-
*/
|
|
763
|
-
function areObjectsShallowEqual(objA, objB) {
|
|
764
|
-
if (Object.keys(objA).length !== Object.keys(objB).length) {
|
|
765
|
-
return false;
|
|
766
|
-
}
|
|
767
|
-
for (var keyA in objA) {
|
|
768
|
-
if (!{}.hasOwnProperty.call(objB, keyA) || objB[keyA] !== objA[keyA]) {
|
|
769
|
-
return false;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
return true;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
/**
|
|
776
|
-
* Shallow compares two arrays
|
|
777
|
-
* @param arrA
|
|
778
|
-
* @param arrB
|
|
779
|
-
* @return {boolean} - whether the arrays are shallow equal
|
|
780
|
-
*/
|
|
781
|
-
function areArraysShallowEqualSameOrder(arrA, arrB) {
|
|
782
|
-
if (arrA.length !== arrB.length) {
|
|
783
|
-
return false;
|
|
784
|
-
}
|
|
785
|
-
for (var i = 0; i < arrA.length; i++) {
|
|
786
|
-
if (arrA[i] !== arrB[i]) {
|
|
787
|
-
return false;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
return true;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
835
|
var INTERVAL_MS = 200;
|
|
794
836
|
var TOLERANCE_PX = 10;
|
|
795
837
|
var next;
|
|
838
|
+
// The observation in progress. A consider handler can end the drag in the middle of an observation tick, for example by
|
|
839
|
+
// removing the drag's window, and the tick must not carry on with a drag that has ended.
|
|
840
|
+
var currentObservation;
|
|
796
841
|
|
|
797
842
|
/**
|
|
798
843
|
* Tracks the dragged elements and performs the side effects when it is dragged over a drop zone (basically dispatching custom-events scrolling)
|
|
@@ -811,6 +856,9 @@
|
|
|
811
856
|
var lastIndexFound;
|
|
812
857
|
var lastIsDraggedInADropZone = false;
|
|
813
858
|
var lastCentrePositionOfDragged;
|
|
859
|
+
var win = getWindowOf(draggedEl);
|
|
860
|
+
var observation = {};
|
|
861
|
+
currentObservation = observation;
|
|
814
862
|
// We are sorting to make sure that in case of nested zones of the same type the one "on top" is considered first
|
|
815
863
|
var dropZonesFromDeepToShallow = Array.from(dropZones).sort(function (dz1, dz2) {
|
|
816
864
|
return getDepth(dz2) - getDepth(dz1);
|
|
@@ -824,7 +872,7 @@
|
|
|
824
872
|
var scrolled = multiScroller.multiScrollIfNeeded();
|
|
825
873
|
// we only want to make a new decision after the element was moved a bit to prevent flickering
|
|
826
874
|
if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - referencePoint.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - referencePoint.y) < TOLERANCE_PX) {
|
|
827
|
-
next =
|
|
875
|
+
next = setTimeoutIn(win, andNow, intervalMs);
|
|
828
876
|
return;
|
|
829
877
|
}
|
|
830
878
|
if (isElementOffDocument(draggedEl)) {
|
|
@@ -853,6 +901,7 @@
|
|
|
853
901
|
// the element is over a container
|
|
854
902
|
if (dz !== lastDropZoneFound) {
|
|
855
903
|
lastDropZoneFound && dispatchDraggedElementLeftContainerForAnother(lastDropZoneFound, draggedEl, dz);
|
|
904
|
+
if (currentObservation !== observation) return;
|
|
856
905
|
dispatchDraggedElementEnteredContainer(dz, indexObj, draggedEl);
|
|
857
906
|
lastDropZoneFound = dz;
|
|
858
907
|
} else if (index !== lastIndexFound) {
|
|
@@ -876,7 +925,8 @@
|
|
|
876
925
|
} else {
|
|
877
926
|
lastIsDraggedInADropZone = true;
|
|
878
927
|
}
|
|
879
|
-
|
|
928
|
+
if (currentObservation !== observation) return;
|
|
929
|
+
next = setTimeoutIn(win, andNow, intervalMs);
|
|
880
930
|
}
|
|
881
931
|
andNow();
|
|
882
932
|
}
|
|
@@ -886,7 +936,9 @@
|
|
|
886
936
|
printDebug(function () {
|
|
887
937
|
return "unobserving";
|
|
888
938
|
});
|
|
889
|
-
|
|
939
|
+
currentObservation = undefined;
|
|
940
|
+
clearTimeoutIn(next);
|
|
941
|
+
next = undefined;
|
|
890
942
|
resetIndexesCache();
|
|
891
943
|
}
|
|
892
944
|
|
|
@@ -912,7 +964,7 @@
|
|
|
912
964
|
stepPx = _scrollingInfo.stepPx;
|
|
913
965
|
if (directionObj) {
|
|
914
966
|
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
915
|
-
|
|
967
|
+
getWindowOf(containerEl).requestAnimationFrame(function () {
|
|
916
968
|
return scrollContainer(containerEl);
|
|
917
969
|
});
|
|
918
970
|
}
|
|
@@ -1001,11 +1053,11 @@
|
|
|
1001
1053
|
*/
|
|
1002
1054
|
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
1003
1055
|
// Even if the scrolling element is small it acts as a scroller for the viewport
|
|
1004
|
-
var rect = el ===
|
|
1056
|
+
var rect = el === el.ownerDocument.scrollingElement ? {
|
|
1005
1057
|
top: 0,
|
|
1006
|
-
bottom:
|
|
1058
|
+
bottom: getWindowOf(el).innerHeight,
|
|
1007
1059
|
left: 0,
|
|
1008
|
-
right:
|
|
1060
|
+
right: getWindowOf(el).innerWidth
|
|
1009
1061
|
} : el.getBoundingClientRect();
|
|
1010
1062
|
if (!isPointInsideRect(point, rect)) {
|
|
1011
1063
|
return null;
|
|
@@ -1050,7 +1102,7 @@
|
|
|
1050
1102
|
return false;
|
|
1051
1103
|
}
|
|
1052
1104
|
var scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(function (el) {
|
|
1053
|
-
return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el ===
|
|
1105
|
+
return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === el.ownerDocument.scrollingElement;
|
|
1054
1106
|
});
|
|
1055
1107
|
for (var i = 0; i < scrollContainersUnderCursor.length; i++) {
|
|
1056
1108
|
var scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
|
|
@@ -1078,8 +1130,8 @@
|
|
|
1078
1130
|
var scrollableContainers = [];
|
|
1079
1131
|
var parent = element;
|
|
1080
1132
|
while (parent) {
|
|
1081
|
-
var
|
|
1082
|
-
overflow =
|
|
1133
|
+
var _getWindowOf$getCompu = getWindowOf(parent).getComputedStyle(parent),
|
|
1134
|
+
overflow = _getWindowOf$getCompu.overflow;
|
|
1083
1135
|
if (overflow.split(" ").some(function (o) {
|
|
1084
1136
|
return o.includes("auto") || o.includes("scroll");
|
|
1085
1137
|
})) {
|
|
@@ -1099,16 +1151,17 @@
|
|
|
1099
1151
|
findScrollableParents(dz).forEach(function (container) {
|
|
1100
1152
|
return scrollingContainers.add(container);
|
|
1101
1153
|
});
|
|
1154
|
+
// The scrolling element might have overflow visible and still be scrollable
|
|
1155
|
+
var scrollingElement = dz.ownerDocument.scrollingElement;
|
|
1156
|
+
if (scrollingElement.scrollHeight > scrollingElement.clientHeight || scrollingElement.scrollWidth > scrollingElement.clientHeight) {
|
|
1157
|
+
scrollingContainers.add(scrollingElement);
|
|
1158
|
+
}
|
|
1102
1159
|
}
|
|
1103
|
-
// The scrolling element might have overflow visible and still be scrollable
|
|
1104
1160
|
} catch (err) {
|
|
1105
1161
|
_iterator.e(err);
|
|
1106
1162
|
} finally {
|
|
1107
1163
|
_iterator.f();
|
|
1108
1164
|
}
|
|
1109
|
-
if (document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight || document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight) {
|
|
1110
|
-
scrollingContainers.add(document.scrollingElement);
|
|
1111
|
-
}
|
|
1112
1165
|
return scrollingContainers;
|
|
1113
1166
|
}
|
|
1114
1167
|
|
|
@@ -1227,6 +1280,7 @@
|
|
|
1227
1280
|
*/
|
|
1228
1281
|
function createDraggedElementFrom(originalElement, positionCenterOnXY) {
|
|
1229
1282
|
var rect = originalElement.getBoundingClientRect();
|
|
1283
|
+
var win = getWindowOf(originalElement);
|
|
1230
1284
|
var draggedEl = svelteNodeClone(originalElement);
|
|
1231
1285
|
copyStylesFromTo(originalElement, draggedEl);
|
|
1232
1286
|
draggedEl.id = DRAGGED_ELEMENT_ID;
|
|
@@ -1239,7 +1293,7 @@
|
|
|
1239
1293
|
var center = findCenter(rect);
|
|
1240
1294
|
elTopPx -= center.y - positionCenterOnXY.y;
|
|
1241
1295
|
elLeftPx -= center.x - positionCenterOnXY.x;
|
|
1242
|
-
|
|
1296
|
+
win.setTimeout(function () {
|
|
1243
1297
|
draggedEl.style.top = "".concat(elTopPx, "px");
|
|
1244
1298
|
draggedEl.style.left = "".concat(elLeftPx, "px");
|
|
1245
1299
|
}, 0);
|
|
@@ -1251,7 +1305,7 @@
|
|
|
1251
1305
|
draggedEl.style.width = "".concat(rect.width, "px");
|
|
1252
1306
|
draggedEl.style.transition = "".concat(trs("top"), ", ").concat(trs("left"), ", ").concat(trs("background-color"), ", ").concat(trs("opacity"), ", ").concat(trs("color"), " ");
|
|
1253
1307
|
// this is a workaround for a strange browser bug that causes the right border to disappear when all the transitions are added at the same time
|
|
1254
|
-
|
|
1308
|
+
win.setTimeout(function () {
|
|
1255
1309
|
return ensureMorphSizeTransitions(draggedEl);
|
|
1256
1310
|
}, 0);
|
|
1257
1311
|
draggedEl.style.zIndex = "9999";
|
|
@@ -1279,7 +1333,7 @@
|
|
|
1279
1333
|
copyStylesFromTo(copyFromEl, draggedEl);
|
|
1280
1334
|
var newRect = copyFromEl.getBoundingClientRect();
|
|
1281
1335
|
var draggedElRect = draggedEl.getBoundingClientRect();
|
|
1282
|
-
var draggedElComputedStyle =
|
|
1336
|
+
var draggedElComputedStyle = getWindowOf(draggedEl).getComputedStyle(draggedEl);
|
|
1283
1337
|
var currentLeft = parseFloat(draggedElComputedStyle.left);
|
|
1284
1338
|
var currentTop = parseFloat(draggedElComputedStyle.top);
|
|
1285
1339
|
var widthChange = newRect.width - draggedElRect.width;
|
|
@@ -1303,7 +1357,7 @@
|
|
|
1303
1357
|
* @param {HTMLElement} copyToEl
|
|
1304
1358
|
*/
|
|
1305
1359
|
function copyStylesFromTo(copyFromEl, copyToEl) {
|
|
1306
|
-
var computedStyle =
|
|
1360
|
+
var computedStyle = getWindowOf(copyFromEl).getComputedStyle(copyFromEl);
|
|
1307
1361
|
Array.from(computedStyle).filter(function (s) {
|
|
1308
1362
|
return s.startsWith("background") || s.startsWith("padding") || s.startsWith("font") || s.startsWith("text") || s.startsWith("align") || s.startsWith("justify") || s.startsWith("display") || s.startsWith("flex") || s.startsWith("border") || s === "opacity" || s === "color" || s === "list-style-type" ||
|
|
1309
1363
|
// copying with and height to make up for rect update timing issues in some browsers
|
|
@@ -1413,9 +1467,10 @@
|
|
|
1413
1467
|
*/
|
|
1414
1468
|
function preventShrinking(el) {
|
|
1415
1469
|
var originalMinHeight = el.style.minHeight;
|
|
1416
|
-
|
|
1470
|
+
var computedStyle = getWindowOf(el).getComputedStyle(el);
|
|
1471
|
+
el.style.minHeight = computedStyle.getPropertyValue("height");
|
|
1417
1472
|
var originalMinWidth = el.style.minWidth;
|
|
1418
|
-
el.style.minWidth =
|
|
1473
|
+
el.style.minWidth = computedStyle.getPropertyValue("width");
|
|
1419
1474
|
return function undo() {
|
|
1420
1475
|
el.style.minHeight = originalMinHeight;
|
|
1421
1476
|
el.style.minWidth = originalMinWidth;
|
|
@@ -1452,6 +1507,11 @@
|
|
|
1452
1507
|
var useCursorForDetectionActive = false;
|
|
1453
1508
|
var pendingDragOwner;
|
|
1454
1509
|
var watchedDropZones = new Set();
|
|
1510
|
+
// The window of the drag in progress: the dragged item's own window, which is not the one that
|
|
1511
|
+
// loaded this module when the zone lives in a same-origin iframe or a popup.
|
|
1512
|
+
var dragWindow;
|
|
1513
|
+
// While the drop animation runs: its timeout and the function that finalizes the drop
|
|
1514
|
+
var dropFinalization;
|
|
1455
1515
|
|
|
1456
1516
|
// a map from type to a set of drop-zones
|
|
1457
1517
|
var typeToDropZones$1 = new Map();
|
|
@@ -1481,14 +1541,21 @@
|
|
|
1481
1541
|
typeToDropZones$1["delete"](type);
|
|
1482
1542
|
}
|
|
1483
1543
|
}
|
|
1544
|
+
// The pointer is only tracked in the drag's window and each window has its own coordinates, so zones in other windows
|
|
1545
|
+
// are not candidates, and neither are zones whose window is gone
|
|
1546
|
+
function getDropZonesInDragWindow(type) {
|
|
1547
|
+
return Array.from(typeToDropZones$1.get(type) || []).filter(function (dz) {
|
|
1548
|
+
return dz.ownerDocument.defaultView === dragWindow;
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1484
1551
|
|
|
1485
1552
|
/* functions to manage observing the dragged element and trigger custom drag-events */
|
|
1486
1553
|
function watchDraggedElement() {
|
|
1487
1554
|
printDebug(function () {
|
|
1488
1555
|
return "watching dragged element";
|
|
1489
1556
|
});
|
|
1490
|
-
var dropZones =
|
|
1491
|
-
if (
|
|
1557
|
+
var dropZones = getDropZonesInDragWindow(draggedElType);
|
|
1558
|
+
if (dropZones.length === 0) return;
|
|
1492
1559
|
if (watchedDropZones.size > 0) unWatchDraggedElement();
|
|
1493
1560
|
watchedDropZones = new Set(dropZones);
|
|
1494
1561
|
var _iterator = _createForOfIteratorHelper(watchedDropZones),
|
|
@@ -1505,7 +1572,7 @@
|
|
|
1505
1572
|
} finally {
|
|
1506
1573
|
_iterator.f();
|
|
1507
1574
|
}
|
|
1508
|
-
|
|
1575
|
+
dragWindow.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop$1);
|
|
1509
1576
|
|
|
1510
1577
|
// it is important that we don't have an interval that is faster than the flip duration because it can cause elements to jump bach and forth
|
|
1511
1578
|
var setIntervalMs = Math.max.apply(Math, _toConsumableArray(Array.from(watchedDropZones).map(function (dz) {
|
|
@@ -1518,8 +1585,8 @@
|
|
|
1518
1585
|
// Returns reference point in document coordinates - either cursor position or element center
|
|
1519
1586
|
var getReferencePoint = useCursorForDetectionActive ? function () {
|
|
1520
1587
|
return {
|
|
1521
|
-
x: currentMousePosition.x +
|
|
1522
|
-
y: currentMousePosition.y +
|
|
1588
|
+
x: currentMousePosition.x + dragWindow.scrollX,
|
|
1589
|
+
y: currentMousePosition.y + dragWindow.scrollY
|
|
1523
1590
|
};
|
|
1524
1591
|
} : function () {
|
|
1525
1592
|
return findCenterOfElement(draggedEl);
|
|
@@ -1545,7 +1612,7 @@
|
|
|
1545
1612
|
_iterator2.f();
|
|
1546
1613
|
}
|
|
1547
1614
|
watchedDropZones = new Set();
|
|
1548
|
-
|
|
1615
|
+
dragWindow.removeEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop$1);
|
|
1549
1616
|
// ensuring multiScroller is not already destroyed before destroying
|
|
1550
1617
|
if (multiScroller) {
|
|
1551
1618
|
multiScroller.destroy();
|
|
@@ -1595,6 +1662,8 @@
|
|
|
1595
1662
|
id: draggedElData[ITEM_ID_KEY],
|
|
1596
1663
|
source: SOURCES.POINTER
|
|
1597
1664
|
});
|
|
1665
|
+
// the handler can end the drag, for example by removing its window
|
|
1666
|
+
if (!isWorkingOnPreviousDrag) return;
|
|
1598
1667
|
}
|
|
1599
1668
|
var shadowElIdx = e.detail.indexObj.index;
|
|
1600
1669
|
shadowElDropZone = e.currentTarget;
|
|
@@ -1644,6 +1713,8 @@
|
|
|
1644
1713
|
id: draggedElData[ITEM_ID_KEY],
|
|
1645
1714
|
source: SOURCES.POINTER
|
|
1646
1715
|
});
|
|
1716
|
+
// the handler can end the drag, for example by removing its window
|
|
1717
|
+
if (!isWorkingOnPreviousDrag) return;
|
|
1647
1718
|
}
|
|
1648
1719
|
// for the origin dz, when the dragged is outside of any, this will be fired in addition to the previous. this is for simplicity
|
|
1649
1720
|
dispatchConsiderEvent(e.currentTarget, items, {
|
|
@@ -1696,10 +1767,10 @@
|
|
|
1696
1767
|
});
|
|
1697
1768
|
finalizingPreviousDrag = true;
|
|
1698
1769
|
// cleanup
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1770
|
+
dragWindow.removeEventListener("mousemove", handleMouseMove);
|
|
1771
|
+
dragWindow.removeEventListener("touchmove", handleMouseMove);
|
|
1772
|
+
dragWindow.removeEventListener("mouseup", handleDrop$1);
|
|
1773
|
+
dragWindow.removeEventListener("touchend", handleDrop$1);
|
|
1703
1774
|
unWatchDraggedElement();
|
|
1704
1775
|
moveDraggedElementToWasDroppedState(draggedEl);
|
|
1705
1776
|
if (!shadowElDropZone) {
|
|
@@ -1714,7 +1785,7 @@
|
|
|
1714
1785
|
var _dzToConfig$get4 = dzToConfig$1.get(shadowElDropZone),
|
|
1715
1786
|
items = _dzToConfig$get4.items,
|
|
1716
1787
|
type = _dzToConfig$get4.type;
|
|
1717
|
-
styleInactiveDropZones(
|
|
1788
|
+
styleInactiveDropZones(getDropZonesInDragWindow(type), function (dz) {
|
|
1718
1789
|
return dzToConfig$1.get(dz).dropTargetStyle;
|
|
1719
1790
|
}, function (dz) {
|
|
1720
1791
|
return dzToConfig$1.get(dz).dropTargetClasses;
|
|
@@ -1773,7 +1844,32 @@
|
|
|
1773
1844
|
var transition = "transform ".concat(dropAnimationDurationMs, "ms ease");
|
|
1774
1845
|
draggedEl.style.transition = draggedEl.style.transition ? draggedEl.style.transition + "," + transition : transition;
|
|
1775
1846
|
draggedEl.style.transform = "translate3d(".concat(newTransform.x, "px, ").concat(newTransform.y, "px, 0)");
|
|
1776
|
-
|
|
1847
|
+
dropFinalization = {
|
|
1848
|
+
timeout: setTimeoutIn(dragWindow, finishDropAnimation, dropAnimationDurationMs),
|
|
1849
|
+
finalize: callback
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
function finishDropAnimation() {
|
|
1853
|
+
var _dropFinalization = dropFinalization,
|
|
1854
|
+
finalize = _dropFinalization.finalize;
|
|
1855
|
+
// cleared first, because a finalize handler can remove the drag's window
|
|
1856
|
+
dropFinalization = undefined;
|
|
1857
|
+
finalize();
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// The drag's window is going away: it was closed or navigated, or its iframe was removed. Its events, timers and animation
|
|
1861
|
+
// frames stop, so finish the drag now, without the drop animation, and let the other windows start new drags.
|
|
1862
|
+
function handleDragWindowHidden() {
|
|
1863
|
+
printDebug(function () {
|
|
1864
|
+
return "the drag's window is going away";
|
|
1865
|
+
});
|
|
1866
|
+
if (!finalizingPreviousDrag) {
|
|
1867
|
+
handleDrop$1();
|
|
1868
|
+
}
|
|
1869
|
+
if (dropFinalization) {
|
|
1870
|
+
clearTimeoutIn(dropFinalization.timeout);
|
|
1871
|
+
finishDropAnimation();
|
|
1872
|
+
}
|
|
1777
1873
|
}
|
|
1778
1874
|
function scheduleDZForRemovalAfterDrop(dz, destroy) {
|
|
1779
1875
|
var scheduledRemoval = {
|
|
@@ -1781,10 +1877,10 @@
|
|
|
1781
1877
|
destroy: destroy
|
|
1782
1878
|
};
|
|
1783
1879
|
scheduledForRemovalAfterDrop.push(scheduledRemoval);
|
|
1784
|
-
|
|
1880
|
+
getWindowOf(dz).requestAnimationFrame(function () {
|
|
1785
1881
|
if (!scheduledForRemovalAfterDrop.includes(scheduledRemoval)) return;
|
|
1786
1882
|
hideElement(dz);
|
|
1787
|
-
|
|
1883
|
+
dz.ownerDocument.body.appendChild(dz);
|
|
1788
1884
|
});
|
|
1789
1885
|
}
|
|
1790
1886
|
/* cleanup */
|
|
@@ -1810,9 +1906,9 @@
|
|
|
1810
1906
|
finalizingPreviousDrag = false;
|
|
1811
1907
|
unlockOriginDzMinDimensions = undefined;
|
|
1812
1908
|
isDraggedOutsideOfAnyDz = false;
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1909
|
+
dragWindow.removeEventListener("pagehide", handleDragWindowHidden);
|
|
1910
|
+
dragWindow = undefined;
|
|
1911
|
+
clearTimeoutIn(touchDragHoldTimer);
|
|
1816
1912
|
touchDragHoldTimer = undefined;
|
|
1817
1913
|
touchHoldElapsed = false;
|
|
1818
1914
|
useCursorForDetectionActive = false;
|
|
@@ -1855,27 +1951,29 @@
|
|
|
1855
1951
|
});
|
|
1856
1952
|
var elToIdx = new Map();
|
|
1857
1953
|
function addMaybeListeners() {
|
|
1858
|
-
|
|
1954
|
+
dragWindow.addEventListener("mousemove", handleMouseMoveMaybeDragStart, {
|
|
1859
1955
|
passive: false
|
|
1860
1956
|
});
|
|
1861
|
-
|
|
1957
|
+
dragWindow.addEventListener("touchmove", handleMouseMoveMaybeDragStart, {
|
|
1862
1958
|
passive: false,
|
|
1863
1959
|
capture: false
|
|
1864
1960
|
});
|
|
1865
|
-
|
|
1961
|
+
dragWindow.addEventListener("mouseup", handleFalseAlarm, {
|
|
1866
1962
|
passive: false
|
|
1867
1963
|
});
|
|
1868
|
-
|
|
1964
|
+
dragWindow.addEventListener("touchend", handleFalseAlarm, {
|
|
1869
1965
|
passive: false
|
|
1870
1966
|
});
|
|
1967
|
+
dragWindow.addEventListener("pagehide", cancelPendingDrag);
|
|
1871
1968
|
}
|
|
1872
1969
|
function removeMaybeListeners() {
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1970
|
+
dragWindow.removeEventListener("mousemove", handleMouseMoveMaybeDragStart);
|
|
1971
|
+
dragWindow.removeEventListener("touchmove", handleMouseMoveMaybeDragStart);
|
|
1972
|
+
dragWindow.removeEventListener("mouseup", handleFalseAlarm);
|
|
1973
|
+
dragWindow.removeEventListener("touchend", handleFalseAlarm);
|
|
1974
|
+
dragWindow.removeEventListener("pagehide", cancelPendingDrag);
|
|
1877
1975
|
if (touchDragHoldTimer) {
|
|
1878
|
-
|
|
1976
|
+
clearTimeoutIn(touchDragHoldTimer);
|
|
1879
1977
|
touchDragHoldTimer = undefined;
|
|
1880
1978
|
touchHoldElapsed = false;
|
|
1881
1979
|
}
|
|
@@ -1883,6 +1981,7 @@
|
|
|
1883
1981
|
function cancelPendingDrag() {
|
|
1884
1982
|
if (pendingDragOwner !== node) return;
|
|
1885
1983
|
removeMaybeListeners();
|
|
1984
|
+
dragWindow = undefined;
|
|
1886
1985
|
pendingDragOwner = undefined;
|
|
1887
1986
|
originalDragTarget = undefined;
|
|
1888
1987
|
dragStartMousePosition = undefined;
|
|
@@ -1894,7 +1993,7 @@
|
|
|
1894
1993
|
|
|
1895
1994
|
// dragging initiated by touch events prevents onclick from initially firing
|
|
1896
1995
|
if (e.type === "touchend") {
|
|
1897
|
-
var clickEvent = new Event("click", {
|
|
1996
|
+
var clickEvent = new (getWindowOf(e.target).Event)("click", {
|
|
1898
1997
|
bubbles: true,
|
|
1899
1998
|
cancelable: true
|
|
1900
1999
|
});
|
|
@@ -1916,10 +2015,8 @@
|
|
|
1916
2015
|
};
|
|
1917
2016
|
if (Math.abs(currentMousePosition.x - dragStartMousePosition.x) >= MIN_MOVEMENT_BEFORE_DRAG_START_PX || Math.abs(currentMousePosition.y - dragStartMousePosition.y) >= MIN_MOVEMENT_BEFORE_DRAG_START_PX) {
|
|
1918
2017
|
// User started scrolling, cancel drag attempt.
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
touchDragHoldTimer = undefined;
|
|
1922
|
-
}
|
|
2018
|
+
clearTimeoutIn(touchDragHoldTimer);
|
|
2019
|
+
touchDragHoldTimer = undefined;
|
|
1923
2020
|
handleFalseAlarm(e);
|
|
1924
2021
|
}
|
|
1925
2022
|
return; // Do not preventDefault so scrolling works.
|
|
@@ -1970,10 +2067,11 @@
|
|
|
1970
2067
|
};
|
|
1971
2068
|
currentMousePosition = _objectSpread2({}, dragStartMousePosition);
|
|
1972
2069
|
originalDragTarget = e.currentTarget;
|
|
2070
|
+
dragWindow = getWindowOf(originalDragTarget);
|
|
1973
2071
|
if (useDelay) {
|
|
1974
2072
|
var pendingTarget = originalDragTarget;
|
|
1975
2073
|
touchHoldElapsed = false;
|
|
1976
|
-
touchDragHoldTimer =
|
|
2074
|
+
touchDragHoldTimer = setTimeoutIn(dragWindow, function () {
|
|
1977
2075
|
// If this action still owns the same pending gesture, transition it to a drag.
|
|
1978
2076
|
if (destroyed || pendingDragOwner !== node || originalDragTarget !== pendingTarget) return;
|
|
1979
2077
|
touchHoldElapsed = true;
|
|
@@ -2026,17 +2124,19 @@
|
|
|
2026
2124
|
originDropZoneRoot.appendChild(originalDragTarget);
|
|
2027
2125
|
// have to watch before we hide, otherwise Svelte 5 $state gets confused
|
|
2028
2126
|
watchDraggedElement();
|
|
2127
|
+
// a consider handler during the first observation can end the drag, for example by removing its window
|
|
2128
|
+
if (!draggedEl) return;
|
|
2029
2129
|
hideElement(originalDragTarget);
|
|
2030
2130
|
// after the removal of the original element we can give the shadow element the original item id so that the host zone can find it and render it correctly if it does lookups by id
|
|
2031
2131
|
shadowElData[ITEM_ID_KEY] = draggedElData[ITEM_ID_KEY];
|
|
2032
2132
|
// to prevent the outline from disappearing
|
|
2033
2133
|
draggedEl.focus();
|
|
2034
2134
|
} else {
|
|
2035
|
-
|
|
2135
|
+
dragWindow.requestAnimationFrame(keepOriginalElementInDom);
|
|
2036
2136
|
}
|
|
2037
2137
|
}
|
|
2038
|
-
|
|
2039
|
-
styleActiveDropZones(
|
|
2138
|
+
dragWindow.requestAnimationFrame(keepOriginalElementInDom);
|
|
2139
|
+
styleActiveDropZones(getDropZonesInDragWindow(config.type).filter(function (dz) {
|
|
2040
2140
|
return dz === originDropZone || !dzToConfig$1.get(dz).dropFromOthersDisabled;
|
|
2041
2141
|
}), function (dz) {
|
|
2042
2142
|
return dzToConfig$1.get(dz).dropTargetStyle;
|
|
@@ -2047,26 +2147,28 @@
|
|
|
2047
2147
|
// removing the original element by removing its data entry
|
|
2048
2148
|
items.splice(currentIdx, 1, shadowElData);
|
|
2049
2149
|
unlockOriginDzMinDimensions = preventShrinking(originDropZone);
|
|
2050
|
-
dispatchConsiderEvent(originDropZone, items, {
|
|
2051
|
-
trigger: TRIGGERS.DRAG_STARTED,
|
|
2052
|
-
id: draggedElData[ITEM_ID_KEY],
|
|
2053
|
-
source: SOURCES.POINTER
|
|
2054
|
-
});
|
|
2055
2150
|
|
|
2056
|
-
// handing over to global handlers - starting to watch the element
|
|
2057
|
-
window
|
|
2151
|
+
// handing over to global handlers - starting to watch the element. This happens before the consider event because
|
|
2152
|
+
// its handler can remove the drag's window, which ends the drag.
|
|
2153
|
+
dragWindow.addEventListener("mousemove", handleMouseMove, {
|
|
2058
2154
|
passive: false
|
|
2059
2155
|
});
|
|
2060
|
-
|
|
2156
|
+
dragWindow.addEventListener("touchmove", handleMouseMove, {
|
|
2061
2157
|
passive: false,
|
|
2062
2158
|
capture: false
|
|
2063
2159
|
});
|
|
2064
|
-
|
|
2160
|
+
dragWindow.addEventListener("mouseup", handleDrop$1, {
|
|
2065
2161
|
passive: false
|
|
2066
2162
|
});
|
|
2067
|
-
|
|
2163
|
+
dragWindow.addEventListener("touchend", handleDrop$1, {
|
|
2068
2164
|
passive: false
|
|
2069
2165
|
});
|
|
2166
|
+
dragWindow.addEventListener("pagehide", handleDragWindowHidden);
|
|
2167
|
+
dispatchConsiderEvent(originDropZone, items, {
|
|
2168
|
+
trigger: TRIGGERS.DRAG_STARTED,
|
|
2169
|
+
id: draggedElData[ITEM_ID_KEY],
|
|
2170
|
+
source: SOURCES.POINTER
|
|
2171
|
+
});
|
|
2070
2172
|
}
|
|
2071
2173
|
function configure(_ref2) {
|
|
2072
2174
|
var _ref2$items = _ref2.items,
|
|
@@ -2095,6 +2197,9 @@
|
|
|
2095
2197
|
dropAnimationDisabled = _ref2$dropAnimationDi === void 0 ? false : _ref2$dropAnimationDi,
|
|
2096
2198
|
_ref2$delayTouchStart = _ref2.delayTouchStart,
|
|
2097
2199
|
delayTouchStartOpt = _ref2$delayTouchStart === void 0 ? false : _ref2$delayTouchStart;
|
|
2200
|
+
var isInDragWindow = isWorkingOnPreviousDrag && node.ownerDocument.defaultView === dragWindow;
|
|
2201
|
+
var wasDropTarget = node === originDropZone || config.type === draggedElType && !config.dropFromOthersDisabled;
|
|
2202
|
+
var isDropTarget = node === originDropZone || newType === draggedElType && !dropFromOthersDisabled;
|
|
2098
2203
|
config.dropAnimationDurationMs = dropAnimationDurationMs;
|
|
2099
2204
|
var effectiveDelayMs = 0;
|
|
2100
2205
|
if (delayTouchStartOpt === true) {
|
|
@@ -2115,41 +2220,26 @@
|
|
|
2115
2220
|
config.useCursorForDetection = useCursorForDetection;
|
|
2116
2221
|
config.dropAnimationDisabled = dropAnimationDisabled;
|
|
2117
2222
|
|
|
2118
|
-
//
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
return dropTargetStyle;
|
|
2127
|
-
}, function () {
|
|
2128
|
-
return dropTargetClasses;
|
|
2129
|
-
});
|
|
2130
|
-
}
|
|
2131
|
-
config.dropTargetStyle = dropTargetStyle;
|
|
2132
|
-
config.dropTargetClasses = _toConsumableArray(dropTargetClasses);
|
|
2133
|
-
|
|
2134
|
-
// realtime update for dropFromOthersDisabled
|
|
2135
|
-
function getConfigProp(dz, propName) {
|
|
2136
|
-
return dzToConfig$1.get(dz) ? dzToConfig$1.get(dz)[propName] : config[propName];
|
|
2137
|
-
}
|
|
2138
|
-
if (initialized && isWorkingOnPreviousDrag && config.dropFromOthersDisabled !== dropFromOthersDisabled) {
|
|
2139
|
-
if (dropFromOthersDisabled) {
|
|
2140
|
-
styleInactiveDropZones([node], function (dz) {
|
|
2141
|
-
return getConfigProp(dz, "dropTargetStyle");
|
|
2142
|
-
}, function (dz) {
|
|
2143
|
-
return getConfigProp(dz, "dropTargetClasses");
|
|
2223
|
+
// Realtime styling follows the same eligibility as drag start. Remove the previously applied styles and
|
|
2224
|
+
// classes before storing the new options, including when disabling incoming drops and changing styles together.
|
|
2225
|
+
if (initialized && isInDragWindow && !finalizingPreviousDrag && (wasDropTarget !== isDropTarget || !areObjectsShallowEqual(dropTargetStyle, config.dropTargetStyle) || !areArraysShallowEqualSameOrder(dropTargetClasses, config.dropTargetClasses))) {
|
|
2226
|
+
if (wasDropTarget) {
|
|
2227
|
+
styleInactiveDropZones([node], function () {
|
|
2228
|
+
return config.dropTargetStyle;
|
|
2229
|
+
}, function () {
|
|
2230
|
+
return config.dropTargetClasses;
|
|
2144
2231
|
});
|
|
2145
|
-
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2232
|
+
}
|
|
2233
|
+
if (isDropTarget) {
|
|
2234
|
+
styleActiveDropZones([node], function () {
|
|
2235
|
+
return dropTargetStyle;
|
|
2236
|
+
}, function () {
|
|
2237
|
+
return dropTargetClasses;
|
|
2150
2238
|
});
|
|
2151
2239
|
}
|
|
2152
2240
|
}
|
|
2241
|
+
config.dropTargetStyle = dropTargetStyle;
|
|
2242
|
+
config.dropTargetClasses = _toConsumableArray(dropTargetClasses);
|
|
2153
2243
|
config.dropFromOthersDisabled = dropFromOthersDisabled;
|
|
2154
2244
|
dzToConfig$1.set(node, config);
|
|
2155
2245
|
registerDropZone$1(node, newType);
|
|
@@ -2174,10 +2264,9 @@
|
|
|
2174
2264
|
}
|
|
2175
2265
|
// updating the idx
|
|
2176
2266
|
elToIdx.set(draggableEl, idx);
|
|
2177
|
-
if (!initialized) {
|
|
2178
|
-
initialized = true;
|
|
2179
|
-
}
|
|
2180
2267
|
}
|
|
2268
|
+
// Empty zones are initialized too: they can receive active-target styling before they have any children.
|
|
2269
|
+
initialized = true;
|
|
2181
2270
|
}
|
|
2182
2271
|
configure(options);
|
|
2183
2272
|
return {
|
|
@@ -2274,14 +2363,17 @@
|
|
|
2274
2363
|
keyboardDragTrigger: DEFAULT_KEYBOARD_DRAG_TRIGGER
|
|
2275
2364
|
};
|
|
2276
2365
|
var ALERT_DIV_ID = "dnd-action-aria-alert";
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2366
|
+
// A map from a document to its alerts div. A zone can live in another window than the one that loaded this module, so each
|
|
2367
|
+
// document with zones gets its own alerts and instructions. It is a Map rather than a WeakMap so the instructions in every
|
|
2368
|
+
// document can be re-rendered; destroyAria removes the entry.
|
|
2369
|
+
var docToAlertsDiv = new Map();
|
|
2370
|
+
function initAriaOnBrowser(doc) {
|
|
2371
|
+
if (docToAlertsDiv.has(doc)) {
|
|
2280
2372
|
// it is already initialized
|
|
2281
2373
|
return;
|
|
2282
2374
|
}
|
|
2283
2375
|
// setting the dynamic alerts
|
|
2284
|
-
alertsDiv =
|
|
2376
|
+
var alertsDiv = doc.createElement("div");
|
|
2285
2377
|
(function initAlertsDiv() {
|
|
2286
2378
|
alertsDiv.id = ALERT_DIV_ID;
|
|
2287
2379
|
// tab index -1 makes the alert be read twice on chrome for some reason
|
|
@@ -2295,45 +2387,60 @@
|
|
|
2295
2387
|
alertsDiv.style.width = "0";
|
|
2296
2388
|
alertsDiv.setAttribute("role", "alert");
|
|
2297
2389
|
})();
|
|
2298
|
-
|
|
2390
|
+
doc.body.prepend(alertsDiv);
|
|
2391
|
+
// forget the documents whose window is gone
|
|
2392
|
+
docToAlertsDiv.forEach(function (_, knownDoc) {
|
|
2393
|
+
return !knownDoc.defaultView && docToAlertsDiv["delete"](knownDoc);
|
|
2394
|
+
});
|
|
2395
|
+
docToAlertsDiv.set(doc, alertsDiv);
|
|
2299
2396
|
|
|
2300
2397
|
// setting the instructions
|
|
2301
2398
|
Object.entries(INSTRUCTION_ID_TO_STRING_KEY).forEach(function (_ref7) {
|
|
2302
2399
|
var _ref8 = _slicedToArray(_ref7, 2),
|
|
2303
2400
|
id = _ref8[0],
|
|
2304
2401
|
key = _ref8[1];
|
|
2305
|
-
return
|
|
2402
|
+
return doc.body.prepend(instructionToHiddenDiv(doc, id, formatWithFallback(key, instructionCtx)));
|
|
2306
2403
|
});
|
|
2307
2404
|
}
|
|
2308
2405
|
|
|
2309
2406
|
/**
|
|
2310
2407
|
* Initializes the static aria instructions so they can be attached to zones
|
|
2408
|
+
* @param {Document} [doc] - the document of the zones, defaults to the one that loaded this module
|
|
2311
2409
|
* @return {{DND_ZONE_ACTIVE: string, DND_ZONE_DRAG_DISABLED: string} | null} - the IDs for static aria instruction (to be used via aria-describedby) or null on the server
|
|
2312
2410
|
*/
|
|
2313
|
-
function initAria() {
|
|
2411
|
+
function initAria(doc) {
|
|
2314
2412
|
if (isOnServer) return null;
|
|
2315
|
-
|
|
2316
|
-
|
|
2413
|
+
// eslint-disable-next-line no-restricted-globals -- the documented default
|
|
2414
|
+
doc = doc || document;
|
|
2415
|
+
if (doc.readyState === "complete") {
|
|
2416
|
+
initAriaOnBrowser(doc);
|
|
2317
2417
|
} else {
|
|
2318
|
-
|
|
2418
|
+
doc.addEventListener("DOMContentLoaded", function () {
|
|
2419
|
+
return initAriaOnBrowser(doc);
|
|
2420
|
+
});
|
|
2319
2421
|
}
|
|
2320
2422
|
return _objectSpread2({}, INSTRUCTION_IDs$1);
|
|
2321
2423
|
}
|
|
2322
2424
|
|
|
2323
2425
|
/**
|
|
2324
|
-
* Removes all the artifacts (dom elements) added by this module
|
|
2426
|
+
* Removes all the artifacts (dom elements) added by this module to the given document
|
|
2427
|
+
* @param {Document} [doc] - defaults to the document that loaded this module
|
|
2325
2428
|
*/
|
|
2326
|
-
function destroyAria() {
|
|
2327
|
-
if (isOnServer
|
|
2429
|
+
function destroyAria(doc) {
|
|
2430
|
+
if (isOnServer) return;
|
|
2431
|
+
// eslint-disable-next-line no-restricted-globals -- the documented default
|
|
2432
|
+
doc = doc || document;
|
|
2433
|
+
var alertsDiv = docToAlertsDiv.get(doc);
|
|
2434
|
+
if (!alertsDiv) return;
|
|
2328
2435
|
Object.keys(INSTRUCTION_ID_TO_STRING_KEY).forEach(function (id) {
|
|
2329
|
-
var
|
|
2330
|
-
return (
|
|
2436
|
+
var _doc$getElementById;
|
|
2437
|
+
return (_doc$getElementById = doc.getElementById(id)) === null || _doc$getElementById === void 0 ? void 0 : _doc$getElementById.remove();
|
|
2331
2438
|
});
|
|
2332
2439
|
alertsDiv.remove();
|
|
2333
|
-
|
|
2440
|
+
docToAlertsDiv["delete"](doc);
|
|
2334
2441
|
}
|
|
2335
|
-
function instructionToHiddenDiv(id, txt) {
|
|
2336
|
-
var div =
|
|
2442
|
+
function instructionToHiddenDiv(doc, id, txt) {
|
|
2443
|
+
var div = doc.createElement("div");
|
|
2337
2444
|
div.id = id;
|
|
2338
2445
|
renderInstruction(div, txt);
|
|
2339
2446
|
div.style.display = "none";
|
|
@@ -2343,7 +2450,7 @@
|
|
|
2343
2450
|
}
|
|
2344
2451
|
function renderInstruction(div, txt) {
|
|
2345
2452
|
div.replaceChildren();
|
|
2346
|
-
var paragraph =
|
|
2453
|
+
var paragraph = div.ownerDocument.createElement("p");
|
|
2347
2454
|
paragraph.textContent = txt;
|
|
2348
2455
|
div.appendChild(paragraph);
|
|
2349
2456
|
}
|
|
@@ -2351,14 +2458,19 @@
|
|
|
2351
2458
|
/**
|
|
2352
2459
|
* Will make the screen reader alert the provided text to the user
|
|
2353
2460
|
* @param {string} txt
|
|
2461
|
+
* @param {Document} [doc] - the document to announce in, for a zone in another window such as an iframe or a popup.
|
|
2462
|
+
* Defaults to the document that loaded this module.
|
|
2354
2463
|
*/
|
|
2355
|
-
function alertToScreenReader(txt) {
|
|
2464
|
+
function alertToScreenReader(txt, doc) {
|
|
2356
2465
|
if (isOnServer) return;
|
|
2357
|
-
|
|
2358
|
-
|
|
2466
|
+
// eslint-disable-next-line no-restricted-globals -- the documented default
|
|
2467
|
+
doc = doc || document;
|
|
2468
|
+
if (!docToAlertsDiv.has(doc)) {
|
|
2469
|
+
initAriaOnBrowser(doc);
|
|
2359
2470
|
}
|
|
2471
|
+
var alertsDiv = docToAlertsDiv.get(doc);
|
|
2360
2472
|
alertsDiv.innerHTML = "";
|
|
2361
|
-
var alertText =
|
|
2473
|
+
var alertText = doc.createTextNode(txt);
|
|
2362
2474
|
alertsDiv.appendChild(alertText);
|
|
2363
2475
|
// this is needed for Safari
|
|
2364
2476
|
alertsDiv.style.display = "none";
|
|
@@ -2428,12 +2540,14 @@
|
|
|
2428
2540
|
}
|
|
2429
2541
|
function refreshInstructions() {
|
|
2430
2542
|
if (isOnServer) return;
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2543
|
+
docToAlertsDiv.forEach(function (alertsDiv, doc) {
|
|
2544
|
+
return Object.entries(INSTRUCTION_ID_TO_STRING_KEY).forEach(function (_ref9) {
|
|
2545
|
+
var _ref10 = _slicedToArray(_ref9, 2),
|
|
2546
|
+
id = _ref10[0],
|
|
2547
|
+
key = _ref10[1];
|
|
2548
|
+
var div = doc.getElementById(id);
|
|
2549
|
+
if (div) renderInstruction(div, formatWithFallback(key, instructionCtx));
|
|
2550
|
+
});
|
|
2437
2551
|
});
|
|
2438
2552
|
}
|
|
2439
2553
|
|
|
@@ -2453,9 +2567,10 @@
|
|
|
2453
2567
|
* escape because this function runs during the drag lifecycle.
|
|
2454
2568
|
* @param {string} key - one of the keys accepted by setAriaStrings
|
|
2455
2569
|
* @param {Object} [ctx] - the interpolation context for that key
|
|
2570
|
+
* @param {Document} [doc] - the document of the zone the message is about, defaults to the one that loaded this module
|
|
2456
2571
|
*/
|
|
2457
|
-
function announceToScreenReader(key, ctx) {
|
|
2458
|
-
alertToScreenReader(formatWithFallback(key, ctx));
|
|
2572
|
+
function announceToScreenReader(key, ctx, doc) {
|
|
2573
|
+
alertToScreenReader(formatWithFallback(key, ctx), doc);
|
|
2459
2574
|
}
|
|
2460
2575
|
|
|
2461
2576
|
var activeTrigger = DEFAULT_KEYBOARD_DRAG_TRIGGER;
|
|
@@ -2503,12 +2618,20 @@
|
|
|
2503
2618
|
var focusedItem;
|
|
2504
2619
|
var focusedItemId;
|
|
2505
2620
|
var focusedItemLabel = "";
|
|
2621
|
+
// Like pointer dragging, a keyboard drag only has destinations in the document it started in.
|
|
2622
|
+
var dragDocument;
|
|
2506
2623
|
var allDragTargets = new WeakSet();
|
|
2507
2624
|
var elToKeyDownListeners = new WeakMap();
|
|
2508
2625
|
var elToFocusListeners = new WeakMap();
|
|
2509
2626
|
var dzToHandles = new Map();
|
|
2510
2627
|
var dzToConfig = new Map();
|
|
2511
2628
|
var typeToDropZones = new Map();
|
|
2629
|
+
// Each document with zones gets its own aria elements, because a zone can live in another window than the one that loaded
|
|
2630
|
+
// this module. That document and the same-origin documents around it, up to the loading document, get keydown, click and
|
|
2631
|
+
// pagehide handlers, so that Escape and a click outside end a drag from any of them. A zone is released from the documents
|
|
2632
|
+
// it registered with, even if it has moved to another document since.
|
|
2633
|
+
var dzToDocuments = new Map();
|
|
2634
|
+
var documentToRegistration = new Map();
|
|
2512
2635
|
|
|
2513
2636
|
/* TODO (potentially)
|
|
2514
2637
|
* what's the deal with the black border of voice-reader not following focus?
|
|
@@ -2518,18 +2641,83 @@
|
|
|
2518
2641
|
var INSTRUCTION_IDs;
|
|
2519
2642
|
|
|
2520
2643
|
/* drop-zones registration management */
|
|
2644
|
+
function getDocumentsAround(doc) {
|
|
2645
|
+
var docs = [doc];
|
|
2646
|
+
// eslint-disable-next-line no-restricted-globals -- the documents above the loading one belong to whatever hosts the app
|
|
2647
|
+
for (var frame = (_doc$defaultView = doc.defaultView) === null || _doc$defaultView === void 0 ? void 0 : _doc$defaultView.frameElement; frame && docs[docs.length - 1] !== document; frame = getWindowOf(frame).frameElement) {
|
|
2648
|
+
var _doc$defaultView;
|
|
2649
|
+
docs.push(frame.ownerDocument);
|
|
2650
|
+
}
|
|
2651
|
+
return docs;
|
|
2652
|
+
}
|
|
2653
|
+
function retainDocuments(dropZoneEl) {
|
|
2654
|
+
var docs = getDocumentsAround(dropZoneEl.ownerDocument);
|
|
2655
|
+
docs.forEach(function (doc, idx) {
|
|
2656
|
+
var registration = documentToRegistration.get(doc);
|
|
2657
|
+
if (!registration) {
|
|
2658
|
+
printDebug(function () {
|
|
2659
|
+
return "adding global keydown and click handlers";
|
|
2660
|
+
});
|
|
2661
|
+
// Handlers of its own, so that removing them through a window that has since navigated to another document
|
|
2662
|
+
// leaves the handlers of that document alone
|
|
2663
|
+
var handlers = {
|
|
2664
|
+
keydown: globalKeyDownHandler,
|
|
2665
|
+
click: globalClickHandler,
|
|
2666
|
+
pagehide: handleWindowHidden
|
|
2667
|
+
};
|
|
2668
|
+
registration = {
|
|
2669
|
+
win: doc.defaultView,
|
|
2670
|
+
zoneCount: 0,
|
|
2671
|
+
documentCount: 0,
|
|
2672
|
+
handlers: {}
|
|
2673
|
+
};
|
|
2674
|
+
Object.entries(handlers).forEach(function (_ref) {
|
|
2675
|
+
var _registration$win;
|
|
2676
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
2677
|
+
type = _ref2[0],
|
|
2678
|
+
handler = _ref2[1];
|
|
2679
|
+
registration.handlers[type] = function (e) {
|
|
2680
|
+
return handler(e);
|
|
2681
|
+
};
|
|
2682
|
+
(_registration$win = registration.win) === null || _registration$win === void 0 ? void 0 : _registration$win.addEventListener(type, registration.handlers[type]);
|
|
2683
|
+
});
|
|
2684
|
+
documentToRegistration.set(doc, registration);
|
|
2685
|
+
}
|
|
2686
|
+
registration.documentCount++;
|
|
2687
|
+
if (idx === 0 && registration.zoneCount++ === 0) {
|
|
2688
|
+
INSTRUCTION_IDs = initAria(doc);
|
|
2689
|
+
}
|
|
2690
|
+
});
|
|
2691
|
+
dzToDocuments.set(dropZoneEl, docs);
|
|
2692
|
+
}
|
|
2693
|
+
function releaseDocuments(dropZoneEl) {
|
|
2694
|
+
var docs = dzToDocuments.get(dropZoneEl);
|
|
2695
|
+
if (!docs) return;
|
|
2696
|
+
dzToDocuments["delete"](dropZoneEl);
|
|
2697
|
+
docs.forEach(function (doc, idx) {
|
|
2698
|
+
var registration = documentToRegistration.get(doc);
|
|
2699
|
+
if (idx === 0 && --registration.zoneCount === 0) {
|
|
2700
|
+
destroyAria(doc);
|
|
2701
|
+
}
|
|
2702
|
+
if (--registration.documentCount > 0) return;
|
|
2703
|
+
printDebug(function () {
|
|
2704
|
+
return "removing global keydown and click handlers";
|
|
2705
|
+
});
|
|
2706
|
+
documentToRegistration["delete"](doc);
|
|
2707
|
+
Object.entries(registration.handlers).forEach(function (_ref3) {
|
|
2708
|
+
var _registration$win2;
|
|
2709
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
2710
|
+
type = _ref4[0],
|
|
2711
|
+
handler = _ref4[1];
|
|
2712
|
+
return (_registration$win2 = registration.win) === null || _registration$win2 === void 0 ? void 0 : _registration$win2.removeEventListener(type, handler);
|
|
2713
|
+
});
|
|
2714
|
+
});
|
|
2715
|
+
}
|
|
2521
2716
|
function registerDropZone(dropZoneEl, type) {
|
|
2717
|
+
var _dzToDocuments$get;
|
|
2522
2718
|
printDebug(function () {
|
|
2523
2719
|
return "registering drop-zone if absent";
|
|
2524
2720
|
});
|
|
2525
|
-
if (typeToDropZones.size === 0) {
|
|
2526
|
-
printDebug(function () {
|
|
2527
|
-
return "adding global keydown and click handlers";
|
|
2528
|
-
});
|
|
2529
|
-
INSTRUCTION_IDs = initAria();
|
|
2530
|
-
window.addEventListener("keydown", globalKeyDownHandler);
|
|
2531
|
-
window.addEventListener("click", globalClickHandler);
|
|
2532
|
-
}
|
|
2533
2721
|
if (!typeToDropZones.has(type)) {
|
|
2534
2722
|
typeToDropZones.set(type, new Set());
|
|
2535
2723
|
}
|
|
@@ -2537,6 +2725,11 @@
|
|
|
2537
2725
|
typeToDropZones.get(type).add(dropZoneEl);
|
|
2538
2726
|
incrementActiveDropZoneCount();
|
|
2539
2727
|
}
|
|
2728
|
+
// a zone that moved to another document since it registered takes its registration along
|
|
2729
|
+
if (((_dzToDocuments$get = dzToDocuments.get(dropZoneEl)) === null || _dzToDocuments$get === void 0 ? void 0 : _dzToDocuments$get[0]) !== dropZoneEl.ownerDocument) {
|
|
2730
|
+
releaseDocuments(dropZoneEl);
|
|
2731
|
+
retainDocuments(dropZoneEl);
|
|
2732
|
+
}
|
|
2540
2733
|
}
|
|
2541
2734
|
function unregisterDropZone(dropZoneEl, type) {
|
|
2542
2735
|
printDebug(function () {
|
|
@@ -2551,15 +2744,7 @@
|
|
|
2551
2744
|
if (dropZones.size === 0) {
|
|
2552
2745
|
typeToDropZones["delete"](type);
|
|
2553
2746
|
}
|
|
2554
|
-
|
|
2555
|
-
printDebug(function () {
|
|
2556
|
-
return "removing global keydown and click handlers";
|
|
2557
|
-
});
|
|
2558
|
-
window.removeEventListener("keydown", globalKeyDownHandler);
|
|
2559
|
-
window.removeEventListener("click", globalClickHandler);
|
|
2560
|
-
INSTRUCTION_IDs = undefined;
|
|
2561
|
-
destroyAria();
|
|
2562
|
-
}
|
|
2747
|
+
releaseDocuments(dropZoneEl);
|
|
2563
2748
|
}
|
|
2564
2749
|
function globalKeyDownHandler(e) {
|
|
2565
2750
|
if (!isDragging) return;
|
|
@@ -2571,21 +2756,50 @@
|
|
|
2571
2756
|
}
|
|
2572
2757
|
}
|
|
2573
2758
|
}
|
|
2574
|
-
function globalClickHandler() {
|
|
2759
|
+
function globalClickHandler(e) {
|
|
2575
2760
|
if (!isDragging) return;
|
|
2576
|
-
if (!allDragTargets.has(document.activeElement)) {
|
|
2761
|
+
if (!allDragTargets.has(e.currentTarget.document.activeElement)) {
|
|
2577
2762
|
printDebug(function () {
|
|
2578
2763
|
return "clicked outside of any draggable";
|
|
2579
2764
|
});
|
|
2580
2765
|
handleDrop();
|
|
2581
2766
|
}
|
|
2582
2767
|
}
|
|
2583
|
-
|
|
2584
|
-
|
|
2768
|
+
|
|
2769
|
+
// The focused zone's window is going away: it was closed or navigated, or its iframe was removed. End the drag so the
|
|
2770
|
+
// zones in the other windows become tab stops again.
|
|
2771
|
+
function handleWindowHidden(e) {
|
|
2772
|
+
if (isDragging && focusedDz && getWindowOf(focusedDz) === e.currentTarget) {
|
|
2773
|
+
printDebug(function () {
|
|
2774
|
+
return "the focused zone's window is going away";
|
|
2775
|
+
});
|
|
2776
|
+
handleDrop();
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
// Tab can cross iframe boundaries, but a destination must still belong to the drag's own document.
|
|
2781
|
+
function isInDragDocument(dropZoneEl) {
|
|
2782
|
+
var doc = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : dragDocument;
|
|
2783
|
+
return dropZoneEl.ownerDocument === doc;
|
|
2784
|
+
}
|
|
2785
|
+
function isAboveOrLeftOf(el, otherEl) {
|
|
2786
|
+
var position = el.getBoundingClientRect();
|
|
2787
|
+
var otherPosition = otherEl.getBoundingClientRect();
|
|
2788
|
+
return position.top < otherPosition.top || position.left < otherPosition.left;
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
// Tab order, focus-driven transfers, styling and announcements must agree about which zones can receive the item.
|
|
2792
|
+
// tabindex=-1 alone is not a restriction: a click or consumer code can still focus a zone.
|
|
2793
|
+
function isKeyboardDropTarget(dropZoneEl) {
|
|
2794
|
+
var config = dzToConfig.get(dropZoneEl);
|
|
2795
|
+
return config.type === draggedItemType && !config.dropFromOthersDisabled && !focusedItem.contains(dropZoneEl) && isInDragDocument(dropZoneEl);
|
|
2796
|
+
}
|
|
2797
|
+
function getActiveDragTabIndex(dropZoneEl) {
|
|
2798
|
+
return dropZoneEl !== focusedDz && isKeyboardDropTarget(dropZoneEl) ? 0 : -1;
|
|
2585
2799
|
}
|
|
2586
2800
|
function refreshActiveDragTabIndices() {
|
|
2587
|
-
dzToConfig.forEach(function (
|
|
2588
|
-
dropZoneEl.tabIndex = getActiveDragTabIndex(dropZoneEl
|
|
2801
|
+
dzToConfig.forEach(function (_, dropZoneEl) {
|
|
2802
|
+
dropZoneEl.tabIndex = getActiveDragTabIndex(dropZoneEl);
|
|
2589
2803
|
});
|
|
2590
2804
|
}
|
|
2591
2805
|
function grabIsAlive() {
|
|
@@ -2605,8 +2819,10 @@
|
|
|
2605
2819
|
});
|
|
2606
2820
|
if (!isDragging) return;
|
|
2607
2821
|
var newlyFocusedDz = e.currentTarget;
|
|
2608
|
-
if (newlyFocusedDz === focusedDz) return;
|
|
2822
|
+
if (newlyFocusedDz === focusedDz || !isKeyboardDropTarget(newlyFocusedDz)) return;
|
|
2609
2823
|
if (!grabIsAlive()) return;
|
|
2824
|
+
var dzFrom = focusedDz;
|
|
2825
|
+
var movedItemId = focusedItemId;
|
|
2610
2826
|
focusedDzLabel = newlyFocusedDz.getAttribute("aria-label") || "";
|
|
2611
2827
|
var _dzToConfig$get = dzToConfig.get(focusedDz),
|
|
2612
2828
|
originItems = _dzToConfig$get.items;
|
|
@@ -2618,7 +2834,7 @@
|
|
|
2618
2834
|
var _dzToConfig$get2 = dzToConfig.get(newlyFocusedDz),
|
|
2619
2835
|
targetItems = _dzToConfig$get2.items,
|
|
2620
2836
|
autoAriaDisabled = _dzToConfig$get2.autoAriaDisabled;
|
|
2621
|
-
if (
|
|
2837
|
+
if (isAboveOrLeftOf(newlyFocusedDz, focusedDz)) {
|
|
2622
2838
|
targetItems.push(itemToMove);
|
|
2623
2839
|
if (!autoAriaDisabled) {
|
|
2624
2840
|
announceToScreenReader("movedToZoneEnd", {
|
|
@@ -2626,7 +2842,7 @@
|
|
|
2626
2842
|
zoneLabel: focusedDzLabel,
|
|
2627
2843
|
position: targetItems.length,
|
|
2628
2844
|
count: targetItems.length
|
|
2629
|
-
});
|
|
2845
|
+
}, newlyFocusedDz.ownerDocument);
|
|
2630
2846
|
}
|
|
2631
2847
|
} else {
|
|
2632
2848
|
targetItems.unshift(itemToMove);
|
|
@@ -2636,12 +2852,11 @@
|
|
|
2636
2852
|
zoneLabel: focusedDzLabel,
|
|
2637
2853
|
position: 1,
|
|
2638
2854
|
count: targetItems.length
|
|
2639
|
-
});
|
|
2855
|
+
}, newlyFocusedDz.ownerDocument);
|
|
2640
2856
|
}
|
|
2641
2857
|
}
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
focusedDz = newlyFocusedDz;
|
|
2858
|
+
// An announcement formatter can end the drag, for example by removing its window. The item still moves.
|
|
2859
|
+
if (isDragging) focusedDz = newlyFocusedDz;
|
|
2645
2860
|
dispatchFinalizeEvent(dzFrom, originItems, {
|
|
2646
2861
|
trigger: TRIGGERS.DROPPED_INTO_ANOTHER,
|
|
2647
2862
|
id: movedItemId,
|
|
@@ -2656,8 +2871,8 @@
|
|
|
2656
2871
|
}
|
|
2657
2872
|
}
|
|
2658
2873
|
function triggerAllDzsUpdate() {
|
|
2659
|
-
dzToHandles.forEach(function (
|
|
2660
|
-
var update =
|
|
2874
|
+
dzToHandles.forEach(function (_ref5, dz) {
|
|
2875
|
+
var update = _ref5.update;
|
|
2661
2876
|
return update(dzToConfig.get(dz));
|
|
2662
2877
|
});
|
|
2663
2878
|
}
|
|
@@ -2672,6 +2887,20 @@
|
|
|
2672
2887
|
var droppedItemId = focusedItemId;
|
|
2673
2888
|
var droppedItemType = draggedItemType;
|
|
2674
2889
|
if (!droppedConfig) return;
|
|
2890
|
+
var droppedItemLabel = focusedItemLabel;
|
|
2891
|
+
var droppedDzLabel = focusedDzLabel;
|
|
2892
|
+
var droppedDocument = dragDocument;
|
|
2893
|
+
// Clear global drag state before running any consumer code: an announcement formatter, a blur handler or a consider
|
|
2894
|
+
// handler. A synchronous handler may destroy the focused zone or remove its window, and neither must recursively
|
|
2895
|
+
// enter handleDrop.
|
|
2896
|
+
focusedItem = null;
|
|
2897
|
+
focusedItemId = null;
|
|
2898
|
+
focusedItemLabel = "";
|
|
2899
|
+
draggedItemType = null;
|
|
2900
|
+
focusedDz = null;
|
|
2901
|
+
focusedDzLabel = "";
|
|
2902
|
+
dragDocument = undefined;
|
|
2903
|
+
isDragging = false;
|
|
2675
2904
|
if (!droppedConfig.autoAriaDisabled) {
|
|
2676
2905
|
// Include the destination and final position so localized messages can describe the completed drop.
|
|
2677
2906
|
var droppedItems = droppedConfig.items;
|
|
@@ -2679,24 +2908,16 @@
|
|
|
2679
2908
|
return item[ITEM_ID_KEY] === droppedItemId;
|
|
2680
2909
|
});
|
|
2681
2910
|
announceToScreenReader("dropped", {
|
|
2682
|
-
itemLabel:
|
|
2683
|
-
zoneLabel:
|
|
2911
|
+
itemLabel: droppedItemLabel,
|
|
2912
|
+
zoneLabel: droppedDzLabel,
|
|
2684
2913
|
position: (droppedIdx < 0 ? 0 : droppedIdx) + 1,
|
|
2685
2914
|
count: droppedItems.length
|
|
2686
|
-
});
|
|
2915
|
+
}, droppedDz.ownerDocument);
|
|
2687
2916
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
2917
|
+
var activeElement = droppedDz.ownerDocument.activeElement;
|
|
2918
|
+
if (allDragTargets.has(activeElement)) {
|
|
2919
|
+
activeElement.blur();
|
|
2690
2920
|
}
|
|
2691
|
-
// Clear global drag state before dispatching. A synchronous handler may destroy the
|
|
2692
|
-
// focused zone, and unregisterDropZone must not recursively enter handleDrop.
|
|
2693
|
-
focusedItem = null;
|
|
2694
|
-
focusedItemId = null;
|
|
2695
|
-
focusedItemLabel = "";
|
|
2696
|
-
draggedItemType = null;
|
|
2697
|
-
focusedDz = null;
|
|
2698
|
-
focusedDzLabel = "";
|
|
2699
|
-
isDragging = false;
|
|
2700
2921
|
if (dispatchConsider) {
|
|
2701
2922
|
dispatchConsiderEvent(droppedDz, droppedConfig.items, {
|
|
2702
2923
|
trigger: TRIGGERS.DRAG_STOPPED,
|
|
@@ -2706,7 +2927,9 @@
|
|
|
2706
2927
|
}
|
|
2707
2928
|
var dropZones = typeToDropZones.get(droppedItemType);
|
|
2708
2929
|
if (dropZones) {
|
|
2709
|
-
styleInactiveDropZones(dropZones
|
|
2930
|
+
styleInactiveDropZones(Array.from(dropZones).filter(function (dz) {
|
|
2931
|
+
return isInDragDocument(dz, droppedDocument);
|
|
2932
|
+
}), function (dz) {
|
|
2710
2933
|
return dzToConfig.get(dz).dropTargetStyle;
|
|
2711
2934
|
}, function (dz) {
|
|
2712
2935
|
return dzToConfig.get(dz).dropTargetClasses;
|
|
@@ -2732,6 +2955,10 @@
|
|
|
2732
2955
|
if (arr.length <= 1) return;
|
|
2733
2956
|
arr.splice(j, 1, arr.splice(i, 1, arr[j])[0]);
|
|
2734
2957
|
}
|
|
2958
|
+
function ownsArrowKey(e) {
|
|
2959
|
+
// Only the grabbed item owns reorder keys. Nested controls and other items keep their own key behaviour.
|
|
2960
|
+
return isDragging && node === focusedDz && isInDragDocument(node) && e.currentTarget === focusedItem && e.target === focusedItem;
|
|
2961
|
+
}
|
|
2735
2962
|
function handleKeyDown(e) {
|
|
2736
2963
|
printDebug(function () {
|
|
2737
2964
|
return ["handling key down", e.key];
|
|
@@ -2762,7 +2989,7 @@
|
|
|
2762
2989
|
case "ArrowDown":
|
|
2763
2990
|
case "ArrowRight":
|
|
2764
2991
|
{
|
|
2765
|
-
if (!
|
|
2992
|
+
if (!ownsArrowKey(e)) return;
|
|
2766
2993
|
e.preventDefault(); // prevent scrolling
|
|
2767
2994
|
e.stopPropagation();
|
|
2768
2995
|
var _dzToConfig$get3 = dzToConfig.get(node),
|
|
@@ -2779,8 +3006,10 @@
|
|
|
2779
3006
|
zoneLabel: focusedDzLabel,
|
|
2780
3007
|
position: idx + 2,
|
|
2781
3008
|
count: items.length
|
|
2782
|
-
});
|
|
3009
|
+
}, node.ownerDocument);
|
|
2783
3010
|
}
|
|
3011
|
+
// An announcement formatter can end or move the drag, for example by removing its window.
|
|
3012
|
+
if (!ownsArrowKey(e)) break;
|
|
2784
3013
|
swap(items, idx, idx + 1);
|
|
2785
3014
|
dispatchFinalizeEvent(node, items, {
|
|
2786
3015
|
trigger: TRIGGERS.DROPPED_INTO_ZONE,
|
|
@@ -2793,7 +3022,7 @@
|
|
|
2793
3022
|
case "ArrowUp":
|
|
2794
3023
|
case "ArrowLeft":
|
|
2795
3024
|
{
|
|
2796
|
-
if (!
|
|
3025
|
+
if (!ownsArrowKey(e)) return;
|
|
2797
3026
|
e.preventDefault(); // prevent scrolling
|
|
2798
3027
|
e.stopPropagation();
|
|
2799
3028
|
var _dzToConfig$get4 = dzToConfig.get(node),
|
|
@@ -2810,8 +3039,10 @@
|
|
|
2810
3039
|
zoneLabel: focusedDzLabel,
|
|
2811
3040
|
position: _idx,
|
|
2812
3041
|
count: _items.length
|
|
2813
|
-
});
|
|
3042
|
+
}, node.ownerDocument);
|
|
2814
3043
|
}
|
|
3044
|
+
// An announcement formatter can end or move the drag, for example by removing its window.
|
|
3045
|
+
if (!ownsArrowKey(e)) break;
|
|
2815
3046
|
swap(_items, _idx, _idx - 1);
|
|
2816
3047
|
dispatchFinalizeEvent(node, _items, {
|
|
2817
3048
|
trigger: TRIGGERS.DROPPED_INTO_ZONE,
|
|
@@ -2832,8 +3063,9 @@
|
|
|
2832
3063
|
focusedDzLabel = node.getAttribute("aria-label") || "";
|
|
2833
3064
|
draggedItemType = config.type;
|
|
2834
3065
|
isDragging = true;
|
|
3066
|
+
dragDocument = node.ownerDocument;
|
|
2835
3067
|
var dropTargets = Array.from(typeToDropZones.get(config.type)).filter(function (dz) {
|
|
2836
|
-
return dz === focusedDz ||
|
|
3068
|
+
return dz === focusedDz || isKeyboardDropTarget(dz);
|
|
2837
3069
|
});
|
|
2838
3070
|
styleActiveDropZones(dropTargets, function (dz) {
|
|
2839
3071
|
return dzToConfig.get(dz).dropTargetStyle;
|
|
@@ -2852,8 +3084,10 @@
|
|
|
2852
3084
|
position: (startIdx < 0 ? 0 : startIdx) + 1,
|
|
2853
3085
|
count: startItems.length,
|
|
2854
3086
|
canMoveBetweenZones: dropTargets.length > 1
|
|
2855
|
-
});
|
|
3087
|
+
}, node.ownerDocument);
|
|
2856
3088
|
}
|
|
3089
|
+
// an announcement formatter can end the drag, for example by removing its window
|
|
3090
|
+
if (!isDragging) return;
|
|
2857
3091
|
dispatchConsiderEvent(node, dzToConfig.get(node).items, {
|
|
2858
3092
|
trigger: TRIGGERS.DRAG_STARTED,
|
|
2859
3093
|
id: focusedItemId,
|
|
@@ -2878,25 +3112,25 @@
|
|
|
2878
3112
|
focusedItemId = items[focusedItemIdx][ITEM_ID_KEY];
|
|
2879
3113
|
focusedItemLabel = children[focusedItemIdx].getAttribute("aria-label") || "";
|
|
2880
3114
|
}
|
|
2881
|
-
function configure(
|
|
2882
|
-
var
|
|
2883
|
-
items =
|
|
2884
|
-
|
|
2885
|
-
newType =
|
|
2886
|
-
|
|
2887
|
-
dragDisabled =
|
|
2888
|
-
|
|
2889
|
-
zoneTabIndex =
|
|
2890
|
-
|
|
2891
|
-
zoneItemTabIndex =
|
|
2892
|
-
|
|
2893
|
-
dropFromOthersDisabled =
|
|
2894
|
-
|
|
2895
|
-
dropTargetStyle =
|
|
2896
|
-
|
|
2897
|
-
dropTargetClasses =
|
|
2898
|
-
|
|
2899
|
-
autoAriaDisabled =
|
|
3115
|
+
function configure(_ref6) {
|
|
3116
|
+
var _ref6$items = _ref6.items,
|
|
3117
|
+
items = _ref6$items === void 0 ? [] : _ref6$items,
|
|
3118
|
+
_ref6$type = _ref6.type,
|
|
3119
|
+
newType = _ref6$type === void 0 ? DEFAULT_DROP_ZONE_TYPE : _ref6$type,
|
|
3120
|
+
_ref6$dragDisabled = _ref6.dragDisabled,
|
|
3121
|
+
dragDisabled = _ref6$dragDisabled === void 0 ? false : _ref6$dragDisabled,
|
|
3122
|
+
_ref6$zoneTabIndex = _ref6.zoneTabIndex,
|
|
3123
|
+
zoneTabIndex = _ref6$zoneTabIndex === void 0 ? 0 : _ref6$zoneTabIndex,
|
|
3124
|
+
_ref6$zoneItemTabInde = _ref6.zoneItemTabIndex,
|
|
3125
|
+
zoneItemTabIndex = _ref6$zoneItemTabInde === void 0 ? 0 : _ref6$zoneItemTabInde,
|
|
3126
|
+
_ref6$dropFromOthersD = _ref6.dropFromOthersDisabled,
|
|
3127
|
+
dropFromOthersDisabled = _ref6$dropFromOthersD === void 0 ? false : _ref6$dropFromOthersD,
|
|
3128
|
+
_ref6$dropTargetStyle = _ref6.dropTargetStyle,
|
|
3129
|
+
dropTargetStyle = _ref6$dropTargetStyle === void 0 ? DEFAULT_DROP_TARGET_STYLE : _ref6$dropTargetStyle,
|
|
3130
|
+
_ref6$dropTargetClass = _ref6.dropTargetClasses,
|
|
3131
|
+
dropTargetClasses = _ref6$dropTargetClass === void 0 ? [] : _ref6$dropTargetClass,
|
|
3132
|
+
_ref6$autoAriaDisable = _ref6.autoAriaDisabled,
|
|
3133
|
+
autoAriaDisabled = _ref6$autoAriaDisable === void 0 ? false : _ref6$autoAriaDisable;
|
|
2900
3134
|
config.items = _toConsumableArray(items);
|
|
2901
3135
|
config.dragDisabled = dragDisabled;
|
|
2902
3136
|
config.dropFromOthersDisabled = dropFromOthersDisabled;
|
|
@@ -2917,14 +3151,14 @@
|
|
|
2917
3151
|
dzToConfig.set(node, config);
|
|
2918
3152
|
var itemMovedToThisZone = false;
|
|
2919
3153
|
if (isDragging) {
|
|
2920
|
-
itemMovedToThisZone = config.type === draggedItemType && config.items.some(function (item) {
|
|
3154
|
+
itemMovedToThisZone = isInDragDocument(node) && config.type === draggedItemType && config.items.some(function (item) {
|
|
2921
3155
|
return item[ITEM_ID_KEY] === focusedItemId;
|
|
2922
3156
|
}) && node !== focusedDz;
|
|
2923
3157
|
if (itemMovedToThisZone) {
|
|
2924
3158
|
focusedDz = node;
|
|
2925
3159
|
focusedDzLabel = node.getAttribute("aria-label") || "";
|
|
2926
3160
|
}
|
|
2927
|
-
node.tabIndex = getActiveDragTabIndex(node
|
|
3161
|
+
node.tabIndex = getActiveDragTabIndex(node);
|
|
2928
3162
|
} else {
|
|
2929
3163
|
node.tabIndex = config.zoneTabIndex;
|
|
2930
3164
|
}
|
|
@@ -2945,7 +3179,7 @@
|
|
|
2945
3179
|
draggableEl.addEventListener("click", handleClick);
|
|
2946
3180
|
elToFocusListeners.set(draggableEl, handleClick);
|
|
2947
3181
|
}
|
|
2948
|
-
if (isDragging && config.type === draggedItemType && ((_config$items$i = config.items[i]) === null || _config$items$i === void 0 ? void 0 : _config$items$i[ITEM_ID_KEY]) === focusedItemId) {
|
|
3182
|
+
if (isDragging && isInDragDocument(node) && config.type === draggedItemType && ((_config$items$i = config.items[i]) === null || _config$items$i === void 0 ? void 0 : _config$items$i[ITEM_ID_KEY]) === focusedItemId) {
|
|
2949
3183
|
printDebug(function () {
|
|
2950
3184
|
return ["focusing on", {
|
|
2951
3185
|
i: i,
|
|
@@ -2962,7 +3196,8 @@
|
|
|
2962
3196
|
for (var i = 0; i < node.children.length; i++) {
|
|
2963
3197
|
_loop(i);
|
|
2964
3198
|
}
|
|
2965
|
-
|
|
3199
|
+
// Focusing the replacement item runs its focus handler, which can end the drag, for example by removing its window
|
|
3200
|
+
if (itemMovedToThisZone && isDragging) {
|
|
2966
3201
|
// Nested actions are configured before their parent action. Refresh only
|
|
2967
3202
|
// after focusedItem points at the replacement so nested zones stay untabbable.
|
|
2968
3203
|
refreshActiveDragTabIndices();
|
|
@@ -3219,22 +3454,27 @@
|
|
|
3219
3454
|
*/
|
|
3220
3455
|
function dragHandle(handle) {
|
|
3221
3456
|
handle.setAttribute("role", "button");
|
|
3457
|
+
var releaseWindow;
|
|
3222
3458
|
function startDrag(e) {
|
|
3223
3459
|
// preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
|
|
3224
3460
|
e.preventDefault();
|
|
3225
3461
|
isItemsDragDisabled.set(false);
|
|
3226
3462
|
|
|
3227
|
-
// Reset the startDrag/isItemsDragDisabled if the user releases the mouse/touch without initiating a drag
|
|
3228
|
-
window
|
|
3229
|
-
|
|
3463
|
+
// Reset the startDrag/isItemsDragDisabled if the user releases the mouse/touch without initiating a drag, or if the
|
|
3464
|
+
// handle's window goes away first
|
|
3465
|
+
releaseWindow = getWindowOf(handle);
|
|
3466
|
+
releaseWindow.addEventListener("mouseup", resetStartDrag);
|
|
3467
|
+
releaseWindow.addEventListener("touchend", resetStartDrag);
|
|
3468
|
+
releaseWindow.addEventListener("pagehide", resetStartDrag);
|
|
3230
3469
|
}
|
|
3231
3470
|
function handleKeyDown(e) {
|
|
3232
3471
|
if (isKeyboardDragTriggerKey(e.key)) isItemsDragDisabled.set(false);
|
|
3233
3472
|
}
|
|
3234
3473
|
function resetStartDrag() {
|
|
3235
3474
|
isItemsDragDisabled.set(true);
|
|
3236
|
-
|
|
3237
|
-
|
|
3475
|
+
releaseWindow.removeEventListener("mouseup", resetStartDrag);
|
|
3476
|
+
releaseWindow.removeEventListener("touchend", resetStartDrag);
|
|
3477
|
+
releaseWindow.removeEventListener("pagehide", resetStartDrag);
|
|
3238
3478
|
}
|
|
3239
3479
|
var recomputeHandleState = function recomputeHandleState() {
|
|
3240
3480
|
var userDisabled = userDragDisabled.get();
|