Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(554)

Side by Side Diff: chrome/browser/resources/ntp4/page_list_view.js

Issue 8637001: [NTP4] Auto-deletion of empty apps panes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: adding back erroneously removed ; Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview PageListView implementation. 6 * @fileoverview PageListView implementation.
7 * PageListView manages page list, dot list, switcher buttons and handles apps 7 * PageListView manages page list, dot list, switcher buttons and handles apps
8 * pages callbacks from backend. 8 * pages callbacks from backend.
9 * 9 *
10 * Note that you need to have AppLauncherHandler in your WebUI to use this code. 10 * Note that you need to have AppLauncherHandler in your WebUI to use this code.
(...skipping 17 matching lines...) Expand all
28 } 28 }
29 29
30 PageListView.prototype = { 30 PageListView.prototype = {
31 /** 31 /**
32 * The CardSlider object to use for changing app pages. 32 * The CardSlider object to use for changing app pages.
33 * @type {CardSlider|undefined} 33 * @type {CardSlider|undefined}
34 */ 34 */
35 cardSlider: undefined, 35 cardSlider: undefined,
36 36
37 /** 37 /**
38 * The frame div for cardSlider. 38 * The frame div for this.cardSlider.
39 * @type {!Element|undefined} 39 * @type {!Element|undefined}
40 */ 40 */
41 sliderFrame: undefined, 41 sliderFrame: undefined,
42 42
43 /** 43 /**
44 * The 'page-list' element. 44 * The 'page-list' element.
45 * @type {!Element|undefined} 45 * @type {!Element|undefined}
46 */ 46 */
47 pageList: undefined, 47 pageList: undefined,
48 48
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 this.updateOfflineEnabledApps_.bind(this)); 182 this.updateOfflineEnabledApps_.bind(this));
183 }, 183 },
184 184
185 /** 185 /**
186 * Appends a tile page. 186 * Appends a tile page.
187 * 187 *
188 * @param {TilePage} page The page element. 188 * @param {TilePage} page The page element.
189 * @param {string} title The title of the tile page. 189 * @param {string} title The title of the tile page.
190 * @param {bool} titleIsEditable If true, the title can be changed. 190 * @param {bool} titleIsEditable If true, the title can be changed.
191 * @param {TilePage} opt_refNode Optional reference node to insert in front 191 * @param {TilePage} opt_refNode Optional reference node to insert in front
192 * of. 192 * of.
193 * When opt_refNode is falsey, |page| will just be appended to the end of 193 * When opt_refNode is falsey, |page| will just be appended to the end of
194 * the page list. 194 * the page list.
195 */ 195 */
196 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { 196 appendTilePage: function(page, title, titleIsEditable, opt_refNode) {
197 // When opt_refNode is falsey, insertBefore acts just like appendChild. 197 // When opt_refNode is falsey, insertBefore acts just like appendChild.
198 this.pageList.insertBefore(page, opt_refNode); 198 this.pageList.insertBefore(page, opt_refNode);
199 199
200 if (!document.documentElement.classList.contains('starting-up')) {
201 // If we're inserting a card in front of the current card, add 1 to the
202 // current index to adjust for the new card in the order.
203 var index = Array.prototype.indexOf.call(this.tilePages, page);
204 if (typeof this.cardSlider.currentCard != 'undefined' &&
205 index <= this.cardSlider.currentCard) {
206 this.cardSlider.currentCard += 1;
207 }
208 if (page instanceof ntp4.AppsPage &&
209 this.shownPage == templateData['apps_page_id'] &&
210 this.getAppsPageIndex(page) <= this.shownPageIndex) {
211 this.shownPageIndex += 1;
212 }
213 }
214
200 // Remember special MostVisitedPage. 215 // Remember special MostVisitedPage.
201 if (typeof ntp4.MostVisitedPage != 'undefined' && 216 if (typeof ntp4.MostVisitedPage != 'undefined' &&
202 page instanceof ntp4.MostVisitedPage) { 217 page instanceof ntp4.MostVisitedPage) {
203 assert(this.tilePages.length == 1, 218 assert(this.tilePages.length == 1,
204 'MostVisitedPage should be added as first tile page'); 219 'MostVisitedPage should be added as first tile page');
205 this.mostVisitedPage = page; 220 this.mostVisitedPage = page;
206 } 221 }
207 222
208 // If we're appending an AppsPage and it's a temporary page, animate it. 223 // If we're appending an AppsPage and it's a temporary page, animate it.
209 var animate = page instanceof ntp4.AppsPage && 224 var animate = page instanceof ntp4.AppsPage &&
(...skipping 10 matching lines...) Expand all
220 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this)); 235 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this));
221 }, 236 },
222 237
223 /** 238 /**
224 * Called by chrome when an existing app has been disabled or 239 * Called by chrome when an existing app has been disabled or
225 * removed/uninstalled from chrome. 240 * removed/uninstalled from chrome.
226 * @param {Object} appData A data structure full of relevant information for 241 * @param {Object} appData A data structure full of relevant information for
227 * the app. 242 * the app.
228 * @param {boolean} isUninstall True if the app is being uninstalled; 243 * @param {boolean} isUninstall True if the app is being uninstalled;
229 * false if the app is being disabled. 244 * false if the app is being disabled.
230 */ 245 */
csilv 2011/12/02 01:57:02 add comment documentation for 'fromPage'
Dan Beam 2011/12/05 18:05:10 Done.
231 appRemoved: function(appData, isUninstall) { 246 appRemoved: function(appData, isUninstall, fromPage) {
232 var app = $(appData.id); 247 var app = $(appData.id);
233 assert(app, 'trying to remove an app that doesn\'t exist'); 248 assert(app, 'trying to remove an app that doesn\'t exist');
234 249
235 if (!isUninstall) 250 if (!isUninstall) {
236 app.replaceAppData(appData); 251 app.replaceAppData(appData);
237 else 252 } else {
238 app.remove(); 253 // Unset the ID immediately, because the app is already gone. But leave
254 // the tile on the page as it animates out.
255 app.id = '';
256 // If the uninstall was from this page, run the blipout animation and
257 // remove the tile in the webkitAnimationEnd handler in apps_page.js.
258 // Otherwise delete the tile without auto-deleting the page to avoid
259 // re-deleting the same page (or the page that slid in to take its
260 // place).
261 if (fromPage) {
262 app.classList.add('removing-tile-contents');
263 } else {
264 var tilePage = app.tile.tilePage;
265 app.tile.remove(false, true);
266 this.removeAppsPageIfEmpty(tilePage, false, true);
267 }
268 }
239 }, 269 },
240 270
241 /** 271 /**
242 * Callback invoked by chrome with the apps available. 272 * Callback invoked by chrome with the apps available.
243 * 273 *
244 * Note that calls to this function can occur at any time, not just in 274 * Note that calls to this function can occur at any time, not just in
245 * response to a getApps request. For example, when a user 275 * response to a getApps request. For example, when a user
246 * installs/uninstalls an app on another synchronized devices. 276 * installs/uninstalls an app on another synchronized devices.
247 * @param {Object} data An object with all the data on available 277 * @param {Object} data An object with all the data on available
248 * applications. 278 * applications.
249 */ 279 */
250 getAppsCallback: function(data) { 280 getAppsCallback: function(data) {
251 var startTime = Date.now(); 281 var startTime = Date.now();
252 282
253 // Clear any existing apps pages and dots. 283 // Clear any existing apps pages and dots.
254 // TODO(rbyers): It might be nice to preserve animation of dots after an 284 // TODO(rbyers): It might be nice to preserve animation of dots after an
255 // uninstall. Could we re-use the existing page and dot elements? It 285 // uninstall. Could we re-use the existing page and dot elements? It
256 // seems unfortunate to have Chrome send us the entire apps list after an 286 // seems unfortunate to have Chrome send us the entire apps list after an
257 // uninstall. 287 // uninstall.
258 while (this.appsPages.length > 0) { 288 while (this.appsPages.length > 0) {
259 var page = this.appsPages[0]; 289 var page = this.appsPages[0];
260 var dot = page.navigationDot;
261 290
262 this.eventTracker.remove(page); 291 this.eventTracker.remove(page);
263 page.tearDown(); 292 this.removeTilePage(page);
264 page.parentNode.removeChild(page);
265 dot.parentNode.removeChild(dot);
266 } 293 }
267 294
268 // Get the array of apps and add any special synthesized entries 295 // Get the array of apps and add any special synthesized entries
269 var apps = data.apps; 296 var apps = data.apps;
270 297
271 // Get a list of page names 298 // Get a list of page names
272 var pageNames = data.appPageNames; 299 var pageNames = data.appsPageNames;
273 300
274 function stringListIsEmpty(list) { 301 function stringListIsEmpty(list) {
275 for (var i = 0; i < list.length; i++) { 302 for (var i = 0; i < list.length; i++) {
276 if (list[i]) 303 if (list[i])
277 return false; 304 return false;
278 } 305 }
279 return true; 306 return true;
280 } 307 }
281 308
282 // Sort by launch index 309 // Sort by launch index
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 * @param {Object} appData A data structure full of relevant information for 358 * @param {Object} appData A data structure full of relevant information for
332 * the app. 359 * the app.
333 */ 360 */
334 appAdded: function(appData, opt_highlight) { 361 appAdded: function(appData, opt_highlight) {
335 if (appData.id == this.highlightAppId) { 362 if (appData.id == this.highlightAppId) {
336 opt_highlight = true; 363 opt_highlight = true;
337 this.highlightAppId = null; 364 this.highlightAppId = null;
338 } 365 }
339 366
340 var pageIndex = appData.page_index || 0; 367 var pageIndex = appData.page_index || 0;
341 368 this.ensureAppsPageAtIndex_(pageIndex);
342 if (pageIndex >= this.appsPages.length) {
343 while (pageIndex >= this.appsPages.length) {
344 this.appendTilePage(new ntp4.AppsPage(),
345 localStrings.getString('appDefaultPageName'),
346 true);
347 }
348 this.updateSliderCards();
349 }
350 369
351 var page = this.appsPages[pageIndex]; 370 var page = this.appsPages[pageIndex];
352 var app = $(appData.id); 371 var app = $(appData.id);
353 if (app) 372 if (app)
354 app.replaceAppData(appData); 373 app.replaceAppData(appData);
355 else 374 else
356 page.appendApp(appData, opt_highlight); 375 page.appendApp(appData, opt_highlight);
357 }, 376 },
358 377
359 /** 378 /**
360 * Callback invoked by chrome whenever an app preference changes. 379 * Callback invoked by chrome whenever an app preference changes.
361 * @param {Object} data An object with all the data on available 380 * @param {Object} data An object with all the data on available
362 * applications. 381 * applications.
363 */ 382 */
364 appsPrefChangedCallback: function(data) { 383 appsPrefChangedCallback: function(data) {
365 for (var i = 0; i < data.apps.length; ++i) { 384 for (var i = 0; i < data.apps.length; ++i) {
366 $(data.apps[i].id).appData = data.apps[i]; 385 var el = $(data.apps[i].id);
386 // There won't be an element when the temporary page is first saved on a
387 // drop on a new apps page.
388 if (el)
389 el.appData = data.apps[i];
367 } 390 }
368 391
369 // Set the App dot names. Skip the first dot (Most Visited). 392 // Set the App dot names. Skip dots that don't belong to apps pages.
370 var dots = this.dotList.getElementsByClassName('dot'); 393 var dots = this.dotList.getElementsByClassName('dot');
371 var start = this.mostVisitedPage ? 1 : 0; 394 var firstAppDot = this.getTilePageIndex(this.appsPages[0]);
372 for (var i = start; i < dots.length; ++i) { 395 for (var i = 0; i < this.appsPages.length; ++i) {
373 dots[i].displayTitle = data.appPageNames[i - start] || ''; 396 dots[firstAppDot + i].displayTitle = data.appsPageNames[i] || '';
374 } 397 }
375 }, 398 },
376 399
377 /** 400 /**
378 * Invoked whenever the pages in apps-page-list have changed so that 401 * Invoked whenever the pages in apps-page-list have changed so that
379 * the Slider knows about the new elements. 402 * the Slider knows about the new elements.
380 */ 403 */
381 updateSliderCards: function() { 404 updateSliderCards: function() {
382 var pageNo = Math.min(this.cardSlider.currentCard, 405 var index = -1;
383 this.tilePages.length - 1); 406 var prevPage = this.shownPage;
384 this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages), 407 var prevIndex = this.shownPageIndex;
385 pageNo); 408 var tiles = Array.prototype.slice.call(this.tilePages);
409 // It doesn't hurt to clamp value this every time, even if it's only
410 // applicable to apps. It helps self-heal strange / un-expected data, i.e.
411 // going from an apps page to the most visited page directly without
412 // setting this.shownPageIndex = 0 somehow.
413 this.shownPageIndex = Math.max(0, Math.min(this.shownPageIndex,
414 this.appsPages.length - 1));
386 switch (this.shownPage) { 415 switch (this.shownPage) {
387 case templateData['apps_page_id']: 416 case templateData['apps_page_id']:
388 this.cardSlider.selectCardByValue( 417 index = tiles.indexOf(this.appsPages[this.shownPageIndex]);
389 this.appsPages[Math.min(this.shownPageIndex,
390 this.appsPages.length - 1)]);
391 break; 418 break;
392 case templateData['most_visited_page_id']: 419 case templateData['most_visited_page_id']:
393 if (this.mostVisitedPage) 420 index = tiles.indexOf(this.mostVisitedPage);
394 this.cardSlider.selectCardByValue(this.mostVisitedPage);
395 break; 421 break;
396 } 422 }
423 // If shownPage was saved as a page that's now disabled or the shownPage
424 // doesn't exist any more, index will be -1. Change to the preferred
425 // default page (first apps pane) in this case.
426 if (index < 0) {
427 this.shownPage = templateData['apps_page_id'];
428 index = tiles.indexOf(this.appsPages[0]);
429 }
430 // Set the new cards and index.
431 this.cardSlider.setCards(tiles, index);
432 // If we got new page or index, update the pref.
433 if (prevIndex != this.shownPageIndex || prevPage != this.shownPage)
434 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
397 }, 435 },
398 436
399 /** 437 /**
400 * Called whenever tiles should be re-arranging themselves out of the way 438 * Called whenever tiles should be re-arranging themselves out of the way
401 * of a moving or insert tile. 439 * of a moving or insert tile.
402 */ 440 */
403 enterRearrangeMode: function() { 441 enterRearrangeMode: function() {
404 var tempPage = new ntp4.AppsPage(); 442 var tempPage = new ntp4.AppsPage();
405 tempPage.classList.add('temporary'); 443 tempPage.classList.add('temporary');
406 this.appendTilePage(tempPage, 444 var pageName = localStrings.getString('appDefaultPageName');
407 localStrings.getString('appDefaultPageName'), 445 this.appendTilePage(tempPage, pageName, true);
408 true);
409 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage);
410 if (this.cardSlider.currentCard >= tempIndex)
411 this.cardSlider.currentCard += 1;
412 this.updateSliderCards(); 446 this.updateSliderCards();
447 this.updatePageSwitchers();
413 448
414 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved()) 449 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved())
415 $('footer').classList.add('showing-trash-mode'); 450 $('footer').classList.add('showing-trash-mode');
416 }, 451 },
417 452
418 /** 453 /**
419 * Invoked whenever some app is released 454 * Invoked whenever some app is released
420 */ 455 */
421 leaveRearrangeMode: function() { 456 leaveRearrangeMode: function() {
422 var tempPage = document.querySelector('.tile-page.temporary'); 457 var tempPage = document.querySelector('.tile-page.temporary');
423 var dot = tempPage.navigationDot; 458 // If there's a temp page and it wasn't removed for being empty.
424 if (!tempPage.tileCount && tempPage != this.cardSlider.currentCardValue) { 459 if (tempPage && !this.removeAppsPageIfEmpty(tempPage, true)) {
425 dot.animateRemove(); 460 this.saveAppsPageName(tempPage, tempPage.navigationDot.displayTitle);
426 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage);
427 if (this.cardSlider.currentCard > tempIndex)
428 this.cardSlider.currentCard -= 1;
429 tempPage.parentNode.removeChild(tempPage);
430 this.updateSliderCards();
431 } else {
432 tempPage.classList.remove('temporary'); 461 tempPage.classList.remove('temporary');
433 this.saveAppPageName(tempPage,
434 localStrings.getString('appDefaultPageName'));
435 } 462 }
436 463
437 $('footer').classList.remove('showing-trash-mode'); 464 $('footer').classList.remove('showing-trash-mode');
438 }, 465 },
439 466
440 /** 467 /**
441 * Callback for the 'pagelayout' event. 468 * Callback for the 'pagelayout' event.
442 * @param {Event} e The event. 469 * @param {Event} e The event.
443 */ 470 */
444 onPageLayout_: function(e) { 471 onPageLayout_: function(e) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 pageSwitcherRight.style.right = scrollbarWidth + 'px'; 508 pageSwitcherRight.style.right = scrollbarWidth + 'px';
482 509
483 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px'; 510 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px';
484 pageSwitcherLeft.style.top = offsetTop; 511 pageSwitcherLeft.style.top = offsetTop;
485 pageSwitcherRight.style.top = offsetTop; 512 pageSwitcherRight.style.top = offsetTop;
486 pageSwitcherLeft.style.paddingBottom = offsetTop; 513 pageSwitcherLeft.style.paddingBottom = offsetTop;
487 pageSwitcherRight.style.paddingBottom = offsetTop; 514 pageSwitcherRight.style.paddingBottom = offsetTop;
488 }, 515 },
489 516
490 /** 517 /**
491 * Returns the index of the given page. 518 * Returns the index of the given apps page.
492 * @param {AppsPage} page The AppsPage for we wish to find. 519 * @param {AppsPage} page The AppsPage we wish to find.
493 * @return {number} The index of |page|, or -1 if it is not here. 520 * @return {number} The index of |page| or -1 if it is not in the
521 * collection.
494 */ 522 */
495 getAppsPageIndex: function(page) { 523 getAppsPageIndex: function(page) {
496 return Array.prototype.indexOf.call(this.appsPages, page); 524 return Array.prototype.indexOf.call(this.appsPages, page);
497 }, 525 },
498 526
499 /** 527 /**
500 * Handler for CARD_CHANGED on cardSlider. 528 * Handler for CARD_CHANGED on cardSlider.
501 * @param {Event} e The CARD_CHANGED event. 529 * @param {Event} e The CARD_CHANGED event.
502 * @private 530 * @private
503 */ 531 */
504 cardChangedHandler_: function(e) { 532 cardChangedHandler_: function(e) {
505 var page = e.cardSlider.currentCardValue; 533 var page = e.cardSlider.currentCardValue;
506 534
507 // Don't change shownPage until startup is done (and page changes actually 535 // Don't change shownPage until startup is done (and page changes actually
508 // reflect user actions). 536 // reflect user actions).
509 if (!document.documentElement.classList.contains('starting-up')) { 537 if (!document.documentElement.classList.contains('starting-up')) {
538 var prevPage = this.shownPage;
539 var prevIndex = this.shownPageIndex;
510 if (page.classList.contains('apps-page')) { 540 if (page.classList.contains('apps-page')) {
511 this.shownPage = templateData['apps_page_id']; 541 this.shownPage = templateData['apps_page_id'];
512 this.shownPageIndex = this.getAppsPageIndex(page); 542 this.shownPageIndex = this.getAppsPageIndex(page);
513 } else if (page.classList.contains('most-visited-page')) { 543 } else if (page.classList.contains('most-visited-page')) {
514 this.shownPage = templateData['most_visited_page_id']; 544 this.shownPage = templateData['most_visited_page_id'];
515 this.shownPageIndex = 0; 545 this.shownPageIndex = 0;
516 } else { 546 } else {
517 console.error('unknown page selected'); 547 console.error('unknown page selected');
518 } 548 }
519 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]); 549 if (prevPage != this.shownPage || prevIndex != this.shownPageIndex)
550 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
520 } 551 }
521 552
522 // Update the active dot 553 // Update the active dot
523 var curDot = this.dotList.getElementsByClassName('selected')[0]; 554 var curDot = this.dotList.getElementsByClassName('selected')[0];
524 if (curDot) 555 if (curDot)
525 curDot.classList.remove('selected'); 556 curDot.classList.remove('selected');
526 page.navigationDot.classList.add('selected'); 557 page.navigationDot.classList.add('selected');
527 this.updatePageSwitchers(); 558 this.updatePageSwitchers();
528 }, 559 },
529 560
530 /* 561 /**
531 * Save the name of an app page. 562 * Save the name of an app page.
532 * Store the app page name into the preferences store. 563 * Store the app page name into the preferences store.
533 * @param {AppsPage} appPage The app page for which we wish to save. 564 * @param {AppsPage} appsPage The app page for which we wish to save.
534 * @param {string} name The name of the page. 565 * @param {string} name The name of the page.
535 */ 566 */
536 saveAppPageName: function(appPage, name) { 567 saveAppsPageName: function(appsPage, name) {
537 var index = this.getAppsPageIndex(appPage); 568 var index = this.getAppsPageIndex(appsPage);
538 assert(index != -1); 569 assert(index != -1);
539 chrome.send('saveAppPageName', [name, index]); 570 chrome.send('saveAppsPageName', [name, index]);
540 }, 571 },
541 572
542 /** 573 /**
543 * Window resize handler. 574 * Window resize handler.
544 * @private 575 * @private
545 */ 576 */
546 onWindowResize_: function(e) { 577 onWindowResize_: function(e) {
547 this.cardSlider.resize(this.sliderFrame.offsetWidth); 578 this.cardSlider.resize(this.sliderFrame.offsetWidth);
548 this.updatePageSwitchers(); 579 this.updatePageSwitchers();
549 }, 580 },
(...skipping 30 matching lines...) Expand all
580 direction = 1; 611 direction = 1;
581 else 612 else
582 return; 613 return;
583 614
584 var cardIndex = 615 var cardIndex =
585 (this.cardSlider.currentCard + direction + 616 (this.cardSlider.currentCard + direction +
586 this.cardSlider.cardCount) % this.cardSlider.cardCount; 617 this.cardSlider.cardCount) % this.cardSlider.cardCount;
587 this.cardSlider.selectCard(cardIndex, true); 618 this.cardSlider.selectCard(cardIndex, true);
588 619
589 e.stopPropagation(); 620 e.stopPropagation();
590 } 621 },
622
623 /**
624 * Re-order apps on this invactive page when an active NTP gets re-ordered.
csilv 2011/12/02 01:57:02 "inactive"
Dan Beam 2011/12/05 18:05:10 Done.
625 * @param {Object} data Position hashmap ordered by app id with indices:
626 * {id => {page_index: ##, app_launch_index: ##}}
627 */
628 appsReordered: function(data) {
629 var pages = Object.keys(data);
630 for (var i = 0; i < pages.length; ++i) {
631 var page = data[pages[i]];
632 var indices = Object.keys(page);
633 for (var j = 0; j < indices.length; ++j) {
634 var app = $(page[indices[j]]);
635 if (i != this.getAppsPageIndex(app.tile.tilePage) ||
636 j != app.tile.index) {
637 var tile = app.tile.remove(false, true);
638 this.ensureAppsPageAtIndex_(i);
639 var appsPage = this.appsPages[i];
640 appsPage.addTileAt(tile.firstChild, j);
641 if (appsPage.classList.contains('selected-card'))
642 app.loadIcon();
643 }
644 }
645 }
646 for (var i = 0; i < this.appsPages.length; ++i) {
647 // If a page is now empty, remove it and move backward one in our
648 // array-like object as it is a live NodeList and the length/indice
649 // change when you update it. Otherwise, reuse cleanupDrag() to
650 // re-position the tiles like when a user is done dragging.
651 if (this.removeAppsPageIfEmpty(this.appsPages[i], false, true))
652 --i;
653 else
654 this.appsPages[i].cleanupDrag();
655 }
656 },
657
658 /**
659 * Ensure there is an apps page at the given |index|. If index is smaller
660 * than the current number of apps pages, additional apps pages will be
661 * created.
662 * @param {number} index An apps page index to ensure exists.
663 */
664 ensureAppsPageAtIndex_: function(index) {
665 if (index >= this.appsPages.length) {
666 var pageName = localStrings.getString('appDefaultPageName');
667 while (index >= this.appsPages.length)
668 this.appendTilePage(new ntp4.AppsPage(), pageName, true);
669 this.updateSliderCards();
670 }
671 },
672
673 /**
674 * Returns the index of a given tile page.
675 * @param {TilePage} page The TilePage we wish to find.
676 * @return {number} The index of |page| or -1 if it is not in the
677 * collection.
678 */
679 getTilePageIndex: function(page) {
680 return Array.prototype.indexOf.call(this.tilePages, page);
681 },
682
683 /**
684 * Move to a non-empty page before/while we delete an empty one.
685 * @param {Element} appsPage An empty apps page that we want to move off of
686 * (probably because it's empty).
687 * @param {=boolean} animate Whether we should animate or not.
688 * @param {=function} callback A callback to be executed when the move is
689 * done.
690 */
691 moveOffEmptyAppsPage: function(appsPage, opt_animate, opt_callback) {
692 assert(appsPage instanceof ntp4.AppsPage,
693 '|appsPage| is really an AppsPage');
694 // Select the page further toward the end than the empty |appsPage|. If
695 // the empty |appsPage| is at the end, the apps page before it will be
696 // selected.
697 var index = this.getAppsPageIndex(appsPage);
698 assert(index >= 0, '|appsPage| is in this.appsPages');
699 var direction = (index == this.appsPages.length - 1 ? -1 : 1);
700 this.cardSlider.selectCard(this.cardSlider.currentCard + direction,
701 opt_animate, opt_callback);
702 },
703
704 /**
705 * Utility function to remove both a tile page and corresponding nav dot.
706 * NOTE: If |animated| is true, this function will return before the
707 * animation is finished.
708 * @param {Element} appsPage An apps page to be removed if it has no tiles.
709 * @param {=boolean} opt_animate An optional param to animate the removal.
710 * @param {=boolean} opt_dontSave Whether we should notify other NTPs this
711 * page was deleted (defaults to yes).
712 * @returns {boolean} If the page was removed.
713 */
714 removeAppsPageIfEmpty: function(appsPage, opt_animate, opt_dontSave) {
715 if (appsPage && appsPage.tileCount === 0) {
716 var whenDone = function() {
717 if (!opt_dontSave) {
718 chrome.send('deleteAppsPage',
719 [this.getAppsPageIndex(appsPage),
720 appsPage.classList.contains('temporary')]);
721 }
722 this.removeTilePage(appsPage, opt_animate);
723 this.updateSliderCards();
724 this.updatePageSwitchers();
725 };
726 if (appsPage == this.cardSlider.currentCardValue)
727 this.moveOffEmptyAppsPage(appsPage, opt_animate, whenDone.bind(this));
728 else
729 whenDone.call(this);
730 return true;
731 }
732 return false;
733 },
734
735 /**
736 * Removes a page and navigation dot (if the navdot exists).
737 * @param {Element} page The page to be removed.
738 * @param {boolean} animate If the removal should be animated.
739 */
740 removeTilePage: function(page, animate) {
741 if (!document.documentElement.classList.contains('starting-up')) {
742 // If the card being deleted is before the current card, keep the same
743 // spot in the list by removing 1 from the current card index.
744 var index = Array.prototype.indexOf.call(this.tilePages, page);
745 if (index < this.cardSlider.currentCard) {
746 this.cardSlider.currentCard -= 1;
747 }
748 // If the page we're about to delete is in front of the current page,
749 // remove 1 from the shown page index.
750 if (page instanceof ntp4.AppsPage &&
751 this.shownPage == templateData['apps_page_id'] &&
752 this.getAppsPageIndex(page) < this.shownPageIndex) {
753 this.shownPageIndex -= 1;
754 }
755 }
756 if (page.navigationDot)
757 page.navigationDot.remove(animate);
758 page.remove();
759 },
591 }; 760 };
592 761
593 return { 762 return {
594 PageListView: PageListView 763 PageListView: PageListView
595 }; 764 };
596 }); 765 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698