1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/newtab/updater.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,184 @@ 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 functionality to update the current grid to a new 1.12 + * set of pinned and blocked sites. It adds, moves and removes sites. 1.13 + */ 1.14 +let gUpdater = { 1.15 + /** 1.16 + * Updates the current grid according to its pinned and blocked sites. 1.17 + * This removes old, moves existing and creates new sites to fill gaps. 1.18 + * @param aCallback The callback to call when finished. 1.19 + */ 1.20 + updateGrid: function Updater_updateGrid(aCallback) { 1.21 + let links = gLinks.getLinks().slice(0, gGrid.cells.length); 1.22 + 1.23 + // Find all sites that remain in the grid. 1.24 + let sites = this._findRemainingSites(links); 1.25 + 1.26 + let self = this; 1.27 + 1.28 + // Remove sites that are no longer in the grid. 1.29 + this._removeLegacySites(sites, function () { 1.30 + // Freeze all site positions so that we can move their DOM nodes around 1.31 + // without any visual impact. 1.32 + self._freezeSitePositions(sites); 1.33 + 1.34 + // Move the sites' DOM nodes to their new position in the DOM. This will 1.35 + // have no visual effect as all the sites have been frozen and will 1.36 + // remain in their current position. 1.37 + self._moveSiteNodes(sites); 1.38 + 1.39 + // Now it's time to animate the sites actually moving to their new 1.40 + // positions. 1.41 + self._rearrangeSites(sites, function () { 1.42 + // Try to fill empty cells and finish. 1.43 + self._fillEmptyCells(links, aCallback); 1.44 + 1.45 + // Update other pages that might be open to keep them synced. 1.46 + gAllPages.update(gPage); 1.47 + }); 1.48 + }); 1.49 + }, 1.50 + 1.51 + /** 1.52 + * Takes an array of links and tries to correlate them to sites contained in 1.53 + * the current grid. If no corresponding site can be found (i.e. the link is 1.54 + * new and a site will be created) then just set it to null. 1.55 + * @param aLinks The array of links to find sites for. 1.56 + * @return Array of sites mapped to the given links (can contain null values). 1.57 + */ 1.58 + _findRemainingSites: function Updater_findRemainingSites(aLinks) { 1.59 + let map = {}; 1.60 + 1.61 + // Create a map to easily retrieve the site for a given URL. 1.62 + gGrid.sites.forEach(function (aSite) { 1.63 + if (aSite) 1.64 + map[aSite.url] = aSite; 1.65 + }); 1.66 + 1.67 + // Map each link to its corresponding site, if any. 1.68 + return aLinks.map(function (aLink) { 1.69 + return aLink && (aLink.url in map) && map[aLink.url]; 1.70 + }); 1.71 + }, 1.72 + 1.73 + /** 1.74 + * Freezes the given sites' positions. 1.75 + * @param aSites The array of sites to freeze. 1.76 + */ 1.77 + _freezeSitePositions: function Updater_freezeSitePositions(aSites) { 1.78 + aSites.forEach(function (aSite) { 1.79 + if (aSite) 1.80 + gTransformation.freezeSitePosition(aSite); 1.81 + }); 1.82 + }, 1.83 + 1.84 + /** 1.85 + * Moves the given sites' DOM nodes to their new positions. 1.86 + * @param aSites The array of sites to move. 1.87 + */ 1.88 + _moveSiteNodes: function Updater_moveSiteNodes(aSites) { 1.89 + let cells = gGrid.cells; 1.90 + 1.91 + // Truncate the given array of sites to not have more sites than cells. 1.92 + // This can happen when the user drags a bookmark (or any other new kind 1.93 + // of link) onto the grid. 1.94 + let sites = aSites.slice(0, cells.length); 1.95 + 1.96 + sites.forEach(function (aSite, aIndex) { 1.97 + let cell = cells[aIndex]; 1.98 + let cellSite = cell.site; 1.99 + 1.100 + // The site's position didn't change. 1.101 + if (!aSite || cellSite != aSite) { 1.102 + let cellNode = cell.node; 1.103 + 1.104 + // Empty the cell if necessary. 1.105 + if (cellSite) 1.106 + cellNode.removeChild(cellSite.node); 1.107 + 1.108 + // Put the new site in place, if any. 1.109 + if (aSite) 1.110 + cellNode.appendChild(aSite.node); 1.111 + } 1.112 + }, this); 1.113 + }, 1.114 + 1.115 + /** 1.116 + * Rearranges the given sites and slides them to their new positions. 1.117 + * @param aSites The array of sites to re-arrange. 1.118 + * @param aCallback The callback to call when finished. 1.119 + */ 1.120 + _rearrangeSites: function Updater_rearrangeSites(aSites, aCallback) { 1.121 + let options = {callback: aCallback, unfreeze: true}; 1.122 + gTransformation.rearrangeSites(aSites, options); 1.123 + }, 1.124 + 1.125 + /** 1.126 + * Removes all sites from the grid that are not in the given links array or 1.127 + * exceed the grid. 1.128 + * @param aSites The array of sites remaining in the grid. 1.129 + * @param aCallback The callback to call when finished. 1.130 + */ 1.131 + _removeLegacySites: function Updater_removeLegacySites(aSites, aCallback) { 1.132 + let batch = []; 1.133 + 1.134 + // Delete sites that were removed from the grid. 1.135 + gGrid.sites.forEach(function (aSite) { 1.136 + // The site must be valid and not in the current grid. 1.137 + if (!aSite || aSites.indexOf(aSite) != -1) 1.138 + return; 1.139 + 1.140 + let deferred = Promise.defer(); 1.141 + batch.push(deferred.promise); 1.142 + 1.143 + // Fade out the to-be-removed site. 1.144 + gTransformation.hideSite(aSite, function () { 1.145 + let node = aSite.node; 1.146 + 1.147 + // Remove the site from the DOM. 1.148 + node.parentNode.removeChild(node); 1.149 + deferred.resolve(); 1.150 + }); 1.151 + }); 1.152 + 1.153 + Promise.all(batch).then(aCallback); 1.154 + }, 1.155 + 1.156 + /** 1.157 + * Tries to fill empty cells with new links if available. 1.158 + * @param aLinks The array of links. 1.159 + * @param aCallback The callback to call when finished. 1.160 + */ 1.161 + _fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) { 1.162 + let {cells, sites} = gGrid; 1.163 + let batch = []; 1.164 + 1.165 + // Find empty cells and fill them. 1.166 + sites.forEach(function (aSite, aIndex) { 1.167 + if (aSite || !aLinks[aIndex]) 1.168 + return; 1.169 + 1.170 + let deferred = Promise.defer(); 1.171 + batch.push(deferred.promise); 1.172 + 1.173 + // Create the new site and fade it in. 1.174 + let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]); 1.175 + 1.176 + // Set the site's initial opacity to zero. 1.177 + site.node.style.opacity = 0; 1.178 + 1.179 + // Flush all style changes for the dynamically inserted site to make 1.180 + // the fade-in transition work. 1.181 + window.getComputedStyle(site.node).opacity; 1.182 + gTransformation.showSite(site, function () deferred.resolve()); 1.183 + }); 1.184 + 1.185 + Promise.all(batch).then(aCallback); 1.186 + } 1.187 +};