mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-11-20 10:33:36 +00:00
223 lines
7.2 KiB
JavaScript
223 lines
7.2 KiB
JavaScript
#ifdef 0
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
#endif
|
|
|
|
/**
|
|
* This singleton provides the ability to re-arrange the current grid to
|
|
* indicate the transformation that results from dropping a cell at a certain
|
|
* position.
|
|
*/
|
|
var gDropPreview = {
|
|
/**
|
|
* Rearranges the sites currently contained in the grid when a site would be
|
|
* dropped onto the given cell.
|
|
* @param aCell The drop target cell.
|
|
* @return The re-arranged array of sites.
|
|
*/
|
|
rearrange: function DropPreview_rearrange(aCell) {
|
|
let sites = gGrid.sites;
|
|
|
|
// Insert the dragged site into the current grid.
|
|
this._insertDraggedSite(sites, aCell);
|
|
|
|
// After the new site has been inserted we need to correct the positions
|
|
// of all pinned tabs that have been moved around.
|
|
this._repositionPinnedSites(sites, aCell);
|
|
|
|
return sites;
|
|
},
|
|
|
|
/**
|
|
* Inserts the currently dragged site into the given array of sites.
|
|
* @param aSites The array of sites to insert into.
|
|
* @param aCell The drop target cell.
|
|
*/
|
|
_insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) {
|
|
let dropIndex = aCell.index;
|
|
let draggedSite = gDrag.draggedSite;
|
|
|
|
// We're currently dragging a site.
|
|
if (draggedSite) {
|
|
let dragCell = draggedSite.cell;
|
|
let dragIndex = dragCell.index;
|
|
|
|
// Move the dragged site into its new position.
|
|
if (dragIndex != dropIndex) {
|
|
aSites.splice(dragIndex, 1);
|
|
aSites.splice(dropIndex, 0, draggedSite);
|
|
}
|
|
// We're handling an external drag item.
|
|
} else {
|
|
aSites.splice(dropIndex, 0, null);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Correct the position of all pinned sites that might have been moved to
|
|
* different positions after the dragged site has been inserted.
|
|
* @param aSites The array of sites containing the dragged site.
|
|
* @param aCell The drop target cell.
|
|
*/
|
|
_repositionPinnedSites:
|
|
function DropPreview_repositionPinnedSites(aSites, aCell) {
|
|
|
|
// Collect all pinned sites.
|
|
let pinnedSites = this._filterPinnedSites(aSites, aCell);
|
|
|
|
// Correct pinned site positions.
|
|
pinnedSites.forEach(function (aSite) {
|
|
aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index];
|
|
aSites[aSite.cell.index] = aSite;
|
|
}, this);
|
|
|
|
// There might be a pinned cell that got pushed out of the grid, try to
|
|
// sneak it in by removing a lower-priority cell.
|
|
if (this._hasOverflowedPinnedSite(aSites, aCell))
|
|
this._repositionOverflowedPinnedSite(aSites, aCell);
|
|
},
|
|
|
|
/**
|
|
* Filter pinned sites out of the grid that are still on their old positions
|
|
* and have not moved.
|
|
* @param aSites The array of sites to filter.
|
|
* @param aCell The drop target cell.
|
|
* @return The filtered array of sites.
|
|
*/
|
|
_filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) {
|
|
let draggedSite = gDrag.draggedSite;
|
|
|
|
// When dropping on a cell that contains a pinned site make sure that all
|
|
// pinned cells surrounding the drop target are moved as well.
|
|
let range = this._getPinnedRange(aCell);
|
|
|
|
return aSites.filter(function (aSite, aIndex) {
|
|
// The site must be valid, pinned and not the dragged site.
|
|
if (!aSite || aSite == draggedSite || !aSite.isPinned())
|
|
return false;
|
|
|
|
let index = aSite.cell.index;
|
|
|
|
// If it's not in the 'pinned range' it's a valid pinned site.
|
|
return (index > range.end || index < range.start);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Determines the range of pinned sites surrounding the drop target cell.
|
|
* @param aCell The drop target cell.
|
|
* @return The range of pinned cells.
|
|
*/
|
|
_getPinnedRange: function DropPreview_getPinnedRange(aCell) {
|
|
let dropIndex = aCell.index;
|
|
let range = {start: dropIndex, end: dropIndex};
|
|
|
|
// We need a pinned range only when dropping on a pinned site.
|
|
if (aCell.containsPinnedSite()) {
|
|
let links = gPinnedLinks.links;
|
|
|
|
// Find all previous siblings of the drop target that are pinned as well.
|
|
while (range.start && links[range.start - 1])
|
|
range.start--;
|
|
|
|
let maxEnd = links.length - 1;
|
|
|
|
// Find all next siblings of the drop target that are pinned as well.
|
|
while (range.end < maxEnd && links[range.end + 1])
|
|
range.end++;
|
|
}
|
|
|
|
return range;
|
|
},
|
|
|
|
/**
|
|
* Checks if the given array of sites contains a pinned site that has
|
|
* been pushed out of the grid.
|
|
* @param aSites The array of sites to check.
|
|
* @param aCell The drop target cell.
|
|
* @return Whether there is an overflowed pinned cell.
|
|
*/
|
|
_hasOverflowedPinnedSite:
|
|
function DropPreview_hasOverflowedPinnedSite(aSites, aCell) {
|
|
|
|
// If the drop target isn't pinned there's no way a pinned site has been
|
|
// pushed out of the grid so we can just exit here.
|
|
if (!aCell.containsPinnedSite())
|
|
return false;
|
|
|
|
let cells = gGrid.cells;
|
|
|
|
// No cells have been pushed out of the grid, nothing to do here.
|
|
if (aSites.length <= cells.length)
|
|
return false;
|
|
|
|
let overflowedSite = aSites[cells.length];
|
|
|
|
// Nothing to do if the site that got pushed out of the grid is not pinned.
|
|
return (overflowedSite && overflowedSite.isPinned());
|
|
},
|
|
|
|
/**
|
|
* We have a overflowed pinned site that we need to re-position so that it's
|
|
* visible again. We try to find a lower-priority cell (empty or containing
|
|
* an unpinned site) that we can move it to.
|
|
* @param aSites The array of sites.
|
|
* @param aCell The drop target cell.
|
|
*/
|
|
_repositionOverflowedPinnedSite:
|
|
function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) {
|
|
|
|
// Try to find a lower-priority cell (empty or containing an unpinned site).
|
|
let index = this._indexOfLowerPrioritySite(aSites, aCell);
|
|
|
|
if (index > -1) {
|
|
let cells = gGrid.cells;
|
|
let dropIndex = aCell.index;
|
|
|
|
// Move all pinned cells to their new positions to let the overflowed
|
|
// site fit into the grid.
|
|
for (let i = index + 1, lastPosition = index; i < aSites.length; i++) {
|
|
if (i != dropIndex) {
|
|
aSites[lastPosition] = aSites[i];
|
|
lastPosition = i;
|
|
}
|
|
}
|
|
|
|
// Finally, remove the overflowed site from its previous position.
|
|
aSites.splice(cells.length, 1);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Finds the index of the last cell that is empty or contains an unpinned
|
|
* site. These are considered to be of a lower priority.
|
|
* @param aSites The array of sites.
|
|
* @param aCell The drop target cell.
|
|
* @return The cell's index.
|
|
*/
|
|
_indexOfLowerPrioritySite:
|
|
function DropPreview_indexOfLowerPrioritySite(aSites, aCell) {
|
|
|
|
let cells = gGrid.cells;
|
|
let dropIndex = aCell.index;
|
|
|
|
// Search (beginning with the last site in the grid) for a site that is
|
|
// empty or unpinned (an thus lower-priority) and can be pushed out of the
|
|
// grid instead of the pinned site.
|
|
for (let i = cells.length - 1; i >= 0; i--) {
|
|
// The cell that is our drop target is not a good choice.
|
|
if (i == dropIndex)
|
|
continue;
|
|
|
|
let site = aSites[i];
|
|
|
|
// We can use the cell only if it's empty or the site is un-pinned.
|
|
if (!site || !site.isPinned())
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
};
|