From a682dda2c287642add6a3f9ed046fc6c85ca1bfb Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Tue, 21 Jan 2014 00:55:24 +0100 Subject: [PATCH] Bug 895359 - Switch about:newtab to Promise.jsm and remove remaining callback r=jaws --- browser/base/content/newtab/newTab.js | 2 +- browser/base/content/newtab/sites.js | 5 +- .../base/content/newtab/transformations.js | 141 +++++++----------- browser/base/content/newtab/updater.js | 93 +++++------- 4 files changed, 90 insertions(+), 151 deletions(-) diff --git a/browser/base/content/newtab/newTab.js b/browser/base/content/newtab/newTab.js index 2ca2ff433c01..ebe043794830 100644 --- a/browser/base/content/newtab/newTab.js +++ b/browser/base/content/newtab/newTab.js @@ -12,7 +12,7 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/PageThumbs.jsm"); Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm"); Cu.import("resource://gre/modules/NewTabUtils.jsm"); -Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); +Cu.import("resource://gre/modules/Promise.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Rect", "resource://gre/modules/Geometry.jsm"); diff --git a/browser/base/content/newtab/sites.js b/browser/base/content/newtab/sites.js index 156ea91baab4..3ec4f956d23f 100644 --- a/browser/base/content/newtab/sites.js +++ b/browser/base/content/newtab/sites.js @@ -60,7 +60,7 @@ Site.prototype = { }, /** - * Unpins the site and calls the given callback when done. + * Unpins the site. */ unpin: function Site_unpin() { if (this.isPinned()) { @@ -79,8 +79,7 @@ Site.prototype = { }, /** - * Blocks the site (removes it from the grid) and calls the given callback - * when done. + * Blocks the site (removes it from the grid). */ block: function Site_block() { if (!gBlockedLinks.isBlocked(this._link)) { diff --git a/browser/base/content/newtab/transformations.js b/browser/base/content/newtab/transformations.js index 7976b12f9620..3e711c90e307 100644 --- a/browser/base/content/newtab/transformations.js +++ b/browser/base/content/newtab/transformations.js @@ -38,46 +38,24 @@ let gTransformation = { return new Rect(left + scrollX, top + scrollY, width, height); }, - /** - * Fades a given node from zero to full opacity. - * @param aNode The node to fade. - * @param aCallback The callback to call when finished. - */ - fadeNodeIn: function Transformation_fadeNodeIn(aNode, aCallback) { - this._setNodeOpacity(aNode, 1, function () { - // Clear the style property. - aNode.style.opacity = ""; - - if (aCallback) - aCallback(); - }); - }, - - /** - * Fades a given node from full to zero opacity. - * @param aNode The node to fade. - * @param aCallback The callback to call when finished. - */ - fadeNodeOut: function Transformation_fadeNodeOut(aNode, aCallback) { - this._setNodeOpacity(aNode, 0, aCallback); - }, - /** * Fades a given site from zero to full opacity. * @param aSite The site to fade. - * @param aCallback The callback to call when finished. */ - showSite: function Transformation_showSite(aSite, aCallback) { - this.fadeNodeIn(aSite.node, aCallback); + showSite: function (aSite) { + let node = aSite.node; + return this._setNodeOpacity(node, 1).then(() => { + // Clear the style property. + node.style.opacity = ""; + }); }, /** * Fades a given site from full to zero opacity. * @param aSite The site to fade. - * @param aCallback The callback to call when finished. */ - hideSite: function Transformation_hideSite(aSite, aCallback) { - this.fadeNodeOut(aSite.node, aCallback); + hideSite: function (aSite) { + return this._setNodeOpacity(aSite.node, 0); }, /** @@ -129,22 +107,11 @@ let gTransformation = { * @param aTarget The slide target. * @param aOptions Set of options (see below). * unfreeze - unfreeze the site after sliding - * callback - the callback to call when finished */ - slideSiteTo: function Transformation_slideSiteTo(aSite, aTarget, aOptions) { + slideSiteTo: function (aSite, aTarget, aOptions) { let currentPosition = this.getNodePosition(aSite.node); let targetPosition = this.getNodePosition(aTarget.node) - let callback = aOptions && aOptions.callback; - - let self = this; - - function finish() { - if (aOptions && aOptions.unfreeze) - self.unfreezeSitePosition(aSite); - - if (callback) - callback(); - } + let promise; // We need to take the width of a cell's border into account. targetPosition.left += this._cellBorderWidths.left; @@ -153,11 +120,17 @@ let gTransformation = { // Nothing to do here if the positions already match. if (currentPosition.left == targetPosition.left && currentPosition.top == targetPosition.top) { - finish(); + promise = Promise.resolve(); } else { this.setSitePosition(aSite, targetPosition); - this._whenTransitionEnded(aSite.node, ["left", "top"], finish); + promise = this._whenTransitionEnded(aSite.node, ["left", "top"]); } + + if (aOptions && aOptions.unfreeze) { + promise = promise.then(() => this.unfreezeSitePosition(aSite)); + } + + return promise; }, /** @@ -166,55 +139,50 @@ let gTransformation = { * @param aSites An array of sites to rearrange. * @param aOptions Set of options (see below). * unfreeze - unfreeze the site after rearranging - * callback - the callback to call when finished */ - rearrangeSites: function Transformation_rearrangeSites(aSites, aOptions) { - let batch = []; + rearrangeSites: function (aSites, aOptions) { + let self = this; let cells = gGrid.cells; - let callback = aOptions && aOptions.callback; let unfreeze = aOptions && aOptions.unfreeze; - aSites.forEach(function (aSite, aIndex) { - // Do not re-arrange empty cells or the dragged site. - if (!aSite || aSite == gDrag.draggedSite) - return; + function* promises() { + let index = 0; - let deferred = Promise.defer(); - batch.push(deferred.promise); - let cb = function () deferred.resolve(); + for (let site of aSites) { + if (site && site !== gDrag.draggedSite) { + if (!cells[index]) { + // The site disappeared from the grid, hide it. + yield self.hideSite(site); + } else if (self._getNodeOpacity(site.node) != 1) { + // The site disappeared before but is now back, show it. + yield self.showSite(site); + } else { + // The site's position has changed, move it around. + yield self._moveSite(site, index, {unfreeze: unfreeze}); + } + } + index++; + } + } - if (!cells[aIndex]) - // The site disappeared from the grid, hide it. - this.hideSite(aSite, cb); - else if (this._getNodeOpacity(aSite.node) != 1) - // The site disappeared before but is now back, show it. - this.showSite(aSite, cb); - else - // The site's position has changed, move it around. - this._moveSite(aSite, aIndex, {unfreeze: unfreeze, callback: cb}); - }, this); - - let wait = Promise.promised(function () callback && callback()); - wait.apply(null, batch); + return Promise.all([p for (p of promises())]); }, /** - * Listens for the 'transitionend' event on a given node and calls the given - * callback. + * Listens for the 'transitionend' event on a given node. * @param aNode The node that is transitioned. * @param aProperties The properties we'll wait to be transitioned. - * @param aCallback The callback to call when finished. */ - _whenTransitionEnded: - function Transformation_whenTransitionEnded(aNode, aProperties, aCallback) { - + _whenTransitionEnded: function (aNode, aProperties) { + let deferred = Promise.defer(); let props = new Set(aProperties); aNode.addEventListener("transitionend", function onEnd(e) { if (props.has(e.propertyName)) { aNode.removeEventListener("transitionend", onEnd); - aCallback(); + deferred.resolve(); } }); + return deferred.promise; }, /** @@ -231,21 +199,14 @@ let gTransformation = { * Sets a given node's opacity. * @param aNode The node to set the opacity value for. * @param aOpacity The opacity value to set. - * @param aCallback The callback to call when finished. */ - _setNodeOpacity: - function Transformation_setNodeOpacity(aNode, aOpacity, aCallback) { - + _setNodeOpacity: function (aNode, aOpacity) { if (this._getNodeOpacity(aNode) == aOpacity) { - if (aCallback) - aCallback(); - } else { - if (aCallback) { - this._whenTransitionEnded(aNode, ["opacity"], aCallback); - } - - aNode.style.opacity = aOpacity; + return Promise.resolve(); } + + aNode.style.opacity = aOpacity; + return this._whenTransitionEnded(aNode, ["opacity"]); }, /** @@ -254,9 +215,9 @@ let gTransformation = { * @param aIndex The target cell's index. * @param aOptions Options that are directly passed to slideSiteTo(). */ - _moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) { + _moveSite: function (aSite, aIndex, aOptions) { this.freezeSitePosition(aSite); - this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions); + return this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions); }, /** diff --git a/browser/base/content/newtab/updater.js b/browser/base/content/newtab/updater.js index 7b483e037f2c..8225906d1b4f 100644 --- a/browser/base/content/newtab/updater.js +++ b/browser/base/content/newtab/updater.js @@ -12,32 +12,29 @@ let gUpdater = { /** * Updates the current grid according to its pinned and blocked sites. * This removes old, moves existing and creates new sites to fill gaps. - * @param aCallback The callback to call when finished. */ - updateGrid: function Updater_updateGrid(aCallback) { + updateGrid: function Updater_updateGrid() { let links = gLinks.getLinks().slice(0, gGrid.cells.length); // Find all sites that remain in the grid. let sites = this._findRemainingSites(links); - let self = this; - // Remove sites that are no longer in the grid. - this._removeLegacySites(sites, function () { + this._removeLegacySites(sites).then(() => { // Freeze all site positions so that we can move their DOM nodes around // without any visual impact. - self._freezeSitePositions(sites); + this._freezeSitePositions(sites); // Move the sites' DOM nodes to their new position in the DOM. This will // have no visual effect as all the sites have been frozen and will // remain in their current position. - self._moveSiteNodes(sites); + this._moveSiteNodes(sites); // Now it's time to animate the sites actually moving to their new // positions. - self._rearrangeSites(sites, function () { + this._rearrangeSites(sites).then(() => { // Try to fill empty cells and finish. - self._fillEmptyCells(links, aCallback); + this._fillEmptyCells(links); // Update other pages that might be open to keep them synced. gAllPages.update(gPage); @@ -112,75 +109,57 @@ let gUpdater = { /** * Rearranges the given sites and slides them to their new positions. * @param aSites The array of sites to re-arrange. - * @param aCallback The callback to call when finished. */ - _rearrangeSites: function Updater_rearrangeSites(aSites, aCallback) { - let options = {callback: aCallback, unfreeze: true}; - gTransformation.rearrangeSites(aSites, options); + _rearrangeSites: function (aSites) { + return gTransformation.rearrangeSites(aSites, {unfreeze: true}); }, /** * Removes all sites from the grid that are not in the given links array or * exceed the grid. * @param aSites The array of sites remaining in the grid. - * @param aCallback The callback to call when finished. */ - _removeLegacySites: function Updater_removeLegacySites(aSites, aCallback) { - let batch = []; + _removeLegacySites: function (aSites) { + let remainingSites = new Set(aSites); - // Delete sites that were removed from the grid. - gGrid.sites.forEach(function (aSite) { - // The site must be valid and not in the current grid. - if (!aSite || aSites.indexOf(aSite) != -1) - return; + function* promises() { + for (let site of gGrid.sites) { + // The site must be valid and not in the current grid. + if (site && !remainingSites.has(site)) { + // Hide the site and remove it from the DOM. + let remove = site.node.remove.bind(site.node); + yield gTransformation.hideSite(site).then(remove); + } + } + } - let deferred = Promise.defer(); - batch.push(deferred.promise); - - // Fade out the to-be-removed site. - gTransformation.hideSite(aSite, function () { - let node = aSite.node; - - // Remove the site from the DOM. - node.parentNode.removeChild(node); - deferred.resolve(); - }); - }); - - let wait = Promise.promised(aCallback); - wait.apply(null, batch); + return Promise.all([p for (p of promises())]); }, /** * Tries to fill empty cells with new links if available. * @param aLinks The array of links. - * @param aCallback The callback to call when finished. */ - _fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) { + _fillEmptyCells: function (aLinks) { let {cells, sites} = gGrid; - let batch = []; + let index = 0; // Find empty cells and fill them. - sites.forEach(function (aSite, aIndex) { - if (aSite || !aLinks[aIndex]) - return; + for (let site of sites) { + if (!site && aLinks[index]) { + // Create the new site and fade it in. + site = gGrid.createSite(aLinks[index], cells[index]); - let deferred = Promise.defer(); - batch.push(deferred.promise); + // Set the site's initial opacity to zero. + site.node.style.opacity = 0; - // Create the new site and fade it in. - let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]); + // Flush all style changes for the dynamically inserted site to make + // the fade-in transition work. + window.getComputedStyle(site.node).opacity; + gTransformation.showSite(site); + } - // Set the site's initial opacity to zero. - site.node.style.opacity = 0; - - // Flush all style changes for the dynamically inserted site to make - // the fade-in transition work. - window.getComputedStyle(site.node).opacity; - gTransformation.showSite(site, function () deferred.resolve()); - }); - - let wait = Promise.promised(aCallback); - wait.apply(null, batch); + index++; + } } };