-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscript_sortable_dnd.js
82 lines (68 loc) · 2.97 KB
/
script_sortable_dnd.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Originally from https://ghostinspector.com/blog/simulate-drag-and-drop-javascript-casperjs/
// trimmed down and modified by @kemokid (Martin Baker) to work with Sortable.js
///
// Probably not going to work with dragging from one list to another
// Call with DOM selectors, eg `triggerSortableDragAndDrop('#drag', '#drop');`
// Returns false if unable to start.
// callback, if present, will be called with true if able to finish, false if not.
// If you receive "false" on the callback, the list is likely not in the beginning state.
var triggerSortableDragAndDrop = function (selectorDrag, selectorDrop, callback) {
var DELAY_INTERVAL_MS = 10;
var MAX_TRIES = 10;
// fetch target elements
var elemDrag = document.querySelector(selectorDrag);
var elemDrop = document.querySelector(selectorDrop);
if (!elemDrag || !elemDrop) {
console.log("can't get elements");
return false;
}
var startingDropRect = elemDrop.getBoundingClientRect();
function rectsEqual(r1, r2) {
return r1.top === r2.top && r1.right === r2.right && r1.bottom === r2.bottom && r1.left === r2.left;
}
// function for triggering mouse events
function fireMouseEvent(type, elem) {
var evt = document.createEvent('MouseEvents');
evt.initMouseEvent(type, true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem);
elem.dispatchEvent(evt);
};
// trigger dragging process on top of drop target
// We sometimes need to do this multiple times due to the vagaries of
// how Sortable manages the list re-arrangement
var counter = 0;
function dragover() {
counter++;
console.log('DRAGOVER #' + counter);
var currentDropRect = elemDrop.getBoundingClientRect();
if (rectsEqual(startingDropRect, currentDropRect) && counter < MAX_TRIES) {
if (counter != 1) console.log("drop target rect hasn't changed, trying again");
// mouseover / mouseout etc events not necessary
// dragenter / dragleave events not necessary either
fireMouseEvent('dragover', elemDrop);
setTimeout(dragover, DELAY_INTERVAL_MS);
} else {
if (rectsEqual(startingDropRect, currentDropRect)) {
console.log("wasn't able to budge drop target after " + MAX_TRIES + " tries, aborting");
fireMouseEvent('drop', elemDrop);
if (callback) callback(false);
} else {
setTimeout(drop, DELAY_INTERVAL_MS);
}
}
}
function drop() {
console.log('DROP');
// release dragged element on top of drop target
fireMouseEvent('drop', elemDrop);
fireMouseEvent('mouseup', elemDrop); // not strictly necessary but I like the symmetry
if (callback) callback(true);
}
// start dragging process
console.log('DRAGSTART');
fireMouseEvent('mousedown', elemDrag);
fireMouseEvent('dragstart', elemDrag);
// after a delay, do the first dragover; this will run up to MAX_TRIES times
// (with a delay between each run) and finally run drop() with a delay:
setTimeout(dragover, DELAY_INTERVAL_MS);
return true;
};