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