| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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('ntp', function() { | 13 cr.define('ntp', function() { |
| 14 'use strict'; | 14 'use strict'; |
| 15 | 15 |
| 16 /** | 16 /** |
| 17 * NewTabView instance. | 17 * NewTabView instance. |
| 18 * @type {!Object|undefined} | 18 * @type {!Object|undefined} |
| 19 */ | 19 */ |
| 20 var newTabView; | 20 var newTabView; |
| 21 | 21 |
| 22 /** | 22 /** |
| 23 * The 'notification-container' element. | |
| 24 * @type {!Element|undefined} | |
| 25 */ | |
| 26 var notificationContainer; | |
| 27 | |
| 28 /** | |
| 29 * If non-null, an info bubble for showing messages to the user. It points at | 23 * If non-null, an info bubble for showing messages to the user. It points at |
| 30 * the Most Visited label, and is used to draw more attention to the | 24 * the Most Visited label, and is used to draw more attention to the |
| 31 * navigation dot UI. | 25 * navigation dot UI. |
| 32 * @type {!cr.ui.Bubble|undefined} | 26 * @type {!cr.ui.Bubble|undefined} |
| 33 */ | 27 */ |
| 34 var promoBubble; | 28 var promoBubble; |
| 35 | 29 |
| 36 /** | 30 /** |
| 37 * If non-null, an bubble confirming that the user has signed into sync. It | 31 * If non-null, an bubble confirming that the user has signed into sync. It |
| 38 * points at the login status at the top of the page. | 32 * points at the login status at the top of the page. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 function() { chrome.send('onLearnMore'); }); | 114 function() { chrome.send('onLearnMore'); }); |
| 121 } | 115 } |
| 122 } | 116 } |
| 123 measureNavDots(); | 117 measureNavDots(); |
| 124 | 118 |
| 125 // Load the current theme colors. | 119 // Load the current theme colors. |
| 126 themeChanged(); | 120 themeChanged(); |
| 127 | 121 |
| 128 newTabView = new NewTabView(); | 122 newTabView = new NewTabView(); |
| 129 | 123 |
| 130 notificationContainer = getRequiredElement('notification-container'); | |
| 131 notificationContainer.addEventListener( | |
| 132 'webkitTransitionEnd', onNotificationTransitionEnd); | |
| 133 | |
| 134 if (!loadTimeData.getBoolean('showWebStoreIcon')) { | 124 if (!loadTimeData.getBoolean('showWebStoreIcon')) { |
| 135 var webStoreIcon = $('chrome-web-store-link'); | 125 var webStoreIcon = $('chrome-web-store-link'); |
| 136 // Not all versions of the NTP have a footer, so this may not exist. | 126 // Not all versions of the NTP have a footer, so this may not exist. |
| 137 if (webStoreIcon) | 127 if (webStoreIcon) |
| 138 webStoreIcon.hidden = true; | 128 webStoreIcon.hidden = true; |
| 139 } else { | 129 } else { |
| 140 var webStoreLink = loadTimeData.getString('webStoreLink'); | 130 var webStoreLink = loadTimeData.getString('webStoreLink'); |
| 141 var url = appendParam(webStoreLink, 'utm_source', 'chrome-ntp-launcher'); | 131 var url = appendParam(webStoreLink, 'utm_source', 'chrome-ntp-launcher'); |
| 142 $('chrome-web-store-link').href = url; | 132 $('chrome-web-store-link').href = url; |
| 143 $('chrome-web-store-link').addEventListener('click', | 133 $('chrome-web-store-link').addEventListener('click', |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 if (loadTimeData.getBoolean('shouldShowSyncLogin')) | 188 if (loadTimeData.getBoolean('shouldShowSyncLogin')) |
| 199 chrome.send('initializeSyncLogin'); | 189 chrome.send('initializeSyncLogin'); |
| 200 | 190 |
| 201 doWhenAllSectionsReady(function() { | 191 doWhenAllSectionsReady(function() { |
| 202 // Tell the slider about the pages. | 192 // Tell the slider about the pages. |
| 203 newTabView.updateSliderCards(); | 193 newTabView.updateSliderCards(); |
| 204 // Mark the current page. | 194 // Mark the current page. |
| 205 newTabView.cardSlider.currentCardValue.navigationDot.classList.add( | 195 newTabView.cardSlider.currentCardValue.navigationDot.classList.add( |
| 206 'selected'); | 196 'selected'); |
| 207 | 197 |
| 208 if (loadTimeData.valueExists('notificationPromoText')) { | |
| 209 var promoText = loadTimeData.getString('notificationPromoText'); | |
| 210 var tags = ['IMG']; | |
| 211 var attrs = { | |
| 212 src: function(node, value) { | |
| 213 return node.tagName == 'IMG' && | |
| 214 /^data\:image\/(?:png|gif|jpe?g)/.test(value); | |
| 215 }, | |
| 216 }; | |
| 217 | |
| 218 var promo = parseHtmlSubset(promoText, tags, attrs); | |
| 219 var promoLink = promo.querySelector('a'); | |
| 220 if (promoLink) { | |
| 221 promoLink.addEventListener('click', function(e) { | |
| 222 chrome.send('notificationPromoLinkClicked'); | |
| 223 }); | |
| 224 } | |
| 225 | |
| 226 showNotification(promo, [], function() { | |
| 227 chrome.send('notificationPromoClosed'); | |
| 228 }, 60000); | |
| 229 chrome.send('notificationPromoViewed'); | |
| 230 } | |
| 231 | |
| 232 cr.dispatchSimpleEvent(document, 'ntpLoaded', true, true); | 198 cr.dispatchSimpleEvent(document, 'ntpLoaded', true, true); |
| 233 document.documentElement.classList.remove('starting-up'); | 199 document.documentElement.classList.remove('starting-up'); |
| 234 | 200 |
| 235 startTime = Date.now(); | 201 startTime = Date.now(); |
| 236 }); | 202 }); |
| 237 } | 203 } |
| 238 | 204 |
| 239 /** | 205 /** |
| 240 * Launches the chrome web store app with the chrome-ntp-launcher | 206 * Launches the chrome web store app with the chrome-ntp-launcher |
| 241 * source. | 207 * source. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 */ | 304 */ |
| 339 function themeChanged(opt_themeData) { | 305 function themeChanged(opt_themeData) { |
| 340 $('themecss').href = 'chrome://theme/css/new_tab_theme.css?' + Date.now(); | 306 $('themecss').href = 'chrome://theme/css/new_tab_theme.css?' + Date.now(); |
| 341 } | 307 } |
| 342 | 308 |
| 343 function setBookmarkBarAttached(attached) { | 309 function setBookmarkBarAttached(attached) { |
| 344 document.documentElement.setAttribute('bookmarkbarattached', attached); | 310 document.documentElement.setAttribute('bookmarkbarattached', attached); |
| 345 } | 311 } |
| 346 | 312 |
| 347 /** | 313 /** |
| 348 * Timeout ID. | |
| 349 * @type {number} | |
| 350 */ | |
| 351 var notificationTimeout = 0; | |
| 352 | |
| 353 /** | |
| 354 * Shows the notification bubble. | |
| 355 * @param {string|Node} message The notification message or node to use as | |
| 356 * message. | |
| 357 * @param {Array<{text: string, action: function()}>} links An array of | |
| 358 * records describing the links in the notification. Each record should | |
| 359 * have a 'text' attribute (the display string) and an 'action' attribute | |
| 360 * (a function to run when the link is activated). | |
| 361 * @param {Function=} opt_closeHandler The callback invoked if the user | |
| 362 * manually dismisses the notification. | |
| 363 * @param {number=} opt_timeout | |
| 364 */ | |
| 365 function showNotification(message, links, opt_closeHandler, opt_timeout) { | |
| 366 window.clearTimeout(notificationTimeout); | |
| 367 | |
| 368 var span = document.querySelector('#notification > span'); | |
| 369 if (typeof message == 'string') { | |
| 370 span.textContent = message; | |
| 371 } else { | |
| 372 span.textContent = ''; // Remove all children. | |
| 373 span.appendChild(message); | |
| 374 } | |
| 375 | |
| 376 var linksBin = $('notificationLinks'); | |
| 377 linksBin.textContent = ''; | |
| 378 for (var i = 0; i < links.length; i++) { | |
| 379 var link = new ActionLink; | |
| 380 link.textContent = links[i].text; | |
| 381 link.action = links[i].action; | |
| 382 link.onclick = function() { | |
| 383 this.action(); | |
| 384 hideNotification(); | |
| 385 }; | |
| 386 linksBin.appendChild(link); | |
| 387 } | |
| 388 | |
| 389 function closeFunc(e) { | |
| 390 if (opt_closeHandler) | |
| 391 opt_closeHandler(); | |
| 392 hideNotification(); | |
| 393 } | |
| 394 | |
| 395 document.querySelector('#notification button').onclick = closeFunc; | |
| 396 document.addEventListener('dragstart', closeFunc); | |
| 397 | |
| 398 notificationContainer.hidden = false; | |
| 399 showNotificationOnCurrentPage(); | |
| 400 | |
| 401 newTabView.cardSlider.frame.addEventListener( | |
| 402 'cardSlider:card_change_ended', onCardChangeEnded); | |
| 403 | |
| 404 var timeout = opt_timeout || 10000; | |
| 405 notificationTimeout = window.setTimeout(hideNotification, timeout); | |
| 406 } | |
| 407 | |
| 408 /** | |
| 409 * Hide the notification bubble. | |
| 410 */ | |
| 411 function hideNotification() { | |
| 412 notificationContainer.classList.add('inactive'); | |
| 413 | |
| 414 newTabView.cardSlider.frame.removeEventListener( | |
| 415 'cardSlider:card_change_ended', onCardChangeEnded); | |
| 416 } | |
| 417 | |
| 418 /** | |
| 419 * Happens when 1 or more consecutive card changes end. | |
| 420 * @param {Event} e The cardSlider:card_change_ended event. | |
| 421 */ | |
| 422 function onCardChangeEnded(e) { | |
| 423 // If we ended on the same page as we started, ignore. | |
| 424 if (newTabView.cardSlider.currentCardValue.notification) | |
| 425 return; | |
| 426 | |
| 427 // Hide the notification the old page. | |
| 428 notificationContainer.classList.add('card-changed'); | |
| 429 | |
| 430 showNotificationOnCurrentPage(); | |
| 431 } | |
| 432 | |
| 433 /** | |
| 434 * Move and show the notification on the current page. | |
| 435 */ | |
| 436 function showNotificationOnCurrentPage() { | |
| 437 var page = newTabView.cardSlider.currentCardValue; | |
| 438 doWhenAllSectionsReady(function() { | |
| 439 if (page != newTabView.cardSlider.currentCardValue) | |
| 440 return; | |
| 441 | |
| 442 // NOTE: This moves the notification to inside of the current page. | |
| 443 page.notification = notificationContainer; | |
| 444 | |
| 445 // Reveal the notification and instruct it to hide itself if ignored. | |
| 446 notificationContainer.classList.remove('inactive'); | |
| 447 | |
| 448 // Gives the browser time to apply this rule before we remove it (causing | |
| 449 // a transition). | |
| 450 window.setTimeout(function() { | |
| 451 notificationContainer.classList.remove('card-changed'); | |
| 452 }, 0); | |
| 453 }); | |
| 454 } | |
| 455 | |
| 456 /** | |
| 457 * When done fading out, set hidden to true so the notification can't be | |
| 458 * tabbed to or clicked. | |
| 459 * @param {Event} e The webkitTransitionEnd event. | |
| 460 */ | |
| 461 function onNotificationTransitionEnd(e) { | |
| 462 if (notificationContainer.classList.contains('inactive')) | |
| 463 notificationContainer.hidden = true; | |
| 464 } | |
| 465 | |
| 466 /** | |
| 467 * Set the dominant color for a node. This will be called in response to | 314 * Set the dominant color for a node. This will be called in response to |
| 468 * getFaviconDominantColor. The node represented by |id| better have a setter | 315 * getFaviconDominantColor. The node represented by |id| better have a setter |
| 469 * for stripeColor. | 316 * for stripeColor. |
| 470 * @param {string} id The ID of a node. | 317 * @param {string} id The ID of a node. |
| 471 * @param {string} color The color represented as a CSS string. | 318 * @param {string} color The color represented as a CSS string. |
| 472 */ | 319 */ |
| 473 function setFaviconDominantColor(id, color) { | 320 function setFaviconDominantColor(id, color) { |
| 474 var node = $(id); | 321 var node = $(id); |
| 475 if (node) | 322 if (node) |
| 476 node.stripeColor = color; | 323 node.stripeColor = color; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 getAppsCallback: getAppsCallback, | 489 getAppsCallback: getAppsCallback, |
| 643 getAppsPageIndex: getAppsPageIndex, | 490 getAppsPageIndex: getAppsPageIndex, |
| 644 getCardSlider: getCardSlider, | 491 getCardSlider: getCardSlider, |
| 645 onLoad: onLoad, | 492 onLoad: onLoad, |
| 646 leaveRearrangeMode: leaveRearrangeMode, | 493 leaveRearrangeMode: leaveRearrangeMode, |
| 647 NtpFollowAction: NtpFollowAction, | 494 NtpFollowAction: NtpFollowAction, |
| 648 saveAppPageName: saveAppPageName, | 495 saveAppPageName: saveAppPageName, |
| 649 setAppToBeHighlighted: setAppToBeHighlighted, | 496 setAppToBeHighlighted: setAppToBeHighlighted, |
| 650 setBookmarkBarAttached: setBookmarkBarAttached, | 497 setBookmarkBarAttached: setBookmarkBarAttached, |
| 651 setFaviconDominantColor: setFaviconDominantColor, | 498 setFaviconDominantColor: setFaviconDominantColor, |
| 652 showNotification: showNotification, | |
| 653 themeChanged: themeChanged, | 499 themeChanged: themeChanged, |
| 654 updateLogin: updateLogin | 500 updateLogin: updateLogin |
| 655 }; | 501 }; |
| 656 }); | 502 }); |
| 657 | 503 |
| 658 document.addEventListener('DOMContentLoaded', ntp.onLoad); | 504 document.addEventListener('DOMContentLoaded', ntp.onLoad); |
| 659 | 505 |
| 660 var toCssPx = cr.ui.toCssPx; | 506 var toCssPx = cr.ui.toCssPx; |
| OLD | NEW |