UNPKG

30.8 kBJavaScriptView Raw
1require("core-js/modules/es.string.replace");
2
3require("core-js/modules/web.dom-collections.iterator");
4
5/*
6
7Forked from https://github.com/timruffles/mobile-drag-drop/ v2.3.0-rc.2
8
9Copyright (c) 2013 Tim Ruffles
10
11Permission is hereby granted, free of charge, to any person obtaining a copy of
12this software and associated documentation files (the "Software"), to deal in
13the Software without restriction, including without limitation the rights to
14use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15the Software, and to permit persons to whom the Software is furnished to do so,
16subject to the following conditions:
17
18The above copyright notice and this permission notice shall be included in all
19copies or substantial portions of the Software.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
23FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
24COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27*/
28const CLASS_PREFIX = "dnd-poly-";
29const CLASS_DRAG_IMAGE = CLASS_PREFIX + "drag-image";
30const CLASS_DRAG_IMAGE_SNAPBACK = CLASS_PREFIX + "snapback";
31const CLASS_DRAG_OPERATION_ICON = CLASS_PREFIX + "icon";
32const EVENT_PREFIX = "dnd-poly-";
33const EVENT_DRAG_DRAGSTART_PENDING = EVENT_PREFIX + "dragstart-pending";
34const EVENT_DRAG_DRAGSTART_CANCEL = EVENT_PREFIX + "dragstart-cancel";
35const ALLOWED_EFFECTS = ["none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all"];
36const DROP_EFFECTS = ["none", "copy", "move", "link"];
37
38function detectFeatures() {
39 const features = {
40 dragEvents: "ondragstart" in document.documentElement,
41 draggable: "draggable" in document.documentElement,
42 userAgentSupportingNativeDnD: undefined
43 };
44 const isBlinkEngine = !!window.chrome || /chrome/i.test(navigator.userAgent);
45 features.userAgentSupportingNativeDnD = !(/iPad|iPhone|iPod|Android/.test(navigator.userAgent) || isBlinkEngine && "ontouchstart" in document.documentElement);
46 return features;
47}
48
49function supportsPassiveEventListener() {
50 let supportsPassiveEventListeners = false;
51
52 try {
53 const opts = Object.defineProperty({}, "passive", {
54 get: function () {
55 supportsPassiveEventListeners = true;
56 }
57 });
58 window.addEventListener("test", null, opts);
59 } catch (e) {}
60
61 return supportsPassiveEventListeners;
62}
63
64const supportsPassive = supportsPassiveEventListener();
65
66function isDOMElement(object) {
67 return object && object.tagName;
68}
69
70function addDocumentListener(ev, handler, passive) {
71 if (passive === void 0) {
72 passive = true;
73 }
74
75 document.addEventListener(ev, handler, supportsPassive ? {
76 passive: passive
77 } : false);
78}
79
80function removeDocumentListener(ev, handler) {
81 document.removeEventListener(ev, handler);
82}
83
84function onEvt(el, event, handler, capture) {
85 if (capture === void 0) {
86 capture = false;
87 }
88
89 const options = supportsPassive ? {
90 passive: true,
91 capture: capture
92 } : capture;
93 el.addEventListener(event, handler, options);
94 return {
95 off: function () {
96 el.removeEventListener(event, handler, options);
97 }
98 };
99}
100
101function prepareNodeCopyAsDragImage(srcNode, dstNode) {
102 if (srcNode.nodeType === 1) {
103 const cs = getComputedStyle(srcNode);
104
105 for (let i = 0; i < cs.length; i++) {
106 const csName = cs[i];
107 dstNode.style.setProperty(csName, cs.getPropertyValue(csName), cs.getPropertyPriority(csName));
108 }
109
110 dstNode.style.pointerEvents = "none";
111 dstNode.removeAttribute("id");
112 dstNode.removeAttribute("class");
113 dstNode.removeAttribute("draggable");
114
115 if (dstNode.nodeName === "CANVAS") {
116 const canvasSrc = srcNode;
117 const canvasDst = dstNode;
118 const canvasSrcImgData = canvasSrc.getContext("2d").getImageData(0, 0, canvasSrc.width, canvasSrc.height);
119 canvasDst.getContext("2d").putImageData(canvasSrcImgData, 0, 0);
120 }
121 }
122
123 if (srcNode.hasChildNodes()) {
124 for (let i = 0; i < srcNode.childNodes.length; i++) {
125 prepareNodeCopyAsDragImage(srcNode.childNodes[i], dstNode.childNodes[i]);
126 }
127 }
128}
129
130function createDragImage(sourceNode) {
131 const dragImage = sourceNode.cloneNode(true);
132 prepareNodeCopyAsDragImage(sourceNode, dragImage);
133 return dragImage;
134}
135
136function average(array) {
137 if (array.length === 0) {
138 return 0;
139 }
140
141 return array.reduce(function (s, v) {
142 return v + s;
143 }, 0) / array.length;
144}
145
146function isTouchIdentifierContainedInTouchEvent(touchEvent, touchIdentifier) {
147 for (let i = 0; i < touchEvent.changedTouches.length; i++) {
148 const touch = touchEvent.changedTouches[i];
149
150 if (touch.identifier === touchIdentifier) {
151 return true;
152 }
153 }
154
155 return false;
156}
157
158function updateCentroidCoordinatesOfTouchesIn(coordinateProp, event, outPoint) {
159 const pageXs = [],
160 pageYs = [];
161
162 for (let i = 0; i < event.touches.length; i++) {
163 const touch = event.touches[i];
164 pageXs.push(touch[coordinateProp + "X"]);
165 pageYs.push(touch[coordinateProp + "Y"]);
166 }
167
168 outPoint.x = average(pageXs);
169 outPoint.y = average(pageYs);
170}
171
172const TRANSFORM_CSS_VENDOR_PREFIXES = ["", "-webkit-"];
173
174function extractTransformStyles(sourceNode) {
175 return TRANSFORM_CSS_VENDOR_PREFIXES.map(function (prefix) {
176 const transform = sourceNode.style[prefix + "transform"];
177
178 if (!transform || transform === "none") {
179 return "";
180 }
181
182 return transform.replace(/translate\(\D*\d+[^,]*,\D*\d+[^,]*\)\s*/g, "");
183 });
184}
185
186function translateElementToPoint(element, pnt, originalTransforms, offset, centerOnCoordinates) {
187 if (centerOnCoordinates === void 0) {
188 centerOnCoordinates = true;
189 }
190
191 let x = pnt.x,
192 y = pnt.y;
193
194 if (offset) {
195 x += offset.x;
196 y += offset.y;
197 }
198
199 if (centerOnCoordinates) {
200 x -= parseInt(element.offsetWidth, 10) / 2;
201 y -= parseInt(element.offsetHeight, 10) / 2;
202 }
203
204 const translate = "translate3d(" + x + "px," + y + "px, 0)";
205
206 for (let i = 0; i < TRANSFORM_CSS_VENDOR_PREFIXES.length; i++) {
207 const transformProp = TRANSFORM_CSS_VENDOR_PREFIXES[i] + "transform";
208 element.style[transformProp] = translate + " " + originalTransforms[i];
209 }
210}
211
212function applyDragImageSnapback(sourceEl, dragImage, dragImageTransforms, transitionEndCb) {
213 const cs = getComputedStyle(sourceEl);
214
215 if (cs.visibility === "hidden" || cs.display === "none") {
216 console.log("dnd-poly: source node is not visible. skipping snapback transition.");
217 transitionEndCb();
218 return;
219 }
220
221 dragImage.classList.add(CLASS_DRAG_IMAGE_SNAPBACK);
222 const csDragImage = getComputedStyle(dragImage);
223 const durationInS = parseFloat(csDragImage.transitionDuration);
224
225 if (isNaN(durationInS) || durationInS === 0) {
226 console.log("dnd-poly: no transition used - skipping snapback");
227 transitionEndCb();
228 return;
229 }
230
231 console.log("dnd-poly: starting dragimage snap back");
232 const rect = sourceEl.getBoundingClientRect();
233 const pnt = {
234 x: rect.left,
235 y: rect.top
236 };
237 pnt.x += document.body.scrollLeft || document.documentElement.scrollLeft;
238 pnt.y += document.body.scrollTop || document.documentElement.scrollTop;
239 pnt.x -= parseInt(cs.marginLeft, 10);
240 pnt.y -= parseInt(cs.marginTop, 10);
241 const delayInS = parseFloat(csDragImage.transitionDelay);
242 const durationInMs = Math.round((durationInS + delayInS) * 1000);
243 translateElementToPoint(dragImage, pnt, dragImageTransforms, undefined, false);
244 setTimeout(transitionEndCb, durationInMs);
245}
246
247const DataTransfer = function () {
248 function DataTransfer(_dataStore, _setDragImageHandler) {
249 this._dataStore = _dataStore;
250 this._setDragImageHandler = _setDragImageHandler;
251 this._dropEffect = DROP_EFFECTS[0];
252 }
253
254 Object.defineProperty(DataTransfer.prototype, "dropEffect", {
255 get: function () {
256 return this._dropEffect;
257 },
258 set: function (value) {
259 if (this._dataStore.mode !== 0 && ALLOWED_EFFECTS.indexOf(value) > -1) {
260 this._dropEffect = value;
261 }
262 },
263 enumerable: true,
264 configurable: true
265 });
266 Object.defineProperty(DataTransfer.prototype, "types", {
267 get: function () {
268 if (this._dataStore.mode !== 0) {
269 return Object.freeze(this._dataStore.types);
270 }
271 },
272 enumerable: true,
273 configurable: true
274 });
275 Object.defineProperty(DataTransfer.prototype, "effectAllowed", {
276 get: function () {
277 return this._dataStore.effectAllowed;
278 },
279 set: function (value) {
280 if (this._dataStore.mode === 2 && ALLOWED_EFFECTS.indexOf(value) > -1) {
281 this._dataStore.effectAllowed = value;
282 }
283 },
284 enumerable: true,
285 configurable: true
286 });
287
288 DataTransfer.prototype.setData = function (type, data) {
289 if (this._dataStore.mode === 2) {
290 if (type.indexOf(" ") > -1) {
291 throw new Error("illegal arg: type contains space");
292 }
293
294 this._dataStore.data[type] = data;
295
296 if (this._dataStore.types.indexOf(type) === -1) {
297 this._dataStore.types.push(type);
298 }
299 }
300 };
301
302 DataTransfer.prototype.getData = function (type) {
303 if (this._dataStore.mode === 1 || this._dataStore.mode === 2) {
304 return this._dataStore.data[type] || "";
305 }
306 };
307
308 DataTransfer.prototype.clearData = function (format) {
309 if (this._dataStore.mode === 2) {
310 if (format && this._dataStore.data[format]) {
311 delete this._dataStore.data[format];
312
313 const index = this._dataStore.types.indexOf(format);
314
315 if (index > -1) {
316 this._dataStore.types.splice(index, 1);
317 }
318
319 return;
320 }
321
322 this._dataStore.data = {};
323 this._dataStore.types = [];
324 }
325 };
326
327 DataTransfer.prototype.setDragImage = function (image, x, y) {
328 if (this._dataStore.mode === 2) {
329 this._setDragImageHandler(image, x, y);
330 }
331 };
332
333 return DataTransfer;
334}();
335
336function tryFindDraggableTarget(event) {
337 let el = event.target;
338
339 do {
340 if (el.draggable === false) {
341 continue;
342 }
343
344 if (el.draggable === true) {
345 return el;
346 }
347
348 if (el.getAttribute && el.getAttribute("draggable") === "true") {
349 return el;
350 }
351 } while ((el = el.parentNode) && el !== document.body);
352}
353
354function determineDropEffect(effectAllowed, sourceNode) {
355 if (!effectAllowed) {
356 if (sourceNode.nodeType === 3 && sourceNode.tagName === "A") {
357 return DROP_EFFECTS[3];
358 }
359
360 return DROP_EFFECTS[1];
361 }
362
363 if (effectAllowed === ALLOWED_EFFECTS[0]) {
364 return DROP_EFFECTS[0];
365 }
366
367 if (effectAllowed.indexOf(ALLOWED_EFFECTS[1]) === 0 || effectAllowed === ALLOWED_EFFECTS[7]) {
368 return DROP_EFFECTS[1];
369 }
370
371 if (effectAllowed.indexOf(ALLOWED_EFFECTS[4]) === 0) {
372 return DROP_EFFECTS[3];
373 }
374
375 if (effectAllowed === ALLOWED_EFFECTS[6]) {
376 return DROP_EFFECTS[2];
377 }
378
379 return DROP_EFFECTS[1];
380}
381
382function createDragEventFromTouch(targetElement, e, type, cancelable, window, dataTransfer, relatedTarget) {
383 if (relatedTarget === void 0) {
384 relatedTarget = null;
385 }
386
387 const touch = e.changedTouches[0];
388 const dndEvent = new Event(type, {
389 bubbles: true,
390 cancelable: cancelable
391 });
392 dndEvent.dataTransfer = dataTransfer;
393 dndEvent.relatedTarget = relatedTarget;
394 dndEvent.screenX = touch.screenX;
395 dndEvent.screenY = touch.screenY;
396 dndEvent.clientX = touch.clientX;
397 dndEvent.clientY = touch.clientY;
398 dndEvent.pageX = touch.pageX;
399 dndEvent.pageY = touch.pageY;
400 const targetRect = targetElement.getBoundingClientRect();
401 dndEvent.offsetX = dndEvent.clientX - targetRect.left;
402 dndEvent.offsetY = dndEvent.clientY - targetRect.top;
403 return dndEvent;
404}
405
406function dispatchDragEvent(dragEvent, targetElement, touchEvent, dataStore, dataTransfer, cancelable, relatedTarget) {
407 if (cancelable === void 0) {
408 cancelable = true;
409 }
410
411 if (relatedTarget === void 0) {
412 relatedTarget = null;
413 }
414
415 console.log("dnd-poly: dispatching " + dragEvent);
416 const leaveEvt = createDragEventFromTouch(targetElement, touchEvent, dragEvent, cancelable, document.defaultView, dataTransfer, relatedTarget);
417 const cancelled = !targetElement.dispatchEvent(leaveEvt);
418 dataStore.mode = 0;
419 return cancelled;
420}
421
422function determineDragOperation(effectAllowed, dropEffect) {
423 if (!effectAllowed || effectAllowed === ALLOWED_EFFECTS[7]) {
424 return dropEffect;
425 }
426
427 if (dropEffect === DROP_EFFECTS[1]) {
428 if (effectAllowed.indexOf(DROP_EFFECTS[1]) === 0) {
429 return DROP_EFFECTS[1];
430 }
431 } else if (dropEffect === DROP_EFFECTS[3]) {
432 if (effectAllowed.indexOf(DROP_EFFECTS[3]) === 0 || effectAllowed.indexOf("Link") > -1) {
433 return DROP_EFFECTS[3];
434 }
435 } else if (dropEffect === DROP_EFFECTS[2]) {
436 if (effectAllowed.indexOf(DROP_EFFECTS[2]) === 0 || effectAllowed.indexOf("Move") > -1) {
437 return DROP_EFFECTS[2];
438 }
439 }
440
441 return DROP_EFFECTS[0];
442}
443
444const DragOperationController = function () {
445 function DragOperationController(_initialEvent, _config, _sourceNode, _dragOperationEndedCb) {
446 this._initialEvent = _initialEvent;
447 this._config = _config;
448 this._sourceNode = _sourceNode;
449 this._dragOperationEndedCb = _dragOperationEndedCb;
450 this._dragOperationState = 0;
451 this._immediateUserSelection = null;
452 this._currentDropTarget = null;
453 console.log("dnd-poly: setting up potential drag operation..");
454 this._lastTouchEvent = _initialEvent;
455 this._initialTouch = _initialEvent.changedTouches[0];
456 this._touchMoveHandler = this._onTouchMove.bind(this);
457 this._touchEndOrCancelHandler = this._onTouchEndOrCancel.bind(this);
458 addDocumentListener("touchmove", this._touchMoveHandler, false);
459 addDocumentListener("touchend", this._touchEndOrCancelHandler, false);
460 addDocumentListener("touchcancel", this._touchEndOrCancelHandler, false);
461 }
462
463 DragOperationController.prototype._setup = function () {
464 const _this = this;
465
466 console.log("dnd-poly: starting drag and drop operation");
467 this._dragOperationState = 1;
468 this._currentDragOperation = DROP_EFFECTS[0];
469 this._dragDataStore = {
470 data: {},
471 effectAllowed: undefined,
472 mode: 3,
473 types: []
474 };
475 this._currentHotspotCoordinates = {
476 x: null,
477 y: null
478 };
479 this._dragImagePageCoordinates = {
480 x: null,
481 y: null
482 };
483 let dragImageSrc = this._sourceNode;
484 this._dataTransfer = new DataTransfer(this._dragDataStore, function (element, x, y) {
485 dragImageSrc = element;
486
487 if (typeof x === "number" || typeof y === "number") {
488 _this._dragImageOffset = {
489 x: x || 0,
490 y: y || 0
491 };
492 }
493 });
494 this._dragDataStore.mode = 2;
495 this._dataTransfer.dropEffect = DROP_EFFECTS[0];
496
497 if (dispatchDragEvent("dragstart", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer)) {
498 console.log("dnd-poly: dragstart cancelled");
499 this._dragOperationState = 3;
500
501 this._cleanup();
502
503 return false;
504 }
505
506 updateCentroidCoordinatesOfTouchesIn("page", this._lastTouchEvent, this._dragImagePageCoordinates);
507
508 const dragImage = this._config.dragImageSetup(dragImageSrc);
509
510 this._dragImageTransforms = extractTransformStyles(dragImage);
511 dragImage.style.position = "absolute";
512 dragImage.style.left = "0px";
513 dragImage.style.top = "0px";
514 dragImage.style.zIndex = "999999";
515 dragImage.classList.add(CLASS_DRAG_IMAGE);
516 dragImage.classList.add(CLASS_DRAG_OPERATION_ICON);
517 this._dragImage = dragImage;
518
519 if (!this._dragImageOffset) {
520 if (this._config.dragImageOffset) {
521 this._dragImageOffset = {
522 x: this._config.dragImageOffset.x,
523 y: this._config.dragImageOffset.y
524 };
525 } else if (this._config.dragImageCenterOnTouch) {
526 const cs = getComputedStyle(dragImageSrc);
527 this._dragImageOffset = {
528 x: 0 - parseInt(cs.marginLeft, 10),
529 y: 0 - parseInt(cs.marginTop, 10)
530 };
531 } else {
532 const targetRect = dragImageSrc.getBoundingClientRect();
533 const cs = getComputedStyle(dragImageSrc);
534 this._dragImageOffset = {
535 x: targetRect.left - this._initialTouch.clientX - parseInt(cs.marginLeft, 10) + targetRect.width / 2,
536 y: targetRect.top - this._initialTouch.clientY - parseInt(cs.marginTop, 10) + targetRect.height / 2
537 };
538 }
539 }
540
541 translateElementToPoint(this._dragImage, this._dragImagePageCoordinates, this._dragImageTransforms, this._dragImageOffset, this._config.dragImageCenterOnTouch);
542 document.body.appendChild(this._dragImage);
543 this._iterationIntervalId = window.setInterval(function () {
544 if (_this._iterationLock) {
545 console.log("dnd-poly: iteration skipped because previous iteration hast not yet finished.");
546 return;
547 }
548
549 _this._iterationLock = true;
550
551 _this._dragAndDropProcessModelIteration();
552
553 _this._iterationLock = false;
554 }, this._config.iterationInterval);
555 return true;
556 };
557
558 DragOperationController.prototype._cleanup = function () {
559 console.log("dnd-poly: cleanup");
560
561 if (this._iterationIntervalId) {
562 clearInterval(this._iterationIntervalId);
563 this._iterationIntervalId = null;
564 }
565
566 removeDocumentListener("touchmove", this._touchMoveHandler);
567 removeDocumentListener("touchend", this._touchEndOrCancelHandler);
568 removeDocumentListener("touchcancel", this._touchEndOrCancelHandler);
569
570 if (this._dragImage) {
571 this._dragImage.parentNode.removeChild(this._dragImage);
572
573 this._dragImage = null;
574 }
575
576 this._dragOperationEndedCb(this._config, this._lastTouchEvent, this._dragOperationState);
577 };
578
579 DragOperationController.prototype._onTouchMove = function (event) {
580 const _this = this;
581
582 if (isTouchIdentifierContainedInTouchEvent(event, this._initialTouch.identifier) === false) {
583 return;
584 }
585
586 this._lastTouchEvent = event;
587
588 if (this._dragOperationState === 0) {
589 let startDrag = void 0;
590
591 if (this._config.dragStartConditionOverride) {
592 try {
593 startDrag = this._config.dragStartConditionOverride(event);
594 } catch (e) {
595 console.error("dnd-poly: error in dragStartConditionOverride hook: " + e);
596 startDrag = false;
597 }
598 } else {
599 startDrag = event.touches.length === 1;
600 }
601
602 if (!startDrag) {
603 this._cleanup();
604
605 return;
606 }
607
608 if (this._setup() === true) {
609 this._initialEvent.preventDefault();
610
611 event.preventDefault();
612 }
613
614 return;
615 }
616
617 console.log("dnd-poly: moving draggable..");
618 event.preventDefault();
619 updateCentroidCoordinatesOfTouchesIn("client", event, this._currentHotspotCoordinates);
620 updateCentroidCoordinatesOfTouchesIn("page", event, this._dragImagePageCoordinates);
621
622 if (this._config.dragImageTranslateOverride) {
623 try {
624 let handledDragImageTranslate_1 = false;
625
626 this._config.dragImageTranslateOverride(event, {
627 x: this._currentHotspotCoordinates.x,
628 y: this._currentHotspotCoordinates.y
629 }, this._immediateUserSelection, function (offsetX, offsetY) {
630 if (!_this._dragImage) {
631 return;
632 }
633
634 handledDragImageTranslate_1 = true;
635 _this._currentHotspotCoordinates.x += offsetX;
636 _this._currentHotspotCoordinates.y += offsetY;
637 _this._dragImagePageCoordinates.x += offsetX;
638 _this._dragImagePageCoordinates.y += offsetY;
639 translateElementToPoint(_this._dragImage, _this._dragImagePageCoordinates, _this._dragImageTransforms, _this._dragImageOffset, _this._config.dragImageCenterOnTouch);
640 });
641
642 if (handledDragImageTranslate_1) {
643 return;
644 }
645 } catch (e) {
646 console.log("dnd-poly: error in dragImageTranslateOverride hook: " + e);
647 }
648 }
649
650 translateElementToPoint(this._dragImage, this._dragImagePageCoordinates, this._dragImageTransforms, this._dragImageOffset, this._config.dragImageCenterOnTouch);
651 };
652
653 DragOperationController.prototype._onTouchEndOrCancel = function (event) {
654 if (isTouchIdentifierContainedInTouchEvent(event, this._initialTouch.identifier) === false) {
655 return;
656 }
657
658 if (this._config.dragImageTranslateOverride) {
659 try {
660 this._config.dragImageTranslateOverride(undefined, undefined, undefined, function () {});
661 } catch (e) {
662 console.log("dnd-poly: error in dragImageTranslateOverride hook: " + e);
663 }
664 }
665
666 if (this._dragOperationState === 0) {
667 this._cleanup();
668
669 return;
670 }
671
672 event.preventDefault();
673 this._dragOperationState = event.type === "touchcancel" ? 3 : 2;
674 };
675
676 DragOperationController.prototype._dragAndDropProcessModelIteration = function () {
677 const _this = this;
678
679 const previousDragOperation = this._currentDragOperation;
680 this._dragDataStore.mode = 3;
681 this._dataTransfer.dropEffect = DROP_EFFECTS[0];
682 const dragCancelled = dispatchDragEvent("drag", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer);
683
684 if (dragCancelled) {
685 console.log("dnd-poly: drag event cancelled.");
686 this._currentDragOperation = DROP_EFFECTS[0];
687 }
688
689 if (dragCancelled || this._dragOperationState === 2 || this._dragOperationState === 3) {
690 const dragFailed = this._dragOperationEnded(this._dragOperationState);
691
692 if (dragFailed) {
693 applyDragImageSnapback(this._sourceNode, this._dragImage, this._dragImageTransforms, function () {
694 _this._finishDragOperation();
695 });
696 return;
697 }
698
699 this._finishDragOperation();
700
701 return;
702 }
703
704 const newUserSelection = this._config.elementFromPoint(this._currentHotspotCoordinates.x, this._currentHotspotCoordinates.y);
705
706 console.log("dnd-poly: new immediate user selection is: " + newUserSelection);
707 const previousTargetElement = this._currentDropTarget;
708
709 if (newUserSelection !== this._immediateUserSelection && newUserSelection !== this._currentDropTarget) {
710 this._immediateUserSelection = newUserSelection;
711
712 if (this._currentDropTarget !== null) {
713 this._dragDataStore.mode = 3;
714 this._dataTransfer.dropEffect = DROP_EFFECTS[0];
715 dispatchDragEvent("dragexit", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false);
716 }
717
718 if (this._immediateUserSelection === null) {
719 this._currentDropTarget = this._immediateUserSelection;
720 console.log("dnd-poly: current drop target changed to null");
721 } else {
722 this._dragDataStore.mode = 3;
723 this._dataTransfer.dropEffect = determineDropEffect(this._dragDataStore.effectAllowed, this._sourceNode);
724
725 if (dispatchDragEvent("dragenter", this._immediateUserSelection, this._lastTouchEvent, this._dragDataStore, this._dataTransfer)) {
726 console.log("dnd-poly: dragenter default prevented");
727 this._currentDropTarget = this._immediateUserSelection;
728 this._currentDragOperation = determineDragOperation(this._dataTransfer.effectAllowed, this._dataTransfer.dropEffect);
729 } else {
730 if (this._immediateUserSelection !== document.body) {
731 this._currentDropTarget = document.body;
732 }
733 }
734 }
735 }
736
737 if (previousTargetElement !== this._currentDropTarget && isDOMElement(previousTargetElement)) {
738 console.log("dnd-poly: current drop target changed.");
739 this._dragDataStore.mode = 3;
740 this._dataTransfer.dropEffect = DROP_EFFECTS[0];
741 dispatchDragEvent("dragleave", previousTargetElement, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false, this._currentDropTarget);
742 }
743
744 if (isDOMElement(this._currentDropTarget)) {
745 this._dragDataStore.mode = 3;
746 this._dataTransfer.dropEffect = determineDropEffect(this._dragDataStore.effectAllowed, this._sourceNode);
747
748 if (dispatchDragEvent("dragover", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer) === false) {
749 console.log("dnd-poly: dragover not prevented on possible drop-target.");
750 this._currentDragOperation = DROP_EFFECTS[0];
751 } else {
752 console.log("dnd-poly: dragover prevented.");
753 this._currentDragOperation = determineDragOperation(this._dataTransfer.effectAllowed, this._dataTransfer.dropEffect);
754 }
755 }
756
757 console.log("dnd-poly: d'n'd iteration ended. current drag operation: " + this._currentDragOperation);
758
759 if (previousDragOperation !== this._currentDragOperation) {
760 this._dragImage.classList.remove(CLASS_PREFIX + previousDragOperation);
761 }
762
763 const currentDragOperationClass = CLASS_PREFIX + this._currentDragOperation;
764
765 this._dragImage.classList.add(currentDragOperationClass);
766 };
767
768 DragOperationController.prototype._dragOperationEnded = function (state) {
769 console.log("dnd-poly: drag operation end detected with " + this._currentDragOperation);
770 const dragFailed = this._currentDragOperation === DROP_EFFECTS[0] || this._currentDropTarget === null || state === 3;
771
772 if (dragFailed) {
773 if (isDOMElement(this._currentDropTarget)) {
774 this._dragDataStore.mode = 3;
775 this._dataTransfer.dropEffect = DROP_EFFECTS[0];
776 dispatchDragEvent("dragleave", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false);
777 }
778 } else {
779 if (isDOMElement(this._currentDropTarget)) {
780 this._dragDataStore.mode = 1;
781 this._dataTransfer.dropEffect = this._currentDragOperation;
782
783 if (dispatchDragEvent("drop", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer) === true) {
784 this._currentDragOperation = this._dataTransfer.dropEffect;
785 } else {
786 this._currentDragOperation = DROP_EFFECTS[0];
787 }
788 }
789 }
790
791 return dragFailed;
792 };
793
794 DragOperationController.prototype._finishDragOperation = function () {
795 console.log("dnd-poly: dragimage snap back transition ended");
796 this._dragDataStore.mode = 3;
797 this._dataTransfer.dropEffect = this._currentDragOperation;
798 dispatchDragEvent("dragend", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false);
799 this._dragOperationState = 2;
800
801 this._cleanup();
802 };
803
804 return DragOperationController;
805}();
806
807const config = {
808 iterationInterval: 150,
809 tryFindDraggableTarget: tryFindDraggableTarget,
810 dragImageSetup: createDragImage,
811 elementFromPoint: function (x, y) {
812 return document.elementFromPoint(x, y);
813 }
814};
815let activeDragOperation;
816
817function onTouchstart(e, composePath) {
818 console.log("dnd-poly: global touchstart");
819
820 if (activeDragOperation) {
821 console.log("dnd-poly: drag operation already active");
822 return;
823 }
824
825 const dragTarget = config.tryFindDraggableTarget(e, composePath);
826
827 if (!dragTarget) {
828 console.log("dnd-poly: no draggable at touchstart coordinates");
829 return;
830 }
831
832 try {
833 activeDragOperation = new DragOperationController(e, config, dragTarget, dragOperationEnded);
834 } catch (err) {
835 dragOperationEnded(config, e, 3);
836 throw err;
837 }
838}
839
840function onDelayTouchstart(evt) {
841 console.log("dnd-poly: setup delayed dragstart..");
842 const el = evt.target;
843 const composePath = evt.composedPath();
844
845 const heldItem = function () {
846 console.log("dnd-poly: starting delayed drag..");
847 end.off();
848 cancel.off();
849 move.off();
850 scroll.off();
851 onTouchstart(evt, composePath);
852 };
853
854 const onReleasedItem = function (event) {
855 console.log("dnd-poly: aborting delayed drag because of " + event.type);
856 end.off();
857 cancel.off();
858 move.off();
859 scroll.off();
860
861 if (el) {
862 el.dispatchEvent(new CustomEvent(EVENT_DRAG_DRAGSTART_CANCEL, {
863 bubbles: true,
864 cancelable: true
865 }));
866 }
867
868 clearTimeout(timer);
869 };
870
871 if (el) {
872 el.dispatchEvent(new CustomEvent(EVENT_DRAG_DRAGSTART_PENDING, {
873 bubbles: true,
874 cancelable: true
875 }));
876 }
877
878 const timer = window.setTimeout(heldItem, config.holdToDrag);
879 const end = onEvt(el, "touchend", onReleasedItem);
880 const cancel = onEvt(el, "touchcancel", onReleasedItem);
881 const move = onEvt(el, "touchmove", onReleasedItem);
882 const scroll = onEvt(window, "scroll", onReleasedItem, true);
883}
884
885function dragOperationEnded(_config, event, state) {
886 if (state === 0) {
887 console.log("dnd-poly: Drag never started. Last event was " + event.type);
888
889 if (_config.defaultActionOverride) {
890 try {
891 _config.defaultActionOverride(event);
892
893 if (event.defaultPrevented) {
894 console.log("dnd-poly: defaultActionOverride has taken care of triggering the default action. preventing default on original event");
895 }
896 } catch (e) {
897 console.log("dnd-poly: error in defaultActionOverride: " + e);
898 }
899 }
900 }
901
902 activeDragOperation = null;
903}
904
905function polyfill(override) {
906 if (override) {
907 Object.keys(override).forEach(function (key) {
908 config[key] = override[key];
909 });
910 }
911
912 if (!config.forceApply) {
913 const detectedFeatures = detectFeatures();
914
915 if (detectedFeatures.userAgentSupportingNativeDnD && detectedFeatures.draggable && detectedFeatures.dragEvents) {
916 return false;
917 }
918 }
919
920 console.log("dnd-poly: Applying mobile drag and drop polyfill.");
921
922 if (config.holdToDrag) {
923 console.log("dnd-poly: holdToDrag set to " + config.holdToDrag);
924 addDocumentListener("touchstart", onDelayTouchstart, false);
925 } else {
926 addDocumentListener("touchstart", onTouchstart, false);
927 }
928
929 return true;
930}
931
932function tryFindDraggableTarget_override(event, composePath) {
933 const cp = composePath || event.composedPath();
934
935 for (let o of cp) {
936 let el = o;
937
938 do {
939 if (el.draggable === false) {
940 continue;
941 }
942
943 if (el.getAttribute && el.getAttribute("draggable") === "true") {
944 return el;
945 }
946 } while ((el = el.parentNode) && el !== document.body);
947 }
948}
949
950function elementFromPoint(x, y) {
951 for (let o of this._path) {
952 if (o.elementFromPoint) {
953 let el = o.elementFromPoint(x, y);
954
955 if (el) {
956 while (el.shadowRoot) {
957 el = el.shadowRoot.elementFromPoint(x, y);
958 }
959
960 return el;
961 }
962 }
963 }
964}
965
966function dragStartConditionOverride(event) {
967 this._path = event.composedPath();
968 return true;
969}
970
971polyfill({
972 tryFindDraggableTarget: tryFindDraggableTarget_override,
973 elementFromPoint: elementFromPoint,
974 dragStartConditionOverride: dragStartConditionOverride,
975 holdToDrag: 500
976});
977//# sourceMappingURL=polyfill.js.map
\No newline at end of file