browser/base/content/newtab/dropTargetShim.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 #ifdef 0
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #endif
     7 /**
     8  * This singleton provides a custom drop target detection. We need this because
     9  * the default DnD target detection relies on the cursor's position. We want
    10  * to pick a drop target based on the dragged site's position.
    11  */
    12 let gDropTargetShim = {
    13   /**
    14    * Cache for the position of all cells, cleaned after drag finished.
    15    */
    16   _cellPositions: null,
    18   /**
    19    * The last drop target that was hovered.
    20    */
    21   _lastDropTarget: null,
    23   /**
    24    * Initializes the drop target shim.
    25    */
    26   init: function () {
    27     gGrid.node.addEventListener("dragstart", this, true);
    28   },
    30   /**
    31    * Add all event listeners needed during a drag operation.
    32    */
    33   _addEventListeners: function () {
    34     gGrid.node.addEventListener("dragend", this);
    36     let docElement = document.documentElement;
    37     docElement.addEventListener("dragover", this);
    38     docElement.addEventListener("dragenter", this);
    39     docElement.addEventListener("drop", this);
    40   },
    42   /**
    43    * Remove all event listeners that were needed during a drag operation.
    44    */
    45   _removeEventListeners: function () {
    46     gGrid.node.removeEventListener("dragend", this);
    48     let docElement = document.documentElement;
    49     docElement.removeEventListener("dragover", this);
    50     docElement.removeEventListener("dragenter", this);
    51     docElement.removeEventListener("drop", this);
    52   },
    54   /**
    55    * Handles all shim events.
    56    */
    57   handleEvent: function (aEvent) {
    58     switch (aEvent.type) {
    59       case "dragstart":
    60         this._dragstart(aEvent);
    61         break;
    62       case "dragenter":
    63         aEvent.preventDefault();
    64         break;
    65       case "dragover":
    66         this._dragover(aEvent);
    67         break;
    68       case "drop":
    69         this._drop(aEvent);
    70         break;
    71       case "dragend":
    72         this._dragend(aEvent);
    73         break;
    74     }
    75   },
    77   /**
    78    * Handles the 'dragstart' event.
    79    * @param aEvent The 'dragstart' event.
    80    */
    81   _dragstart: function (aEvent) {
    82     if (aEvent.target.classList.contains("newtab-link")) {
    83       gGrid.lock();
    84       this._addEventListeners();
    85     }
    86   },
    88   /**
    89    * Handles the 'dragover' event.
    90    * @param aEvent The 'dragover' event.
    91    */
    92   _dragover: function (aEvent) {
    93     // XXX bug 505521 - Use the dragover event to retrieve the
    94     //                  current mouse coordinates while dragging.
    95     let sourceNode = aEvent.dataTransfer.mozSourceNode.parentNode;
    96     gDrag.drag(sourceNode._newtabSite, aEvent);
    98     // Find the current drop target, if there's one.
    99     this._updateDropTarget(aEvent);
   101     // If we have a valid drop target,
   102     // let the drag-and-drop service know.
   103     if (this._lastDropTarget) {
   104       aEvent.preventDefault();
   105     }
   106   },
   108   /**
   109    * Handles the 'drop' event.
   110    * @param aEvent The 'drop' event.
   111    */
   112   _drop: function (aEvent) {
   113     // We're accepting all drops.
   114     aEvent.preventDefault();
   116     // Make sure to determine the current drop target
   117     // in case the dragover event hasn't been fired.
   118     this._updateDropTarget(aEvent);
   120     // A site was successfully dropped.
   121     this._dispatchEvent(aEvent, "drop", this._lastDropTarget);
   122   },
   124   /**
   125    * Handles the 'dragend' event.
   126    * @param aEvent The 'dragend' event.
   127    */
   128   _dragend: function (aEvent) {
   129     if (this._lastDropTarget) {
   130       if (aEvent.dataTransfer.mozUserCancelled) {
   131         // The drag operation was cancelled.
   132         this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
   133         this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget);
   134       }
   136       // Clean up.
   137       this._lastDropTarget = null;
   138       this._cellPositions = null;
   139     }
   141     gGrid.unlock();
   142     this._removeEventListeners();
   143   },
   145   /**
   146    * Tries to find the current drop target and will fire
   147    * appropriate dragenter, dragexit, and dragleave events.
   148    * @param aEvent The current drag event.
   149    */
   150   _updateDropTarget: function (aEvent) {
   151     // Let's see if we find a drop target.
   152     let target = this._findDropTarget(aEvent);
   154     if (target != this._lastDropTarget) {
   155       if (this._lastDropTarget)
   156         // We left the last drop target.
   157         this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
   159       if (target)
   160         // We're now hovering a (new) drop target.
   161         this._dispatchEvent(aEvent, "dragenter", target);
   163       if (this._lastDropTarget)
   164         // We left the last drop target.
   165         this._dispatchEvent(aEvent, "dragleave", this._lastDropTarget);
   167       this._lastDropTarget = target;
   168     }
   169   },
   171   /**
   172    * Determines the current drop target by matching the dragged site's position
   173    * against all cells in the grid.
   174    * @return The currently hovered drop target or null.
   175    */
   176   _findDropTarget: function () {
   177     // These are the minimum intersection values - we want to use the cell if
   178     // the site is >= 50% hovering its position.
   179     let minWidth = gDrag.cellWidth / 2;
   180     let minHeight = gDrag.cellHeight / 2;
   182     let cellPositions = this._getCellPositions();
   183     let rect = gTransformation.getNodePosition(gDrag.draggedSite.node);
   185     // Compare each cell's position to the dragged site's position.
   186     for (let i = 0; i < cellPositions.length; i++) {
   187       let inter = rect.intersect(cellPositions[i].rect);
   189       // If the intersection is big enough we found a drop target.
   190       if (inter.width >= minWidth && inter.height >= minHeight)
   191         return cellPositions[i].cell;
   192     }
   194     // No drop target found.
   195     return null;
   196   },
   198   /**
   199    * Gets the positions of all cell nodes.
   200    * @return The (cached) cell positions.
   201    */
   202   _getCellPositions: function DropTargetShim_getCellPositions() {
   203     if (this._cellPositions)
   204       return this._cellPositions;
   206     return this._cellPositions = gGrid.cells.map(function (cell) {
   207       return {cell: cell, rect: gTransformation.getNodePosition(cell.node)};
   208     });
   209   },
   211   /**
   212    * Dispatches a custom DragEvent on the given target node.
   213    * @param aEvent The source event.
   214    * @param aType The event type.
   215    * @param aTarget The target node that receives the event.
   216    */
   217   _dispatchEvent: function (aEvent, aType, aTarget) {
   218     let node = aTarget.node;
   219     let event = document.createEvent("DragEvents");
   221     // The event should not bubble to prevent recursion.
   222     event.initDragEvent(aType, false, true, window, 0, 0, 0, 0, 0, false, false,
   223                         false, false, 0, node, aEvent.dataTransfer);
   225     node.dispatchEvent(event);
   226   }
   227 };

mercurial