1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/newtab/dropPreview.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,222 @@ 1.4 +#ifdef 0 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#endif 1.9 + 1.10 +/** 1.11 + * This singleton provides the ability to re-arrange the current grid to 1.12 + * indicate the transformation that results from dropping a cell at a certain 1.13 + * position. 1.14 + */ 1.15 +let gDropPreview = { 1.16 + /** 1.17 + * Rearranges the sites currently contained in the grid when a site would be 1.18 + * dropped onto the given cell. 1.19 + * @param aCell The drop target cell. 1.20 + * @return The re-arranged array of sites. 1.21 + */ 1.22 + rearrange: function DropPreview_rearrange(aCell) { 1.23 + let sites = gGrid.sites; 1.24 + 1.25 + // Insert the dragged site into the current grid. 1.26 + this._insertDraggedSite(sites, aCell); 1.27 + 1.28 + // After the new site has been inserted we need to correct the positions 1.29 + // of all pinned tabs that have been moved around. 1.30 + this._repositionPinnedSites(sites, aCell); 1.31 + 1.32 + return sites; 1.33 + }, 1.34 + 1.35 + /** 1.36 + * Inserts the currently dragged site into the given array of sites. 1.37 + * @param aSites The array of sites to insert into. 1.38 + * @param aCell The drop target cell. 1.39 + */ 1.40 + _insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) { 1.41 + let dropIndex = aCell.index; 1.42 + let draggedSite = gDrag.draggedSite; 1.43 + 1.44 + // We're currently dragging a site. 1.45 + if (draggedSite) { 1.46 + let dragCell = draggedSite.cell; 1.47 + let dragIndex = dragCell.index; 1.48 + 1.49 + // Move the dragged site into its new position. 1.50 + if (dragIndex != dropIndex) { 1.51 + aSites.splice(dragIndex, 1); 1.52 + aSites.splice(dropIndex, 0, draggedSite); 1.53 + } 1.54 + // We're handling an external drag item. 1.55 + } else { 1.56 + aSites.splice(dropIndex, 0, null); 1.57 + } 1.58 + }, 1.59 + 1.60 + /** 1.61 + * Correct the position of all pinned sites that might have been moved to 1.62 + * different positions after the dragged site has been inserted. 1.63 + * @param aSites The array of sites containing the dragged site. 1.64 + * @param aCell The drop target cell. 1.65 + */ 1.66 + _repositionPinnedSites: 1.67 + function DropPreview_repositionPinnedSites(aSites, aCell) { 1.68 + 1.69 + // Collect all pinned sites. 1.70 + let pinnedSites = this._filterPinnedSites(aSites, aCell); 1.71 + 1.72 + // Correct pinned site positions. 1.73 + pinnedSites.forEach(function (aSite) { 1.74 + aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index]; 1.75 + aSites[aSite.cell.index] = aSite; 1.76 + }, this); 1.77 + 1.78 + // There might be a pinned cell that got pushed out of the grid, try to 1.79 + // sneak it in by removing a lower-priority cell. 1.80 + if (this._hasOverflowedPinnedSite(aSites, aCell)) 1.81 + this._repositionOverflowedPinnedSite(aSites, aCell); 1.82 + }, 1.83 + 1.84 + /** 1.85 + * Filter pinned sites out of the grid that are still on their old positions 1.86 + * and have not moved. 1.87 + * @param aSites The array of sites to filter. 1.88 + * @param aCell The drop target cell. 1.89 + * @return The filtered array of sites. 1.90 + */ 1.91 + _filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) { 1.92 + let draggedSite = gDrag.draggedSite; 1.93 + 1.94 + // When dropping on a cell that contains a pinned site make sure that all 1.95 + // pinned cells surrounding the drop target are moved as well. 1.96 + let range = this._getPinnedRange(aCell); 1.97 + 1.98 + return aSites.filter(function (aSite, aIndex) { 1.99 + // The site must be valid, pinned and not the dragged site. 1.100 + if (!aSite || aSite == draggedSite || !aSite.isPinned()) 1.101 + return false; 1.102 + 1.103 + let index = aSite.cell.index; 1.104 + 1.105 + // If it's not in the 'pinned range' it's a valid pinned site. 1.106 + return (index > range.end || index < range.start); 1.107 + }); 1.108 + }, 1.109 + 1.110 + /** 1.111 + * Determines the range of pinned sites surrounding the drop target cell. 1.112 + * @param aCell The drop target cell. 1.113 + * @return The range of pinned cells. 1.114 + */ 1.115 + _getPinnedRange: function DropPreview_getPinnedRange(aCell) { 1.116 + let dropIndex = aCell.index; 1.117 + let range = {start: dropIndex, end: dropIndex}; 1.118 + 1.119 + // We need a pinned range only when dropping on a pinned site. 1.120 + if (aCell.containsPinnedSite()) { 1.121 + let links = gPinnedLinks.links; 1.122 + 1.123 + // Find all previous siblings of the drop target that are pinned as well. 1.124 + while (range.start && links[range.start - 1]) 1.125 + range.start--; 1.126 + 1.127 + let maxEnd = links.length - 1; 1.128 + 1.129 + // Find all next siblings of the drop target that are pinned as well. 1.130 + while (range.end < maxEnd && links[range.end + 1]) 1.131 + range.end++; 1.132 + } 1.133 + 1.134 + return range; 1.135 + }, 1.136 + 1.137 + /** 1.138 + * Checks if the given array of sites contains a pinned site that has 1.139 + * been pushed out of the grid. 1.140 + * @param aSites The array of sites to check. 1.141 + * @param aCell The drop target cell. 1.142 + * @return Whether there is an overflowed pinned cell. 1.143 + */ 1.144 + _hasOverflowedPinnedSite: 1.145 + function DropPreview_hasOverflowedPinnedSite(aSites, aCell) { 1.146 + 1.147 + // If the drop target isn't pinned there's no way a pinned site has been 1.148 + // pushed out of the grid so we can just exit here. 1.149 + if (!aCell.containsPinnedSite()) 1.150 + return false; 1.151 + 1.152 + let cells = gGrid.cells; 1.153 + 1.154 + // No cells have been pushed out of the grid, nothing to do here. 1.155 + if (aSites.length <= cells.length) 1.156 + return false; 1.157 + 1.158 + let overflowedSite = aSites[cells.length]; 1.159 + 1.160 + // Nothing to do if the site that got pushed out of the grid is not pinned. 1.161 + return (overflowedSite && overflowedSite.isPinned()); 1.162 + }, 1.163 + 1.164 + /** 1.165 + * We have a overflowed pinned site that we need to re-position so that it's 1.166 + * visible again. We try to find a lower-priority cell (empty or containing 1.167 + * an unpinned site) that we can move it to. 1.168 + * @param aSites The array of sites. 1.169 + * @param aCell The drop target cell. 1.170 + */ 1.171 + _repositionOverflowedPinnedSite: 1.172 + function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) { 1.173 + 1.174 + // Try to find a lower-priority cell (empty or containing an unpinned site). 1.175 + let index = this._indexOfLowerPrioritySite(aSites, aCell); 1.176 + 1.177 + if (index > -1) { 1.178 + let cells = gGrid.cells; 1.179 + let dropIndex = aCell.index; 1.180 + 1.181 + // Move all pinned cells to their new positions to let the overflowed 1.182 + // site fit into the grid. 1.183 + for (let i = index + 1, lastPosition = index; i < aSites.length; i++) { 1.184 + if (i != dropIndex) { 1.185 + aSites[lastPosition] = aSites[i]; 1.186 + lastPosition = i; 1.187 + } 1.188 + } 1.189 + 1.190 + // Finally, remove the overflowed site from its previous position. 1.191 + aSites.splice(cells.length, 1); 1.192 + } 1.193 + }, 1.194 + 1.195 + /** 1.196 + * Finds the index of the last cell that is empty or contains an unpinned 1.197 + * site. These are considered to be of a lower priority. 1.198 + * @param aSites The array of sites. 1.199 + * @param aCell The drop target cell. 1.200 + * @return The cell's index. 1.201 + */ 1.202 + _indexOfLowerPrioritySite: 1.203 + function DropPreview_indexOfLowerPrioritySite(aSites, aCell) { 1.204 + 1.205 + let cells = gGrid.cells; 1.206 + let dropIndex = aCell.index; 1.207 + 1.208 + // Search (beginning with the last site in the grid) for a site that is 1.209 + // empty or unpinned (an thus lower-priority) and can be pushed out of the 1.210 + // grid instead of the pinned site. 1.211 + for (let i = cells.length - 1; i >= 0; i--) { 1.212 + // The cell that is our drop target is not a good choice. 1.213 + if (i == dropIndex) 1.214 + continue; 1.215 + 1.216 + let site = aSites[i]; 1.217 + 1.218 + // We can use the cell only if it's empty or the site is un-pinned. 1.219 + if (!site || !site.isPinned()) 1.220 + return i; 1.221 + } 1.222 + 1.223 + return -1; 1.224 + } 1.225 +};