Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * @fileoverview PageListView implementation. | |
| 7 * PageListView manages page list, dot list, switcher buttons and glue apps | |
|
Evan Stade
2011/11/09 00:19:00
glue apps?
also, final period
xiyuan
2011/11/09 19:21:53
Done.
Comments updated to:
PageListView manages p
| |
| 8 * pages with backend. | |
| 9 */ | |
| 10 | |
| 11 cr.define('ntp4', function() { | |
| 12 'use strict'; | |
| 13 | |
| 14 /** | |
| 15 * Object for accessing localized strings. | |
| 16 * @type {!LocalStrings} | |
| 17 */ | |
| 18 var localStrings = new LocalStrings; | |
| 19 | |
| 20 /** | |
| 21 * Creates a PageListView object. | |
| 22 * @constructor | |
| 23 * @extends {Object} | |
| 24 */ | |
| 25 function PageListView() { | |
| 26 } | |
| 27 | |
| 28 PageListView.prototype = { | |
| 29 /** | |
| 30 * The CardSlider object to use for changing app pages. | |
| 31 * @type {CardSlider|undefined} | |
| 32 */ | |
| 33 cardSlider: undefined, | |
| 34 | |
| 35 /** | |
| 36 * The frame div for cardSlider. | |
| 37 * @type {!Element|undefined} | |
| 38 */ | |
| 39 sliderFrame: undefined, | |
| 40 | |
| 41 /** | |
| 42 * The 'page-list' element. | |
| 43 * @type {!Element|undefined} | |
| 44 */ | |
| 45 pageList: undefined, | |
| 46 | |
| 47 /** | |
| 48 * A list of all 'tile-page' elements. | |
| 49 * @type {!NodeList|undefined} | |
| 50 */ | |
| 51 tilePages: undefined, | |
| 52 | |
| 53 /** | |
| 54 * A list of all 'apps-page' elements. | |
| 55 * @type {!NodeList|undefined} | |
| 56 */ | |
| 57 appsPages: undefined, | |
| 58 | |
| 59 /** | |
| 60 * The Most Visited page. | |
| 61 * @type {!Element|undefined} | |
| 62 */ | |
| 63 mostVisitedPage: undefined, | |
| 64 | |
| 65 /** | |
| 66 * The Bookmarks page. | |
| 67 * @type {!Element|undefined} | |
| 68 */ | |
| 69 bookmarksPage: undefined, | |
| 70 | |
| 71 /** | |
| 72 * The 'dots-list' element. | |
| 73 * @type {!Element|undefined} | |
| 74 */ | |
| 75 dotList: undefined, | |
| 76 | |
| 77 /** | |
| 78 * The left and right paging buttons. | |
| 79 * @type {!Element|undefined} | |
| 80 */ | |
| 81 pageSwitcherStart: undefined, | |
| 82 pageSwitcherEnd: undefined, | |
| 83 | |
| 84 /** | |
| 85 * The 'trash' element. Note that technically this is unnecessary, | |
| 86 * JavaScript creates the object for us based on the id. But I don't want | |
| 87 * to rely on the ID being the same, and JSCompiler doesn't know about it. | |
| 88 * @type {!Element|undefined} | |
| 89 */ | |
| 90 trash: undefined, | |
| 91 | |
| 92 /** | |
| 93 * The type of page that is currently shown. The value is a numerical ID. | |
| 94 * @type {number} | |
| 95 */ | |
| 96 shownPage: 0, | |
| 97 | |
| 98 /** | |
| 99 * The index of the page that is currently shown, within the page type. | |
| 100 * For example if the third Apps page is showing, this will be 2. | |
| 101 * @type {number} | |
| 102 */ | |
| 103 shownPageIndex: 0, | |
| 104 | |
| 105 /** | |
| 106 * EventTracker for managing event listeners for page events. | |
| 107 * @type {!EventTracker} | |
| 108 */ | |
| 109 eventTracker: new EventTracker, | |
| 110 | |
| 111 /** | |
| 112 * If non-null, this is the ID of the app to highlight to the user the next | |
| 113 * time getAppsCallback runs. "Highlight" in this case means to switch to | |
| 114 * the page and run the new tile animation. | |
| 115 * @type {String} | |
| 116 */ | |
| 117 highlightAppId: null, | |
| 118 | |
| 119 /** | |
| 120 * Initializes page list view. | |
| 121 */ | |
| 122 initialize: function() { | |
| 123 this.pageList = getRequiredElement('page-list'); | |
| 124 | |
| 125 this.dotList = getRequiredElement('dot-list'); | |
| 126 cr.ui.decorate(this.dotList, ntp4.DotList); | |
| 127 | |
| 128 this.trash = getRequiredElement('trash'); | |
| 129 new ntp4.Trash(this.trash); | |
| 130 | |
| 131 this.pageSwitcherStart = $('page-switcher-start'); | |
|
Evan Stade
2011/11/09 00:19:00
why is this code here rather than in new_tab.js?
xiyuan
2011/11/09 19:21:53
Switcher buttons might not be NTP specific. I thin
| |
| 132 if (this.pageSwitcherStart) | |
| 133 ntp4.initializePageSwitcher(this.pageSwitcherStart); | |
| 134 | |
| 135 this.pageSwitcherEnd = $('page-switcher-end'); | |
| 136 if (this.pageSwitcherEnd) | |
| 137 ntp4.initializePageSwitcher(this.pageSwitcherEnd); | |
| 138 | |
| 139 this.shownPage = templateData['shown_page_type']; | |
| 140 this.shownPageIndex = templateData['shown_page_index']; | |
| 141 | |
| 142 // Request data on the apps so we can fill them in. | |
| 143 // Note that this is kicked off asynchronously. 'getAppsCallback' will be | |
| 144 // invoked at some point after this function returns. | |
| 145 chrome.send('getApps'); | |
| 146 | |
| 147 document.addEventListener('keydown', this.onDocKeyDown.bind(this)); | |
| 148 // Prevent touch events from triggering any sort of native scrolling | |
| 149 document.addEventListener('touchmove', function(e) { | |
| 150 e.preventDefault(); | |
| 151 }, true); | |
| 152 | |
| 153 this.tilePages = this.pageList.getElementsByClassName('tile-page'); | |
| 154 this.appsPages = this.pageList.getElementsByClassName('apps-page'); | |
| 155 | |
| 156 // Initialize the cardSlider without any cards at the moment | |
| 157 this.sliderFrame = getRequiredElement('card-slider-frame'); | |
| 158 this.cardSlider = new CardSlider(this.sliderFrame, this.pageList, | |
| 159 this.sliderFrame.offsetWidth); | |
| 160 this.cardSlider.initialize(); | |
| 161 | |
| 162 // Handle the page being changed | |
| 163 this.pageList.addEventListener( | |
| 164 CardSlider.EventType.CARD_CHANGED, | |
| 165 this.cardChangedHandler.bind(this)); | |
| 166 | |
| 167 // Ensure the slider is resized appropriately with the window | |
| 168 window.addEventListener('resize', this.onWindowResize_.bind(this)); | |
| 169 | |
| 170 // Update apps when online state changes. | |
| 171 window.addEventListener('online', this.updateOfflineEnabledApps); | |
| 172 window.addEventListener('offline', this.updateOfflineEnabledApps); | |
| 173 }, | |
| 174 | |
| 175 /** | |
| 176 * Appends a tile page (for bookmarks or most visited). | |
| 177 * | |
| 178 * @param {TilePage} page The page element. | |
| 179 * @param {string} title The title of the tile page. | |
| 180 * @param {bool} titleIsEditable If true, the title can be changed. | |
| 181 * @param {TilePage} opt_refNode Optional reference node to insert in front | |
| 182 * of. | |
| 183 * When opt_refNode is falsey, |page| will just be appended to the end of | |
| 184 * the page list. | |
| 185 */ | |
| 186 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { | |
| 187 // If no opt_refNode given, use bookmarksPage (if any). | |
| 188 if (!opt_refNode) | |
| 189 opt_refNode = this.bookmarksPage; | |
| 190 | |
| 191 // When opt_refNode is falsey, insertBefore acts just like appendChild. | |
| 192 this.pageList.insertBefore(page, opt_refNode); | |
| 193 | |
| 194 // Remember special MostVisitedPage and BookmarksPage. | |
| 195 if (typeof ntp4.MostVisitedPage != 'undefined' && | |
| 196 page instanceof ntp4.MostVisitedPage) { | |
| 197 assert(this.tilePages.length == 1, | |
| 198 'MostVisitedPage should be added as first tile page'); | |
| 199 this.mostVisitedPage = page; | |
| 200 } | |
| 201 if (typeof ntp4.BookmarksPage != 'undefined' && | |
| 202 page instanceof ntp4.BookmarksPage) { | |
| 203 this.bookmarksPage = page; | |
| 204 } | |
| 205 | |
| 206 // If we're appending an AppsPage and it's a temporary page, animate it. | |
| 207 var animate = page instanceof ntp4.AppsPage && | |
| 208 page.classList.contains('temporary'); | |
| 209 // Make a deep copy of the dot template to add a new one. | |
| 210 var newDot = new ntp4.NavDot(page, title, titleIsEditable, animate); | |
| 211 page.navigationDot = newDot; | |
| 212 this.dotList.insertBefore(newDot, opt_refNode ? opt_refNode.navigationDot | |
| 213 : null); | |
| 214 // Set a tab index on the first dot. | |
| 215 if (this.dotList.dots.length == 1) | |
| 216 newDot.tabIndex = 3; | |
| 217 | |
| 218 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this)); | |
| 219 }, | |
| 220 | |
| 221 /** | |
| 222 * Called by chrome when an existing app has been disabled or | |
| 223 * removed/uninstalled from chrome. | |
| 224 * @param {Object} appData A data structure full of relevant information for | |
| 225 * the app. | |
| 226 * @param {boolean} isUninstall True if the app is being uninstalled; | |
| 227 * false if the app is being disabled. | |
| 228 */ | |
| 229 appRemoved: function(appData, isUninstall) { | |
| 230 var app = $(appData.id); | |
| 231 assert(app, 'trying to remove an app that doesn\'t exist'); | |
| 232 | |
| 233 if (!isUninstall) | |
| 234 app.replaceAppData(appData); | |
| 235 else | |
| 236 app.remove(); | |
| 237 }, | |
| 238 | |
| 239 /** | |
| 240 * Callback invoked by chrome with the apps available. | |
| 241 * | |
| 242 * Note that calls to this function can occur at any time, not just in | |
| 243 * response to a getApps request. For example, when a user | |
| 244 * installs/uninstalls an app on another synchronized devices. | |
| 245 * @param {Object} data An object with all the data on available | |
| 246 * applications. | |
| 247 */ | |
| 248 getAppsCallback: function(data) { | |
| 249 var startTime = Date.now(); | |
| 250 | |
| 251 // Clear any existing apps pages and dots. | |
| 252 // TODO(rbyers): It might be nice to preserve animation of dots after an | |
| 253 // uninstall. Could we re-use the existing page and dot elements? It | |
| 254 // seems unfortunate to have Chrome send us the entire apps list after an | |
| 255 // uninstall. | |
| 256 while (this.appsPages.length > 0) { | |
| 257 var page = this.appsPages[0]; | |
| 258 var dot = page.navigationDot; | |
| 259 | |
| 260 this.eventTracker.remove(page); | |
| 261 page.tearDown(); | |
| 262 page.parentNode.removeChild(page); | |
| 263 dot.parentNode.removeChild(dot); | |
| 264 } | |
| 265 | |
| 266 // Get the array of apps and add any special synthesized entries | |
| 267 var apps = data.apps; | |
| 268 | |
| 269 // Get a list of page names | |
| 270 var pageNames = data.appPageNames; | |
| 271 | |
| 272 function stringListIsEmpty(list) { | |
| 273 for (var i = 0; i < list.length; i++) { | |
| 274 if (list[i]) | |
| 275 return false; | |
| 276 } | |
| 277 return true; | |
| 278 } | |
| 279 | |
| 280 // Sort by launch index | |
| 281 apps.sort(function(a, b) { | |
| 282 return a.app_launch_index - b.app_launch_index; | |
| 283 }); | |
| 284 | |
| 285 // An app to animate (in case it was just installed). | |
| 286 var highlightApp; | |
| 287 | |
| 288 // Add the apps, creating pages as necessary | |
| 289 for (var i = 0; i < apps.length; i++) { | |
| 290 var app = apps[i]; | |
| 291 var pageIndex = (app.page_index || 0); | |
| 292 while (pageIndex >= this.appsPages.length) { | |
| 293 var pageName = localStrings.getString('appDefaultPageName'); | |
| 294 if (this.appsPages.length < pageNames.length) | |
| 295 pageName = pageNames[this.appsPages.length]; | |
| 296 | |
| 297 var origPageCount = this.appsPages.length; | |
| 298 this.appendTilePage(new ntp4.AppsPage(), pageName, true); | |
| 299 // Confirm that appsPages is a live object, updated when a new page is | |
| 300 // added (otherwise we'd have an infinite loop) | |
| 301 assert(this.appsPages.length == origPageCount + 1, | |
| 302 'expected new page'); | |
| 303 } | |
| 304 | |
| 305 if (app.id == this.highlightAppId) | |
| 306 highlightApp = app; | |
| 307 else | |
| 308 this.appsPages[pageIndex].appendApp(app); | |
| 309 } | |
| 310 | |
| 311 ntp4.AppsPage.setPromo(data.showPromo ? data : null); | |
| 312 | |
| 313 // Tell the slider about the pages. | |
| 314 this.updateSliderCards(); | |
| 315 | |
| 316 if (highlightApp) | |
| 317 this.appAdded(highlightApp, true); | |
| 318 | |
| 319 // Mark the current page. | |
| 320 this.cardSlider.currentCardValue.navigationDot.classList.add('selected'); | |
| 321 logEvent('apps.layout: ' + (Date.now() - startTime)); | |
| 322 | |
| 323 document.documentElement.classList.remove('starting-up'); | |
| 324 }, | |
| 325 | |
| 326 /** | |
| 327 * Called by chrome when a new app has been added to chrome or has been | |
| 328 * enabled if previously disabled. | |
| 329 * @param {Object} appData A data structure full of relevant information for | |
| 330 * the app. | |
| 331 */ | |
| 332 appAdded: function(appData, opt_highlight) { | |
| 333 if (appData.id == this.highlightAppId) { | |
| 334 opt_highlight = true; | |
| 335 this.highlightAppId = null; | |
| 336 } | |
| 337 | |
| 338 var pageIndex = appData.page_index || 0; | |
| 339 | |
| 340 if (pageIndex >= this.appsPages.length) { | |
| 341 while (pageIndex >= this.appsPages.length) { | |
| 342 this.appendTilePage(new ntp4.AppsPage(), | |
| 343 localStrings.getString('appDefaultPageName'), | |
| 344 true); | |
| 345 } | |
| 346 this.updateSliderCards(); | |
| 347 } | |
| 348 | |
| 349 var page = this.appsPages[pageIndex]; | |
| 350 var app = $(appData.id); | |
| 351 if (app) | |
| 352 app.replaceAppData(appData); | |
| 353 else | |
| 354 page.appendApp(appData, opt_highlight); | |
| 355 }, | |
| 356 | |
| 357 /** | |
| 358 * Callback invoked by chrome whenever an app preference changes. | |
| 359 * @param {Object} data An object with all the data on available | |
| 360 * applications. | |
| 361 */ | |
| 362 appsPrefChangeCallback: function(data) { | |
| 363 for (var i = 0; i < data.apps.length; ++i) { | |
| 364 $(data.apps[i].id).appData = data.apps[i]; | |
| 365 } | |
| 366 | |
| 367 // Set the App dot names. Skip the first and last dots (Most Visited and | |
| 368 // Bookmarks). | |
| 369 var dots = this.dotList.getElementsByClassName('dot'); | |
| 370 // TODO(csilv): Remove this calcluation if/when we remove the flag for | |
| 371 // for the bookmarks page. | |
| 372 var start = this.mostVisitedPage ? 1 : 0; | |
| 373 var length = this.bookmarksPage ? dots.length - 1 : dots.length; | |
| 374 for (var i = start; i < length; ++i) { | |
| 375 dots[i].displayTitle = data.appPageNames[i - start] || ''; | |
| 376 } | |
| 377 }, | |
| 378 | |
| 379 /** | |
| 380 * Invoked whenever the pages in apps-page-list have changed so that | |
| 381 * the Slider knows about the new elements. | |
| 382 */ | |
| 383 updateSliderCards: function() { | |
| 384 var pageNo = Math.min(this.cardSlider.currentCard, | |
| 385 this.tilePages.length - 1); | |
| 386 this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages), | |
| 387 pageNo); | |
| 388 switch (this.shownPage) { | |
| 389 case templateData['apps_page_id']: | |
| 390 this.cardSlider.selectCardByValue( | |
| 391 this.appsPages[Math.min(this.shownPageIndex, | |
| 392 this.appsPages.length - 1)]); | |
| 393 break; | |
| 394 case templateData['bookmarks_page_id']: | |
| 395 if (this.bookmarksPage) | |
| 396 this.cardSlider.selectCardByValue(this.bookmarksPage); | |
| 397 break; | |
| 398 case templateData['most_visited_page_id']: | |
| 399 if (this.mostVisitedPage) | |
| 400 this.cardSlider.selectCardByValue(this.mostVisitedPage); | |
| 401 break; | |
| 402 } | |
| 403 }, | |
| 404 | |
| 405 /** | |
| 406 * Called whenever tiles should be re-arranging themselves out of the way | |
| 407 * of a moving or insert tile. | |
| 408 */ | |
| 409 enterRearrangeMode: function() { | |
| 410 var tempPage = new ntp4.AppsPage(); | |
| 411 tempPage.classList.add('temporary'); | |
| 412 this.appendTilePage(tempPage, | |
| 413 localStrings.getString('appDefaultPageName'), | |
| 414 true); | |
| 415 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage); | |
| 416 if (this.cardSlider.currentCard >= tempIndex) | |
| 417 this.cardSlider.currentCard += 1; | |
| 418 this.updateSliderCards(); | |
| 419 | |
| 420 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved()) | |
| 421 $('footer').classList.add('showing-trash-mode'); | |
| 422 }, | |
| 423 | |
| 424 /** | |
| 425 * Invoked whenever some app is released | |
| 426 * @param {Grabber.Event} e The Grabber RELEASE event. | |
| 427 */ | |
| 428 leaveRearrangeMode: function(e) { | |
| 429 var tempPage = document.querySelector('.tile-page.temporary'); | |
| 430 var dot = tempPage.navigationDot; | |
| 431 if (!tempPage.tileCount && tempPage != this.cardSlider.currentCardValue) { | |
| 432 dot.animateRemove(); | |
| 433 var tempIndex = Array.prototype.indexOf.call(this.tilePages, tempPage); | |
| 434 if (this.cardSlider.currentCard > tempIndex) | |
| 435 this.cardSlider.currentCard -= 1; | |
| 436 tempPage.parentNode.removeChild(tempPage); | |
| 437 this.updateSliderCards(); | |
| 438 } else { | |
| 439 tempPage.classList.remove('temporary'); | |
| 440 this.saveAppPageName(tempPage, | |
| 441 localStrings.getString('appDefaultPageName')); | |
| 442 } | |
| 443 | |
| 444 $('footer').classList.remove('showing-trash-mode'); | |
| 445 }, | |
| 446 | |
| 447 /** | |
| 448 * Callback for the 'pagelayout' event. | |
| 449 * @param {Event} e The event. | |
| 450 */ | |
| 451 onPageLayout_: function(e) { | |
| 452 if (Array.prototype.indexOf.call(this.tilePages, e.currentTarget) != | |
| 453 this.cardSlider.currentCard) { | |
| 454 return; | |
| 455 } | |
| 456 | |
| 457 this.updatePageSwitchers(); | |
| 458 }, | |
| 459 | |
| 460 /** | |
| 461 * Adjusts the size and position of the page switchers according to the | |
| 462 * layout of the current card. | |
| 463 */ | |
| 464 updatePageSwitchers: function() { | |
| 465 if (!this.pageSwitcherStart || !this.pageSwitcherEnd) | |
| 466 return; | |
| 467 | |
| 468 var page = this.cardSlider.currentCardValue; | |
| 469 | |
| 470 this.pageSwitcherStart.hidden = !page || | |
| 471 (this.cardSlider.currentCard == 0); | |
| 472 this.pageSwitcherEnd.hidden = !page || | |
| 473 (this.cardSlider.currentCard == this.cardSlider.cardCount - 1); | |
| 474 | |
| 475 if (!page) | |
| 476 return; | |
| 477 | |
| 478 var pageSwitcherLeft = isRTL() ? this.pageSwitcherEnd | |
| 479 : this.pageSwitcherStart; | |
| 480 var pageSwitcherRight = isRTL() ? this.pageSwitcherStart | |
| 481 : this.pageSwitcherEnd; | |
| 482 var scrollbarWidth = page.scrollbarWidth; | |
| 483 pageSwitcherLeft.style.width = | |
| 484 (page.sideMargin + 13) + 'px'; | |
| 485 pageSwitcherLeft.style.left = '0'; | |
| 486 pageSwitcherRight.style.width = | |
| 487 (page.sideMargin - scrollbarWidth + 13) + 'px'; | |
| 488 pageSwitcherRight.style.right = scrollbarWidth + 'px'; | |
| 489 | |
| 490 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px'; | |
| 491 pageSwitcherLeft.style.top = offsetTop; | |
| 492 pageSwitcherRight.style.top = offsetTop; | |
| 493 pageSwitcherLeft.style.paddingBottom = offsetTop; | |
| 494 pageSwitcherRight.style.paddingBottom = offsetTop; | |
| 495 }, | |
| 496 | |
| 497 /** | |
| 498 * Returns the index of the given page. | |
| 499 * @param {AppsPage} page The AppsPage for we wish to find. | |
| 500 * @return {number} The index of |page|, or -1 if it is not here. | |
| 501 */ | |
| 502 getAppsPageIndex: function(page) { | |
| 503 return Array.prototype.indexOf.call(this.appsPages, page); | |
| 504 }, | |
| 505 | |
| 506 /** | |
| 507 * Handler for CARD_CHANGED on cardSlider. | |
| 508 * @param {Event} e The CARD_CHANGED event. | |
| 509 */ | |
| 510 cardChangedHandler: function(e) { | |
| 511 var page = e.cardSlider.currentCardValue; | |
| 512 | |
| 513 // Don't change shownPage until startup is done (and page changes actually | |
| 514 // reflect user actions). | |
| 515 if (!document.documentElement.classList.contains('starting-up')) { | |
| 516 if (page.classList.contains('apps-page')) { | |
| 517 this.shownPage = templateData['apps_page_id']; | |
| 518 this.shownPageIndex = this.getAppsPageIndex(page); | |
| 519 } else if (page.classList.contains('most-visited-page')) { | |
| 520 this.shownPage = templateData['most_visited_page_id']; | |
| 521 this.shownPageIndex = 0; | |
| 522 } else if (page.classList.contains('bookmarks-page')) { | |
| 523 this.shownPage = templateData['bookmarks_page_id']; | |
| 524 this.shownPageIndex = 0; | |
| 525 } else { | |
| 526 console.error('unknown page selected'); | |
| 527 } | |
| 528 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]); | |
| 529 } | |
| 530 | |
| 531 // Update the active dot | |
| 532 var curDot = this.dotList.getElementsByClassName('selected')[0]; | |
| 533 if (curDot) | |
| 534 curDot.classList.remove('selected'); | |
| 535 page.navigationDot.classList.add('selected'); | |
| 536 this.updatePageSwitchers(); | |
| 537 }, | |
| 538 | |
| 539 /* | |
| 540 * Save the name of an app page. | |
| 541 * Store the app page name into the preferences store. | |
| 542 * @param {AppsPage} appPage The app page for which we wish to save. | |
| 543 * @param {string} name The name of the page. | |
| 544 */ | |
| 545 saveAppPageName: function(appPage, name) { | |
| 546 var index = this.getAppsPageIndex(appPage); | |
| 547 assert(index != -1); | |
| 548 chrome.send('saveAppPageName', [name, index]); | |
| 549 }, | |
| 550 | |
| 551 /** | |
| 552 * Window resize handler. | |
| 553 * @private | |
| 554 */ | |
| 555 onWindowResize_: function(e) { | |
| 556 this.cardSlider.resize(this.sliderFrame.offsetWidth); | |
| 557 this.updatePageSwitchers(); | |
| 558 }, | |
| 559 | |
| 560 /** | |
| 561 * Listener for offline status change events. Updates apps that are | |
| 562 * not offline-enabled to be grayscale if the browser is offline. | |
| 563 */ | |
| 564 updateOfflineEnabledApps: function() { | |
| 565 var apps = document.querySelectorAll('.app'); | |
| 566 for (var i = 0; i < apps.length; ++i) { | |
| 567 if (apps[i].appData.enabled && !apps[i].appData.offline_enabled) { | |
| 568 apps[i].setIcon(); | |
| 569 apps[i].loadIcon(); | |
| 570 } | |
| 571 } | |
| 572 }, | |
| 573 | |
| 574 /** | |
| 575 * Handler for key events on the page. Ctrl-Arrow will switch the visible | |
| 576 * page. | |
| 577 * @param {Event} e The KeyboardEvent. | |
| 578 */ | |
| 579 onDocKeyDown: function(e) { | |
| 580 if (!e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) | |
| 581 return; | |
| 582 | |
| 583 var direction = 0; | |
| 584 if (e.keyIdentifier == 'Left') | |
| 585 direction = -1; | |
| 586 else if (e.keyIdentifier == 'Right') | |
| 587 direction = 1; | |
| 588 else | |
| 589 return; | |
| 590 | |
| 591 var cardIndex = | |
| 592 (this.cardSlider.currentCard + direction + | |
| 593 this.cardSlider.cardCount) % this.cardSlider.cardCount; | |
| 594 this.cardSlider.selectCard(cardIndex, true); | |
| 595 | |
| 596 e.stopPropagation(); | |
| 597 } | |
| 598 }; | |
| 599 | |
| 600 return { | |
| 601 PageListView: PageListView | |
| 602 }; | |
| 603 }); | |
| OLD | NEW |