michael@0: #ifdef 0 michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #endif michael@0: michael@0: // A little delay that prevents the grid from being too sensitive when dragging michael@0: // sites around. michael@0: const DELAY_REARRANGE_MS = 100; michael@0: michael@0: /** michael@0: * This singleton implements site dropping functionality. michael@0: */ michael@0: let gDrop = { michael@0: /** michael@0: * The last drop target. michael@0: */ michael@0: _lastDropTarget: null, michael@0: michael@0: /** michael@0: * Handles the 'dragenter' event. michael@0: * @param aCell The drop target cell. michael@0: */ michael@0: enter: function Drop_enter(aCell) { michael@0: this._delayedRearrange(aCell); michael@0: }, michael@0: michael@0: /** michael@0: * Handles the 'dragexit' event. michael@0: * @param aCell The drop target cell. michael@0: * @param aEvent The 'dragexit' event. michael@0: */ michael@0: exit: function Drop_exit(aCell, aEvent) { michael@0: if (aEvent.dataTransfer && !aEvent.dataTransfer.mozUserCancelled) { michael@0: this._delayedRearrange(); michael@0: } else { michael@0: // The drag operation has been cancelled. michael@0: this._cancelDelayedArrange(); michael@0: this._rearrange(); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Handles the 'drop' event. michael@0: * @param aCell The drop target cell. michael@0: * @param aEvent The 'dragexit' event. michael@0: */ michael@0: drop: function Drop_drop(aCell, aEvent) { michael@0: // The cell that is the drop target could contain a pinned site. We need michael@0: // to find out where that site has gone and re-pin it there. michael@0: if (aCell.containsPinnedSite()) michael@0: this._repinSitesAfterDrop(aCell); michael@0: michael@0: // Pin the dragged or insert the new site. michael@0: this._pinDraggedSite(aCell, aEvent); michael@0: michael@0: this._cancelDelayedArrange(); michael@0: michael@0: // Update the grid and move all sites to their new places. michael@0: gUpdater.updateGrid(); michael@0: }, michael@0: michael@0: /** michael@0: * Re-pins all pinned sites in their (new) positions. michael@0: * @param aCell The drop target cell. michael@0: */ michael@0: _repinSitesAfterDrop: function Drop_repinSitesAfterDrop(aCell) { michael@0: let sites = gDropPreview.rearrange(aCell); michael@0: michael@0: // Filter out pinned sites. michael@0: let pinnedSites = sites.filter(function (aSite) { michael@0: return aSite && aSite.isPinned(); michael@0: }); michael@0: michael@0: // Re-pin all shifted pinned cells. michael@0: pinnedSites.forEach(function (aSite) aSite.pin(sites.indexOf(aSite)), this); michael@0: }, michael@0: michael@0: /** michael@0: * Pins the dragged site in its new place. michael@0: * @param aCell The drop target cell. michael@0: * @param aEvent The 'dragexit' event. michael@0: */ michael@0: _pinDraggedSite: function Drop_pinDraggedSite(aCell, aEvent) { michael@0: let index = aCell.index; michael@0: let draggedSite = gDrag.draggedSite; michael@0: michael@0: if (draggedSite) { michael@0: // Pin the dragged site at its new place. michael@0: if (aCell != draggedSite.cell) michael@0: draggedSite.pin(index); michael@0: } else { michael@0: let link = gDragDataHelper.getLinkFromDragEvent(aEvent); michael@0: if (link) { michael@0: // A new link was dragged onto the grid. Create it by pinning its URL. michael@0: gPinnedLinks.pin(link, index); michael@0: michael@0: // Make sure the newly added link is not blocked. michael@0: gBlockedLinks.unblock(link); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Time a rearrange with a little delay. michael@0: * @param aCell The drop target cell. michael@0: */ michael@0: _delayedRearrange: function Drop_delayedRearrange(aCell) { michael@0: // The last drop target didn't change so there's no need to re-arrange. michael@0: if (this._lastDropTarget == aCell) michael@0: return; michael@0: michael@0: let self = this; michael@0: michael@0: function callback() { michael@0: self._rearrangeTimeout = null; michael@0: self._rearrange(aCell); michael@0: } michael@0: michael@0: this._cancelDelayedArrange(); michael@0: this._rearrangeTimeout = setTimeout(callback, DELAY_REARRANGE_MS); michael@0: michael@0: // Store the last drop target. michael@0: this._lastDropTarget = aCell; michael@0: }, michael@0: michael@0: /** michael@0: * Cancels a timed rearrange, if any. michael@0: */ michael@0: _cancelDelayedArrange: function Drop_cancelDelayedArrange() { michael@0: if (this._rearrangeTimeout) { michael@0: clearTimeout(this._rearrangeTimeout); michael@0: this._rearrangeTimeout = null; michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Rearrange all sites in the grid depending on the current drop target. michael@0: * @param aCell The drop target cell. michael@0: */ michael@0: _rearrange: function Drop_rearrange(aCell) { michael@0: let sites = gGrid.sites; michael@0: michael@0: // We need to rearrange the grid only if there's a current drop target. michael@0: if (aCell) michael@0: sites = gDropPreview.rearrange(aCell); michael@0: michael@0: gTransformation.rearrangeSites(sites, {unfreeze: !aCell}); michael@0: } michael@0: };