OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 }); |
OLD | NEW |