|
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 |
|
6 |
|
7 /** |
|
8 * This singleton provides the ability to re-arrange the current grid to |
|
9 * indicate the transformation that results from dropping a cell at a certain |
|
10 * position. |
|
11 */ |
|
12 let gDropPreview = { |
|
13 /** |
|
14 * Rearranges the sites currently contained in the grid when a site would be |
|
15 * dropped onto the given cell. |
|
16 * @param aCell The drop target cell. |
|
17 * @return The re-arranged array of sites. |
|
18 */ |
|
19 rearrange: function DropPreview_rearrange(aCell) { |
|
20 let sites = gGrid.sites; |
|
21 |
|
22 // Insert the dragged site into the current grid. |
|
23 this._insertDraggedSite(sites, aCell); |
|
24 |
|
25 // After the new site has been inserted we need to correct the positions |
|
26 // of all pinned tabs that have been moved around. |
|
27 this._repositionPinnedSites(sites, aCell); |
|
28 |
|
29 return sites; |
|
30 }, |
|
31 |
|
32 /** |
|
33 * Inserts the currently dragged site into the given array of sites. |
|
34 * @param aSites The array of sites to insert into. |
|
35 * @param aCell The drop target cell. |
|
36 */ |
|
37 _insertDraggedSite: function DropPreview_insertDraggedSite(aSites, aCell) { |
|
38 let dropIndex = aCell.index; |
|
39 let draggedSite = gDrag.draggedSite; |
|
40 |
|
41 // We're currently dragging a site. |
|
42 if (draggedSite) { |
|
43 let dragCell = draggedSite.cell; |
|
44 let dragIndex = dragCell.index; |
|
45 |
|
46 // Move the dragged site into its new position. |
|
47 if (dragIndex != dropIndex) { |
|
48 aSites.splice(dragIndex, 1); |
|
49 aSites.splice(dropIndex, 0, draggedSite); |
|
50 } |
|
51 // We're handling an external drag item. |
|
52 } else { |
|
53 aSites.splice(dropIndex, 0, null); |
|
54 } |
|
55 }, |
|
56 |
|
57 /** |
|
58 * Correct the position of all pinned sites that might have been moved to |
|
59 * different positions after the dragged site has been inserted. |
|
60 * @param aSites The array of sites containing the dragged site. |
|
61 * @param aCell The drop target cell. |
|
62 */ |
|
63 _repositionPinnedSites: |
|
64 function DropPreview_repositionPinnedSites(aSites, aCell) { |
|
65 |
|
66 // Collect all pinned sites. |
|
67 let pinnedSites = this._filterPinnedSites(aSites, aCell); |
|
68 |
|
69 // Correct pinned site positions. |
|
70 pinnedSites.forEach(function (aSite) { |
|
71 aSites[aSites.indexOf(aSite)] = aSites[aSite.cell.index]; |
|
72 aSites[aSite.cell.index] = aSite; |
|
73 }, this); |
|
74 |
|
75 // There might be a pinned cell that got pushed out of the grid, try to |
|
76 // sneak it in by removing a lower-priority cell. |
|
77 if (this._hasOverflowedPinnedSite(aSites, aCell)) |
|
78 this._repositionOverflowedPinnedSite(aSites, aCell); |
|
79 }, |
|
80 |
|
81 /** |
|
82 * Filter pinned sites out of the grid that are still on their old positions |
|
83 * and have not moved. |
|
84 * @param aSites The array of sites to filter. |
|
85 * @param aCell The drop target cell. |
|
86 * @return The filtered array of sites. |
|
87 */ |
|
88 _filterPinnedSites: function DropPreview_filterPinnedSites(aSites, aCell) { |
|
89 let draggedSite = gDrag.draggedSite; |
|
90 |
|
91 // When dropping on a cell that contains a pinned site make sure that all |
|
92 // pinned cells surrounding the drop target are moved as well. |
|
93 let range = this._getPinnedRange(aCell); |
|
94 |
|
95 return aSites.filter(function (aSite, aIndex) { |
|
96 // The site must be valid, pinned and not the dragged site. |
|
97 if (!aSite || aSite == draggedSite || !aSite.isPinned()) |
|
98 return false; |
|
99 |
|
100 let index = aSite.cell.index; |
|
101 |
|
102 // If it's not in the 'pinned range' it's a valid pinned site. |
|
103 return (index > range.end || index < range.start); |
|
104 }); |
|
105 }, |
|
106 |
|
107 /** |
|
108 * Determines the range of pinned sites surrounding the drop target cell. |
|
109 * @param aCell The drop target cell. |
|
110 * @return The range of pinned cells. |
|
111 */ |
|
112 _getPinnedRange: function DropPreview_getPinnedRange(aCell) { |
|
113 let dropIndex = aCell.index; |
|
114 let range = {start: dropIndex, end: dropIndex}; |
|
115 |
|
116 // We need a pinned range only when dropping on a pinned site. |
|
117 if (aCell.containsPinnedSite()) { |
|
118 let links = gPinnedLinks.links; |
|
119 |
|
120 // Find all previous siblings of the drop target that are pinned as well. |
|
121 while (range.start && links[range.start - 1]) |
|
122 range.start--; |
|
123 |
|
124 let maxEnd = links.length - 1; |
|
125 |
|
126 // Find all next siblings of the drop target that are pinned as well. |
|
127 while (range.end < maxEnd && links[range.end + 1]) |
|
128 range.end++; |
|
129 } |
|
130 |
|
131 return range; |
|
132 }, |
|
133 |
|
134 /** |
|
135 * Checks if the given array of sites contains a pinned site that has |
|
136 * been pushed out of the grid. |
|
137 * @param aSites The array of sites to check. |
|
138 * @param aCell The drop target cell. |
|
139 * @return Whether there is an overflowed pinned cell. |
|
140 */ |
|
141 _hasOverflowedPinnedSite: |
|
142 function DropPreview_hasOverflowedPinnedSite(aSites, aCell) { |
|
143 |
|
144 // If the drop target isn't pinned there's no way a pinned site has been |
|
145 // pushed out of the grid so we can just exit here. |
|
146 if (!aCell.containsPinnedSite()) |
|
147 return false; |
|
148 |
|
149 let cells = gGrid.cells; |
|
150 |
|
151 // No cells have been pushed out of the grid, nothing to do here. |
|
152 if (aSites.length <= cells.length) |
|
153 return false; |
|
154 |
|
155 let overflowedSite = aSites[cells.length]; |
|
156 |
|
157 // Nothing to do if the site that got pushed out of the grid is not pinned. |
|
158 return (overflowedSite && overflowedSite.isPinned()); |
|
159 }, |
|
160 |
|
161 /** |
|
162 * We have a overflowed pinned site that we need to re-position so that it's |
|
163 * visible again. We try to find a lower-priority cell (empty or containing |
|
164 * an unpinned site) that we can move it to. |
|
165 * @param aSites The array of sites. |
|
166 * @param aCell The drop target cell. |
|
167 */ |
|
168 _repositionOverflowedPinnedSite: |
|
169 function DropPreview_repositionOverflowedPinnedSite(aSites, aCell) { |
|
170 |
|
171 // Try to find a lower-priority cell (empty or containing an unpinned site). |
|
172 let index = this._indexOfLowerPrioritySite(aSites, aCell); |
|
173 |
|
174 if (index > -1) { |
|
175 let cells = gGrid.cells; |
|
176 let dropIndex = aCell.index; |
|
177 |
|
178 // Move all pinned cells to their new positions to let the overflowed |
|
179 // site fit into the grid. |
|
180 for (let i = index + 1, lastPosition = index; i < aSites.length; i++) { |
|
181 if (i != dropIndex) { |
|
182 aSites[lastPosition] = aSites[i]; |
|
183 lastPosition = i; |
|
184 } |
|
185 } |
|
186 |
|
187 // Finally, remove the overflowed site from its previous position. |
|
188 aSites.splice(cells.length, 1); |
|
189 } |
|
190 }, |
|
191 |
|
192 /** |
|
193 * Finds the index of the last cell that is empty or contains an unpinned |
|
194 * site. These are considered to be of a lower priority. |
|
195 * @param aSites The array of sites. |
|
196 * @param aCell The drop target cell. |
|
197 * @return The cell's index. |
|
198 */ |
|
199 _indexOfLowerPrioritySite: |
|
200 function DropPreview_indexOfLowerPrioritySite(aSites, aCell) { |
|
201 |
|
202 let cells = gGrid.cells; |
|
203 let dropIndex = aCell.index; |
|
204 |
|
205 // Search (beginning with the last site in the grid) for a site that is |
|
206 // empty or unpinned (an thus lower-priority) and can be pushed out of the |
|
207 // grid instead of the pinned site. |
|
208 for (let i = cells.length - 1; i >= 0; i--) { |
|
209 // The cell that is our drop target is not a good choice. |
|
210 if (i == dropIndex) |
|
211 continue; |
|
212 |
|
213 let site = aSites[i]; |
|
214 |
|
215 // We can use the cell only if it's empty or the site is un-pinned. |
|
216 if (!site || !site.isPinned()) |
|
217 return i; |
|
218 } |
|
219 |
|
220 return -1; |
|
221 } |
|
222 }; |