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

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

Issue 10823052: Refactoring the NTP. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 5 months 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
jeremycho_google 2012/07/31 03:09:16 I don't see a diff for this file.
pedrosimonetti2 2012/08/03 18:14:01 I think they were identical. On 2012/07/31 03:09:
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview PageListView implementation.
7 * PageListView manages page list, dot list, switcher buttons and handles apps
8 * pages callbacks from backend.
9 *
10 * Note that you need to have AppLauncherHandler in your WebUI to use this code.
11 */
12
13 cr.define('ntp', function() {
14 'use strict';
15
16 /**
17 * Creates a PageListView object.
18 * @constructor
19 * @extends {Object}
20 */
21 function PageListView() {
22 }
23
24 PageListView.prototype = {
25 /**
26 * The CardSlider object to use for changing app pages.
27 * @type {CardSlider|undefined}
28 */
29 cardSlider: undefined,
30
31 /**
32 * The frame div for this.cardSlider.
33 * @type {!Element|undefined}
34 */
35 sliderFrame: undefined,
36
37 /**
38 * The 'page-list' element.
39 * @type {!Element|undefined}
40 */
41 pageList: undefined,
42
43 /**
44 * A list of all 'tile-page' elements.
45 * @type {!NodeList|undefined}
46 */
47 tilePages: undefined,
48
49 /**
50 * A list of all 'apps-page' elements.
51 * @type {!NodeList|undefined}
52 */
53 appsPages: undefined,
54
55 /**
56 * The Suggestions page.
57 * @type {!Element|undefined}
58 */
59 suggestionsPage: undefined,
60
61 /**
62 * The Most Visited page.
63 * @type {!Element|undefined}
64 */
65 mostVisitedPage: undefined,
66
67 /**
68 * The 'dots-list' element.
69 * @type {!Element|undefined}
70 */
71 dotList: undefined,
72
73 /**
74 * The left and right paging buttons.
75 * @type {!Element|undefined}
76 */
77 pageSwitcherStart: undefined,
78 pageSwitcherEnd: undefined,
79
80 /**
81 * The 'trash' element. Note that technically this is unnecessary,
82 * JavaScript creates the object for us based on the id. But I don't want
83 * to rely on the ID being the same, and JSCompiler doesn't know about it.
84 * @type {!Element|undefined}
85 */
86 trash: undefined,
87
88 /**
89 * The type of page that is currently shown. The value is a numerical ID.
90 * @type {number}
91 */
92 shownPage: 0,
93
94 /**
95 * The index of the page that is currently shown, within the page type.
96 * For example if the third Apps page is showing, this will be 2.
97 * @type {number}
98 */
99 shownPageIndex: 0,
100
101 /**
102 * EventTracker for managing event listeners for page events.
103 * @type {!EventTracker}
104 */
105 eventTracker: new EventTracker,
106
107 /**
108 * If non-null, this is the ID of the app to highlight to the user the next
109 * time getAppsCallback runs. "Highlight" in this case means to switch to
110 * the page and run the new tile animation.
111 * @type {?string}
112 */
113 highlightAppId: null,
114
115 /**
116 * Initializes page list view.
117 * @param {!Element} pageList A DIV element to host all pages.
118 * @param {!Element} dotList An UL element to host nav dots. Each dot
119 * represents a page.
120 * @param {!Element} cardSliderFrame The card slider frame that hosts
121 * pageList and switcher buttons.
122 * @param {!Element|undefined} opt_trash Optional trash element.
123 * @param {!Element|undefined} opt_pageSwitcherStart Optional start page
124 * switcher button.
125 * @param {!Element|undefined} opt_pageSwitcherEnd Optional end page
126 * switcher button.
127 */
128 initialize: function(pageList, dotList, cardSliderFrame, opt_trash,
129 opt_pageSwitcherStart, opt_pageSwitcherEnd) {
130 this.pageList = pageList;
131
132 this.dotList = dotList;
133 cr.ui.decorate(this.dotList, ntp.DotList);
134
135 this.trash = opt_trash;
136 if (this.trash)
137 new ntp.Trash(this.trash);
138
139 this.pageSwitcherStart = opt_pageSwitcherStart;
140 if (this.pageSwitcherStart)
141 ntp.initializePageSwitcher(this.pageSwitcherStart);
142
143 this.pageSwitcherEnd = opt_pageSwitcherEnd;
144 if (this.pageSwitcherEnd)
145 ntp.initializePageSwitcher(this.pageSwitcherEnd);
146
147 this.shownPage = loadTimeData.getInteger('shown_page_type');
148 this.shownPageIndex = loadTimeData.getInteger('shown_page_index');
149
150 if (loadTimeData.getBoolean('showApps')) {
151 // Request data on the apps so we can fill them in.
152 // Note that this is kicked off asynchronously. 'getAppsCallback' will
153 // be invoked at some point after this function returns.
154 chrome.send('getApps');
155 } else {
156 // No apps page.
157 if (this.shownPage == loadTimeData.getInteger('apps_page_id')) {
158 this.setShownPage_(
159 loadTimeData.getInteger('most_visited_page_id'), 0);
160 }
161
162 document.body.classList.add('bare-minimum');
163 }
164
165 document.addEventListener('keydown', this.onDocKeyDown_.bind(this));
166 // Prevent touch events from triggering any sort of native scrolling.
167 document.addEventListener('touchmove', function(e) {
168 e.preventDefault();
169 }, true);
170
171 this.tilePages = this.pageList.getElementsByClassName('tile-page');
172 this.appsPages = this.pageList.getElementsByClassName('apps-page');
173
174 // Initialize the cardSlider without any cards at the moment.
175 this.sliderFrame = cardSliderFrame;
176 this.cardSlider = new cr.ui.CardSlider(this.sliderFrame, this.pageList,
177 this.sliderFrame.offsetWidth);
178
179 // Handle mousewheel events anywhere in the card slider, so that wheel
180 // events on the page switchers will still scroll the page.
181 // This listener must be added before the card slider is initialized,
182 // because it needs to be called before the card slider's handler.
183 var cardSlider = this.cardSlider;
184 cardSliderFrame.addEventListener('mousewheel', function(e) {
185 if (cardSlider.currentCardValue.handleMouseWheel(e)) {
186 e.preventDefault(); // Prevent default scroll behavior.
187 e.stopImmediatePropagation(); // Prevent horizontal card flipping.
188 }
189 });
190
191 this.cardSlider.initialize(
192 loadTimeData.getBoolean('isSwipeTrackingFromScrollEventsEnabled'));
193
194 // Handle events from the card slider.
195 this.pageList.addEventListener('cardSlider:card_changed',
196 this.onCardChanged_.bind(this));
197 this.pageList.addEventListener('cardSlider:card_added',
198 this.onCardAdded_.bind(this));
199 this.pageList.addEventListener('cardSlider:card_removed',
200 this.onCardRemoved_.bind(this));
201
202 // Ensure the slider is resized appropriately with the window.
203 window.addEventListener('resize', this.onWindowResize_.bind(this));
204
205 // Update apps when online state changes.
206 window.addEventListener('online',
207 this.updateOfflineEnabledApps_.bind(this));
208 window.addEventListener('offline',
209 this.updateOfflineEnabledApps_.bind(this));
210 },
211
212 /**
213 * Appends a tile page.
214 *
215 * @param {TilePage} page The page element.
216 * @param {string} title The title of the tile page.
217 * @param {bool} titleIsEditable If true, the title can be changed.
218 * @param {TilePage} opt_refNode Optional reference node to insert in front
219 * of.
220 * When opt_refNode is falsey, |page| will just be appended to the end of
221 * the page list.
222 */
223 appendTilePage: function(page, title, titleIsEditable, opt_refNode) {
224 if (opt_refNode) {
225 var refIndex = this.getTilePageIndex(opt_refNode);
226 this.cardSlider.addCardAtIndex(page, refIndex);
227 } else {
228 this.cardSlider.appendCard(page);
229 }
230
231 // Remember special MostVisitedPage.
232 if (typeof ntp.MostVisitedPage != 'undefined' &&
233 page instanceof ntp.MostVisitedPage) {
234 assert(this.tilePages.length == 1,
235 'MostVisitedPage should be added as first tile page');
236 this.mostVisitedPage = page;
237 }
238
239 if (typeof ntp.SuggestionsPage != 'undefined' &&
240 page instanceof ntp.SuggestionsPage) {
241 this.suggestionsPage = page;
242 }
243
244 // If we're appending an AppsPage and it's a temporary page, animate it.
245 var animate = page instanceof ntp.AppsPage &&
246 page.classList.contains('temporary');
247 // Make a deep copy of the dot template to add a new one.
248 var newDot = new ntp.NavDot(page, title, titleIsEditable, animate);
249 page.navigationDot = newDot;
250 this.dotList.insertBefore(newDot,
251 opt_refNode ? opt_refNode.navigationDot : null);
252 // Set a tab index on the first dot.
253 if (this.dotList.dots.length == 1)
254 newDot.tabIndex = 3;
255
256 this.eventTracker.add(page, 'pagelayout', this.onPageLayout_.bind(this));
257 },
258
259 /**
260 * Called by chrome when an app has changed positions.
261 * @param {Object} appData The data for the app. This contains page and
262 * position indices.
263 */
264 appMoved: function(appData) {
265 assert(loadTimeData.getBoolean('showApps'));
266
267 var app = $(appData.id);
268 assert(app, 'trying to move an app that doesn\'t exist');
269 app.remove(false);
270
271 this.appsPages[appData.page_index].insertApp(appData, false);
272 },
273
274 /**
275 * Called by chrome when an existing app has been disabled or
276 * removed/uninstalled from chrome.
277 * @param {Object} appData A data structure full of relevant information for
278 * the app.
279 * @param {boolean} isUninstall True if the app is being uninstalled;
280 * false if the app is being disabled.
281 * @param {boolean} fromPage True if the removal was from the current page.
282 */
283 appRemoved: function(appData, isUninstall, fromPage) {
284 assert(loadTimeData.getBoolean('showApps'));
285
286 var app = $(appData.id);
287 assert(app, 'trying to remove an app that doesn\'t exist');
288
289 if (!isUninstall)
290 app.replaceAppData(appData);
291 else
292 app.remove(!!fromPage);
293 },
294
295 /**
296 * @return {boolean} If the page is still starting up.
297 * @private
298 */
299 isStartingUp_: function() {
300 return document.documentElement.classList.contains('starting-up');
301 },
302
303 /**
304 * Tracks whether apps have been loaded at least once.
305 * @type {boolean}
306 * @private
307 */
308 appsLoaded_: false,
309
310 /**
311 * Callback invoked by chrome with the apps available.
312 *
313 * Note that calls to this function can occur at any time, not just in
314 * response to a getApps request. For example, when a user
315 * installs/uninstalls an app on another synchronized devices.
316 * @param {Object} data An object with all the data on available
317 * applications.
318 */
319 getAppsCallback: function(data) {
320 assert(loadTimeData.getBoolean('showApps'));
321
322 var startTime = Date.now();
323
324 // Remember this to select the correct card when done rebuilding.
325 var prevCurrentCard = this.cardSlider.currentCard;
326
327 // Make removal of pages and dots as quick as possible with less DOM
328 // operations, reflows, or repaints. We set currentCard = 0 and remove
329 // from the end to not encounter any auto-magic card selections in the
330 // process and we hide the card slider throughout.
331 this.cardSlider.currentCard = 0;
332
333 // Clear any existing apps pages and dots.
334 // TODO(rbyers): It might be nice to preserve animation of dots after an
335 // uninstall. Could we re-use the existing page and dot elements? It
336 // seems unfortunate to have Chrome send us the entire apps list after an
337 // uninstall.
338 while (this.appsPages.length > 0)
339 this.removeTilePageAndDot_(this.appsPages[this.appsPages.length - 1]);
340
341 // Get the array of apps and add any special synthesized entries
342 var apps = data.apps;
343
344 // Get a list of page names
345 var pageNames = data.appPageNames;
346
347 function stringListIsEmpty(list) {
348 for (var i = 0; i < list.length; i++) {
349 if (list[i])
350 return false;
351 }
352 return true;
353 }
354
355 // Sort by launch ordinal
356 apps.sort(function(a, b) {
357 return a.app_launch_ordinal > b.app_launch_ordinal ? 1 :
358 a.app_launch_ordinal < b.app_launch_ordinal ? -1 : 0;
359 });
360
361 // An app to animate (in case it was just installed).
362 var highlightApp;
363
364 // If there are any pages after the apps, add new pages before them.
365 var lastAppsPage = (this.appsPages.length > 0) ?
366 this.appsPages[this.appsPages.length - 1] : null;
367 var lastAppsPageIndex = (lastAppsPage != null) ?
368 Array.prototype.indexOf.call(this.tilePages, lastAppsPage) : -1;
369 var nextPageAfterApps = lastAppsPageIndex != -1 ?
370 this.tilePages[lastAppsPageIndex + 1] : null;
371
372 // Add the apps, creating pages as necessary
373 for (var i = 0; i < apps.length; i++) {
374 var app = apps[i];
375 var pageIndex = app.page_index || 0;
376 while (pageIndex >= this.appsPages.length) {
377 var pageName = loadTimeData.getString('appDefaultPageName');
378 if (this.appsPages.length < pageNames.length)
379 pageName = pageNames[this.appsPages.length];
380
381 var origPageCount = this.appsPages.length;
382 this.appendTilePage(new ntp.AppsPage(), pageName, true,
383 nextPageAfterApps);
384 // Confirm that appsPages is a live object, updated when a new page is
385 // added (otherwise we'd have an infinite loop)
386 assert(this.appsPages.length == origPageCount + 1,
387 'expected new page');
388 }
389
390 if (app.id == this.highlightAppId)
391 highlightApp = app;
392 else
393 this.appsPages[pageIndex].insertApp(app, false);
394 }
395
396 ntp.AppsPage.setPromo(data.showPromo ? data : null);
397
398 this.cardSlider.currentCard = prevCurrentCard;
399
400 if (highlightApp)
401 this.appAdded(highlightApp, true);
402
403 logEvent('apps.layout: ' + (Date.now() - startTime));
404
405 // Tell the slider about the pages and mark the current page.
406 this.updateSliderCards();
407 this.cardSlider.currentCardValue.navigationDot.classList.add('selected');
408
409 if (!this.appsLoaded_) {
410 this.appsLoaded_ = true;
411 cr.dispatchSimpleEvent(document, 'sectionready', true, true);
412 }
413 },
414
415 /**
416 * Called by chrome when a new app has been added to chrome or has been
417 * enabled if previously disabled.
418 * @param {Object} appData A data structure full of relevant information for
419 * the app.
420 * @param {boolean=} opt_highlight Whether the app about to be added should
421 * be highlighted.
422 */
423 appAdded: function(appData, opt_highlight) {
424 assert(loadTimeData.getBoolean('showApps'));
425
426 if (appData.id == this.highlightAppId) {
427 opt_highlight = true;
428 this.highlightAppId = null;
429 }
430
431 var pageIndex = appData.page_index || 0;
432
433 if (pageIndex >= this.appsPages.length) {
434 while (pageIndex >= this.appsPages.length) {
435 this.appendTilePage(new ntp.AppsPage(),
436 loadTimeData.getString('appDefaultPageName'),
437 true);
438 }
439 this.updateSliderCards();
440 }
441
442 var page = this.appsPages[pageIndex];
443 var app = $(appData.id);
444 if (app) {
445 app.replaceAppData(appData);
446 } else if (opt_highlight) {
447 page.insertAndHighlightApp(appData);
448 this.setShownPage_(loadTimeData.getInteger('apps_page_id'),
449 appData.page_index);
450 } else {
451 page.insertApp(appData, false);
452 }
453 },
454
455 /**
456 * Callback invoked by chrome whenever an app preference changes.
457 * @param {Object} data An object with all the data on available
458 * applications.
459 */
460 appsPrefChangedCallback: function(data) {
461 assert(loadTimeData.getBoolean('showApps'));
462
463 for (var i = 0; i < data.apps.length; ++i) {
464 $(data.apps[i].id).appData = data.apps[i];
465 }
466
467 // Set the App dot names. Skip the first dot (Most Visited).
468 var dots = this.dotList.getElementsByClassName('dot');
469 var start = this.mostVisitedPage ? 1 : 0;
470 for (var i = start; i < dots.length; ++i) {
471 dots[i].displayTitle = data.appPageNames[i - start] || '';
472 }
473 },
474
475 /**
476 * Invoked whenever the pages in apps-page-list have changed so that
477 * the Slider knows about the new elements.
478 */
479 updateSliderCards: function() {
480 var pageNo = Math.max(0, Math.min(this.cardSlider.currentCard,
481 this.tilePages.length - 1));
482 this.cardSlider.setCards(Array.prototype.slice.call(this.tilePages),
483 pageNo);
484 switch (this.shownPage) {
485 case loadTimeData.getInteger('apps_page_id'):
486 this.cardSlider.selectCardByValue(
487 this.appsPages[Math.min(this.shownPageIndex,
488 this.appsPages.length - 1)]);
489 break;
490 case loadTimeData.getInteger('most_visited_page_id'):
491 if (this.mostVisitedPage)
492 this.cardSlider.selectCardByValue(this.mostVisitedPage);
493 break;
494 case loadTimeData.getInteger('suggestions_page_id'):
495 if (this.suggestionsPage)
496 this.cardSlider.selectCardByValue(this.suggestionsPage);
497 break;
498 }
499 },
500
501 /**
502 * Called whenever tiles should be re-arranging themselves out of the way
503 * of a moving or insert tile.
504 */
505 enterRearrangeMode: function() {
506 if (loadTimeData.getBoolean('showApps')) {
507 var tempPage = new ntp.AppsPage();
508 tempPage.classList.add('temporary');
509 var pageName = loadTimeData.getString('appDefaultPageName');
510 this.appendTilePage(tempPage, pageName, true);
511 }
512
513 if (ntp.getCurrentlyDraggingTile().firstChild.canBeRemoved())
514 $('footer').classList.add('showing-trash-mode');
515
516 document.documentElement.classList.add('dragging-mode');
517 },
518
519 /**
520 * Invoked whenever some app is released
521 */
522 leaveRearrangeMode: function() {
523 var tempPage = document.querySelector('.tile-page.temporary');
524 if (tempPage) {
525 var dot = tempPage.navigationDot;
526 if (!tempPage.tileCount &&
527 tempPage != this.cardSlider.currentCardValue) {
528 this.removeTilePageAndDot_(tempPage, true);
529 } else {
530 tempPage.classList.remove('temporary');
531 this.saveAppPageName(tempPage,
532 loadTimeData.getString('appDefaultPageName'));
533 }
534 }
535
536 $('footer').classList.remove('showing-trash-mode');
537 document.documentElement.classList.remove('dragging-mode');
538 },
539
540 /**
541 * Callback for the 'pagelayout' event.
542 * @param {Event} e The event.
543 */
544 onPageLayout_: function(e) {
545 if (Array.prototype.indexOf.call(this.tilePages, e.currentTarget) !=
546 this.cardSlider.currentCard) {
547 return;
548 }
549
550 this.updatePageSwitchers();
551 },
552
553 /**
554 * Adjusts the size and position of the page switchers according to the
555 * layout of the current card.
556 */
557 updatePageSwitchers: function() {
558 return; // TODO(xci) delete
559 if (!this.pageSwitcherStart || !this.pageSwitcherEnd)
560 return;
561
562 var page = this.cardSlider.currentCardValue;
563
564 this.pageSwitcherStart.hidden = !page ||
565 (this.cardSlider.currentCard == 0);
566 this.pageSwitcherEnd.hidden = !page ||
567 (this.cardSlider.currentCard == this.cardSlider.cardCount - 1);
568
569 if (!page)
570 return;
571
572 var pageSwitcherLeft = isRTL() ? this.pageSwitcherEnd :
573 this.pageSwitcherStart;
574 var pageSwitcherRight = isRTL() ? this.pageSwitcherStart :
575 this.pageSwitcherEnd;
576 var scrollbarWidth = page.scrollbarWidth;
577 pageSwitcherLeft.style.width =
578 (page.sideMargin + 13) + 'px';
579 pageSwitcherLeft.style.left = '0';
580 pageSwitcherRight.style.width =
581 (page.sideMargin - scrollbarWidth + 13) + 'px';
582 pageSwitcherRight.style.right = scrollbarWidth + 'px';
583
584 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px';
585 pageSwitcherLeft.style.top = offsetTop;
586 pageSwitcherRight.style.top = offsetTop;
587 pageSwitcherLeft.style.paddingBottom = offsetTop;
588 pageSwitcherRight.style.paddingBottom = offsetTop;
589 },
590
591 /**
592 * Returns the index of the given apps page.
593 * @param {AppsPage} page The AppsPage we wish to find.
594 * @return {number} The index of |page| or -1 if it is not in the
595 * collection.
596 */
597 getAppsPageIndex: function(page) {
598 return Array.prototype.indexOf.call(this.appsPages, page);
599 },
600
601 /**
602 * Handler for cardSlider:card_changed events from this.cardSlider.
603 * @param {Event} e The cardSlider:card_changed event.
604 * @private
605 */
606 onCardChanged_: function(e) {
607 var page = e.cardSlider.currentCardValue;
608
609 // Don't change shownPage until startup is done (and page changes actually
610 // reflect user actions).
611 if (!this.isStartingUp_()) {
612 if (page.classList.contains('apps-page')) {
613 this.setShownPage_(loadTimeData.getInteger('apps_page_id'),
614 this.getAppsPageIndex(page));
615 } else if (page.classList.contains('most-visited-page')) {
616 this.setShownPage_(
617 loadTimeData.getInteger('most_visited_page_id'), 0);
618 } else if (page.classList.contains('suggestions-page')) {
619 this.setShownPage_(loadTimeData.getInteger('suggestions_page_id'), 0);
620 } else {
621 console.error('unknown page selected');
622 }
623 }
624
625 // Update the active dot
626 var curDot = this.dotList.getElementsByClassName('selected')[0];
627 if (curDot)
628 curDot.classList.remove('selected');
629 page.navigationDot.classList.add('selected');
630 this.updatePageSwitchers();
631 },
632
633 /**
634 * Saves/updates the newly selected page to open when first loading the NTP.
635 * @type {number} shownPage The new shown page type.
636 * @type {number} shownPageIndex The new shown page index.
637 * @private
638 */
639 setShownPage_: function(shownPage, shownPageIndex) {
640 assert(shownPageIndex >= 0);
641 this.shownPage = shownPage;
642 this.shownPageIndex = shownPageIndex;
643 chrome.send('pageSelected', [this.shownPage, this.shownPageIndex]);
644 },
645
646 /**
647 * Listen for card additions to update the page switchers or the current
648 * card accordingly.
649 * @param {Event} e A card removed or added event.
650 */
651 onCardAdded_: function(e) {
652 // When the second arg passed to insertBefore is falsey, it acts just like
653 // appendChild.
654 this.pageList.insertBefore(e.addedCard, this.tilePages[e.addedIndex]);
655 this.onCardAddedOrRemoved_();
656 },
657
658 /**
659 * Listen for card removals to update the page switchers or the current card
660 * accordingly.
661 * @param {Event} e A card removed or added event.
662 */
663 onCardRemoved_: function(e) {
664 e.removedCard.parentNode.removeChild(e.removedCard);
665 this.onCardAddedOrRemoved_();
666 },
667
668 /**
669 * Called when a card is removed or added.
670 * @private
671 */
672 onCardAddedOrRemoved_: function() {
673 if (this.isStartingUp_())
674 return;
675
676 // Without repositioning there were issues - http://crbug.com/133457.
677 this.cardSlider.repositionFrame();
678 this.updatePageSwitchers();
679 },
680
681 /**
682 * Save the name of an apps page.
683 * Store the apps page name into the preferences store.
684 * @param {AppsPage} appsPage The app page for which we wish to save.
685 * @param {string} name The name of the page.
686 */
687 saveAppPageName: function(appPage, name) {
688 var index = this.getAppsPageIndex(appPage);
689 assert(index != -1);
690 chrome.send('saveAppPageName', [name, index]);
691 },
692
693 /**
694 * Window resize handler.
695 * @private
696 */
697 onWindowResize_: function(e) {
698 this.cardSlider.resize(this.sliderFrame.offsetWidth);
699 this.updatePageSwitchers();
700 },
701
702 /**
703 * Listener for offline status change events. Updates apps that are
704 * not offline-enabled to be grayscale if the browser is offline.
705 * @private
706 */
707 updateOfflineEnabledApps_: function() {
708 var apps = document.querySelectorAll('.app');
709 for (var i = 0; i < apps.length; ++i) {
710 if (apps[i].appData.enabled && !apps[i].appData.offline_enabled) {
711 apps[i].setIcon();
712 apps[i].loadIcon();
713 }
714 }
715 },
716
717 /**
718 * Handler for key events on the page. Ctrl-Arrow will switch the visible
719 * page.
720 * @param {Event} e The KeyboardEvent.
721 * @private
722 */
723 onDocKeyDown_: function(e) {
724 if (!e.ctrlKey || e.altKey || e.metaKey || e.shiftKey)
725 return;
726
727 var direction = 0;
728 if (e.keyIdentifier == 'Left')
729 direction = -1;
730 else if (e.keyIdentifier == 'Right')
731 direction = 1;
732 else
733 return;
734
735 var cardIndex =
736 (this.cardSlider.currentCard + direction +
737 this.cardSlider.cardCount) % this.cardSlider.cardCount;
738 this.cardSlider.selectCard(cardIndex, true);
739
740 e.stopPropagation();
741 },
742
743 /**
744 * Returns the index of a given tile page.
745 * @param {TilePage} page The TilePage we wish to find.
746 * @return {number} The index of |page| or -1 if it is not in the
747 * collection.
748 */
749 getTilePageIndex: function(page) {
750 return Array.prototype.indexOf.call(this.tilePages, page);
751 },
752
753 /**
754 * Removes a page and navigation dot (if the navdot exists).
755 * @param {TilePage} page The page to be removed.
756 * @param {boolean=} opt_animate If the removal should be animated.
757 */
758 removeTilePageAndDot_: function(page, opt_animate) {
759 if (page.navigationDot)
760 page.navigationDot.remove(opt_animate);
761 this.cardSlider.removeCard(page);
762 },
763 };
764
765 return {
766 PageListView: PageListView
767 };
768 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698