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 |