|
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 functionality to update the current grid to a new |
|
9 * set of pinned and blocked sites. It adds, moves and removes sites. |
|
10 */ |
|
11 let gUpdater = { |
|
12 /** |
|
13 * Updates the current grid according to its pinned and blocked sites. |
|
14 * This removes old, moves existing and creates new sites to fill gaps. |
|
15 * @param aCallback The callback to call when finished. |
|
16 */ |
|
17 updateGrid: function Updater_updateGrid(aCallback) { |
|
18 let links = gLinks.getLinks().slice(0, gGrid.cells.length); |
|
19 |
|
20 // Find all sites that remain in the grid. |
|
21 let sites = this._findRemainingSites(links); |
|
22 |
|
23 let self = this; |
|
24 |
|
25 // Remove sites that are no longer in the grid. |
|
26 this._removeLegacySites(sites, function () { |
|
27 // Freeze all site positions so that we can move their DOM nodes around |
|
28 // without any visual impact. |
|
29 self._freezeSitePositions(sites); |
|
30 |
|
31 // Move the sites' DOM nodes to their new position in the DOM. This will |
|
32 // have no visual effect as all the sites have been frozen and will |
|
33 // remain in their current position. |
|
34 self._moveSiteNodes(sites); |
|
35 |
|
36 // Now it's time to animate the sites actually moving to their new |
|
37 // positions. |
|
38 self._rearrangeSites(sites, function () { |
|
39 // Try to fill empty cells and finish. |
|
40 self._fillEmptyCells(links, aCallback); |
|
41 |
|
42 // Update other pages that might be open to keep them synced. |
|
43 gAllPages.update(gPage); |
|
44 }); |
|
45 }); |
|
46 }, |
|
47 |
|
48 /** |
|
49 * Takes an array of links and tries to correlate them to sites contained in |
|
50 * the current grid. If no corresponding site can be found (i.e. the link is |
|
51 * new and a site will be created) then just set it to null. |
|
52 * @param aLinks The array of links to find sites for. |
|
53 * @return Array of sites mapped to the given links (can contain null values). |
|
54 */ |
|
55 _findRemainingSites: function Updater_findRemainingSites(aLinks) { |
|
56 let map = {}; |
|
57 |
|
58 // Create a map to easily retrieve the site for a given URL. |
|
59 gGrid.sites.forEach(function (aSite) { |
|
60 if (aSite) |
|
61 map[aSite.url] = aSite; |
|
62 }); |
|
63 |
|
64 // Map each link to its corresponding site, if any. |
|
65 return aLinks.map(function (aLink) { |
|
66 return aLink && (aLink.url in map) && map[aLink.url]; |
|
67 }); |
|
68 }, |
|
69 |
|
70 /** |
|
71 * Freezes the given sites' positions. |
|
72 * @param aSites The array of sites to freeze. |
|
73 */ |
|
74 _freezeSitePositions: function Updater_freezeSitePositions(aSites) { |
|
75 aSites.forEach(function (aSite) { |
|
76 if (aSite) |
|
77 gTransformation.freezeSitePosition(aSite); |
|
78 }); |
|
79 }, |
|
80 |
|
81 /** |
|
82 * Moves the given sites' DOM nodes to their new positions. |
|
83 * @param aSites The array of sites to move. |
|
84 */ |
|
85 _moveSiteNodes: function Updater_moveSiteNodes(aSites) { |
|
86 let cells = gGrid.cells; |
|
87 |
|
88 // Truncate the given array of sites to not have more sites than cells. |
|
89 // This can happen when the user drags a bookmark (or any other new kind |
|
90 // of link) onto the grid. |
|
91 let sites = aSites.slice(0, cells.length); |
|
92 |
|
93 sites.forEach(function (aSite, aIndex) { |
|
94 let cell = cells[aIndex]; |
|
95 let cellSite = cell.site; |
|
96 |
|
97 // The site's position didn't change. |
|
98 if (!aSite || cellSite != aSite) { |
|
99 let cellNode = cell.node; |
|
100 |
|
101 // Empty the cell if necessary. |
|
102 if (cellSite) |
|
103 cellNode.removeChild(cellSite.node); |
|
104 |
|
105 // Put the new site in place, if any. |
|
106 if (aSite) |
|
107 cellNode.appendChild(aSite.node); |
|
108 } |
|
109 }, this); |
|
110 }, |
|
111 |
|
112 /** |
|
113 * Rearranges the given sites and slides them to their new positions. |
|
114 * @param aSites The array of sites to re-arrange. |
|
115 * @param aCallback The callback to call when finished. |
|
116 */ |
|
117 _rearrangeSites: function Updater_rearrangeSites(aSites, aCallback) { |
|
118 let options = {callback: aCallback, unfreeze: true}; |
|
119 gTransformation.rearrangeSites(aSites, options); |
|
120 }, |
|
121 |
|
122 /** |
|
123 * Removes all sites from the grid that are not in the given links array or |
|
124 * exceed the grid. |
|
125 * @param aSites The array of sites remaining in the grid. |
|
126 * @param aCallback The callback to call when finished. |
|
127 */ |
|
128 _removeLegacySites: function Updater_removeLegacySites(aSites, aCallback) { |
|
129 let batch = []; |
|
130 |
|
131 // Delete sites that were removed from the grid. |
|
132 gGrid.sites.forEach(function (aSite) { |
|
133 // The site must be valid and not in the current grid. |
|
134 if (!aSite || aSites.indexOf(aSite) != -1) |
|
135 return; |
|
136 |
|
137 let deferred = Promise.defer(); |
|
138 batch.push(deferred.promise); |
|
139 |
|
140 // Fade out the to-be-removed site. |
|
141 gTransformation.hideSite(aSite, function () { |
|
142 let node = aSite.node; |
|
143 |
|
144 // Remove the site from the DOM. |
|
145 node.parentNode.removeChild(node); |
|
146 deferred.resolve(); |
|
147 }); |
|
148 }); |
|
149 |
|
150 Promise.all(batch).then(aCallback); |
|
151 }, |
|
152 |
|
153 /** |
|
154 * Tries to fill empty cells with new links if available. |
|
155 * @param aLinks The array of links. |
|
156 * @param aCallback The callback to call when finished. |
|
157 */ |
|
158 _fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) { |
|
159 let {cells, sites} = gGrid; |
|
160 let batch = []; |
|
161 |
|
162 // Find empty cells and fill them. |
|
163 sites.forEach(function (aSite, aIndex) { |
|
164 if (aSite || !aLinks[aIndex]) |
|
165 return; |
|
166 |
|
167 let deferred = Promise.defer(); |
|
168 batch.push(deferred.promise); |
|
169 |
|
170 // Create the new site and fade it in. |
|
171 let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]); |
|
172 |
|
173 // Set the site's initial opacity to zero. |
|
174 site.node.style.opacity = 0; |
|
175 |
|
176 // Flush all style changes for the dynamically inserted site to make |
|
177 // the fade-in transition work. |
|
178 window.getComputedStyle(site.node).opacity; |
|
179 gTransformation.showSite(site, function () deferred.resolve()); |
|
180 }); |
|
181 |
|
182 Promise.all(batch).then(aCallback); |
|
183 } |
|
184 }; |