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 New tab page | 6 * @fileoverview New tab page |
7 * This is the main code for the new tab page used by touch-enabled Chrome | 7 * This is the main code for the new tab page used by touch-enabled Chrome |
8 * browsers. For now this is still a prototype. | 8 * browsers. For now this is still a prototype. |
9 */ | 9 */ |
10 | 10 |
11 // Use an anonymous function to enable strict mode just for this file (which | 11 // Use an anonymous function to enable strict mode just for this file (which |
12 // will be concatenated with other files when embedded in Chrome | 12 // will be concatenated with other files when embedded in Chrome |
13 cr.define('ntp4', function() { | 13 cr.define('ntp4', function() { |
14 'use strict'; | 14 'use strict'; |
15 | 15 |
16 /** | 16 /** |
17 * The CardSlider object to use for changing app pages. | 17 * NewTabView instance. |
18 * @type {CardSlider|undefined} | 18 * @type {!Object|undefined} |
19 */ | 19 */ |
20 var cardSlider; | 20 var newTabView; |
21 | |
22 /** | |
23 * The 'page-list' element. | |
24 * @type {!Element|undefined} | |
25 */ | |
26 var pageList; | |
27 | |
28 /** | |
29 * A list of all 'tile-page' elements. | |
30 * @type {!NodeList|undefined} | |
31 */ | |
32 var tilePages; | |
33 | |
34 /** | |
35 * The Most Visited page. | |
36 * @type {!Element|undefined} | |
37 */ | |
38 var mostVisitedPage; | |
39 | |
40 /** | |
41 * A list of all 'apps-page' elements. | |
42 * @type {!NodeList|undefined} | |
43 */ | |
44 var appsPages; | |
45 | |
46 /** | |
47 * The Bookmarks page. | |
48 * @type {!Element|undefined} | |
49 */ | |
50 var bookmarksPage; | |
51 | |
52 /** | |
53 * The 'dots-list' element. | |
54 * @type {!Element|undefined} | |
55 */ | |
56 var dotList; | |
57 | |
58 /** | |
59 * Live list of the navigation dots. | |
60 * @type {!NodeList|undefined} | |
61 */ | |
62 var navDots; | |
63 | 21 |
64 /** | 22 /** |
65 * The 'notification-container' element. | 23 * The 'notification-container' element. |
66 * @type {!Element|undefined} | 24 * @type {!Element|undefined} |
67 */ | 25 */ |
68 var notificationContainer; | 26 var notificationContainer; |
69 | 27 |
70 /** | 28 /** |
71 * The left and right paging buttons. | |
72 * @type {!Element|undefined} | |
73 */ | |
74 var pageSwitcherStart; | |
75 var pageSwitcherEnd; | |
76 | |
77 /** | |
78 * The 'trash' element. Note that technically this is unnecessary, | |
79 * JavaScript creates the object for us based on the id. But I don't want | |
80 * to rely on the ID being the same, and JSCompiler doesn't know about it. | |
81 * @type {!Element|undefined} | |
82 */ | |
83 var trash; | |
84 | |
85 /** | |
86 * The type of page that is currently shown. The value is a numerical ID. | |
87 * @type {number} | |
88 */ | |
89 var shownPage = 0; | |
90 | |
91 /** | |
92 * The index of the page that is currently shown, within the page type. | |
93 * For example if the third Apps page is showing, this will be 2. | |
94 * @type {number} | |
95 */ | |
96 var shownPageIndex = 0; | |
97 | |
98 /** | |
99 * EventTracker for managing event listeners for page events. | |
100 * @type {!EventTracker} | |
101 */ | |
102 var eventTracker = new EventTracker; | |
103 | |
104 /** | |
105 * Object for accessing localized strings. | 29 * Object for accessing localized strings. |
106 * @type {!LocalStrings} | 30 * @type {!LocalStrings} |
107 */ | 31 */ |
108 var localStrings = new LocalStrings; | 32 var localStrings = new LocalStrings; |
109 | 33 |
110 /** | 34 /** |
111 * If non-null, this is the ID of the app to highlight to the user the next | |
112 * time getAppsCallback runs. "Highlight" in this case means to switch to | |
113 * the page and run the new tile animation. | |
114 * @type {String} | |
115 */ | |
116 var highlightAppId = null; | |
117 | |
118 /** | |
119 * If non-null, an info bubble for showing messages to the user. It points at | 35 * If non-null, an info bubble for showing messages to the user. It points at |
120 * the Most Visited label, and is used to draw more attention to the | 36 * the Most Visited label, and is used to draw more attention to the |
121 * navigation dot UI. | 37 * navigation dot UI. |
122 * @type {!Element|undefined} | 38 * @type {!Element|undefined} |
123 */ | 39 */ |
124 var infoBubble; | 40 var infoBubble; |
125 | 41 |
126 /** | 42 /** |
127 * If non-null, an bubble confirming that the user has signed into sync. It | 43 * If non-null, an bubble confirming that the user has signed into sync. It |
128 * points at the login status at the top of the page. | 44 * points at the login status at the top of the page. |
(...skipping 10 matching lines...) Expand all Loading... | |
139 /** | 55 /** |
140 * The time in milliseconds for most transitions. This should match what's | 56 * The time in milliseconds for most transitions. This should match what's |
141 * in new_tab.css. Unfortunately there's no better way to try to time | 57 * in new_tab.css. Unfortunately there's no better way to try to time |
142 * something to occur until after a transition has completed. | 58 * something to occur until after a transition has completed. |
143 * @type {number} | 59 * @type {number} |
144 * @const | 60 * @const |
145 */ | 61 */ |
146 var DEFAULT_TRANSITION_TIME = 500; | 62 var DEFAULT_TRANSITION_TIME = 500; |
147 | 63 |
148 /** | 64 /** |
65 * Creates a NewTabView object. NewTabView extends PageListView with | |
66 * new tab UI specific logics. | |
67 * @constructor | |
68 * @extends {PageListView} | |
69 */ | |
70 function NewTabView() { | |
71 this.initialize(getRequiredElement('page-list'), | |
72 getRequiredElement('dot-list'), | |
73 getRequiredElement('card-slider-frame'), | |
74 getRequiredElement('trash'), | |
75 $('page-switcher-start'), | |
Evan Stade
2011/11/10 00:02:21
getRequiredElement?
xiyuan
2011/11/10 18:25:07
Done.
| |
76 $('page-switcher-end')); | |
77 } | |
78 | |
79 NewTabView.prototype = { | |
80 __proto__: ntp4.PageListView.prototype, | |
81 | |
82 /** @inheritDoc */ | |
83 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { | |
84 ntp4.PageListView.prototype.appendTilePage.apply(this, arguments); | |
85 | |
86 if (infoBubble) | |
87 window.setTimeout(infoBubble.reposition.bind(infoBubble), 0); | |
88 } | |
89 }; | |
90 | |
91 /** | |
149 * Invoked at startup once the DOM is available to initialize the app. | 92 * Invoked at startup once the DOM is available to initialize the app. |
150 */ | 93 */ |
151 function initialize() { | 94 function load() { |
152 cr.enablePlatformSpecificCSSRules(); | 95 cr.enablePlatformSpecificCSSRules(); |
153 | 96 |
154 // Load the current theme colors. | 97 // Load the current theme colors. |
155 themeChanged(); | 98 themeChanged(); |
156 | 99 |
157 dotList = getRequiredElement('dot-list'); | 100 newTabView = new NewTabView(); |
158 dotList.addEventListener('keydown', onDotListKeyDown); | |
159 navDots = dotList.getElementsByClassName('dot'); | |
160 | |
161 pageList = getRequiredElement('page-list'); | |
162 trash = getRequiredElement('trash'); | |
163 new ntp4.Trash(trash); | |
164 | |
165 shownPage = templateData['shown_page_type']; | |
166 shownPageIndex = templateData['shown_page_index']; | |
167 | |
168 // Request data on the apps so we can fill them in. | |
169 // Note that this is kicked off asynchronously. 'getAppsCallback' will be | |
170 // invoked at some point after this function returns. | |
171 chrome.send('getApps'); | |
172 | |
173 document.addEventListener('keydown', onKeyDown); | |
174 // Prevent touch events from triggering any sort of native scrolling | |
175 document.addEventListener('touchmove', function(e) { | |
176 e.preventDefault(); | |
177 }, true); | |
178 | |
179 tilePages = pageList.getElementsByClassName('tile-page'); | |
180 appsPages = pageList.getElementsByClassName('apps-page'); | |
181 | |
182 pageSwitcherStart = getRequiredElement('page-switcher-start'); | |
183 ntp4.initializePageSwitcher(pageSwitcherStart); | |
184 pageSwitcherEnd = getRequiredElement('page-switcher-end'); | |
185 ntp4.initializePageSwitcher(pageSwitcherEnd); | |
186 | 101 |
187 notificationContainer = getRequiredElement('notification-container'); | 102 notificationContainer = getRequiredElement('notification-container'); |
188 notificationContainer.addEventListener( | 103 notificationContainer.addEventListener( |
189 'webkitTransitionEnd', onNotificationTransitionEnd); | 104 'webkitTransitionEnd', onNotificationTransitionEnd); |
190 | 105 |
191 // Initialize the cardSlider without any cards at the moment | |
192 var sliderFrame = getRequiredElement('card-slider-frame'); | |
193 cardSlider = new CardSlider(sliderFrame, pageList, sliderFrame.offsetWidth); | |
194 cardSlider.initialize(); | |
195 | |
196 // Ensure the slider is resized appropriately with the window | |
197 window.addEventListener('resize', function() { | |
198 cardSlider.resize(sliderFrame.offsetWidth); | |
199 updatePageSwitchers(); | |
200 }); | |
201 | |
202 // Handle the page being changed | |
203 pageList.addEventListener( | |
204 CardSlider.EventType.CARD_CHANGED, | |
205 cardChangedHandler); | |
206 | |
207 cr.ui.decorate($('recently-closed-menu-button'), ntp4.RecentMenuButton); | 106 cr.ui.decorate($('recently-closed-menu-button'), ntp4.RecentMenuButton); |
208 chrome.send('getRecentlyClosedTabs'); | 107 chrome.send('getRecentlyClosedTabs'); |
209 | 108 |
210 mostVisitedPage = new ntp4.MostVisitedPage(); | 109 newTabView.appendTilePage(new ntp4.MostVisitedPage(), |
211 appendTilePage(mostVisitedPage, localStrings.getString('mostvisited'), | 110 localStrings.getString('mostvisited'), |
212 false); | 111 false); |
213 chrome.send('getMostVisited'); | 112 chrome.send('getMostVisited'); |
214 | 113 |
215 if (localStrings.getString('login_status_message')) { | 114 if (localStrings.getString('login_status_message')) { |
216 loginBubble = new cr.ui.Bubble; | 115 loginBubble = new cr.ui.Bubble; |
217 loginBubble.anchorNode = $('login-container'); | 116 loginBubble.anchorNode = $('login-container'); |
218 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); | 117 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); |
219 loginBubble.bubbleAlignment = | 118 loginBubble.bubbleAlignment = |
220 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; | 119 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; |
221 loginBubble.deactivateToDismissDelay = 2000; | 120 loginBubble.deactivateToDismissDelay = 2000; |
222 loginBubble.setCloseButtonVisible(false); | 121 loginBubble.setCloseButtonVisible(false); |
(...skipping 12 matching lines...) Expand all Loading... | |
235 } | 134 } |
236 | 135 |
237 var dismissButton = loginBubble.querySelector('#login-status-dismiss'); | 136 var dismissButton = loginBubble.querySelector('#login-status-dismiss'); |
238 dismissButton.onclick = loginBubble.hide.bind(loginBubble); | 137 dismissButton.onclick = loginBubble.hide.bind(loginBubble); |
239 | 138 |
240 // The anchor node won't be updated until updateLogin is called so don't | 139 // The anchor node won't be updated until updateLogin is called so don't |
241 // show the bubble yet. | 140 // show the bubble yet. |
242 shouldShowLoginBubble = true; | 141 shouldShowLoginBubble = true; |
243 } else if (localStrings.getString('ntp4_intro_message')) { | 142 } else if (localStrings.getString('ntp4_intro_message')) { |
244 infoBubble = new cr.ui.Bubble; | 143 infoBubble = new cr.ui.Bubble; |
245 infoBubble.anchorNode = mostVisitedPage.navigationDot; | 144 infoBubble.anchorNode = newTabView.mostVisitedPage.navigationDot; |
246 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); | 145 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); |
247 infoBubble.handleCloseEvent = function() { | 146 infoBubble.handleCloseEvent = function() { |
248 this.hide(); | 147 this.hide(); |
249 chrome.send('introMessageDismissed'); | 148 chrome.send('introMessageDismissed'); |
250 } | 149 } |
251 | 150 |
252 var bubbleContent = $('ntp4-intro-bubble-contents'); | 151 var bubbleContent = $('ntp4-intro-bubble-contents'); |
253 infoBubble.content = bubbleContent; | 152 infoBubble.content = bubbleContent; |
254 bubbleContent.hidden = false; | 153 bubbleContent.hidden = false; |
255 | 154 |
256 var learnMoreLink = infoBubble.querySelector('a'); | 155 var learnMoreLink = infoBubble.querySelector('a'); |
257 learnMoreLink.href = localStrings.getString('ntp4_intro_url'); | 156 learnMoreLink.href = localStrings.getString('ntp4_intro_url'); |
258 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); | 157 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); |
259 | 158 |
260 infoBubble.show(); | 159 infoBubble.show(); |
261 } | 160 } |
262 | 161 |
263 var bookmarkFeatures = localStrings.getString('bookmark_features'); | 162 var bookmarkFeatures = localStrings.getString('bookmark_features'); |
264 if (bookmarkFeatures == 'true') { | 163 if (bookmarkFeatures == 'true') { |
265 bookmarksPage = new ntp4.BookmarksPage(); | 164 newTabView.appendTilePage(new ntp4.BookmarksPage(), |
266 appendTilePage(bookmarksPage, localStrings.getString('bookmarksPage'), | 165 localStrings.getString('bookmarksPage'), |
267 false); | 166 false); |
268 chrome.send('getBookmarksData'); | 167 chrome.send('getBookmarksData'); |
269 } | 168 } |
270 | 169 |
271 var serverpromo = localStrings.getString('serverpromo'); | 170 var serverpromo = localStrings.getString('serverpromo'); |
272 if (serverpromo) { | 171 if (serverpromo) { |
273 showNotification(parseHtmlSubset(serverpromo), [], function() { | 172 showNotification(parseHtmlSubset(serverpromo), [], function() { |
274 chrome.send('closeNotificationPromo'); | 173 chrome.send('closeNotificationPromo'); |
275 }, 60000); | 174 }, 60000); |
276 chrome.send('notificationPromoViewed'); | 175 chrome.send('notificationPromoViewed'); |
277 } | 176 } |
278 | 177 |
279 var loginContainer = getRequiredElement('login-container'); | 178 var loginContainer = getRequiredElement('login-container'); |
280 loginContainer.addEventListener('click', function() { | 179 loginContainer.addEventListener('click', function() { |
281 var rect = loginContainer.getBoundingClientRect(); | 180 var rect = loginContainer.getBoundingClientRect(); |
282 chrome.send('showSyncLoginUI', | 181 chrome.send('showSyncLoginUI', |
283 [rect.left, rect.top, rect.width, rect.height]); | 182 [rect.left, rect.top, rect.width, rect.height]); |
284 }); | 183 }); |
285 chrome.send('initializeSyncLogin'); | 184 chrome.send('initializeSyncLogin'); |
286 } | 185 } |
287 | 186 |
288 /** | |
289 * Simple common assertion API | |
290 * @param {*} condition The condition to test. Note that this may be used to | |
291 * test whether a value is defined or not, and we don't want to force a | |
292 * cast to Boolean. | |
293 * @param {string=} opt_message A message to use in any error. | |
294 */ | |
295 function assert(condition, opt_message) { | |
296 'use strict'; | |
297 if (!condition) { | |
298 var msg = 'Assertion failed'; | |
299 if (opt_message) | |
300 msg = msg + ': ' + opt_message; | |
301 throw new Error(msg); | |
302 } | |
303 } | |
304 | |
305 /** | |
306 * Get an element that's known to exist by its ID. We use this instead of just | |
307 * calling getElementById and not checking the result because this lets us | |
308 * satisfy the JSCompiler type system. | |
309 * @param {string} id The identifier name. | |
310 * @return {!Element} the Element. | |
311 */ | |
312 function getRequiredElement(id) { | |
313 var element = document.getElementById(id); | |
314 assert(element, 'Missing required element: ' + id); | |
315 return element; | |
316 } | |
317 | |
318 /** | |
319 * Callback invoked by chrome with the apps available. | |
320 * | |
321 * Note that calls to this function can occur at any time, not just in | |
322 * response to a getApps request. For example, when a user installs/uninstalls | |
323 * an app on another synchronized devices. | |
324 * @param {Object} data An object with all the data on available | |
325 * applications. | |
326 */ | |
327 function getAppsCallback(data) { | |
328 var startTime = Date.now(); | |
329 | |
330 // Clear any existing apps pages and dots. | |
331 // TODO(rbyers): It might be nice to preserve animation of dots after an | |
332 // uninstall. Could we re-use the existing page and dot elements? It seems | |
333 // unfortunate to have Chrome send us the entire apps list after an | |
334 // uninstall. | |
335 while (appsPages.length > 0) { | |
336 var page = appsPages[0]; | |
337 var dot = page.navigationDot; | |
338 | |
339 eventTracker.remove(page); | |
340 page.tearDown(); | |
341 page.parentNode.removeChild(page); | |
342 dot.parentNode.removeChild(dot); | |
343 } | |
344 | |
345 // Get the array of apps and add any special synthesized entries | |
346 var apps = data.apps; | |
347 | |
348 // Get a list of page names | |
349 var pageNames = data.appPageNames; | |
350 | |
351 function stringListIsEmpty(list) { | |
352 for (var i = 0; i < list.length; i++) { | |
353 if (list[i]) | |
354 return false; | |
355 } | |
356 return true; | |
357 } | |
358 | |
359 // Sort by launch index | |
360 apps.sort(function(a, b) { | |
361 return a.app_launch_index - b.app_launch_index; | |
362 }); | |
363 | |
364 // An app to animate (in case it was just installed). | |
365 var highlightApp; | |
366 | |
367 // Add the apps, creating pages as necessary | |
368 for (var i = 0; i < apps.length; i++) { | |
369 var app = apps[i]; | |
370 var pageIndex = (app.page_index || 0); | |
371 while (pageIndex >= appsPages.length) { | |
372 var pageName = localStrings.getString('appDefaultPageName'); | |
373 if (appsPages.length < pageNames.length) | |
374 pageName = pageNames[appsPages.length]; | |
375 | |
376 var origPageCount = appsPages.length; | |
377 appendTilePage(new ntp4.AppsPage(), pageName, true, bookmarksPage); | |
378 // Confirm that appsPages is a live object, updated when a new page is | |
379 // added (otherwise we'd have an infinite loop) | |
380 assert(appsPages.length == origPageCount + 1, 'expected new page'); | |
381 } | |
382 | |
383 if (app.id == highlightAppId) | |
384 highlightApp = app; | |
385 else | |
386 appsPages[pageIndex].appendApp(app); | |
387 } | |
388 | |
389 ntp4.AppsPage.setPromo(data.showPromo ? data : null); | |
390 | |
391 // Tell the slider about the pages. | |
392 updateSliderCards(); | |
393 | |
394 if (highlightApp) | |
395 appAdded(highlightApp, true); | |
396 | |
397 // Mark the current page. | |
398 cardSlider.currentCardValue.navigationDot.classList.add('selected'); | |
399 logEvent('apps.layout: ' + (Date.now() - startTime)); | |
400 | |
401 document.documentElement.classList.remove('starting-up'); | |
402 } | |
403 | |
404 /** | |
405 * Called by chrome when a new app has been added to chrome or has been | |
406 * enabled if previously disabled. | |
407 * @param {Object} appData A data structure full of relevant information for | |
408 * the app. | |
409 */ | |
410 function appAdded(appData, opt_highlight) { | |
411 if (appData.id == highlightAppId) { | |
412 opt_highlight = true; | |
413 highlightAppId = null; | |
414 } | |
415 | |
416 var pageIndex = appData.page_index || 0; | |
417 | |
418 if (pageIndex >= appsPages.length) { | |
419 while (pageIndex >= appsPages.length) { | |
420 appendTilePage(new ntp4.AppsPage(), | |
421 localStrings.getString('appDefaultPageName'), true, | |
422 bookmarksPage); | |
423 } | |
424 updateSliderCards(); | |
425 } | |
426 | |
427 var page = appsPages[pageIndex]; | |
428 var app = $(appData.id); | |
429 if (app) | |
430 app.replaceAppData(appData); | |
431 else | |
432 page.appendApp(appData, opt_highlight); | |
433 } | |
434 | |
435 /** | |
436 * Sets that an app should be highlighted if it is added. Called right before | |
437 * appAdded for new installs. | |
438 */ | |
439 function setAppToBeHighlighted(appId) { | |
440 highlightAppId = appId; | |
441 } | |
442 | |
443 /** | |
444 * Called by chrome when an existing app has been disabled or | |
445 * removed/uninstalled from chrome. | |
446 * @param {Object} appData A data structure full of relevant information for | |
447 * the app. | |
448 * @param {boolean} isUninstall True if the app is being uninstalled; | |
449 * false if the app is being disabled. | |
450 */ | |
451 function appRemoved(appData, isUninstall) { | |
452 var app = $(appData.id); | |
453 assert(app, 'trying to remove an app that doesn\'t exist'); | |
454 | |
455 if (!isUninstall) | |
456 app.replaceAppData(appData); | |
457 else | |
458 app.remove(); | |
459 } | |
460 | |
461 /** | |
462 * Given a theme resource name, construct a URL for it. | |
463 * @param {string} resourceName The name of the resource. | |
464 * @return {string} A url which can be used to load the resource. | |
465 */ | |
466 function getThemeUrl(resourceName) { | |
467 return 'chrome://theme/' + resourceName; | |
468 } | |
469 | |
470 /** | |
471 * Callback invoked by chrome whenever an app preference changes. | |
472 * @param {Object} data An object with all the data on available | |
473 * applications. | |
474 */ | |
475 function appsPrefChangeCallback(data) { | |
476 for (var i = 0; i < data.apps.length; ++i) { | |
477 $(data.apps[i].id).appData = data.apps[i]; | |
478 } | |
479 | |
480 // Set the App dot names. Skip the first and last dots (Most Visited and | |
481 // Bookmarks). | |
482 var dots = dotList.getElementsByClassName('dot'); | |
483 // TODO(csilv): Remove this calcluation if/when we remove the flag for | |
484 // for the bookmarks page. | |
485 var length = bookmarksPage ? dots.length - 1 : dots.length; | |
486 for (var i = 1; i < length; ++i) { | |
487 dots[i].displayTitle = data.appPageNames[i - 1] || ''; | |
488 } | |
489 } | |
490 | |
491 /** | |
492 * Listener for offline status change events. Updates apps that are | |
493 * not offline-enabled to be grayscale if the browser is offline. | |
494 */ | |
495 function updateOfflineEnabledApps() { | |
496 var apps = document.querySelectorAll('.app'); | |
497 for (var i = 0; i < apps.length; ++i) { | |
498 if (apps[i].appData.enabled && !apps[i].appData.offline_enabled) { | |
499 apps[i].setIcon(); | |
500 apps[i].loadIcon(); | |
501 } | |
502 } | |
503 } | |
504 | |
505 function getCardSlider() { | |
506 return cardSlider; | |
507 } | |
508 | |
509 /** | |
510 * Invoked whenever the pages in apps-page-list have changed so that | |
511 * the Slider knows about the new elements. | |
512 */ | |
513 function updateSliderCards() { | |
514 var pageNo = Math.min(cardSlider.currentCard, tilePages.length - 1); | |
515 cardSlider.setCards(Array.prototype.slice.call(tilePages), pageNo); | |
516 switch (shownPage) { | |
517 case templateData['apps_page_id']: | |
518 cardSlider.selectCardByValue( | |
519 appsPages[Math.min(shownPageIndex, appsPages.length - 1)]); | |
520 break; | |
521 case templateData['bookmarks_page_id']: | |
522 if (bookmarksPage) | |
523 cardSlider.selectCardByValue(bookmarksPage); | |
524 break; | |
525 case templateData['most_visited_page_id']: | |
526 cardSlider.selectCardByValue(mostVisitedPage); | |
527 break; | |
528 } | |
529 } | |
530 | |
531 /** | |
532 * Appends a tile page (for bookmarks or most visited). | |
533 * | |
534 * @param {TilePage} page The page element. | |
535 * @param {string} title The title of the tile page. | |
536 * @param {bool} titleIsEditable If true, the title can be changed. | |
537 * @param {TilePage} opt_refNode Optional reference node to insert in front | |
538 * of. | |
539 * When opt_refNode is falsey, |page| will just be appended to the end of the | |
540 * page list. | |
541 */ | |
542 function appendTilePage(page, title, titleIsEditable, opt_refNode) { | |
543 // When opt_refNode is falsey, insertBefore acts just like appendChild. | |
544 pageList.insertBefore(page, opt_refNode); | |
545 | |
546 // If we're appending an AppsPage and it's a temporary page, animate it. | |
547 var animate = page instanceof ntp4.AppsPage && | |
548 page.classList.contains('temporary'); | |
549 // Make a deep copy of the dot template to add a new one. | |
550 var newDot = new ntp4.NavDot(page, title, titleIsEditable, animate); | |
551 page.navigationDot = newDot; | |
552 dotList.insertBefore(newDot, opt_refNode ? opt_refNode.navigationDot | |
553 : null); | |
554 // Set a tab index on the first dot. | |
555 if (navDots.length == 1) | |
556 newDot.tabIndex = 3; | |
557 | |
558 if (infoBubble) | |
559 window.setTimeout(infoBubble.reposition.bind(infoBubble), 0); | |
560 | |
561 eventTracker.add(page, 'pagelayout', onPageLayout); | |
562 } | |
563 | |
564 /** | |
565 * Search an elements ancestor chain for the nearest element that is a member | |
566 * of the specified class. | |
567 * @param {!Element} element The element to start searching from. | |
568 * @param {string} className The name of the class to locate. | |
569 * @return {Element} The first ancestor of the specified class or null. | |
570 */ | |
571 function getParentByClassName(element, className) { | |
572 for (var e = element; e; e = e.parentElement) { | |
573 if (e.classList.contains(className)) | |
574 return e; | |
575 } | |
576 return null; | |
577 } | |
578 | |
579 /** | |
580 * Called whenever tiles should be re-arranging themselves out of the way of a | |
581 * moving or insert tile. | |
582 */ | |
583 function enterRearrangeMode() { | |
584 var tempPage = new ntp4.AppsPage(); | |
585 tempPage.classList.add('temporary'); | |
586 appendTilePage(tempPage, localStrings.getString('appDefaultPageName'), | |
587 true, bookmarksPage); | |
588 var tempIndex = Array.prototype.indexOf.call(tilePages, tempPage); | |
589 if (cardSlider.currentCard >= tempIndex) | |
590 cardSlider.currentCard += 1; | |
591 updateSliderCards(); | |
592 | |
593 if (ntp4.getCurrentlyDraggingTile().firstChild.canBeRemoved()) | |
594 $('footer').classList.add('showing-trash-mode'); | |
595 } | |
596 | |
597 /** | |
598 * Invoked whenever some app is released | |
599 * @param {Grabber.Event} e The Grabber RELEASE event. | |
600 */ | |
601 function leaveRearrangeMode(e) { | |
602 var tempPage = document.querySelector('.tile-page.temporary'); | |
603 var dot = tempPage.navigationDot; | |
604 if (!tempPage.tileCount && tempPage != cardSlider.currentCardValue) { | |
605 dot.animateRemove(); | |
606 var tempIndex = Array.prototype.indexOf.call(tilePages, tempPage); | |
607 if (cardSlider.currentCard > tempIndex) | |
608 cardSlider.currentCard -= 1; | |
609 tempPage.parentNode.removeChild(tempPage); | |
610 updateSliderCards(); | |
611 } else { | |
612 tempPage.classList.remove('temporary'); | |
613 saveAppPageName(tempPage, localStrings.getString('appDefaultPageName')); | |
614 } | |
615 | |
616 $('footer').classList.remove('showing-trash-mode'); | |
617 } | |
618 | |
619 /** | |
620 * Handler for key events on the page. Ctrl-Arrow will switch the visible | |
621 * page. | |
622 * @param {Event} e The KeyboardEvent. | |
623 */ | |
624 function onKeyDown(e) { | |
625 if (!e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) | |
626 return; | |
627 | |
628 var direction = 0; | |
629 if (e.keyIdentifier == 'Left') | |
630 direction = -1; | |
631 else if (e.keyIdentifier == 'Right') | |
632 direction = 1; | |
633 else | |
634 return; | |
635 | |
636 var cardIndex = | |
637 (cardSlider.currentCard + direction + cardSlider.cardCount) % | |
638 cardSlider.cardCount; | |
639 cardSlider.selectCard(cardIndex, true); | |
640 | |
641 e.stopPropagation(); | |
642 } | |
643 | |
644 /** | |
645 * Handler for key events on the dot list. These keys will change the focus | |
646 * element. | |
647 * @param {Event} e The KeyboardEvent. | |
648 */ | |
649 function onDotListKeyDown(e) { | |
650 if (e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) | |
651 return; | |
652 | |
653 var direction = 0; | |
654 if (e.keyIdentifier == 'Left') | |
655 direction = -1; | |
656 else if (e.keyIdentifier == 'Right') | |
657 direction = 1; | |
658 else | |
659 return; | |
660 | |
661 var focusDot = dotList.querySelector('.dot:focus'); | |
662 if (!focusDot) | |
663 return; | |
664 var focusIndex = Array.prototype.indexOf.call(navDots, focusDot); | |
665 var newFocusIndex = focusIndex + direction; | |
666 if (focusIndex == newFocusIndex) | |
667 return; | |
668 | |
669 newFocusIndex = (newFocusIndex + navDots.length) % navDots.length; | |
670 navDots[newFocusIndex].tabIndex = 3; | |
671 navDots[newFocusIndex].focus(); | |
672 focusDot.tabIndex = -1; | |
673 | |
674 e.stopPropagation(); | |
675 e.preventDefault(); | |
676 } | |
677 | |
678 /** | |
679 * Callback for the 'click' event on a page switcher. | |
680 * @param {Event} e The event. | |
681 */ | |
682 function onPageSwitcherClicked(e) { | |
683 cardSlider.selectCard(cardSlider.currentCard + | |
684 (e.currentTarget == pageSwitcherStart ? -1 : 1), true); | |
685 } | |
686 | |
687 /** | |
688 * Handler for the mousewheel event on a pager. We pass through the scroll | |
689 * to the page. | |
690 * @param {Event} e The mousewheel event. | |
691 */ | |
692 function onPageSwitcherScrolled(e) { | |
693 cardSlider.currentCardValue.scrollBy(-e.wheelDeltaY); | |
694 }; | |
695 | |
696 /** | |
697 * Callback for the 'pagelayout' event. | |
698 * @param {Event} e The event. | |
699 */ | |
700 function onPageLayout(e) { | |
701 if (Array.prototype.indexOf.call(tilePages, e.currentTarget) != | |
702 cardSlider.currentCard) { | |
703 return; | |
704 } | |
705 | |
706 updatePageSwitchers(); | |
707 } | |
708 | |
709 /** | |
710 * Adjusts the size and position of the page switchers according to the | |
711 * layout of the current card. | |
712 */ | |
713 function updatePageSwitchers() { | |
714 var page = cardSlider.currentCardValue; | |
715 | |
716 pageSwitcherStart.hidden = !page || (cardSlider.currentCard == 0); | |
717 pageSwitcherEnd.hidden = !page || | |
718 (cardSlider.currentCard == cardSlider.cardCount - 1); | |
719 | |
720 if (!page) | |
721 return; | |
722 | |
723 var pageSwitcherLeft = isRTL() ? pageSwitcherEnd : pageSwitcherStart; | |
724 var pageSwitcherRight = isRTL() ? pageSwitcherStart : pageSwitcherEnd; | |
725 var scrollbarWidth = page.scrollbarWidth; | |
726 pageSwitcherLeft.style.width = | |
727 (page.sideMargin + 13) + 'px'; | |
728 pageSwitcherLeft.style.left = '0'; | |
729 pageSwitcherRight.style.width = | |
730 (page.sideMargin - scrollbarWidth + 13) + 'px'; | |
731 pageSwitcherRight.style.right = scrollbarWidth + 'px'; | |
732 | |
733 var offsetTop = page.querySelector('.tile-page-content').offsetTop + 'px'; | |
734 pageSwitcherLeft.style.top = offsetTop; | |
735 pageSwitcherRight.style.top = offsetTop; | |
736 pageSwitcherLeft.style.paddingBottom = offsetTop; | |
737 pageSwitcherRight.style.paddingBottom = offsetTop; | |
738 } | |
739 | |
740 /** | |
741 * Returns the index of the given page. | |
742 * @param {AppsPage} page The AppsPage for we wish to find. | |
743 * @return {number} The index of |page|, or -1 if it is not here. | |
744 */ | |
745 function getAppsPageIndex(page) { | |
746 return Array.prototype.indexOf.call(appsPages, page); | |
747 } | |
748 | |
749 // TODO(estade): rename newtab.css to new_tab_theme.css | 187 // TODO(estade): rename newtab.css to new_tab_theme.css |
750 function themeChanged(hasAttribution) { | 188 function themeChanged(hasAttribution) { |
751 $('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now(); | 189 $('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now(); |
752 if (typeof hasAttribution != 'undefined') | 190 if (typeof hasAttribution != 'undefined') |
753 document.documentElement.setAttribute('hasattribution', hasAttribution); | 191 document.documentElement.setAttribute('hasattribution', hasAttribution); |
754 updateLogo(); | 192 updateLogo(); |
755 updateAttribution(); | 193 updateAttribution(); |
756 } | 194 } |
757 | 195 |
758 /** | 196 /** |
(...skipping 15 matching lines...) Expand all Loading... | |
774 if (document.documentElement.getAttribute('hasattribution') == 'true') { | 212 if (document.documentElement.getAttribute('hasattribution') == 'true') { |
775 $('attribution-img').src = | 213 $('attribution-img').src = |
776 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' + Date.now(); | 214 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' + Date.now(); |
777 attribution.hidden = false; | 215 attribution.hidden = false; |
778 } else { | 216 } else { |
779 attribution.hidden = true; | 217 attribution.hidden = true; |
780 } | 218 } |
781 } | 219 } |
782 | 220 |
783 /** | 221 /** |
784 * Handler for CARD_CHANGED on cardSlider. | |
785 * @param {Event} e The CARD_CHANGED event. | |
786 */ | |
787 function cardChangedHandler(e) { | |
788 var page = e.cardSlider.currentCardValue; | |
789 | |
790 // Don't change shownPage until startup is done (and page changes actually | |
791 // reflect user actions). | |
792 if (!document.documentElement.classList.contains('starting-up')) { | |
793 if (page.classList.contains('apps-page')) { | |
794 shownPage = templateData['apps_page_id']; | |
795 shownPageIndex = getAppsPageIndex(page); | |
796 } else if (page.classList.contains('most-visited-page')) { | |
797 shownPage = templateData['most_visited_page_id']; | |
798 shownPageIndex = 0; | |
799 } else if (page.classList.contains('bookmarks-page')) { | |
800 shownPage = templateData['bookmarks_page_id']; | |
801 shownPageIndex = 0; | |
802 } else { | |
803 console.error('unknown page selected'); | |
804 } | |
805 chrome.send('pageSelected', [shownPage, shownPageIndex]); | |
806 } | |
807 | |
808 // Update the active dot | |
809 var curDot = dotList.getElementsByClassName('selected')[0]; | |
810 if (curDot) | |
811 curDot.classList.remove('selected'); | |
812 page.navigationDot.classList.add('selected'); | |
813 updatePageSwitchers(); | |
814 } | |
815 | |
816 /** | |
817 * Timeout ID. | 222 * Timeout ID. |
818 * @type {number} | 223 * @type {number} |
819 */ | 224 */ |
820 var notificationTimeout_ = 0; | 225 var notificationTimeout_ = 0; |
821 | 226 |
822 /** | 227 /** |
823 * Shows the notification bubble. | 228 * Shows the notification bubble. |
824 * @param {string|Node} message The notification message or node to use as | 229 * @param {string|Node} message The notification message or node to use as |
825 * message. | 230 * message. |
826 * @param {Array.<{text: string, action: function()}>} links An array of | 231 * @param {Array.<{text: string, action: function()}>} links An array of |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
883 function onNotificationTransitionEnd(e) { | 288 function onNotificationTransitionEnd(e) { |
884 if (notificationContainer.classList.contains('inactive')); | 289 if (notificationContainer.classList.contains('inactive')); |
885 notificationContainer.hidden = true; | 290 notificationContainer.hidden = true; |
886 } | 291 } |
887 | 292 |
888 function setRecentlyClosedTabs(dataItems) { | 293 function setRecentlyClosedTabs(dataItems) { |
889 $('recently-closed-menu-button').dataItems = dataItems; | 294 $('recently-closed-menu-button').dataItems = dataItems; |
890 } | 295 } |
891 | 296 |
892 function setMostVisitedPages(data, hasBlacklistedUrls) { | 297 function setMostVisitedPages(data, hasBlacklistedUrls) { |
893 mostVisitedPage.data = data; | 298 newTabView.mostVisitedPage.data = data; |
894 } | 299 } |
895 | 300 |
896 function setBookmarksData(data) { | 301 function setBookmarksData(data) { |
897 bookmarksPage.data = data; | 302 newTabView.bookmarksPage.data = data; |
303 } | |
304 | |
305 function bookmarkImportBegan() { | |
306 newTabView.bookmarksPage.bookmarkImportBegan.apply( | |
307 newTabView.bookmarksPage, | |
308 arguments); | |
309 } | |
310 | |
311 function bookmarkImportEnded() { | |
312 newTabView.bookmarksPage.bookmarkImportEnded.apply( | |
313 newTabView.bookmarksPage, | |
314 arguments); | |
315 } | |
316 | |
317 function bookmarkNodeAdded() { | |
318 newTabView.bookmarksPage.bookmarkNodeAdded.apply( | |
319 newTabView.bookmarksPage, | |
320 arguments); | |
321 } | |
322 | |
323 function bookmarkNodeChanged() { | |
324 newTabView.bookmarksPage.bookmarkNodeChanged.apply( | |
325 newTabView.bookmarksPage, | |
326 arguments); | |
327 } | |
328 | |
329 function bookmarkNodeChildrenReordered() { | |
330 newTabView.bookmarksPage.bookmarkNodeChildrenReordered.apply( | |
331 newTabView.bookmarksPage, | |
332 arguments); | |
333 } | |
334 | |
335 function bookmarkNodeMoved() { | |
336 newTabView.bookmarksPage.bookmarkNodeMoved.apply( | |
337 newTabView.bookmarksPage, | |
338 arguments); | |
339 } | |
340 | |
341 function bookmarkNodeRemoved() { | |
342 newTabView.bookmarksPage.bookmarkNodeRemoved.apply( | |
343 newTabView.bookmarksPage, | |
344 arguments); | |
898 } | 345 } |
899 | 346 |
900 /** | 347 /** |
901 * Check the directionality of the page. | |
902 * @return {boolean} True if Chrome is running an RTL UI. | |
903 */ | |
904 function isRTL() { | |
905 return document.documentElement.dir == 'rtl'; | |
906 } | |
907 | |
908 /* | |
909 * Save the name of an app page. | |
910 * Store the app page name into the preferences store. | |
911 * @param {AppsPage} appPage The app page for which we wish to save. | |
912 * @param {string} name The name of the page. | |
913 */ | |
914 function saveAppPageName(appPage, name) { | |
915 var index = getAppsPageIndex(appPage); | |
916 assert(index != -1); | |
917 chrome.send('saveAppPageName', [name, index]); | |
918 } | |
919 | |
920 function bookmarkImportBegan() { | |
921 bookmarksPage.bookmarkImportBegan.apply(bookmarksPage, arguments); | |
922 } | |
923 | |
924 function bookmarkImportEnded() { | |
925 bookmarksPage.bookmarkImportEnded.apply(bookmarksPage, arguments); | |
926 } | |
927 | |
928 function bookmarkNodeAdded() { | |
929 bookmarksPage.bookmarkNodeAdded.apply(bookmarksPage, arguments); | |
930 } | |
931 | |
932 function bookmarkNodeChanged() { | |
933 bookmarksPage.bookmarkNodeChanged.apply(bookmarksPage, arguments); | |
934 } | |
935 | |
936 function bookmarkNodeChildrenReordered() { | |
937 bookmarksPage.bookmarkNodeChildrenReordered.apply(bookmarksPage, arguments); | |
938 } | |
939 | |
940 function bookmarkNodeMoved() { | |
941 bookmarksPage.bookmarkNodeMoved.apply(bookmarksPage, arguments); | |
942 } | |
943 | |
944 function bookmarkNodeRemoved() { | |
945 bookmarksPage.bookmarkNodeRemoved.apply(bookmarksPage, arguments); | |
946 } | |
947 | |
948 /** | |
949 * Set the dominant color for a node. This will be called in response to | 348 * Set the dominant color for a node. This will be called in response to |
950 * getFaviconDominantColor. The node represented by |id| better have a setter | 349 * getFaviconDominantColor. The node represented by |id| better have a setter |
951 * for stripeColor. | 350 * for stripeColor. |
952 * @param {string} id The ID of a node. | 351 * @param {string} id The ID of a node. |
953 * @param {string} color The color represented as a CSS string. | 352 * @param {string} color The color represented as a CSS string. |
954 */ | 353 */ |
955 function setStripeColor(id, color) { | 354 function setStripeColor(id, color) { |
956 var node = $(id); | 355 var node = $(id); |
957 if (node) | 356 if (node) |
958 node.stripeColor = color; | 357 node.stripeColor = color; |
(...skipping 15 matching lines...) Expand all Loading... | |
974 $('login-container').hidden = true; | 373 $('login-container').hidden = true; |
975 $('card-slider-frame').classList.remove('showing-login-area'); | 374 $('card-slider-frame').classList.remove('showing-login-area'); |
976 } | 375 } |
977 if (shouldShowLoginBubble) { | 376 if (shouldShowLoginBubble) { |
978 window.setTimeout(loginBubble.show.bind(loginBubble), 0); | 377 window.setTimeout(loginBubble.show.bind(loginBubble), 0); |
979 chrome.send('loginMessageSeen'); | 378 chrome.send('loginMessageSeen'); |
980 shouldShowLoginBubble = false; | 379 shouldShowLoginBubble = false; |
981 } | 380 } |
982 } | 381 } |
983 | 382 |
383 /** | |
384 * Wrappers to forward the callback to corresponding PageListView member. | |
385 */ | |
386 function appAdded(appData, opt_highlight) { | |
387 newTabView.appAdded(appData, opt_highlight); | |
388 } | |
389 | |
390 function appRemoved(appData, isUninstall) { | |
391 newTabView.appRemoved(appData, isUninstall); | |
392 } | |
393 | |
394 function appsPrefChangeCallback(data) { | |
395 newTabView.appsPrefChangedCallback(data); | |
396 } | |
397 | |
398 function enterRearrangeMode() { | |
399 newTabView.enterRearrangeMode(); | |
400 } | |
401 | |
402 function getAppsCallback(data) { | |
403 newTabView.getAppsCallback(data); | |
404 } | |
405 | |
406 function getAppsPageIndex(page) { | |
407 newTabView.getAppsPageIndex(page); | |
408 } | |
409 | |
410 function getCardSlider() { | |
411 return newTabView.cardSlider; | |
412 } | |
413 | |
414 function leaveRearrangeMode(e) { | |
415 newTabView.leaveRearrangeMode(e); | |
416 } | |
417 | |
418 function saveAppPageName(appPage, name) { | |
419 newTabView.saveAppPageName(appPage, name); | |
420 } | |
421 | |
422 function setAppToBeHighlighted(appId) { | |
423 newTabView.highlightAppId = appId; | |
424 } | |
425 | |
984 // Return an object with all the exports | 426 // Return an object with all the exports |
985 return { | 427 return { |
986 appAdded: appAdded, | 428 appAdded: appAdded, |
987 appRemoved: appRemoved, | 429 appRemoved: appRemoved, |
988 appsPrefChangeCallback: appsPrefChangeCallback, | 430 appsPrefChangeCallback: appsPrefChangeCallback, |
989 assert: assert, | |
990 bookmarkImportBegan: bookmarkImportBegan, | 431 bookmarkImportBegan: bookmarkImportBegan, |
991 bookmarkImportEnded: bookmarkImportEnded, | 432 bookmarkImportEnded: bookmarkImportEnded, |
992 bookmarkNodeAdded: bookmarkNodeAdded, | 433 bookmarkNodeAdded: bookmarkNodeAdded, |
993 bookmarkNodeChanged: bookmarkNodeChanged, | 434 bookmarkNodeChanged: bookmarkNodeChanged, |
994 bookmarkNodeChildrenReordered: bookmarkNodeChildrenReordered, | 435 bookmarkNodeChildrenReordered: bookmarkNodeChildrenReordered, |
995 bookmarkNodeMoved: bookmarkNodeMoved, | 436 bookmarkNodeMoved: bookmarkNodeMoved, |
996 bookmarkNodeRemoved: bookmarkNodeRemoved, | 437 bookmarkNodeRemoved: bookmarkNodeRemoved, |
997 enterRearrangeMode: enterRearrangeMode, | 438 enterRearrangeMode: enterRearrangeMode, |
998 getAppsCallback: getAppsCallback, | 439 getAppsCallback: getAppsCallback, |
999 getAppsPageIndex: getAppsPageIndex, | 440 getAppsPageIndex: getAppsPageIndex, |
1000 getCardSlider: getCardSlider, | 441 getCardSlider: getCardSlider, |
1001 initialize: initialize, | |
1002 isRTL: isRTL, | |
1003 leaveRearrangeMode: leaveRearrangeMode, | 442 leaveRearrangeMode: leaveRearrangeMode, |
443 load: load, | |
1004 saveAppPageName: saveAppPageName, | 444 saveAppPageName: saveAppPageName, |
1005 setAppToBeHighlighted: setAppToBeHighlighted, | 445 setAppToBeHighlighted: setAppToBeHighlighted, |
1006 setBookmarksData: setBookmarksData, | 446 setBookmarksData: setBookmarksData, |
1007 setMostVisitedPages: setMostVisitedPages, | 447 setMostVisitedPages: setMostVisitedPages, |
1008 setRecentlyClosedTabs: setRecentlyClosedTabs, | 448 setRecentlyClosedTabs: setRecentlyClosedTabs, |
1009 setStripeColor: setStripeColor, | 449 setStripeColor: setStripeColor, |
1010 showNotification: showNotification, | 450 showNotification: showNotification, |
1011 themeChanged: themeChanged, | 451 themeChanged: themeChanged, |
1012 updateLogin: updateLogin, | 452 updateLogin: updateLogin |
1013 updateOfflineEnabledApps: updateOfflineEnabledApps | |
1014 }; | 453 }; |
1015 }); | 454 }); |
1016 | 455 |
1017 // publish ntp globals | 456 // publish ntp globals |
1018 // TODO(estade): update the content handlers to use ntp namespace instead of | 457 // TODO(estade): update the content handlers to use ntp namespace instead of |
1019 // making these global. | 458 // making these global. |
1020 var assert = ntp4.assert; | |
1021 var getAppsCallback = ntp4.getAppsCallback; | 459 var getAppsCallback = ntp4.getAppsCallback; |
1022 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback; | 460 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback; |
1023 var themeChanged = ntp4.themeChanged; | 461 var themeChanged = ntp4.themeChanged; |
1024 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs; | 462 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs; |
1025 var setMostVisitedPages = ntp4.setMostVisitedPages; | 463 var setMostVisitedPages = ntp4.setMostVisitedPages; |
1026 var updateLogin = ntp4.updateLogin; | 464 var updateLogin = ntp4.updateLogin; |
1027 | 465 |
1028 document.addEventListener('DOMContentLoaded', ntp4.initialize); | 466 document.addEventListener('DOMContentLoaded', ntp4.load); |
Evan Stade
2011/11/10 00:02:21
can you make it onLoad
xiyuan
2011/11/10 18:25:07
Done.
| |
1029 window.addEventListener('online', ntp4.updateOfflineEnabledApps); | |
1030 window.addEventListener('offline', ntp4.updateOfflineEnabledApps); | |
OLD | NEW |