Index: chrome/browser/resources/ntp4/page_list_view.js |
diff --git a/chrome/browser/resources/ntp4/page_list_view.js b/chrome/browser/resources/ntp4/page_list_view.js |
index d35f41bcebfce973595e6df5179e947fb4b8eaa2..2c9e54cfff8390b7544c73010d812d8806b8f114 100644 |
--- a/chrome/browser/resources/ntp4/page_list_view.js |
+++ b/chrome/browser/resources/ntp4/page_list_view.js |
@@ -167,10 +167,13 @@ cr.define('ntp4', function() { |
this.sliderFrame.offsetWidth); |
this.cardSlider.initialize(); |
- // Handle the page being changed |
- this.pageList.addEventListener( |
- cr.ui.CardSlider.EventType.CARD_CHANGED, |
- this.cardChangedHandler_.bind(this)); |
+ // Handle events from the card slider. |
+ this.pageList.addEventListener('cardSlider:card_changed', |
+ this.onCardChanged_.bind(this)); |
+ this.pageList.addEventListener('cardSlider:card_added', |
+ this.onCardAdded_.bind(this)); |
+ this.pageList.addEventListener('cardSlider:card_removed', |
+ this.onCardRemoved_.bind(this)); |
// Ensure the slider is resized appropriately with the window |
window.addEventListener('resize', this.onWindowResize_.bind(this)); |
@@ -194,8 +197,12 @@ cr.define('ntp4', function() { |
* the page list. |
*/ |
appendTilePage: function(page, title, titleIsEditable, opt_refNode) { |
- // When opt_refNode is falsey, insertBefore acts just like appendChild. |
- this.pageList.insertBefore(page, opt_refNode); |
+ if (opt_refNode) { |
+ var refIndex = this.getTilePageIndex(opt_refNode); |
+ this.cardSlider.insertCardAtIndex(page, refIndex); |
+ } else { |
+ this.cardSlider.appendCard(page); |
+ } |
// Remember special MostVisitedPage. |
if (typeof ntp4.MostVisitedPage != 'undefined' && |
@@ -227,15 +234,24 @@ cr.define('ntp4', function() { |
* the app. |
* @param {boolean} isUninstall True if the app is being uninstalled; |
* false if the app is being disabled. |
+ * @param {boolean} fromPage True if the removal was from the current page. |
*/ |
- appRemoved: function(appData, isUninstall) { |
+ appRemoved: function(appData, isUninstall, fromPage) { |
var app = $(appData.id); |
assert(app, 'trying to remove an app that doesn\'t exist'); |
if (!isUninstall) |
app.replaceAppData(appData); |
else |
- app.remove(); |
+ app.remove(!!fromPage); |
+ }, |
+ |
+ /** |
+ * @return {boolean} If the page is still starting up. |
+ * @private |
+ */ |
+ isStartingUp_: function() { |
+ return document.documentElement.classList.contains('starting-up'); |
}, |
/** |
@@ -250,20 +266,22 @@ cr.define('ntp4', function() { |
getAppsCallback: function(data) { |
var startTime = Date.now(); |
+ // Remember this to select the correct card when done rebuilding. |
+ var prevCurrentCard = this.cardSlider.currentCard; |
+ |
+ // Make removal of pages and dots as quick as possible with less DOM |
+ // operations, reflows, or repaints. We set currentCard = 0 and remove |
+ // from the end to not encounter any auto-magic card selections in the |
+ // process and we hide the card slider throughout. |
+ this.cardSlider.currentCard = 0; |
+ |
// Clear any existing apps pages and dots. |
// TODO(rbyers): It might be nice to preserve animation of dots after an |
// uninstall. Could we re-use the existing page and dot elements? It |
// seems unfortunate to have Chrome send us the entire apps list after an |
// uninstall. |
- while (this.appsPages.length > 0) { |
- var page = this.appsPages[0]; |
- var dot = page.navigationDot; |
- |
- this.eventTracker.remove(page); |
- page.tearDown(); |
- page.parentNode.removeChild(page); |
- dot.parentNode.removeChild(dot); |
- } |
+ while (this.appsPages.length > 0) |
+ this.removeTilePageAndDot_(this.appsPages[this.appsPages.length - 1]); |
// Get the array of apps and add any special synthesized entries |
var apps = data.apps; |
@@ -313,6 +331,8 @@ cr.define('ntp4', function() { |
ntp4.AppsPage.setPromo(data.showPromo ? data : null); |
+ this.cardSlider.currentCard = prevCurrentCard; |
+ |
// Tell the slider about the pages. |
this.updateSliderCards(); |
@@ -380,10 +400,10 @@ cr.define('ntp4', function() { |
* the Slider knows about the new elements. |
*/ |
updateSliderCards: function() { |
- var pageNo = Math.min(this.cardSlider.currentCard, |
- this.tilePages.length - 1); |
+ var pageNo = Math.max(0, Math.min(this.cardSlider.currentCard, |
+ this.tilePages.length - 1)); |
this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages), |
- pageNo); |
+ pageNo); |
switch (this.shownPage) { |
case templateData['apps_page_id']: |
this.cardSlider.selectCardByValue( |
@@ -404,13 +424,8 @@ cr.define('ntp4', function() { |
enterRearrangeMode: function() { |
var tempPage = new ntp4.AppsPage(); |
tempPage.classList.add('temporary'); |
- this.appendTilePage(tempPage, |
- localStrings.getString('appDefaultPageName'), |
- true); |
- var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage); |
- if (this.cardSlider.currentCard >= tempIndex) |
- this.cardSlider.currentCard += 1; |
- this.updateSliderCards(); |
+ var pageName = localStrings.getString('appDefaultPageName'); |
+ this.appendTilePage(tempPage, pageName, true); |
if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved()) |
$('footer').classList.add('showing-trash-mode'); |
@@ -423,12 +438,7 @@ cr.define('ntp4', function() { |
var tempPage = document.querySelector('.tile-page.temporary'); |
var dot = tempPage.navigationDot; |
if (!tempPage.tileCount && tempPage != this.cardSlider.currentCardValue) { |
- dot.animateRemove(); |
- var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage); |
- if (this.cardSlider.currentCard > tempIndex) |
- this.cardSlider.currentCard -= 1; |
- tempPage.parentNode.removeChild(tempPage); |
- this.updateSliderCards(); |
+ this.removeTilePageAndDot_(tempPage, true); |
} else { |
tempPage.classList.remove('temporary'); |
this.saveAppPageName(tempPage, |
@@ -499,16 +509,16 @@ cr.define('ntp4', function() { |
}, |
/** |
- * Handler for CARD_CHANGED on cardSlider. |
- * @param {Event} e The CARD_CHANGED event. |
+ * Handler for cardSlider:card_changed events from this.cardSlider. |
+ * @param {Event} e The cardSlider:card_changed event. |
* @private |
*/ |
- cardChangedHandler_: function(e) { |
+ onCardChanged_: function(e) { |
var page = e.cardSlider.currentCardValue; |
// Don't change shownPage until startup is done (and page changes actually |
// reflect user actions). |
- if (!document.documentElement.classList.contains('starting-up')) { |
+ if (!this.isStartingUp_()) { |
if (page.classList.contains('apps-page')) { |
this.shownPage = templateData.apps_page_id; |
this.shownPageIndex = this.getAppsPageIndex(page); |
@@ -529,10 +539,34 @@ cr.define('ntp4', function() { |
this.updatePageSwitchers(); |
}, |
- /* |
- * Save the name of an app page. |
- * Store the app page name into the preferences store. |
- * @param {AppsPage} appPage The app page for which we wish to save. |
+ /** |
+ * Listen for card additions to update the page switchers or the current |
+ * card accordingly. |
+ * @param {Event} e A card removed or added event. |
+ */ |
+ onCardAdded_: function(e) { |
+ // When the second arg passed to insertBefore is falsey, it acts just like |
+ // appendChild. |
+ this.pageList.insertBefore(e.addedCard, this.tilePages[e.addedIndex]); |
+ if (!this.isStartingUp_()) |
+ this.updatePageSwitchers(); |
+ }, |
+ |
+ /** |
+ * Listen for card removals to update the page switchers or the current card |
+ * accordingly. |
+ * @param {Event} e A card removed or added event. |
+ */ |
+ onCardRemoved_: function(e) { |
+ e.removedCard.parentNode.removeChild(e.removedCard); |
+ if (!this.isStartingUp_()) |
+ this.updatePageSwitchers(); |
+ }, |
+ |
+ /** |
+ * Save the name of an apps page. |
+ * Store the apps page name into the preferences store. |
+ * @param {AppsPage} appsPage The app page for which we wish to save. |
* @param {string} name The name of the page. |
*/ |
saveAppPageName: function(appPage, name) { |
@@ -589,7 +623,28 @@ cr.define('ntp4', function() { |
this.cardSlider.selectCard(cardIndex, true); |
e.stopPropagation(); |
- } |
+ }, |
+ |
+ /** |
+ * Returns the index of a given tile page. |
+ * @param {TilePage} page The TilePage we wish to find. |
+ * @return {number} The index of |page| or -1 if it is not in the |
+ * collection. |
+ */ |
+ getTilePageIndex: function(page) { |
+ return Array.prototype.indexOf.call(this.tilePages, page); |
+ }, |
+ |
+ /** |
+ * Removes a page and navigation dot (if the navdot exists). |
+ * @param {TilePage} page The page to be removed. |
+ * @param {boolean=} opt_animate If the removal should be animated. |
+ */ |
+ removeTilePageAndDot_: function(page, opt_animate) { |
+ if (page.navigationDot) |
+ page.navigationDot.remove(opt_animate); |
+ this.cardSlider.removeCard(page); |
+ }, |
}; |
return { |