svelte-dnd-action 0.9.40 → 0.9.41
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 +2 -3
- package/dist/index.js +213 -175
- package/dist/index.mjs +213 -175
- package/package.json +1 -1
- package/src/helpers/intersection.js +1 -21
- package/src/helpers/listUtil.js +0 -9
- package/src/helpers/multiScroller.js +74 -0
- package/src/helpers/observer.js +5 -7
- package/src/helpers/scroller.js +36 -2
- package/src/pointerAction.js +6 -5
- package/src/helpers/windowScroller.js +0 -48
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ It is being actively maintained.
|
|
|
22
22
|
- Rich animations (can be opted out of)
|
|
23
23
|
- Touch support
|
|
24
24
|
- Define what can be dropped where (dnd-zones optionally have a "type")
|
|
25
|
-
- Scroll dnd-zones and/or the window horizontally or vertically by placing the dragged element next to the edge
|
|
25
|
+
- Scroll dnd-zones (of the relevant "type"), parent containers that contains them and/or the window horizontally or vertically by placing the dragged element next to the edge
|
|
26
26
|
- Supports advanced use-cases such as various flavours of copy-on-drag and custom drag handles (see examples below)
|
|
27
27
|
- Performant and small footprint (no external dependencies, no fluff code)
|
|
28
28
|
- Fully accessible (beta) - keyboard support, aria attributes and assistive instructions for screen readers
|
|
@@ -82,7 +82,7 @@ npm install --save-dev svelte-dnd-action
|
|
|
82
82
|
width: 50%;
|
|
83
83
|
padding: 0.3em;
|
|
84
84
|
border: 1px solid black;
|
|
85
|
-
/* this will allow the dragged element to scroll the list */
|
|
85
|
+
/* this will allow the dragged element to scroll the list although starting in version 0.9.41 the lib would detect any scrollable parent*/
|
|
86
86
|
overflow: scroll;
|
|
87
87
|
height: 200px;
|
|
88
88
|
}
|
|
@@ -207,7 +207,6 @@ If you want to implement your own custom screen-reader alerts, roles and instruc
|
|
|
207
207
|
- Any data that should "survive" when the items are dragged around and dropped should be included in the `items` array that is passed in.
|
|
208
208
|
- The host component must refresh the items that are passed in to the custom-action when receiving consider and finalize events (do not omit any handler).
|
|
209
209
|
- FYI, the library assumes it is okay to add a temporary item to the items list in any of the dnd-zones while an element is dragged around.
|
|
210
|
-
- If you want dragged items to be able to scroll the container, make sure the scroll-container (the element with overflow:scroll) is the dnd-zone (the element decorated with this custom action)
|
|
211
210
|
- Svelte's built-in transitions might not play nice with this library. Luckily, it is an easy issue to work around. There are examples above.
|
|
212
211
|
|
|
213
212
|
### Overriding the item id key name
|
package/dist/index.js
CHANGED
|
@@ -501,33 +501,13 @@
|
|
|
501
501
|
|
|
502
502
|
/**
|
|
503
503
|
* @param {HTMLElement} el - the element to check
|
|
504
|
-
* @returns {boolean} - true if the element in its entirety is off
|
|
504
|
+
* @returns {boolean} - true if the element in its entirety is off-screen including the scrollable area (the normal dom events look at the mouse rather than the element)
|
|
505
505
|
*/
|
|
506
506
|
function isElementOffDocument(el) {
|
|
507
507
|
var rect = getAbsoluteRect(el);
|
|
508
508
|
return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
-
/**
|
|
512
|
-
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
513
|
-
* @param {Point} point
|
|
514
|
-
* @param {HTMLElement} el
|
|
515
|
-
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
516
|
-
*/
|
|
517
|
-
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
518
|
-
var rect = getAbsoluteRect(el);
|
|
519
|
-
if (!isPointInsideRect(point, rect)) {
|
|
520
|
-
return null;
|
|
521
|
-
}
|
|
522
|
-
return {
|
|
523
|
-
top: point.y - rect.top,
|
|
524
|
-
bottom: rect.bottom - point.y,
|
|
525
|
-
left: point.x - rect.left,
|
|
526
|
-
// TODO - figure out what is so special about right (why the rect is too big)
|
|
527
|
-
right: Math.min(rect.right, document.documentElement.clientWidth) - point.x
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
|
|
531
511
|
var dzToShadowIndexToRect;
|
|
532
512
|
|
|
533
513
|
/**
|
|
@@ -541,17 +521,6 @@
|
|
|
541
521
|
}
|
|
542
522
|
resetIndexesCache();
|
|
543
523
|
|
|
544
|
-
/**
|
|
545
|
-
* Resets the cache that allows for smarter "would be index" resolution for a specific dropzone, should be called after the zone was scrolled
|
|
546
|
-
* @param {HTMLElement} dz
|
|
547
|
-
*/
|
|
548
|
-
function resetIndexesCacheForDz(dz) {
|
|
549
|
-
printDebug(function () {
|
|
550
|
-
return "resetting indexes cache for dz";
|
|
551
|
-
});
|
|
552
|
-
dzToShadowIndexToRect["delete"](dz);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
524
|
/**
|
|
556
525
|
* Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
|
|
557
526
|
* Helpful in order to determine "would be index" more effectively
|
|
@@ -634,102 +603,6 @@
|
|
|
634
603
|
};
|
|
635
604
|
}
|
|
636
605
|
|
|
637
|
-
var SCROLL_ZONE_PX = 25;
|
|
638
|
-
function makeScroller() {
|
|
639
|
-
var scrollingInfo;
|
|
640
|
-
function resetScrolling() {
|
|
641
|
-
scrollingInfo = {
|
|
642
|
-
directionObj: undefined,
|
|
643
|
-
stepPx: 0
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
resetScrolling();
|
|
647
|
-
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
|
|
648
|
-
function scrollContainer(containerEl) {
|
|
649
|
-
var _scrollingInfo = scrollingInfo,
|
|
650
|
-
directionObj = _scrollingInfo.directionObj,
|
|
651
|
-
stepPx = _scrollingInfo.stepPx;
|
|
652
|
-
if (directionObj) {
|
|
653
|
-
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
654
|
-
window.requestAnimationFrame(function () {
|
|
655
|
-
return scrollContainer(containerEl);
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
function calcScrollStepPx(distancePx) {
|
|
660
|
-
return SCROLL_ZONE_PX - distancePx;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
665
|
-
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
666
|
-
* @return {boolean} - true if scrolling was needed
|
|
667
|
-
*/
|
|
668
|
-
function scrollIfNeeded(pointer, elementToScroll) {
|
|
669
|
-
if (!elementToScroll) {
|
|
670
|
-
return false;
|
|
671
|
-
}
|
|
672
|
-
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
|
|
673
|
-
if (distances === null) {
|
|
674
|
-
resetScrolling();
|
|
675
|
-
return false;
|
|
676
|
-
}
|
|
677
|
-
var isAlreadyScrolling = !!scrollingInfo.directionObj;
|
|
678
|
-
var scrollingVertically = false,
|
|
679
|
-
scrollingHorizontally = false;
|
|
680
|
-
// vertical
|
|
681
|
-
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
|
|
682
|
-
if (distances.bottom < SCROLL_ZONE_PX) {
|
|
683
|
-
scrollingVertically = true;
|
|
684
|
-
scrollingInfo.directionObj = {
|
|
685
|
-
x: 0,
|
|
686
|
-
y: 1
|
|
687
|
-
};
|
|
688
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
|
|
689
|
-
} else if (distances.top < SCROLL_ZONE_PX) {
|
|
690
|
-
scrollingVertically = true;
|
|
691
|
-
scrollingInfo.directionObj = {
|
|
692
|
-
x: 0,
|
|
693
|
-
y: -1
|
|
694
|
-
};
|
|
695
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
|
|
696
|
-
}
|
|
697
|
-
if (!isAlreadyScrolling && scrollingVertically) {
|
|
698
|
-
scrollContainer(elementToScroll);
|
|
699
|
-
return true;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
// horizontal
|
|
703
|
-
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
|
|
704
|
-
if (distances.right < SCROLL_ZONE_PX) {
|
|
705
|
-
scrollingHorizontally = true;
|
|
706
|
-
scrollingInfo.directionObj = {
|
|
707
|
-
x: 1,
|
|
708
|
-
y: 0
|
|
709
|
-
};
|
|
710
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
|
|
711
|
-
} else if (distances.left < SCROLL_ZONE_PX) {
|
|
712
|
-
scrollingHorizontally = true;
|
|
713
|
-
scrollingInfo.directionObj = {
|
|
714
|
-
x: -1,
|
|
715
|
-
y: 0
|
|
716
|
-
};
|
|
717
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
|
|
718
|
-
}
|
|
719
|
-
if (!isAlreadyScrolling && scrollingHorizontally) {
|
|
720
|
-
scrollContainer(elementToScroll);
|
|
721
|
-
return true;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
resetScrolling();
|
|
725
|
-
return false;
|
|
726
|
-
}
|
|
727
|
-
return {
|
|
728
|
-
scrollIfNeeded: scrollIfNeeded,
|
|
729
|
-
resetScrolling: resetScrolling
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
|
|
733
606
|
/**
|
|
734
607
|
* @param {Object} object
|
|
735
608
|
* @return {string}
|
|
@@ -795,9 +668,6 @@
|
|
|
795
668
|
|
|
796
669
|
var INTERVAL_MS = 200;
|
|
797
670
|
var TOLERANCE_PX = 10;
|
|
798
|
-
var _makeScroller = makeScroller(),
|
|
799
|
-
scrollIfNeeded = _makeScroller.scrollIfNeeded,
|
|
800
|
-
resetScrolling = _makeScroller.resetScrolling;
|
|
801
671
|
var next;
|
|
802
672
|
|
|
803
673
|
/**
|
|
@@ -805,9 +675,11 @@
|
|
|
805
675
|
* @param {Set<HTMLElement>} dropZones
|
|
806
676
|
* @param {HTMLElement} draggedEl
|
|
807
677
|
* @param {number} [intervalMs = INTERVAL_MS]
|
|
678
|
+
* @param {MultiScroller} multiScroller
|
|
808
679
|
*/
|
|
809
680
|
function observe(draggedEl, dropZones) {
|
|
810
681
|
var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
|
|
682
|
+
var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
|
|
811
683
|
// initialization
|
|
812
684
|
var lastDropZoneFound;
|
|
813
685
|
var lastIndexFound;
|
|
@@ -823,7 +695,7 @@
|
|
|
823
695
|
*/
|
|
824
696
|
function andNow() {
|
|
825
697
|
var currentCenterOfDragged = findCenterOfElement(draggedEl);
|
|
826
|
-
var scrolled =
|
|
698
|
+
var scrolled = multiScroller.multiScrollIfNeeded();
|
|
827
699
|
// we only want to make a new decision after the element was moved a bit to prevent flickering
|
|
828
700
|
if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
|
|
829
701
|
next = window.setTimeout(andNow, intervalMs);
|
|
@@ -844,7 +716,7 @@
|
|
|
844
716
|
try {
|
|
845
717
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
846
718
|
var dz = _step.value;
|
|
847
|
-
if (scrolled)
|
|
719
|
+
if (scrolled) resetIndexesCache();
|
|
848
720
|
var indexObj = findWouldBeIndex(draggedEl, dz);
|
|
849
721
|
if (indexObj === null) {
|
|
850
722
|
// it is not inside
|
|
@@ -889,61 +761,225 @@
|
|
|
889
761
|
return "unobserving";
|
|
890
762
|
});
|
|
891
763
|
clearTimeout(next);
|
|
892
|
-
resetScrolling();
|
|
893
764
|
resetIndexesCache();
|
|
894
765
|
}
|
|
895
766
|
|
|
896
|
-
var
|
|
897
|
-
var mousePosition;
|
|
767
|
+
var SCROLL_ZONE_PX = 30;
|
|
898
768
|
|
|
899
769
|
/**
|
|
900
|
-
*
|
|
901
|
-
*
|
|
902
|
-
* @param {{clientX: number, clientY: number}} e
|
|
770
|
+
* Will make a scroller that can scroll any element given to it in any direction
|
|
771
|
+
* @returns {{scrollIfNeeded: function(Point, HTMLElement): boolean, resetScrolling: function(void):void}}
|
|
903
772
|
*/
|
|
904
|
-
function
|
|
905
|
-
var
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
var _makeScroller$1 = makeScroller(),
|
|
912
|
-
scrollIfNeeded$1 = _makeScroller$1.scrollIfNeeded,
|
|
913
|
-
resetScrolling$1 = _makeScroller$1.resetScrolling;
|
|
914
|
-
var next$1;
|
|
915
|
-
function loop() {
|
|
916
|
-
if (mousePosition) {
|
|
917
|
-
var scrolled = scrollIfNeeded$1(mousePosition, document.documentElement);
|
|
918
|
-
if (scrolled) resetIndexesCache();
|
|
773
|
+
function makeScroller() {
|
|
774
|
+
var scrollingInfo;
|
|
775
|
+
function resetScrolling() {
|
|
776
|
+
scrollingInfo = {
|
|
777
|
+
directionObj: undefined,
|
|
778
|
+
stepPx: 0
|
|
779
|
+
};
|
|
919
780
|
}
|
|
920
|
-
|
|
781
|
+
resetScrolling();
|
|
782
|
+
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
|
|
783
|
+
function scrollContainer(containerEl) {
|
|
784
|
+
var _scrollingInfo = scrollingInfo,
|
|
785
|
+
directionObj = _scrollingInfo.directionObj,
|
|
786
|
+
stepPx = _scrollingInfo.stepPx;
|
|
787
|
+
if (directionObj) {
|
|
788
|
+
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
789
|
+
window.requestAnimationFrame(function () {
|
|
790
|
+
return scrollContainer(containerEl);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function calcScrollStepPx(distancePx) {
|
|
795
|
+
return SCROLL_ZONE_PX - distancePx;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* @param {Point} pointer - the pointer will be used to decide in which direction to scroll
|
|
800
|
+
* @param {HTMLElement} elementToScroll - the scroll container
|
|
801
|
+
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
802
|
+
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
803
|
+
* @return {boolean} - true if scrolling was needed
|
|
804
|
+
*/
|
|
805
|
+
function scrollIfNeeded(pointer, elementToScroll) {
|
|
806
|
+
if (!elementToScroll) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
|
|
810
|
+
if (distances === null) {
|
|
811
|
+
resetScrolling();
|
|
812
|
+
return false;
|
|
813
|
+
}
|
|
814
|
+
var isAlreadyScrolling = !!scrollingInfo.directionObj;
|
|
815
|
+
var scrollingVertically = false,
|
|
816
|
+
scrollingHorizontally = false;
|
|
817
|
+
// vertical
|
|
818
|
+
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
|
|
819
|
+
if (distances.bottom < SCROLL_ZONE_PX) {
|
|
820
|
+
scrollingVertically = true;
|
|
821
|
+
scrollingInfo.directionObj = {
|
|
822
|
+
x: 0,
|
|
823
|
+
y: 1
|
|
824
|
+
};
|
|
825
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
|
|
826
|
+
} else if (distances.top < SCROLL_ZONE_PX) {
|
|
827
|
+
scrollingVertically = true;
|
|
828
|
+
scrollingInfo.directionObj = {
|
|
829
|
+
x: 0,
|
|
830
|
+
y: -1
|
|
831
|
+
};
|
|
832
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
|
|
833
|
+
}
|
|
834
|
+
if (!isAlreadyScrolling && scrollingVertically) {
|
|
835
|
+
scrollContainer(elementToScroll);
|
|
836
|
+
return true;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
// horizontal
|
|
840
|
+
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
|
|
841
|
+
if (distances.right < SCROLL_ZONE_PX) {
|
|
842
|
+
scrollingHorizontally = true;
|
|
843
|
+
scrollingInfo.directionObj = {
|
|
844
|
+
x: 1,
|
|
845
|
+
y: 0
|
|
846
|
+
};
|
|
847
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
|
|
848
|
+
} else if (distances.left < SCROLL_ZONE_PX) {
|
|
849
|
+
scrollingHorizontally = true;
|
|
850
|
+
scrollingInfo.directionObj = {
|
|
851
|
+
x: -1,
|
|
852
|
+
y: 0
|
|
853
|
+
};
|
|
854
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
|
|
855
|
+
}
|
|
856
|
+
if (!isAlreadyScrolling && scrollingHorizontally) {
|
|
857
|
+
scrollContainer(elementToScroll);
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
resetScrolling();
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
return {
|
|
865
|
+
scrollIfNeeded: scrollIfNeeded,
|
|
866
|
+
resetScrolling: resetScrolling
|
|
867
|
+
};
|
|
921
868
|
}
|
|
922
869
|
|
|
923
870
|
/**
|
|
924
|
-
*
|
|
871
|
+
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
872
|
+
* @param {Point} point
|
|
873
|
+
* @param {HTMLElement} el
|
|
874
|
+
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
925
875
|
*/
|
|
926
|
-
function
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
876
|
+
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
877
|
+
// Even if the scrolling element is small it acts as a scroller for the viewport
|
|
878
|
+
var rect = el === document.scrollingElement ? {
|
|
879
|
+
top: 0,
|
|
880
|
+
bottom: window.innerHeight,
|
|
881
|
+
left: 0,
|
|
882
|
+
right: window.innerWidth
|
|
883
|
+
} : el.getBoundingClientRect();
|
|
884
|
+
if (!isPointInsideRect(point, rect)) {
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
top: point.y - rect.top,
|
|
889
|
+
bottom: rect.bottom - point.y,
|
|
890
|
+
left: point.x - rect.left,
|
|
891
|
+
right: rect.right - point.x
|
|
892
|
+
};
|
|
933
893
|
}
|
|
934
894
|
|
|
935
895
|
/**
|
|
936
|
-
|
|
896
|
+
@typedef {Object} MultiScroller
|
|
897
|
+
@property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
|
|
898
|
+
/**
|
|
899
|
+
* Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
|
|
900
|
+
* @param {HTMLElement[]} baseElementsForScrolling
|
|
901
|
+
* @param {function():Point} getPointerPosition
|
|
902
|
+
* @return {MultiScroller}
|
|
937
903
|
*/
|
|
938
|
-
function
|
|
904
|
+
function createMultiScroller() {
|
|
905
|
+
var baseElementsForScrolling = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
906
|
+
var getPointerPosition = arguments.length > 1 ? arguments[1] : undefined;
|
|
939
907
|
printDebug(function () {
|
|
940
|
-
return "
|
|
908
|
+
return "creating multi-scroller";
|
|
909
|
+
});
|
|
910
|
+
var scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
|
|
911
|
+
var scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort(function (dz1, dz2) {
|
|
912
|
+
return getDepth(dz2) - getDepth(dz1);
|
|
941
913
|
});
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
914
|
+
var _makeScroller = makeScroller(),
|
|
915
|
+
scrollIfNeeded = _makeScroller.scrollIfNeeded;
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* @return {boolean} - was any container scrolled
|
|
919
|
+
*/
|
|
920
|
+
function tick() {
|
|
921
|
+
var mousePosition = getPointerPosition();
|
|
922
|
+
if (!mousePosition || !scrollingContainersDeepToShallow) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
var scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(function (el) {
|
|
926
|
+
return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement;
|
|
927
|
+
});
|
|
928
|
+
for (var i = 0; i < scrollContainersUnderCursor.length; i++) {
|
|
929
|
+
var scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
|
|
930
|
+
if (scrolled) {
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
return {
|
|
937
|
+
multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : function () {
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// internal utils
|
|
944
|
+
function findScrollableParents(element) {
|
|
945
|
+
if (!element) {
|
|
946
|
+
return [];
|
|
947
|
+
}
|
|
948
|
+
var scrollableContainers = [];
|
|
949
|
+
var parent = element;
|
|
950
|
+
while (parent) {
|
|
951
|
+
var _window$getComputedSt = window.getComputedStyle(parent),
|
|
952
|
+
overflow = _window$getComputedSt.overflow;
|
|
953
|
+
if (overflow.split(" ").some(function (o) {
|
|
954
|
+
return o.includes("auto") || o.includes("scroll");
|
|
955
|
+
})) {
|
|
956
|
+
scrollableContainers.push(parent);
|
|
957
|
+
}
|
|
958
|
+
parent = parent.parentElement;
|
|
959
|
+
}
|
|
960
|
+
return scrollableContainers;
|
|
961
|
+
}
|
|
962
|
+
function findRelevantScrollContainers(dropZones) {
|
|
963
|
+
var scrollingContainers = new Set();
|
|
964
|
+
var _iterator = _createForOfIteratorHelper(dropZones),
|
|
965
|
+
_step;
|
|
966
|
+
try {
|
|
967
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
968
|
+
var dz = _step.value;
|
|
969
|
+
findScrollableParents(dz).forEach(function (container) {
|
|
970
|
+
return scrollingContainers.add(container);
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
// The scrolling element might have overflow visible and still be scrollable
|
|
974
|
+
} catch (err) {
|
|
975
|
+
_iterator.e(err);
|
|
976
|
+
} finally {
|
|
977
|
+
_iterator.f();
|
|
978
|
+
}
|
|
979
|
+
if (document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight || document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight) {
|
|
980
|
+
scrollingContainers.add(document.scrollingElement);
|
|
981
|
+
}
|
|
982
|
+
return scrollingContainers;
|
|
947
983
|
}
|
|
948
984
|
|
|
949
985
|
/**
|
|
@@ -1292,7 +1328,6 @@
|
|
|
1292
1328
|
printDebug(function () {
|
|
1293
1329
|
return "watching dragged element";
|
|
1294
1330
|
});
|
|
1295
|
-
armWindowScroller();
|
|
1296
1331
|
var dropZones = typeToDropZones.get(draggedElType);
|
|
1297
1332
|
var _iterator = _createForOfIteratorHelper(dropZones),
|
|
1298
1333
|
_step;
|
|
@@ -1309,18 +1344,21 @@
|
|
|
1309
1344
|
_iterator.f();
|
|
1310
1345
|
}
|
|
1311
1346
|
window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
|
|
1347
|
+
|
|
1312
1348
|
// 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
|
|
1313
1349
|
var setIntervalMs = Math.max.apply(Math, _toConsumableArray(Array.from(dropZones.keys()).map(function (dz) {
|
|
1314
1350
|
return dzToConfig.get(dz).dropAnimationDurationMs;
|
|
1315
1351
|
})));
|
|
1316
|
-
var observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); //if
|
|
1317
|
-
|
|
1352
|
+
var observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); // if setIntervalMs is 0 it goes to 20, otherwise it is max between it and min observation.
|
|
1353
|
+
var multiScroller = createMultiScroller(dropZones, function () {
|
|
1354
|
+
return currentMousePosition;
|
|
1355
|
+
});
|
|
1356
|
+
observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
|
|
1318
1357
|
}
|
|
1319
1358
|
function unWatchDraggedElement() {
|
|
1320
1359
|
printDebug(function () {
|
|
1321
1360
|
return "unwatching dragged element";
|
|
1322
1361
|
});
|
|
1323
|
-
disarmWindowScroller();
|
|
1324
1362
|
var dropZones = typeToDropZones.get(draggedElType);
|
|
1325
1363
|
var _iterator2 = _createForOfIteratorHelper(dropZones),
|
|
1326
1364
|
_step2;
|
package/dist/index.mjs
CHANGED
|
@@ -495,33 +495,13 @@ function calcDistanceBetweenCenters(elA, elB) {
|
|
|
495
495
|
|
|
496
496
|
/**
|
|
497
497
|
* @param {HTMLElement} el - the element to check
|
|
498
|
-
* @returns {boolean} - true if the element in its entirety is off
|
|
498
|
+
* @returns {boolean} - true if the element in its entirety is off-screen including the scrollable area (the normal dom events look at the mouse rather than the element)
|
|
499
499
|
*/
|
|
500
500
|
function isElementOffDocument(el) {
|
|
501
501
|
var rect = getAbsoluteRect(el);
|
|
502
502
|
return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
/**
|
|
506
|
-
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
507
|
-
* @param {Point} point
|
|
508
|
-
* @param {HTMLElement} el
|
|
509
|
-
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
510
|
-
*/
|
|
511
|
-
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
512
|
-
var rect = getAbsoluteRect(el);
|
|
513
|
-
if (!isPointInsideRect(point, rect)) {
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
|
-
return {
|
|
517
|
-
top: point.y - rect.top,
|
|
518
|
-
bottom: rect.bottom - point.y,
|
|
519
|
-
left: point.x - rect.left,
|
|
520
|
-
// TODO - figure out what is so special about right (why the rect is too big)
|
|
521
|
-
right: Math.min(rect.right, document.documentElement.clientWidth) - point.x
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
|
|
525
505
|
var dzToShadowIndexToRect;
|
|
526
506
|
|
|
527
507
|
/**
|
|
@@ -535,17 +515,6 @@ function resetIndexesCache() {
|
|
|
535
515
|
}
|
|
536
516
|
resetIndexesCache();
|
|
537
517
|
|
|
538
|
-
/**
|
|
539
|
-
* Resets the cache that allows for smarter "would be index" resolution for a specific dropzone, should be called after the zone was scrolled
|
|
540
|
-
* @param {HTMLElement} dz
|
|
541
|
-
*/
|
|
542
|
-
function resetIndexesCacheForDz(dz) {
|
|
543
|
-
printDebug(function () {
|
|
544
|
-
return "resetting indexes cache for dz";
|
|
545
|
-
});
|
|
546
|
-
dzToShadowIndexToRect["delete"](dz);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
518
|
/**
|
|
550
519
|
* Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
|
|
551
520
|
* Helpful in order to determine "would be index" more effectively
|
|
@@ -628,102 +597,6 @@ function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
|
|
|
628
597
|
};
|
|
629
598
|
}
|
|
630
599
|
|
|
631
|
-
var SCROLL_ZONE_PX = 25;
|
|
632
|
-
function makeScroller() {
|
|
633
|
-
var scrollingInfo;
|
|
634
|
-
function resetScrolling() {
|
|
635
|
-
scrollingInfo = {
|
|
636
|
-
directionObj: undefined,
|
|
637
|
-
stepPx: 0
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
resetScrolling();
|
|
641
|
-
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
|
|
642
|
-
function scrollContainer(containerEl) {
|
|
643
|
-
var _scrollingInfo = scrollingInfo,
|
|
644
|
-
directionObj = _scrollingInfo.directionObj,
|
|
645
|
-
stepPx = _scrollingInfo.stepPx;
|
|
646
|
-
if (directionObj) {
|
|
647
|
-
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
648
|
-
window.requestAnimationFrame(function () {
|
|
649
|
-
return scrollContainer(containerEl);
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
function calcScrollStepPx(distancePx) {
|
|
654
|
-
return SCROLL_ZONE_PX - distancePx;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
659
|
-
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
660
|
-
* @return {boolean} - true if scrolling was needed
|
|
661
|
-
*/
|
|
662
|
-
function scrollIfNeeded(pointer, elementToScroll) {
|
|
663
|
-
if (!elementToScroll) {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
|
|
667
|
-
if (distances === null) {
|
|
668
|
-
resetScrolling();
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
671
|
-
var isAlreadyScrolling = !!scrollingInfo.directionObj;
|
|
672
|
-
var scrollingVertically = false,
|
|
673
|
-
scrollingHorizontally = false;
|
|
674
|
-
// vertical
|
|
675
|
-
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
|
|
676
|
-
if (distances.bottom < SCROLL_ZONE_PX) {
|
|
677
|
-
scrollingVertically = true;
|
|
678
|
-
scrollingInfo.directionObj = {
|
|
679
|
-
x: 0,
|
|
680
|
-
y: 1
|
|
681
|
-
};
|
|
682
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
|
|
683
|
-
} else if (distances.top < SCROLL_ZONE_PX) {
|
|
684
|
-
scrollingVertically = true;
|
|
685
|
-
scrollingInfo.directionObj = {
|
|
686
|
-
x: 0,
|
|
687
|
-
y: -1
|
|
688
|
-
};
|
|
689
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
|
|
690
|
-
}
|
|
691
|
-
if (!isAlreadyScrolling && scrollingVertically) {
|
|
692
|
-
scrollContainer(elementToScroll);
|
|
693
|
-
return true;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
// horizontal
|
|
697
|
-
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
|
|
698
|
-
if (distances.right < SCROLL_ZONE_PX) {
|
|
699
|
-
scrollingHorizontally = true;
|
|
700
|
-
scrollingInfo.directionObj = {
|
|
701
|
-
x: 1,
|
|
702
|
-
y: 0
|
|
703
|
-
};
|
|
704
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
|
|
705
|
-
} else if (distances.left < SCROLL_ZONE_PX) {
|
|
706
|
-
scrollingHorizontally = true;
|
|
707
|
-
scrollingInfo.directionObj = {
|
|
708
|
-
x: -1,
|
|
709
|
-
y: 0
|
|
710
|
-
};
|
|
711
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
|
|
712
|
-
}
|
|
713
|
-
if (!isAlreadyScrolling && scrollingHorizontally) {
|
|
714
|
-
scrollContainer(elementToScroll);
|
|
715
|
-
return true;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
resetScrolling();
|
|
719
|
-
return false;
|
|
720
|
-
}
|
|
721
|
-
return {
|
|
722
|
-
scrollIfNeeded: scrollIfNeeded,
|
|
723
|
-
resetScrolling: resetScrolling
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
|
|
727
600
|
/**
|
|
728
601
|
* @param {Object} object
|
|
729
602
|
* @return {string}
|
|
@@ -789,9 +662,6 @@ function areArraysShallowEqualSameOrder(arrA, arrB) {
|
|
|
789
662
|
|
|
790
663
|
var INTERVAL_MS = 200;
|
|
791
664
|
var TOLERANCE_PX = 10;
|
|
792
|
-
var _makeScroller = makeScroller(),
|
|
793
|
-
scrollIfNeeded = _makeScroller.scrollIfNeeded,
|
|
794
|
-
resetScrolling = _makeScroller.resetScrolling;
|
|
795
665
|
var next;
|
|
796
666
|
|
|
797
667
|
/**
|
|
@@ -799,9 +669,11 @@ var next;
|
|
|
799
669
|
* @param {Set<HTMLElement>} dropZones
|
|
800
670
|
* @param {HTMLElement} draggedEl
|
|
801
671
|
* @param {number} [intervalMs = INTERVAL_MS]
|
|
672
|
+
* @param {MultiScroller} multiScroller
|
|
802
673
|
*/
|
|
803
674
|
function observe(draggedEl, dropZones) {
|
|
804
675
|
var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
|
|
676
|
+
var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
|
|
805
677
|
// initialization
|
|
806
678
|
var lastDropZoneFound;
|
|
807
679
|
var lastIndexFound;
|
|
@@ -817,7 +689,7 @@ function observe(draggedEl, dropZones) {
|
|
|
817
689
|
*/
|
|
818
690
|
function andNow() {
|
|
819
691
|
var currentCenterOfDragged = findCenterOfElement(draggedEl);
|
|
820
|
-
var scrolled =
|
|
692
|
+
var scrolled = multiScroller.multiScrollIfNeeded();
|
|
821
693
|
// we only want to make a new decision after the element was moved a bit to prevent flickering
|
|
822
694
|
if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
|
|
823
695
|
next = window.setTimeout(andNow, intervalMs);
|
|
@@ -838,7 +710,7 @@ function observe(draggedEl, dropZones) {
|
|
|
838
710
|
try {
|
|
839
711
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
840
712
|
var dz = _step.value;
|
|
841
|
-
if (scrolled)
|
|
713
|
+
if (scrolled) resetIndexesCache();
|
|
842
714
|
var indexObj = findWouldBeIndex(draggedEl, dz);
|
|
843
715
|
if (indexObj === null) {
|
|
844
716
|
// it is not inside
|
|
@@ -883,61 +755,225 @@ function unobserve() {
|
|
|
883
755
|
return "unobserving";
|
|
884
756
|
});
|
|
885
757
|
clearTimeout(next);
|
|
886
|
-
resetScrolling();
|
|
887
758
|
resetIndexesCache();
|
|
888
759
|
}
|
|
889
760
|
|
|
890
|
-
var
|
|
891
|
-
var mousePosition;
|
|
761
|
+
var SCROLL_ZONE_PX = 30;
|
|
892
762
|
|
|
893
763
|
/**
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
* @param {{clientX: number, clientY: number}} e
|
|
764
|
+
* Will make a scroller that can scroll any element given to it in any direction
|
|
765
|
+
* @returns {{scrollIfNeeded: function(Point, HTMLElement): boolean, resetScrolling: function(void):void}}
|
|
897
766
|
*/
|
|
898
|
-
function
|
|
899
|
-
var
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
}
|
|
905
|
-
var _makeScroller$1 = makeScroller(),
|
|
906
|
-
scrollIfNeeded$1 = _makeScroller$1.scrollIfNeeded,
|
|
907
|
-
resetScrolling$1 = _makeScroller$1.resetScrolling;
|
|
908
|
-
var next$1;
|
|
909
|
-
function loop() {
|
|
910
|
-
if (mousePosition) {
|
|
911
|
-
var scrolled = scrollIfNeeded$1(mousePosition, document.documentElement);
|
|
912
|
-
if (scrolled) resetIndexesCache();
|
|
767
|
+
function makeScroller() {
|
|
768
|
+
var scrollingInfo;
|
|
769
|
+
function resetScrolling() {
|
|
770
|
+
scrollingInfo = {
|
|
771
|
+
directionObj: undefined,
|
|
772
|
+
stepPx: 0
|
|
773
|
+
};
|
|
913
774
|
}
|
|
914
|
-
|
|
775
|
+
resetScrolling();
|
|
776
|
+
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
|
|
777
|
+
function scrollContainer(containerEl) {
|
|
778
|
+
var _scrollingInfo = scrollingInfo,
|
|
779
|
+
directionObj = _scrollingInfo.directionObj,
|
|
780
|
+
stepPx = _scrollingInfo.stepPx;
|
|
781
|
+
if (directionObj) {
|
|
782
|
+
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
783
|
+
window.requestAnimationFrame(function () {
|
|
784
|
+
return scrollContainer(containerEl);
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function calcScrollStepPx(distancePx) {
|
|
789
|
+
return SCROLL_ZONE_PX - distancePx;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* @param {Point} pointer - the pointer will be used to decide in which direction to scroll
|
|
794
|
+
* @param {HTMLElement} elementToScroll - the scroll container
|
|
795
|
+
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
796
|
+
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
797
|
+
* @return {boolean} - true if scrolling was needed
|
|
798
|
+
*/
|
|
799
|
+
function scrollIfNeeded(pointer, elementToScroll) {
|
|
800
|
+
if (!elementToScroll) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
|
|
804
|
+
if (distances === null) {
|
|
805
|
+
resetScrolling();
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
var isAlreadyScrolling = !!scrollingInfo.directionObj;
|
|
809
|
+
var scrollingVertically = false,
|
|
810
|
+
scrollingHorizontally = false;
|
|
811
|
+
// vertical
|
|
812
|
+
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
|
|
813
|
+
if (distances.bottom < SCROLL_ZONE_PX) {
|
|
814
|
+
scrollingVertically = true;
|
|
815
|
+
scrollingInfo.directionObj = {
|
|
816
|
+
x: 0,
|
|
817
|
+
y: 1
|
|
818
|
+
};
|
|
819
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
|
|
820
|
+
} else if (distances.top < SCROLL_ZONE_PX) {
|
|
821
|
+
scrollingVertically = true;
|
|
822
|
+
scrollingInfo.directionObj = {
|
|
823
|
+
x: 0,
|
|
824
|
+
y: -1
|
|
825
|
+
};
|
|
826
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
|
|
827
|
+
}
|
|
828
|
+
if (!isAlreadyScrolling && scrollingVertically) {
|
|
829
|
+
scrollContainer(elementToScroll);
|
|
830
|
+
return true;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// horizontal
|
|
834
|
+
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
|
|
835
|
+
if (distances.right < SCROLL_ZONE_PX) {
|
|
836
|
+
scrollingHorizontally = true;
|
|
837
|
+
scrollingInfo.directionObj = {
|
|
838
|
+
x: 1,
|
|
839
|
+
y: 0
|
|
840
|
+
};
|
|
841
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
|
|
842
|
+
} else if (distances.left < SCROLL_ZONE_PX) {
|
|
843
|
+
scrollingHorizontally = true;
|
|
844
|
+
scrollingInfo.directionObj = {
|
|
845
|
+
x: -1,
|
|
846
|
+
y: 0
|
|
847
|
+
};
|
|
848
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
|
|
849
|
+
}
|
|
850
|
+
if (!isAlreadyScrolling && scrollingHorizontally) {
|
|
851
|
+
scrollContainer(elementToScroll);
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
resetScrolling();
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
return {
|
|
859
|
+
scrollIfNeeded: scrollIfNeeded,
|
|
860
|
+
resetScrolling: resetScrolling
|
|
861
|
+
};
|
|
915
862
|
}
|
|
916
863
|
|
|
917
864
|
/**
|
|
918
|
-
*
|
|
865
|
+
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
866
|
+
* @param {Point} point
|
|
867
|
+
* @param {HTMLElement} el
|
|
868
|
+
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
919
869
|
*/
|
|
920
|
-
function
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
870
|
+
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
871
|
+
// Even if the scrolling element is small it acts as a scroller for the viewport
|
|
872
|
+
var rect = el === document.scrollingElement ? {
|
|
873
|
+
top: 0,
|
|
874
|
+
bottom: window.innerHeight,
|
|
875
|
+
left: 0,
|
|
876
|
+
right: window.innerWidth
|
|
877
|
+
} : el.getBoundingClientRect();
|
|
878
|
+
if (!isPointInsideRect(point, rect)) {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
top: point.y - rect.top,
|
|
883
|
+
bottom: rect.bottom - point.y,
|
|
884
|
+
left: point.x - rect.left,
|
|
885
|
+
right: rect.right - point.x
|
|
886
|
+
};
|
|
927
887
|
}
|
|
928
888
|
|
|
929
889
|
/**
|
|
930
|
-
|
|
890
|
+
@typedef {Object} MultiScroller
|
|
891
|
+
@property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
|
|
892
|
+
/**
|
|
893
|
+
* Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
|
|
894
|
+
* @param {HTMLElement[]} baseElementsForScrolling
|
|
895
|
+
* @param {function():Point} getPointerPosition
|
|
896
|
+
* @return {MultiScroller}
|
|
931
897
|
*/
|
|
932
|
-
function
|
|
898
|
+
function createMultiScroller() {
|
|
899
|
+
var baseElementsForScrolling = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
900
|
+
var getPointerPosition = arguments.length > 1 ? arguments[1] : undefined;
|
|
933
901
|
printDebug(function () {
|
|
934
|
-
return "
|
|
902
|
+
return "creating multi-scroller";
|
|
903
|
+
});
|
|
904
|
+
var scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
|
|
905
|
+
var scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort(function (dz1, dz2) {
|
|
906
|
+
return getDepth(dz2) - getDepth(dz1);
|
|
935
907
|
});
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
908
|
+
var _makeScroller = makeScroller(),
|
|
909
|
+
scrollIfNeeded = _makeScroller.scrollIfNeeded;
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* @return {boolean} - was any container scrolled
|
|
913
|
+
*/
|
|
914
|
+
function tick() {
|
|
915
|
+
var mousePosition = getPointerPosition();
|
|
916
|
+
if (!mousePosition || !scrollingContainersDeepToShallow) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
var scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(function (el) {
|
|
920
|
+
return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement;
|
|
921
|
+
});
|
|
922
|
+
for (var i = 0; i < scrollContainersUnderCursor.length; i++) {
|
|
923
|
+
var scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
|
|
924
|
+
if (scrolled) {
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
return {
|
|
931
|
+
multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : function () {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// internal utils
|
|
938
|
+
function findScrollableParents(element) {
|
|
939
|
+
if (!element) {
|
|
940
|
+
return [];
|
|
941
|
+
}
|
|
942
|
+
var scrollableContainers = [];
|
|
943
|
+
var parent = element;
|
|
944
|
+
while (parent) {
|
|
945
|
+
var _window$getComputedSt = window.getComputedStyle(parent),
|
|
946
|
+
overflow = _window$getComputedSt.overflow;
|
|
947
|
+
if (overflow.split(" ").some(function (o) {
|
|
948
|
+
return o.includes("auto") || o.includes("scroll");
|
|
949
|
+
})) {
|
|
950
|
+
scrollableContainers.push(parent);
|
|
951
|
+
}
|
|
952
|
+
parent = parent.parentElement;
|
|
953
|
+
}
|
|
954
|
+
return scrollableContainers;
|
|
955
|
+
}
|
|
956
|
+
function findRelevantScrollContainers(dropZones) {
|
|
957
|
+
var scrollingContainers = new Set();
|
|
958
|
+
var _iterator = _createForOfIteratorHelper(dropZones),
|
|
959
|
+
_step;
|
|
960
|
+
try {
|
|
961
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
962
|
+
var dz = _step.value;
|
|
963
|
+
findScrollableParents(dz).forEach(function (container) {
|
|
964
|
+
return scrollingContainers.add(container);
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
// The scrolling element might have overflow visible and still be scrollable
|
|
968
|
+
} catch (err) {
|
|
969
|
+
_iterator.e(err);
|
|
970
|
+
} finally {
|
|
971
|
+
_iterator.f();
|
|
972
|
+
}
|
|
973
|
+
if (document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight || document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight) {
|
|
974
|
+
scrollingContainers.add(document.scrollingElement);
|
|
975
|
+
}
|
|
976
|
+
return scrollingContainers;
|
|
941
977
|
}
|
|
942
978
|
|
|
943
979
|
/**
|
|
@@ -1286,7 +1322,6 @@ function watchDraggedElement() {
|
|
|
1286
1322
|
printDebug(function () {
|
|
1287
1323
|
return "watching dragged element";
|
|
1288
1324
|
});
|
|
1289
|
-
armWindowScroller();
|
|
1290
1325
|
var dropZones = typeToDropZones.get(draggedElType);
|
|
1291
1326
|
var _iterator = _createForOfIteratorHelper(dropZones),
|
|
1292
1327
|
_step;
|
|
@@ -1303,18 +1338,21 @@ function watchDraggedElement() {
|
|
|
1303
1338
|
_iterator.f();
|
|
1304
1339
|
}
|
|
1305
1340
|
window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
|
|
1341
|
+
|
|
1306
1342
|
// 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
|
|
1307
1343
|
var setIntervalMs = Math.max.apply(Math, _toConsumableArray(Array.from(dropZones.keys()).map(function (dz) {
|
|
1308
1344
|
return dzToConfig.get(dz).dropAnimationDurationMs;
|
|
1309
1345
|
})));
|
|
1310
|
-
var observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); //if
|
|
1311
|
-
|
|
1346
|
+
var observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); // if setIntervalMs is 0 it goes to 20, otherwise it is max between it and min observation.
|
|
1347
|
+
var multiScroller = createMultiScroller(dropZones, function () {
|
|
1348
|
+
return currentMousePosition;
|
|
1349
|
+
});
|
|
1350
|
+
observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
|
|
1312
1351
|
}
|
|
1313
1352
|
function unWatchDraggedElement() {
|
|
1314
1353
|
printDebug(function () {
|
|
1315
1354
|
return "unwatching dragged element";
|
|
1316
1355
|
});
|
|
1317
|
-
disarmWindowScroller();
|
|
1318
1356
|
var dropZones = typeToDropZones.get(draggedElType);
|
|
1319
1357
|
var _iterator2 = _createForOfIteratorHelper(dropZones),
|
|
1320
1358
|
_step2;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-dnd-action",
|
|
3
3
|
"description": "*An awesome drag and drop library for Svelte 3 and 4 (not using the browser's built-in dnd, thanks god): Rich animations, nested containers, touch support and more *",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.41",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/isaacHagoel/svelte-dnd-action.git"
|
|
@@ -150,29 +150,9 @@ export function calcDistanceBetweenCenters(elA, elB) {
|
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
152
|
* @param {HTMLElement} el - the element to check
|
|
153
|
-
* @returns {boolean} - true if the element in its entirety is off
|
|
153
|
+
* @returns {boolean} - true if the element in its entirety is off-screen including the scrollable area (the normal dom events look at the mouse rather than the element)
|
|
154
154
|
*/
|
|
155
155
|
export function isElementOffDocument(el) {
|
|
156
156
|
const rect = getAbsoluteRect(el);
|
|
157
157
|
return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
162
|
-
* @param {Point} point
|
|
163
|
-
* @param {HTMLElement} el
|
|
164
|
-
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
165
|
-
*/
|
|
166
|
-
export function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
167
|
-
const rect = getAbsoluteRect(el);
|
|
168
|
-
if (!isPointInsideRect(point, rect)) {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
return {
|
|
172
|
-
top: point.y - rect.top,
|
|
173
|
-
bottom: rect.bottom - point.y,
|
|
174
|
-
left: point.x - rect.left,
|
|
175
|
-
// TODO - figure out what is so special about right (why the rect is too big)
|
|
176
|
-
right: Math.min(rect.right, document.documentElement.clientWidth) - point.x
|
|
177
|
-
};
|
|
178
|
-
}
|
package/src/helpers/listUtil.js
CHANGED
|
@@ -12,15 +12,6 @@ export function resetIndexesCache() {
|
|
|
12
12
|
}
|
|
13
13
|
resetIndexesCache();
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Resets the cache that allows for smarter "would be index" resolution for a specific dropzone, should be called after the zone was scrolled
|
|
17
|
-
* @param {HTMLElement} dz
|
|
18
|
-
*/
|
|
19
|
-
export function resetIndexesCacheForDz(dz) {
|
|
20
|
-
printDebug(() => "resetting indexes cache for dz");
|
|
21
|
-
dzToShadowIndexToRect.delete(dz);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
15
|
/**
|
|
25
16
|
* Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
|
|
26
17
|
* Helpful in order to determine "would be index" more effectively
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {makeScroller} from "./scroller";
|
|
2
|
+
import {printDebug} from "../constants";
|
|
3
|
+
import {getDepth} from "./util";
|
|
4
|
+
import {isPointInsideRect} from "./intersection";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
@typedef {Object} MultiScroller
|
|
8
|
+
@property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
|
|
9
|
+
/**
|
|
10
|
+
* Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
|
|
11
|
+
* @param {HTMLElement[]} baseElementsForScrolling
|
|
12
|
+
* @param {function():Point} getPointerPosition
|
|
13
|
+
* @return {MultiScroller}
|
|
14
|
+
*/
|
|
15
|
+
export function createMultiScroller(baseElementsForScrolling = [], getPointerPosition) {
|
|
16
|
+
printDebug(() => "creating multi-scroller");
|
|
17
|
+
const scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
|
|
18
|
+
const scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort((dz1, dz2) => getDepth(dz2) - getDepth(dz1));
|
|
19
|
+
const {scrollIfNeeded} = makeScroller();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @return {boolean} - was any container scrolled
|
|
23
|
+
*/
|
|
24
|
+
function tick() {
|
|
25
|
+
const mousePosition = getPointerPosition();
|
|
26
|
+
if (!mousePosition || !scrollingContainersDeepToShallow) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(
|
|
30
|
+
el => isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement
|
|
31
|
+
);
|
|
32
|
+
for (let i = 0; i < scrollContainersUnderCursor.length; i++) {
|
|
33
|
+
const scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
|
|
34
|
+
if (scrolled) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : () => false
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// internal utils
|
|
46
|
+
function findScrollableParents(element) {
|
|
47
|
+
if (!element) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const scrollableContainers = [];
|
|
51
|
+
let parent = element;
|
|
52
|
+
while (parent) {
|
|
53
|
+
const {overflow} = window.getComputedStyle(parent);
|
|
54
|
+
if (overflow.split(" ").some(o => o.includes("auto") || o.includes("scroll"))) {
|
|
55
|
+
scrollableContainers.push(parent);
|
|
56
|
+
}
|
|
57
|
+
parent = parent.parentElement;
|
|
58
|
+
}
|
|
59
|
+
return scrollableContainers;
|
|
60
|
+
}
|
|
61
|
+
function findRelevantScrollContainers(dropZones) {
|
|
62
|
+
const scrollingContainers = new Set();
|
|
63
|
+
for (let dz of dropZones) {
|
|
64
|
+
findScrollableParents(dz).forEach(container => scrollingContainers.add(container));
|
|
65
|
+
}
|
|
66
|
+
// The scrolling element might have overflow visible and still be scrollable
|
|
67
|
+
if (
|
|
68
|
+
document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight ||
|
|
69
|
+
document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight
|
|
70
|
+
) {
|
|
71
|
+
scrollingContainers.add(document.scrollingElement);
|
|
72
|
+
}
|
|
73
|
+
return scrollingContainers;
|
|
74
|
+
}
|
package/src/helpers/observer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {findWouldBeIndex, resetIndexesCache
|
|
1
|
+
import {findWouldBeIndex, resetIndexesCache} from "./listUtil";
|
|
2
2
|
import {findCenterOfElement, isElementOffDocument} from "./intersection";
|
|
3
3
|
import {
|
|
4
4
|
dispatchDraggedElementEnteredContainer,
|
|
@@ -7,13 +7,11 @@ import {
|
|
|
7
7
|
dispatchDraggedLeftDocument,
|
|
8
8
|
dispatchDraggedElementIsOverIndex
|
|
9
9
|
} from "./dispatcher";
|
|
10
|
-
import {makeScroller} from "./scroller";
|
|
11
10
|
import {getDepth} from "./util";
|
|
12
11
|
import {printDebug} from "../constants";
|
|
13
12
|
|
|
14
13
|
const INTERVAL_MS = 200;
|
|
15
14
|
const TOLERANCE_PX = 10;
|
|
16
|
-
const {scrollIfNeeded, resetScrolling} = makeScroller();
|
|
17
15
|
let next;
|
|
18
16
|
|
|
19
17
|
/**
|
|
@@ -21,8 +19,9 @@ let next;
|
|
|
21
19
|
* @param {Set<HTMLElement>} dropZones
|
|
22
20
|
* @param {HTMLElement} draggedEl
|
|
23
21
|
* @param {number} [intervalMs = INTERVAL_MS]
|
|
22
|
+
* @param {MultiScroller} multiScroller
|
|
24
23
|
*/
|
|
25
|
-
export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
24
|
+
export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS, multiScroller) {
|
|
26
25
|
// initialization
|
|
27
26
|
let lastDropZoneFound;
|
|
28
27
|
let lastIndexFound;
|
|
@@ -36,7 +35,7 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
|
36
35
|
*/
|
|
37
36
|
function andNow() {
|
|
38
37
|
const currentCenterOfDragged = findCenterOfElement(draggedEl);
|
|
39
|
-
const scrolled =
|
|
38
|
+
const scrolled = multiScroller.multiScrollIfNeeded();
|
|
40
39
|
// we only want to make a new decision after the element was moved a bit to prevent flickering
|
|
41
40
|
if (
|
|
42
41
|
!scrolled &&
|
|
@@ -57,7 +56,7 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
|
57
56
|
// this is a simple algorithm, potential improvement: first look at lastDropZoneFound
|
|
58
57
|
let isDraggedInADropZone = false;
|
|
59
58
|
for (const dz of dropZonesFromDeepToShallow) {
|
|
60
|
-
if (scrolled)
|
|
59
|
+
if (scrolled) resetIndexesCache();
|
|
61
60
|
const indexObj = findWouldBeIndex(draggedEl, dz);
|
|
62
61
|
if (indexObj === null) {
|
|
63
62
|
// it is not inside
|
|
@@ -95,6 +94,5 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
|
95
94
|
export function unobserve() {
|
|
96
95
|
printDebug(() => "unobserving");
|
|
97
96
|
clearTimeout(next);
|
|
98
|
-
resetScrolling();
|
|
99
97
|
resetIndexesCache();
|
|
100
98
|
}
|
package/src/helpers/scroller.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const SCROLL_ZONE_PX =
|
|
1
|
+
import {isPointInsideRect} from "./intersection";
|
|
2
|
+
const SCROLL_ZONE_PX = 30;
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Will make a scroller that can scroll any element given to it in any direction
|
|
6
|
+
* @returns {{scrollIfNeeded: function(Point, HTMLElement): boolean, resetScrolling: function(void):void}}
|
|
7
|
+
*/
|
|
4
8
|
export function makeScroller() {
|
|
5
9
|
let scrollingInfo;
|
|
6
10
|
function resetScrolling() {
|
|
@@ -20,6 +24,8 @@ export function makeScroller() {
|
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
/**
|
|
27
|
+
* @param {Point} pointer - the pointer will be used to decide in which direction to scroll
|
|
28
|
+
* @param {HTMLElement} elementToScroll - the scroll container
|
|
23
29
|
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
24
30
|
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
25
31
|
* @return {boolean} - true if scrolling was needed
|
|
@@ -76,3 +82,31 @@ export function makeScroller() {
|
|
|
76
82
|
resetScrolling
|
|
77
83
|
};
|
|
78
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
88
|
+
* @param {Point} point
|
|
89
|
+
* @param {HTMLElement} el
|
|
90
|
+
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
91
|
+
*/
|
|
92
|
+
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
93
|
+
// Even if the scrolling element is small it acts as a scroller for the viewport
|
|
94
|
+
const rect =
|
|
95
|
+
el === document.scrollingElement
|
|
96
|
+
? {
|
|
97
|
+
top: 0,
|
|
98
|
+
bottom: window.innerHeight,
|
|
99
|
+
left: 0,
|
|
100
|
+
right: window.innerWidth
|
|
101
|
+
}
|
|
102
|
+
: el.getBoundingClientRect();
|
|
103
|
+
if (!isPointInsideRect(point, rect)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
top: point.y - rect.top,
|
|
108
|
+
bottom: rect.bottom - point.y,
|
|
109
|
+
left: point.x - rect.left,
|
|
110
|
+
right: rect.right - point.x
|
|
111
|
+
};
|
|
112
|
+
}
|
package/src/pointerAction.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
TRIGGERS
|
|
10
10
|
} from "./constants";
|
|
11
11
|
import {observe, unobserve} from "./helpers/observer";
|
|
12
|
-
import {
|
|
12
|
+
import {createMultiScroller} from "./helpers/multiScroller";
|
|
13
13
|
import {
|
|
14
14
|
createDraggedElementFrom,
|
|
15
15
|
decorateShadowEl,
|
|
@@ -88,22 +88,23 @@ function unregisterDropZone(dropZoneEl, type) {
|
|
|
88
88
|
/* functions to manage observing the dragged element and trigger custom drag-events */
|
|
89
89
|
function watchDraggedElement() {
|
|
90
90
|
printDebug(() => "watching dragged element");
|
|
91
|
-
armWindowScroller();
|
|
92
91
|
const dropZones = typeToDropZones.get(draggedElType);
|
|
92
|
+
|
|
93
93
|
for (const dz of dropZones) {
|
|
94
94
|
dz.addEventListener(DRAGGED_ENTERED_EVENT_NAME, handleDraggedEntered);
|
|
95
95
|
dz.addEventListener(DRAGGED_LEFT_EVENT_NAME, handleDraggedLeft);
|
|
96
96
|
dz.addEventListener(DRAGGED_OVER_INDEX_EVENT_NAME, handleDraggedIsOverIndex);
|
|
97
97
|
}
|
|
98
98
|
window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
|
|
99
|
+
|
|
99
100
|
// 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
|
|
100
101
|
const setIntervalMs = Math.max(...Array.from(dropZones.keys()).map(dz => dzToConfig.get(dz).dropAnimationDurationMs));
|
|
101
|
-
const observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); //if
|
|
102
|
-
|
|
102
|
+
const observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); // if setIntervalMs is 0 it goes to 20, otherwise it is max between it and min observation.
|
|
103
|
+
const multiScroller = createMultiScroller(dropZones, () => currentMousePosition);
|
|
104
|
+
observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
|
|
103
105
|
}
|
|
104
106
|
function unWatchDraggedElement() {
|
|
105
107
|
printDebug(() => "unwatching dragged element");
|
|
106
|
-
disarmWindowScroller();
|
|
107
108
|
const dropZones = typeToDropZones.get(draggedElType);
|
|
108
109
|
for (const dz of dropZones) {
|
|
109
110
|
dz.removeEventListener(DRAGGED_ENTERED_EVENT_NAME, handleDraggedEntered);
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {makeScroller} from "./scroller";
|
|
2
|
-
import {printDebug} from "../constants";
|
|
3
|
-
import {resetIndexesCache} from "./listUtil";
|
|
4
|
-
|
|
5
|
-
const INTERVAL_MS = 300;
|
|
6
|
-
let mousePosition;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Do not use this! it is visible for testing only until we get over the issue Cypress not triggering the mousemove listeners
|
|
10
|
-
* // TODO - make private (remove export)
|
|
11
|
-
* @param {{clientX: number, clientY: number}} e
|
|
12
|
-
*/
|
|
13
|
-
export function updateMousePosition(e) {
|
|
14
|
-
const c = e.touches ? e.touches[0] : e;
|
|
15
|
-
mousePosition = {x: c.clientX, y: c.clientY};
|
|
16
|
-
}
|
|
17
|
-
const {scrollIfNeeded, resetScrolling} = makeScroller();
|
|
18
|
-
let next;
|
|
19
|
-
|
|
20
|
-
function loop() {
|
|
21
|
-
if (mousePosition) {
|
|
22
|
-
const scrolled = scrollIfNeeded(mousePosition, document.documentElement);
|
|
23
|
-
if (scrolled) resetIndexesCache();
|
|
24
|
-
}
|
|
25
|
-
next = window.setTimeout(loop, INTERVAL_MS);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* will start watching the mouse pointer and scroll the window if it goes next to the edges
|
|
30
|
-
*/
|
|
31
|
-
export function armWindowScroller() {
|
|
32
|
-
printDebug(() => "arming window scroller");
|
|
33
|
-
window.addEventListener("mousemove", updateMousePosition);
|
|
34
|
-
window.addEventListener("touchmove", updateMousePosition);
|
|
35
|
-
loop();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* will stop watching the mouse pointer and won't scroll the window anymore
|
|
40
|
-
*/
|
|
41
|
-
export function disarmWindowScroller() {
|
|
42
|
-
printDebug(() => "disarming window scroller");
|
|
43
|
-
window.removeEventListener("mousemove", updateMousePosition);
|
|
44
|
-
window.removeEventListener("touchmove", updateMousePosition);
|
|
45
|
-
mousePosition = undefined;
|
|
46
|
-
window.clearTimeout(next);
|
|
47
|
-
resetScrolling();
|
|
48
|
-
}
|