browser/base/content/newtab/updater.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:edd7d5d3207a
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 };

mercurial