| 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. |
| 66 * @constructor |
| 67 * @extends {PageListView} |
| 68 */ |
| 69 function NewTabView() { |
| 70 this.__proto__ = NewTabView.prototype; |
| 71 this.initialize(); |
| 72 } |
| 73 |
| 74 NewTabView.prototype = { |
| 75 __proto__: ntp4.PageListView.prototype, |
| 76 |
| 77 /** @inheritDoc */ |
| 78 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { |
| 79 ntp4.PageListView.prototype.appendTilePage.apply(this, arguments); |
| 80 |
| 81 if (infoBubble) |
| 82 window.setTimeout(infoBubble.reposition.bind(infoBubble), 0); |
| 83 } |
| 84 }; |
| 85 |
| 86 /** |
| 149 * Invoked at startup once the DOM is available to initialize the app. | 87 * Invoked at startup once the DOM is available to initialize the app. |
| 150 */ | 88 */ |
| 151 function initialize() { | 89 function initialize() { |
| 152 cr.enablePlatformSpecificCSSRules(); | 90 cr.enablePlatformSpecificCSSRules(); |
| 153 | 91 |
| 154 // Load the current theme colors. | 92 // Load the current theme colors. |
| 155 themeChanged(); | 93 themeChanged(); |
| 156 | 94 |
| 157 dotList = getRequiredElement('dot-list'); | 95 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 | 96 |
| 187 notificationContainer = getRequiredElement('notification-container'); | 97 notificationContainer = getRequiredElement('notification-container'); |
| 188 notificationContainer.addEventListener( | 98 notificationContainer.addEventListener( |
| 189 'webkitTransitionEnd', onNotificationTransitionEnd); | 99 'webkitTransitionEnd', onNotificationTransitionEnd); |
| 190 | 100 |
| 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); | 101 cr.ui.decorate($('recently-closed-menu-button'), ntp4.RecentMenuButton); |
| 208 chrome.send('getRecentlyClosedTabs'); | 102 chrome.send('getRecentlyClosedTabs'); |
| 209 | 103 |
| 210 mostVisitedPage = new ntp4.MostVisitedPage(); | 104 newTabView.appendTilePage(new ntp4.MostVisitedPage(), |
| 211 appendTilePage(mostVisitedPage, localStrings.getString('mostvisited'), | 105 localStrings.getString('mostvisited'), |
| 212 false); | 106 false); |
| 213 chrome.send('getMostVisited'); | 107 chrome.send('getMostVisited'); |
| 214 | 108 |
| 215 if (localStrings.getString('login_status_message')) { | 109 if (localStrings.getString('login_status_message')) { |
| 216 loginBubble = new cr.ui.Bubble; | 110 loginBubble = new cr.ui.Bubble; |
| 217 loginBubble.anchorNode = $('login-container'); | 111 loginBubble.anchorNode = $('login-container'); |
| 218 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); | 112 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); |
| 219 loginBubble.bubbleAlignment = | 113 loginBubble.bubbleAlignment = |
| 220 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; | 114 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; |
| 221 loginBubble.deactivateToDismissDelay = 2000; | 115 loginBubble.deactivateToDismissDelay = 2000; |
| 222 loginBubble.setCloseButtonVisible(false); | 116 loginBubble.setCloseButtonVisible(false); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 235 } | 129 } |
| 236 | 130 |
| 237 var dismissButton = loginBubble.querySelector('#login-status-dismiss'); | 131 var dismissButton = loginBubble.querySelector('#login-status-dismiss'); |
| 238 dismissButton.onclick = loginBubble.hide.bind(loginBubble); | 132 dismissButton.onclick = loginBubble.hide.bind(loginBubble); |
| 239 | 133 |
| 240 // The anchor node won't be updated until updateLogin is called so don't | 134 // The anchor node won't be updated until updateLogin is called so don't |
| 241 // show the bubble yet. | 135 // show the bubble yet. |
| 242 shouldShowLoginBubble = true; | 136 shouldShowLoginBubble = true; |
| 243 } else if (localStrings.getString('ntp4_intro_message')) { | 137 } else if (localStrings.getString('ntp4_intro_message')) { |
| 244 infoBubble = new cr.ui.Bubble; | 138 infoBubble = new cr.ui.Bubble; |
| 245 infoBubble.anchorNode = mostVisitedPage.navigationDot; | 139 infoBubble.anchorNode = newTabView.mostVisitedPage.navigationDot; |
| 246 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); | 140 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); |
| 247 infoBubble.handleCloseEvent = function() { | 141 infoBubble.handleCloseEvent = function() { |
| 248 this.hide(); | 142 this.hide(); |
| 249 chrome.send('introMessageDismissed'); | 143 chrome.send('introMessageDismissed'); |
| 250 } | 144 } |
| 251 | 145 |
| 252 var bubbleContent = $('ntp4-intro-bubble-contents'); | 146 var bubbleContent = $('ntp4-intro-bubble-contents'); |
| 253 infoBubble.content = bubbleContent; | 147 infoBubble.content = bubbleContent; |
| 254 bubbleContent.hidden = false; | 148 bubbleContent.hidden = false; |
| 255 | 149 |
| 256 var learnMoreLink = infoBubble.querySelector('a'); | 150 var learnMoreLink = infoBubble.querySelector('a'); |
| 257 learnMoreLink.href = localStrings.getString('ntp4_intro_url'); | 151 learnMoreLink.href = localStrings.getString('ntp4_intro_url'); |
| 258 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); | 152 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); |
| 259 | 153 |
| 260 infoBubble.show(); | 154 infoBubble.show(); |
| 261 } | 155 } |
| 262 | 156 |
| 263 var bookmarkFeatures = localStrings.getString('bookmark_features'); | 157 var bookmarkFeatures = localStrings.getString('bookmark_features'); |
| 264 if (bookmarkFeatures == 'true') { | 158 if (bookmarkFeatures == 'true') { |
| 265 bookmarksPage = new ntp4.BookmarksPage(); | 159 newTabView.appendTilePage(new ntp4.BookmarksPage(), |
| 266 appendTilePage(bookmarksPage, localStrings.getString('bookmarksPage'), | 160 localStrings.getString('bookmarksPage'), |
| 267 false); | 161 false); |
| 268 chrome.send('getBookmarksData'); | 162 chrome.send('getBookmarksData'); |
| 269 } | 163 } |
| 270 | 164 |
| 271 var serverpromo = localStrings.getString('serverpromo'); | 165 var serverpromo = localStrings.getString('serverpromo'); |
| 272 if (serverpromo) { | 166 if (serverpromo) { |
| 273 showNotification(parseHtmlSubset(serverpromo), [], function() { | 167 showNotification(parseHtmlSubset(serverpromo), [], function() { |
| 274 chrome.send('closeNotificationPromo'); | 168 chrome.send('closeNotificationPromo'); |
| 275 }, 60000); | 169 }, 60000); |
| 276 chrome.send('notificationPromoViewed'); | 170 chrome.send('notificationPromoViewed'); |
| 277 } | 171 } |
| 278 | 172 |
| 279 var loginContainer = getRequiredElement('login-container'); | 173 var loginContainer = getRequiredElement('login-container'); |
| 280 loginContainer.addEventListener('click', function() { | 174 loginContainer.addEventListener('click', function() { |
| 281 var rect = loginContainer.getBoundingClientRect(); | 175 var rect = loginContainer.getBoundingClientRect(); |
| 282 chrome.send('showSyncLoginUI', | 176 chrome.send('showSyncLoginUI', |
| 283 [rect.left, rect.top, rect.width, rect.height]); | 177 [rect.left, rect.top, rect.width, rect.height]); |
| 284 }); | 178 }); |
| 285 chrome.send('initializeSyncLogin'); | 179 chrome.send('initializeSyncLogin'); |
| 286 } | 180 } |
| 287 | 181 |
| 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 | 182 // TODO(estade): rename newtab.css to new_tab_theme.css |
| 750 function themeChanged(hasAttribution) { | 183 function themeChanged(hasAttribution) { |
| 751 $('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now(); | 184 $('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now(); |
| 752 if (typeof hasAttribution != 'undefined') | 185 if (typeof hasAttribution != 'undefined') |
| 753 document.documentElement.setAttribute('hasattribution', hasAttribution); | 186 document.documentElement.setAttribute('hasattribution', hasAttribution); |
| 754 updateLogo(); | 187 updateLogo(); |
| 755 updateAttribution(); | 188 updateAttribution(); |
| 756 } | 189 } |
| 757 | 190 |
| 758 /** | 191 /** |
| (...skipping 15 matching lines...) Expand all Loading... |
| 774 if (document.documentElement.getAttribute('hasattribution') == 'true') { | 207 if (document.documentElement.getAttribute('hasattribution') == 'true') { |
| 775 $('attribution-img').src = | 208 $('attribution-img').src = |
| 776 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' + Date.now(); | 209 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' + Date.now(); |
| 777 attribution.hidden = false; | 210 attribution.hidden = false; |
| 778 } else { | 211 } else { |
| 779 attribution.hidden = true; | 212 attribution.hidden = true; |
| 780 } | 213 } |
| 781 } | 214 } |
| 782 | 215 |
| 783 /** | 216 /** |
| 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. | 217 * Timeout ID. |
| 818 * @type {number} | 218 * @type {number} |
| 819 */ | 219 */ |
| 820 var notificationTimeout_ = 0; | 220 var notificationTimeout_ = 0; |
| 821 | 221 |
| 822 /** | 222 /** |
| 823 * Shows the notification bubble. | 223 * Shows the notification bubble. |
| 824 * @param {string|Node} message The notification message or node to use as | 224 * @param {string|Node} message The notification message or node to use as |
| 825 * message. | 225 * message. |
| 826 * @param {Array.<{text: string, action: function()}>} links An array of | 226 * @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) { | 283 function onNotificationTransitionEnd(e) { |
| 884 if (notificationContainer.classList.contains('inactive')); | 284 if (notificationContainer.classList.contains('inactive')); |
| 885 notificationContainer.hidden = true; | 285 notificationContainer.hidden = true; |
| 886 } | 286 } |
| 887 | 287 |
| 888 function setRecentlyClosedTabs(dataItems) { | 288 function setRecentlyClosedTabs(dataItems) { |
| 889 $('recently-closed-menu-button').dataItems = dataItems; | 289 $('recently-closed-menu-button').dataItems = dataItems; |
| 890 } | 290 } |
| 891 | 291 |
| 892 function setMostVisitedPages(data, hasBlacklistedUrls) { | 292 function setMostVisitedPages(data, hasBlacklistedUrls) { |
| 893 mostVisitedPage.data = data; | 293 newTabView.mostVisitedPage.data = data; |
| 894 } | 294 } |
| 895 | 295 |
| 896 function setBookmarksData(data) { | 296 function setBookmarksData(data) { |
| 897 bookmarksPage.data = data; | 297 newTabView.bookmarksPage.data = data; |
| 298 } |
| 299 |
| 300 function bookmarkImportBegan() { |
| 301 newTabView.bookmarksPage.bookmarkImportBegan.apply( |
| 302 newTabView.bookmarksPage, |
| 303 arguments); |
| 304 } |
| 305 |
| 306 function bookmarkImportEnded() { |
| 307 newTabView.bookmarksPage.bookmarkImportEnded.apply( |
| 308 newTabView.bookmarksPage, |
| 309 arguments); |
| 310 } |
| 311 |
| 312 function bookmarkNodeAdded() { |
| 313 newTabView.bookmarksPage.bookmarkNodeAdded.apply( |
| 314 newTabView.bookmarksPage, |
| 315 arguments); |
| 316 } |
| 317 |
| 318 function bookmarkNodeChanged() { |
| 319 newTabView.bookmarksPage.bookmarkNodeChanged.apply( |
| 320 newTabView.bookmarksPage, |
| 321 arguments); |
| 322 } |
| 323 |
| 324 function bookmarkNodeChildrenReordered() { |
| 325 newTabView.bookmarksPage.bookmarkNodeChildrenReordered.apply( |
| 326 newTabView.bookmarksPage, |
| 327 arguments); |
| 328 } |
| 329 |
| 330 function bookmarkNodeMoved() { |
| 331 newTabView.bookmarksPage.bookmarkNodeMoved.apply( |
| 332 newTabView.bookmarksPage, |
| 333 arguments); |
| 334 } |
| 335 |
| 336 function bookmarkNodeRemoved() { |
| 337 newTabView.bookmarksPage.bookmarkNodeRemoved.apply( |
| 338 newTabView.bookmarksPage, |
| 339 arguments); |
| 898 } | 340 } |
| 899 | 341 |
| 900 /** | 342 /** |
| 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 | 343 * 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 | 344 * getFaviconDominantColor. The node represented by |id| better have a setter |
| 951 * for stripeColor. | 345 * for stripeColor. |
| 952 * @param {string} id The ID of a node. | 346 * @param {string} id The ID of a node. |
| 953 * @param {string} color The color represented as a CSS string. | 347 * @param {string} color The color represented as a CSS string. |
| 954 */ | 348 */ |
| 955 function setStripeColor(id, color) { | 349 function setStripeColor(id, color) { |
| 956 var node = $(id); | 350 var node = $(id); |
| 957 if (node) | 351 if (node) |
| 958 node.stripeColor = color; | 352 node.stripeColor = color; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 976 } | 370 } |
| 977 if (shouldShowLoginBubble) { | 371 if (shouldShowLoginBubble) { |
| 978 window.setTimeout(loginBubble.show.bind(loginBubble), 0); | 372 window.setTimeout(loginBubble.show.bind(loginBubble), 0); |
| 979 chrome.send('loginMessageSeen'); | 373 chrome.send('loginMessageSeen'); |
| 980 shouldShowLoginBubble = false; | 374 shouldShowLoginBubble = false; |
| 981 } | 375 } |
| 982 } | 376 } |
| 983 | 377 |
| 984 // Return an object with all the exports | 378 // Return an object with all the exports |
| 985 return { | 379 return { |
| 986 appAdded: appAdded, | |
| 987 appRemoved: appRemoved, | |
| 988 appsPrefChangeCallback: appsPrefChangeCallback, | |
| 989 assert: assert, | |
| 990 bookmarkImportBegan: bookmarkImportBegan, | 380 bookmarkImportBegan: bookmarkImportBegan, |
| 991 bookmarkImportEnded: bookmarkImportEnded, | 381 bookmarkImportEnded: bookmarkImportEnded, |
| 992 bookmarkNodeAdded: bookmarkNodeAdded, | 382 bookmarkNodeAdded: bookmarkNodeAdded, |
| 993 bookmarkNodeChanged: bookmarkNodeChanged, | 383 bookmarkNodeChanged: bookmarkNodeChanged, |
| 994 bookmarkNodeChildrenReordered: bookmarkNodeChildrenReordered, | 384 bookmarkNodeChildrenReordered: bookmarkNodeChildrenReordered, |
| 995 bookmarkNodeMoved: bookmarkNodeMoved, | 385 bookmarkNodeMoved: bookmarkNodeMoved, |
| 996 bookmarkNodeRemoved: bookmarkNodeRemoved, | 386 bookmarkNodeRemoved: bookmarkNodeRemoved, |
| 997 enterRearrangeMode: enterRearrangeMode, | |
| 998 getAppsCallback: getAppsCallback, | |
| 999 getAppsPageIndex: getAppsPageIndex, | |
| 1000 getCardSlider: getCardSlider, | |
| 1001 initialize: initialize, | 387 initialize: initialize, |
| 1002 isRTL: isRTL, | |
| 1003 leaveRearrangeMode: leaveRearrangeMode, | |
| 1004 saveAppPageName: saveAppPageName, | |
| 1005 setAppToBeHighlighted: setAppToBeHighlighted, | |
| 1006 setBookmarksData: setBookmarksData, | 388 setBookmarksData: setBookmarksData, |
| 1007 setMostVisitedPages: setMostVisitedPages, | 389 setMostVisitedPages: setMostVisitedPages, |
| 1008 setRecentlyClosedTabs: setRecentlyClosedTabs, | 390 setRecentlyClosedTabs: setRecentlyClosedTabs, |
| 1009 setStripeColor: setStripeColor, | 391 setStripeColor: setStripeColor, |
| 1010 showNotification: showNotification, | 392 showNotification: showNotification, |
| 1011 themeChanged: themeChanged, | 393 themeChanged: themeChanged, |
| 1012 updateLogin: updateLogin, | 394 updateLogin: updateLogin |
| 1013 updateOfflineEnabledApps: updateOfflineEnabledApps | |
| 1014 }; | 395 }; |
| 1015 }); | 396 }); |
| 1016 | 397 |
| 1017 // publish ntp globals | 398 // publish ntp globals |
| 1018 // TODO(estade): update the content handlers to use ntp namespace instead of | 399 // TODO(estade): update the content handlers to use ntp namespace instead of |
| 1019 // making these global. | 400 // making these global. |
| 1020 var assert = ntp4.assert; | |
| 1021 var getAppsCallback = ntp4.getAppsCallback; | |
| 1022 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback; | |
| 1023 var themeChanged = ntp4.themeChanged; | 401 var themeChanged = ntp4.themeChanged; |
| 1024 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs; | 402 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs; |
| 1025 var setMostVisitedPages = ntp4.setMostVisitedPages; | 403 var setMostVisitedPages = ntp4.setMostVisitedPages; |
| 1026 var updateLogin = ntp4.updateLogin; | 404 var updateLogin = ntp4.updateLogin; |
| 1027 | 405 |
| 1028 document.addEventListener('DOMContentLoaded', ntp4.initialize); | 406 document.addEventListener('DOMContentLoaded', ntp4.initialize); |
| 1029 window.addEventListener('online', ntp4.updateOfflineEnabledApps); | |
| 1030 window.addEventListener('offline', ntp4.updateOfflineEnabledApps); | |
| OLD | NEW |