UNPKG

32.8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var disposable_1 = require("@phosphor/disposable");
4/**
5 * An object which manages a drag-drop operation.
6 *
7 * A drag object dispatches four different events to drop targets:
8 *
9 * - `'p-dragenter'` - Dispatched when the mouse enters the target
10 * element. This event must be canceled in order to receive any
11 * of the other events.
12 *
13 * - `'p-dragover'` - Dispatched when the mouse moves over the drop
14 * target. It must cancel the event and set the `dropAction` to one
15 * of the supported actions in order to receive drop events.
16 *
17 * - `'p-dragleave'` - Dispatched when the mouse leaves the target
18 * element. This includes moving the mouse into child elements.
19 *
20 * - `'p-drop'`- Dispatched when the mouse is released over the target
21 * element when the target indicates an appropriate drop action. If
22 * the event is canceled, the indicated drop action is returned to
23 * the initiator through the resolved promise.
24 *
25 * A drag operation can be terminated at any time by pressing `Escape`
26 * or by disposing the drag object.
27 *
28 * A drag object has the ability to automatically scroll a scrollable
29 * element when the mouse is hovered near one of its edges. To enable
30 * this, add the `data-p-dragscroll` attribute to any element which
31 * the drag object should consider for scrolling.
32 *
33 * #### Notes
34 * This class is designed to be used when dragging and dropping custom
35 * data *within* a single application. It is *not* a replacement for
36 * the native drag-drop API. Instead, it provides an API which allows
37 * drag operations to be initiated programmatically and enables the
38 * transfer of arbitrary non-string objects; features which are not
39 * possible with the native drag-drop API.
40 */
41var Drag = /** @class */ (function () {
42 /**
43 * Construct a new drag object.
44 *
45 * @param options - The options for initializing the drag.
46 */
47 function Drag(options) {
48 var _this = this;
49 /**
50 * The scroll loop handler function.
51 */
52 this._onScrollFrame = function () {
53 // Bail early if there is no scroll target.
54 if (!_this._scrollTarget) {
55 return;
56 }
57 // Unpack the scroll target.
58 var _a = _this._scrollTarget, element = _a.element, edge = _a.edge, distance = _a.distance;
59 // Calculate the scroll delta using nonlinear acceleration.
60 var d = Private.SCROLL_EDGE_SIZE - distance;
61 var f = Math.pow(d / Private.SCROLL_EDGE_SIZE, 2);
62 var s = Math.max(1, Math.round(f * Private.SCROLL_EDGE_SIZE));
63 // Scroll the element in the specified direction.
64 switch (edge) {
65 case 'top':
66 element.scrollTop -= s;
67 break;
68 case 'left':
69 element.scrollLeft -= s;
70 break;
71 case 'right':
72 element.scrollLeft += s;
73 break;
74 case 'bottom':
75 element.scrollTop += s;
76 break;
77 }
78 // Request the next cycle of the scroll loop.
79 requestAnimationFrame(_this._onScrollFrame);
80 };
81 this._disposed = false;
82 this._dropAction = 'none';
83 this._override = null;
84 this._currentTarget = null;
85 this._currentElement = null;
86 this._promise = null;
87 this._scrollTarget = null;
88 this._resolve = null;
89 this.mimeData = options.mimeData;
90 this.dragImage = options.dragImage || null;
91 this.proposedAction = options.proposedAction || 'copy';
92 this.supportedActions = options.supportedActions || 'all';
93 this.source = options.source || null;
94 }
95 /**
96 * Dispose of the resources held by the drag object.
97 *
98 * #### Notes
99 * This will cancel the drag operation if it is active.
100 */
101 Drag.prototype.dispose = function () {
102 // Do nothing if the drag object is already disposed.
103 if (this._disposed) {
104 return;
105 }
106 this._disposed = true;
107 // If there is a current target, dispatch a drag leave event.
108 if (this._currentTarget) {
109 var event_1 = Private.createMouseEvent('mouseup', -1, -1);
110 Private.dispatchDragLeave(this, this._currentTarget, null, event_1);
111 }
112 // Finalize the drag object with `'none'`.
113 this._finalize('none');
114 };
115 Object.defineProperty(Drag.prototype, "isDisposed", {
116 /**
117 * Test whether the drag object is disposed.
118 */
119 get: function () {
120 return this._disposed;
121 },
122 enumerable: true,
123 configurable: true
124 });
125 /**
126 * Start the drag operation at the specified client position.
127 *
128 * @param clientX - The client X position for the drag start.
129 *
130 * @param clientY - The client Y position for the drag start.
131 *
132 * @returns A promise which resolves to the result of the drag.
133 *
134 * #### Notes
135 * If the drag has already been started, the promise created by the
136 * first call to `start` is returned.
137 *
138 * If the drag operation has ended, or if the drag object has been
139 * disposed, the returned promise will resolve to `'none'`.
140 *
141 * The drag object will be automatically disposed when drag operation
142 * completes. This means `Drag` objects are for single-use only.
143 *
144 * This method assumes the left mouse button is already held down.
145 */
146 Drag.prototype.start = function (clientX, clientY) {
147 var _this = this;
148 // If the drag object is already disposed, resolve to `None`.
149 if (this._disposed) {
150 return Promise.resolve('none');
151 }
152 // If the drag has already been started, return the promise.
153 if (this._promise) {
154 return this._promise;
155 }
156 // Install the document listeners for the drag object.
157 this._addListeners();
158 // Attach the drag image at the specified client position.
159 this._attachDragImage(clientX, clientY);
160 // Create the promise which will be resolved on completion.
161 this._promise = new Promise(function (resolve, reject) {
162 _this._resolve = resolve;
163 });
164 // Trigger a fake move event to kick off the drag operation.
165 var event = Private.createMouseEvent('mousemove', clientX, clientY);
166 document.dispatchEvent(event);
167 // Return the pending promise for the drag operation.
168 return this._promise;
169 };
170 /**
171 * Handle the DOM events for the drag operation.
172 *
173 * @param event - The DOM event sent to the drag object.
174 *
175 * #### Notes
176 * This method implements the DOM `EventListener` interface and is
177 * called in response to events on the document. It should not be
178 * called directly by user code.
179 */
180 Drag.prototype.handleEvent = function (event) {
181 switch (event.type) {
182 case 'mousemove':
183 this._evtMouseMove(event);
184 break;
185 case 'mouseup':
186 this._evtMouseUp(event);
187 break;
188 case 'keydown':
189 this._evtKeyDown(event);
190 break;
191 default:
192 // Stop all other events during drag-drop.
193 event.preventDefault();
194 event.stopPropagation();
195 break;
196 }
197 };
198 /**
199 * Handle the `'mousemove'` event for the drag object.
200 */
201 Drag.prototype._evtMouseMove = function (event) {
202 // Stop all input events during drag-drop.
203 event.preventDefault();
204 event.stopPropagation();
205 // Update the current target node and dispatch enter/leave events.
206 this._updateCurrentTarget(event);
207 // Update the drag scroll element.
208 this._updateDragScroll(event);
209 // Move the drag image to the specified client position. This is
210 // performed *after* dispatching to prevent unnecessary reflows.
211 this._moveDragImage(event.clientX, event.clientY);
212 };
213 /**
214 * Handle the `'mouseup'` event for the drag object.
215 */
216 Drag.prototype._evtMouseUp = function (event) {
217 // Stop all input events during drag-drop.
218 event.preventDefault();
219 event.stopPropagation();
220 // Do nothing if the left button is not released.
221 if (event.button !== 0) {
222 return;
223 }
224 // Update the current target node and dispatch enter/leave events.
225 // This prevents a subtle issue where the DOM mutates under the
226 // cursor after the last move event but before the drop event.
227 this._updateCurrentTarget(event);
228 // If there is no current target, finalize with `'none'`.
229 if (!this._currentTarget) {
230 this._finalize('none');
231 return;
232 }
233 // If the last drop action was `'none'`, dispatch a leave event
234 // to the current target and finalize the drag with `'none'`.
235 if (this._dropAction === 'none') {
236 Private.dispatchDragLeave(this, this._currentTarget, null, event);
237 this._finalize('none');
238 return;
239 }
240 // Dispatch the drop event at the current target and finalize
241 // with the resulting drop action.
242 var action = Private.dispatchDrop(this, this._currentTarget, event);
243 this._finalize(action);
244 };
245 /**
246 * Handle the `'keydown'` event for the drag object.
247 */
248 Drag.prototype._evtKeyDown = function (event) {
249 // Stop all input events during drag-drop.
250 event.preventDefault();
251 event.stopPropagation();
252 // Cancel the drag if `Escape` is pressed.
253 if (event.keyCode === 27) {
254 this.dispose();
255 }
256 };
257 /**
258 * Add the document event listeners for the drag object.
259 */
260 Drag.prototype._addListeners = function () {
261 document.addEventListener('mousedown', this, true);
262 document.addEventListener('mousemove', this, true);
263 document.addEventListener('mouseup', this, true);
264 document.addEventListener('mouseenter', this, true);
265 document.addEventListener('mouseleave', this, true);
266 document.addEventListener('mouseover', this, true);
267 document.addEventListener('mouseout', this, true);
268 document.addEventListener('keydown', this, true);
269 document.addEventListener('keyup', this, true);
270 document.addEventListener('keypress', this, true);
271 document.addEventListener('contextmenu', this, true);
272 };
273 /**
274 * Remove the document event listeners for the drag object.
275 */
276 Drag.prototype._removeListeners = function () {
277 document.removeEventListener('mousedown', this, true);
278 document.removeEventListener('mousemove', this, true);
279 document.removeEventListener('mouseup', this, true);
280 document.removeEventListener('mouseenter', this, true);
281 document.removeEventListener('mouseleave', this, true);
282 document.removeEventListener('mouseover', this, true);
283 document.removeEventListener('mouseout', this, true);
284 document.removeEventListener('keydown', this, true);
285 document.removeEventListener('keyup', this, true);
286 document.removeEventListener('keypress', this, true);
287 document.removeEventListener('contextmenu', this, true);
288 };
289 /**
290 * Update the drag scroll element under the mouse.
291 */
292 Drag.prototype._updateDragScroll = function (event) {
293 // Find the scroll target under the mouse.
294 var target = Private.findScrollTarget(event);
295 // Bail if there is nothing to scroll.
296 if (!this._scrollTarget && !target) {
297 return;
298 }
299 // Start the scroll loop if needed.
300 if (!this._scrollTarget) {
301 setTimeout(this._onScrollFrame, 500);
302 }
303 // Update the scroll target.
304 this._scrollTarget = target;
305 };
306 /**
307 * Update the current target node using the given mouse event.
308 */
309 Drag.prototype._updateCurrentTarget = function (event) {
310 // Fetch common local state.
311 var prevTarget = this._currentTarget;
312 var currTarget = this._currentTarget;
313 var prevElem = this._currentElement;
314 // Find the current indicated element at the given position.
315 var currElem = document.elementFromPoint(event.clientX, event.clientY);
316 // Update the current element reference.
317 this._currentElement = currElem;
318 // If the indicated element changes from the previous iteration,
319 // and is different from the current target, dispatch the exit
320 // event to the target.
321 if (currElem !== prevElem && currElem !== currTarget) {
322 Private.dispatchDragExit(this, currTarget, currElem, event);
323 }
324 // If the indicated element changes from the previous iteration,
325 // and is different from the current target, dispatch the enter
326 // event and compute the new target element.
327 if (currElem !== prevElem && currElem !== currTarget) {
328 currTarget = Private.dispatchDragEnter(this, currElem, currTarget, event);
329 }
330 // If the current target element has changed, update the current
331 // target reference and dispatch the leave event to the old target.
332 if (currTarget !== prevTarget) {
333 this._currentTarget = currTarget;
334 Private.dispatchDragLeave(this, prevTarget, currTarget, event);
335 }
336 // Dispatch the drag over event and update the drop action.
337 var action = Private.dispatchDragOver(this, currTarget, event);
338 this._setDropAction(action);
339 };
340 /**
341 * Attach the drag image element at the specified location.
342 *
343 * This is a no-op if there is no drag image element.
344 */
345 Drag.prototype._attachDragImage = function (clientX, clientY) {
346 if (!this.dragImage) {
347 return;
348 }
349 this.dragImage.classList.add('p-mod-drag-image');
350 var style = this.dragImage.style;
351 style.pointerEvents = 'none';
352 style.position = 'fixed';
353 style.top = clientY + "px";
354 style.left = clientX + "px";
355 document.body.appendChild(this.dragImage);
356 };
357 /**
358 * Move the drag image element to the specified location.
359 *
360 * This is a no-op if there is no drag image element.
361 */
362 Drag.prototype._moveDragImage = function (clientX, clientY) {
363 if (!this.dragImage) {
364 return;
365 }
366 var style = this.dragImage.style;
367 style.top = clientY + "px";
368 style.left = clientX + "px";
369 };
370 /**
371 * Detach the drag image element from the DOM.
372 *
373 * This is a no-op if there is no drag image element.
374 */
375 Drag.prototype._detachDragImage = function () {
376 if (!this.dragImage) {
377 return;
378 }
379 var parent = this.dragImage.parentNode;
380 if (!parent) {
381 return;
382 }
383 parent.removeChild(this.dragImage);
384 };
385 /**
386 * Set the internal drop action state and update the drag cursor.
387 */
388 Drag.prototype._setDropAction = function (action) {
389 action = Private.validateAction(action, this.supportedActions);
390 if (this._override && this._dropAction === action) {
391 return;
392 }
393 switch (action) {
394 case 'none':
395 this._dropAction = action;
396 this._override = Drag.overrideCursor('no-drop');
397 break;
398 case 'copy':
399 this._dropAction = action;
400 this._override = Drag.overrideCursor('copy');
401 break;
402 case 'link':
403 this._dropAction = action;
404 this._override = Drag.overrideCursor('alias');
405 break;
406 case 'move':
407 this._dropAction = action;
408 this._override = Drag.overrideCursor('move');
409 break;
410 }
411 };
412 /**
413 * Finalize the drag operation and resolve the drag promise.
414 */
415 Drag.prototype._finalize = function (action) {
416 // Store the resolve function as a temp variable.
417 var resolve = this._resolve;
418 // Remove the document event listeners.
419 this._removeListeners();
420 // Detach the drag image.
421 this._detachDragImage();
422 // Dispose of the cursor override.
423 if (this._override) {
424 this._override.dispose();
425 this._override = null;
426 }
427 // Clear the mime data.
428 this.mimeData.clear();
429 // Clear the rest of the internal drag state.
430 this._disposed = true;
431 this._dropAction = 'none';
432 this._currentTarget = null;
433 this._currentElement = null;
434 this._scrollTarget = null;
435 this._promise = null;
436 this._resolve = null;
437 // Finally, resolve the promise to the given drop action.
438 if (resolve) {
439 resolve(action);
440 }
441 };
442 return Drag;
443}());
444exports.Drag = Drag;
445/**
446 * The namespace for the `Drag` class statics.
447 */
448(function (Drag) {
449 /**
450 * Override the cursor icon for the entire document.
451 *
452 * @param cursor - The string representing the cursor style.
453 *
454 * @returns A disposable which will clear the override when disposed.
455 *
456 * #### Notes
457 * The most recent call to `overrideCursor` takes precedence.
458 * Disposing an old override has no effect on the current override.
459 *
460 * This utility function is used by the `Drag` class to override the
461 * mouse cursor during a drag-drop operation, but it can also be used
462 * by other classes to fix the cursor icon during normal mouse drags.
463 *
464 * #### Example
465 * ```typescript
466 * import { Drag } from '@phosphor/dragdrop';
467 *
468 * // Force the cursor to be 'wait' for the entire document.
469 * let override = Drag.overrideCursor('wait');
470 *
471 * // Clear the override by disposing the return value.
472 * override.dispose();
473 * ```
474 */
475 function overrideCursor(cursor) {
476 var id = ++overrideCursorID;
477 document.body.style.cursor = cursor;
478 document.body.classList.add('p-mod-override-cursor');
479 return new disposable_1.DisposableDelegate(function () {
480 if (id === overrideCursorID) {
481 document.body.style.cursor = '';
482 document.body.classList.remove('p-mod-override-cursor');
483 }
484 });
485 }
486 Drag.overrideCursor = overrideCursor;
487 /**
488 * The internal id for the active cursor override.
489 */
490 var overrideCursorID = 0;
491})(Drag = exports.Drag || (exports.Drag = {}));
492exports.Drag = Drag;
493/**
494 * The namespace for the module implementation details.
495 */
496var Private;
497(function (Private) {
498 /**
499 * The size of a drag scroll edge, in pixels.
500 */
501 Private.SCROLL_EDGE_SIZE = 20;
502 /**
503 * Validate the given action is one of the supported actions.
504 *
505 * Returns the given action or `'none'` if the action is unsupported.
506 */
507 function validateAction(action, supported) {
508 return (actionTable[action] & supportedTable[supported]) ? action : 'none';
509 }
510 Private.validateAction = validateAction;
511 /**
512 * Create a left mouse event at the given position.
513 *
514 * @param type - The event type for the mouse event.
515 *
516 * @param clientX - The client X position.
517 *
518 * @param clientY - The client Y position.
519 *
520 * @returns A newly created and initialized mouse event.
521 */
522 function createMouseEvent(type, clientX, clientY) {
523 var event = document.createEvent('MouseEvent');
524 event.initMouseEvent(type, true, true, window, 0, 0, 0, clientX, clientY, false, false, false, false, 0, null);
525 return event;
526 }
527 Private.createMouseEvent = createMouseEvent;
528 /**
529 * Find the drag scroll target under the mouse, if any.
530 */
531 function findScrollTarget(event) {
532 // Look up the client mouse position.
533 var x = event.clientX;
534 var y = event.clientY;
535 // Get the element under the mouse.
536 var element = document.elementFromPoint(x, y);
537 // Search for a scrollable target based on the mouse position.
538 // The null assert in third clause of for-loop is required due to:
539 // https://github.com/Microsoft/TypeScript/issues/14143
540 for (; element; element = element.parentElement) {
541 // Ignore elements which are not marked as scrollable.
542 if (!element.hasAttribute('data-p-dragscroll')) {
543 continue;
544 }
545 // Set up the coordinate offsets for the element.
546 var offsetX = 0;
547 var offsetY = 0;
548 if (element === document.body) {
549 offsetX = window.pageXOffset;
550 offsetY = window.pageYOffset;
551 }
552 // Get the element bounds in viewport coordinates.
553 var r = element.getBoundingClientRect();
554 var top_1 = r.top + offsetY;
555 var left = r.left + offsetX;
556 var right = left + r.width;
557 var bottom = top_1 + r.height;
558 // Skip the element if it's not under the mouse.
559 if (x < left || x >= right || y < top_1 || y >= bottom) {
560 continue;
561 }
562 // Compute the distance to each edge.
563 var dl = x - left + 1;
564 var dt = y - top_1 + 1;
565 var dr = right - x;
566 var db = bottom - y;
567 // Find the smallest of the edge distances.
568 var distance = Math.min(dl, dt, dr, db);
569 // Skip the element if the mouse is not within a scroll edge.
570 if (distance > Private.SCROLL_EDGE_SIZE) {
571 continue;
572 }
573 // Set up the edge result variable.
574 var edge = void 0;
575 // Find the edge for the computed distance.
576 switch (distance) {
577 case db:
578 edge = 'bottom';
579 break;
580 case dt:
581 edge = 'top';
582 break;
583 case dr:
584 edge = 'right';
585 break;
586 case dl:
587 edge = 'left';
588 break;
589 default:
590 throw 'unreachable';
591 }
592 // Compute how much the element can scroll in width and height.
593 var dsw = element.scrollWidth - element.clientWidth;
594 var dsh = element.scrollHeight - element.clientHeight;
595 // Determine if the element should be scrolled for the edge.
596 var shouldScroll = void 0;
597 switch (edge) {
598 case 'top':
599 shouldScroll = dsh > 0 && element.scrollTop > 0;
600 break;
601 case 'left':
602 shouldScroll = dsw > 0 && element.scrollLeft > 0;
603 break;
604 case 'right':
605 shouldScroll = dsw > 0 && element.scrollLeft < dsw;
606 break;
607 case 'bottom':
608 shouldScroll = dsh > 0 && element.scrollTop < dsh;
609 break;
610 default:
611 throw 'unreachable';
612 }
613 // Skip the element if it should not be scrolled.
614 if (!shouldScroll) {
615 continue;
616 }
617 // Return the drag scroll target.
618 return { element: element, edge: edge, distance: distance };
619 }
620 // No drag scroll target was found.
621 return null;
622 }
623 Private.findScrollTarget = findScrollTarget;
624 /**
625 * Dispatch a drag enter event to the indicated element.
626 *
627 * @param drag - The drag object associated with the action.
628 *
629 * @param currElem - The currently indicated element, or `null`. This
630 * is the "immediate user selection" from the whatwg spec.
631 *
632 * @param currTarget - The current drag target element, or `null`. This
633 * is the "current target element" from the whatwg spec.
634 *
635 * @param event - The mouse event related to the action.
636 *
637 * @returns The element to use as the current drag target. This is the
638 * "current target element" from the whatwg spec, and may be `null`.
639 *
640 * #### Notes
641 * This largely implements the drag enter portion of the whatwg spec:
642 * https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model
643 */
644 function dispatchDragEnter(drag, currElem, currTarget, event) {
645 // If the current element is null, return null as the new target.
646 if (!currElem) {
647 return null;
648 }
649 // Dispatch a drag enter event to the current element.
650 var dragEvent = createDragEvent('p-dragenter', drag, event, currTarget);
651 var canceled = !currElem.dispatchEvent(dragEvent);
652 // If the event was canceled, use the current element as the new target.
653 if (canceled) {
654 return currElem;
655 }
656 // If the current element is the document body, keep the original target.
657 if (currElem === document.body) {
658 return currTarget;
659 }
660 // Dispatch a drag enter event on the document body.
661 dragEvent = createDragEvent('p-dragenter', drag, event, currTarget);
662 document.body.dispatchEvent(dragEvent);
663 // Ignore the event cancellation, and use the body as the new target.
664 return document.body;
665 }
666 Private.dispatchDragEnter = dispatchDragEnter;
667 /**
668 * Dispatch a drag exit event to the indicated element.
669 *
670 * @param drag - The drag object associated with the action.
671 *
672 * @param prevTarget - The previous target element, or `null`. This
673 * is the previous "current target element" from the whatwg spec.
674 *
675 * @param currTarget - The current drag target element, or `null`. This
676 * is the "current target element" from the whatwg spec.
677 *
678 * @param event - The mouse event related to the action.
679 *
680 * #### Notes
681 * This largely implements the drag exit portion of the whatwg spec:
682 * https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model
683 */
684 function dispatchDragExit(drag, prevTarget, currTarget, event) {
685 // If the previous target is null, do nothing.
686 if (!prevTarget) {
687 return;
688 }
689 // Dispatch the drag exit event to the previous target.
690 var dragEvent = createDragEvent('p-dragexit', drag, event, currTarget);
691 prevTarget.dispatchEvent(dragEvent);
692 }
693 Private.dispatchDragExit = dispatchDragExit;
694 /**
695 * Dispatch a drag leave event to the indicated element.
696 *
697 * @param drag - The drag object associated with the action.
698 *
699 * @param prevTarget - The previous target element, or `null`. This
700 * is the previous "current target element" from the whatwg spec.
701 *
702 * @param currTarget - The current drag target element, or `null`. This
703 * is the "current target element" from the whatwg spec.
704 *
705 * @param event - The mouse event related to the action.
706 *
707 * #### Notes
708 * This largely implements the drag leave portion of the whatwg spec:
709 * https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model
710 */
711 function dispatchDragLeave(drag, prevTarget, currTarget, event) {
712 // If the previous target is null, do nothing.
713 if (!prevTarget) {
714 return;
715 }
716 // Dispatch the drag leave event to the previous target.
717 var dragEvent = createDragEvent('p-dragleave', drag, event, currTarget);
718 prevTarget.dispatchEvent(dragEvent);
719 }
720 Private.dispatchDragLeave = dispatchDragLeave;
721 /**
722 * Dispatch a drag over event to the indicated element.
723 *
724 * @param drag - The drag object associated with the action.
725 *
726 * @param currTarget - The current drag target element, or `null`. This
727 * is the "current target element" from the whatwg spec.
728 *
729 * @param event - The mouse event related to the action.
730 *
731 * @returns The `DropAction` result of the drag over event.
732 *
733 * #### Notes
734 * This largely implements the drag over portion of the whatwg spec:
735 * https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model
736 */
737 function dispatchDragOver(drag, currTarget, event) {
738 // If there is no current target, the drop action is none.
739 if (!currTarget) {
740 return 'none';
741 }
742 // Dispatch the drag over event to the current target.
743 var dragEvent = createDragEvent('p-dragover', drag, event, null);
744 var canceled = !currTarget.dispatchEvent(dragEvent);
745 // If the event was canceled, return the drop action result.
746 if (canceled) {
747 return dragEvent.dropAction;
748 }
749 // Otherwise, the effective drop action is none.
750 return 'none';
751 }
752 Private.dispatchDragOver = dispatchDragOver;
753 /**
754 * Dispatch a drop event to the indicated element.
755 *
756 * @param drag - The drag object associated with the action.
757 *
758 * @param currTarget - The current drag target element, or `null`. This
759 * is the "current target element" from the whatwg spec.
760 *
761 * @param event - The mouse event related to the action.
762 *
763 * @returns The `DropAction` result of the drop event.
764 *
765 * #### Notes
766 * This largely implements the drag over portion of the whatwg spec:
767 * https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model
768 */
769 function dispatchDrop(drag, currTarget, event) {
770 // If there is no current target, the drop action is none.
771 if (!currTarget) {
772 return 'none';
773 }
774 // Dispatch the drop event to the current target.
775 var dragEvent = createDragEvent('p-drop', drag, event, null);
776 var canceled = !currTarget.dispatchEvent(dragEvent);
777 // If the event was canceled, return the drop action result.
778 if (canceled) {
779 return dragEvent.dropAction;
780 }
781 // Otherwise, the effective drop action is none.
782 return 'none';
783 }
784 Private.dispatchDrop = dispatchDrop;
785 /**
786 * A lookup table from drop action to bit value.
787 */
788 var actionTable = {
789 'none': 0x0,
790 'copy': 0x1,
791 'link': 0x2,
792 'move': 0x4
793 };
794 /**
795 * A lookup table from supported action to drop action bit mask.
796 */
797 var supportedTable = {
798 'none': actionTable['none'],
799 'copy': actionTable['copy'],
800 'link': actionTable['link'],
801 'move': actionTable['move'],
802 'copy-link': actionTable['copy'] | actionTable['link'],
803 'copy-move': actionTable['copy'] | actionTable['move'],
804 'link-move': actionTable['link'] | actionTable['move'],
805 'all': actionTable['copy'] | actionTable['link'] | actionTable['move']
806 };
807 /**
808 * Create a new initialized `IDragEvent` from the given data.
809 *
810 * @param type - The event type for the drag event.
811 *
812 * @param drag - The drag object to use for seeding the drag data.
813 *
814 * @param event - The mouse event to use for seeding the mouse data.
815 *
816 * @param related - The related target for the event, or `null`.
817 *
818 * @returns A new object which implements `IDragEvent`.
819 */
820 function createDragEvent(type, drag, event, related) {
821 // Create a new mouse event to use as the drag event. Currently,
822 // JS engines do now allow user-defined Event subclasses.
823 var dragEvent = document.createEvent('MouseEvent');
824 // Initialize the mouse event data.
825 dragEvent.initMouseEvent(type, true, true, window, 0, event.screenX, event.screenY, event.clientX, event.clientY, event.ctrlKey, event.altKey, event.shiftKey, event.metaKey, event.button, related);
826 // Forcefully add the custom drag event properties.
827 dragEvent.dropAction = 'none';
828 dragEvent.mimeData = drag.mimeData;
829 dragEvent.proposedAction = drag.proposedAction;
830 dragEvent.supportedActions = drag.supportedActions;
831 dragEvent.source = drag.source;
832 // Return the fully initialized drag event.
833 return dragEvent;
834 }
835})(Private || (Private = {}));