| 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. | 23 * The 'notification-container' element. |
| 24 * @type {!Element|undefined} | 24 * @type {!Element|undefined} |
| 25 */ | 25 */ |
| 26 var notificationContainer; | 26 var notificationContainer; |
| 27 | 27 |
| 28 /** | 28 /** |
| 29 * Object for accessing localized strings. | |
| 30 * @type {!LocalStrings} | |
| 31 */ | |
| 32 var localStrings = new LocalStrings; | |
| 33 | |
| 34 /** | |
| 35 * If non-null, an info bubble for showing messages to the user. It points at | 29 * If non-null, an info bubble for showing messages to the user. It points at |
| 36 * the Most Visited label, and is used to draw more attention to the | 30 * the Most Visited label, and is used to draw more attention to the |
| 37 * navigation dot UI. | 31 * navigation dot UI. |
| 38 * @type {!Element|undefined} | 32 * @type {!Element|undefined} |
| 39 */ | 33 */ |
| 40 var infoBubble; | 34 var infoBubble; |
| 41 | 35 |
| 42 /** | 36 /** |
| 43 * If non-null, an bubble confirming that the user has signed into sync. It | 37 * If non-null, an bubble confirming that the user has signed into sync. It |
| 44 * points at the login status at the top of the page. | 38 * points at the login status at the top of the page. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 69 | 63 |
| 70 /** | 64 /** |
| 71 * Creates a NewTabView object. NewTabView extends PageListView with | 65 * Creates a NewTabView object. NewTabView extends PageListView with |
| 72 * new tab UI specific logics. | 66 * new tab UI specific logics. |
| 73 * @constructor | 67 * @constructor |
| 74 * @extends {PageListView} | 68 * @extends {PageListView} |
| 75 */ | 69 */ |
| 76 function NewTabView() { | 70 function NewTabView() { |
| 77 var pageSwitcherStart = null; | 71 var pageSwitcherStart = null; |
| 78 var pageSwitcherEnd = null; | 72 var pageSwitcherEnd = null; |
| 79 if (templateData.showApps) { | 73 if (loadTimeData.getValue('showApps')) { |
| 80 pageSwitcherStart = getRequiredElement('page-switcher-start'); | 74 pageSwitcherStart = getRequiredElement('page-switcher-start'); |
| 81 pageSwitcherEnd = getRequiredElement('page-switcher-end'); | 75 pageSwitcherEnd = getRequiredElement('page-switcher-end'); |
| 82 } | 76 } |
| 83 this.initialize(getRequiredElement('page-list'), | 77 this.initialize(getRequiredElement('page-list'), |
| 84 getRequiredElement('dot-list'), | 78 getRequiredElement('dot-list'), |
| 85 getRequiredElement('card-slider-frame'), | 79 getRequiredElement('card-slider-frame'), |
| 86 getRequiredElement('trash'), | 80 getRequiredElement('trash'), |
| 87 pageSwitcherStart, pageSwitcherEnd); | 81 pageSwitcherStart, pageSwitcherEnd); |
| 88 } | 82 } |
| 89 | 83 |
| 90 NewTabView.prototype = { | 84 NewTabView.prototype = { |
| 91 __proto__: ntp.PageListView.prototype, | 85 __proto__: ntp.PageListView.prototype, |
| 92 | 86 |
| 93 /** @inheritDoc */ | 87 /** @inheritDoc */ |
| 94 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { | 88 appendTilePage: function(page, title, titleIsEditable, opt_refNode) { |
| 95 ntp.PageListView.prototype.appendTilePage.apply(this, arguments); | 89 ntp.PageListView.prototype.appendTilePage.apply(this, arguments); |
| 96 | 90 |
| 97 if (infoBubble) | 91 if (infoBubble) |
| 98 window.setTimeout(infoBubble.reposition.bind(infoBubble), 0); | 92 window.setTimeout(infoBubble.reposition.bind(infoBubble), 0); |
| 99 } | 93 } |
| 100 }; | 94 }; |
| 101 | 95 |
| 102 /** | 96 /** |
| 103 * Invoked at startup once the DOM is available to initialize the app. | 97 * Invoked at startup once the DOM is available to initialize the app. |
| 104 */ | 98 */ |
| 105 function onLoad() { | 99 function onLoad() { |
| 106 sectionsToWaitFor = templateData.showApps ? 2 : 1; | 100 sectionsToWaitFor = loadTimeData.getBoolean('showApps') ? 2 : 1; |
| 107 measureNavDots(); | 101 measureNavDots(); |
| 108 | 102 |
| 109 // Load the current theme colors. | 103 // Load the current theme colors. |
| 110 themeChanged(); | 104 themeChanged(); |
| 111 | 105 |
| 112 newTabView = new NewTabView(); | 106 newTabView = new NewTabView(); |
| 113 | 107 |
| 114 notificationContainer = getRequiredElement('notification-container'); | 108 notificationContainer = getRequiredElement('notification-container'); |
| 115 notificationContainer.addEventListener( | 109 notificationContainer.addEventListener( |
| 116 'webkitTransitionEnd', onNotificationTransitionEnd); | 110 'webkitTransitionEnd', onNotificationTransitionEnd); |
| 117 | 111 |
| 118 cr.ui.decorate($('recently-closed-menu-button'), ntp.RecentMenuButton); | 112 cr.ui.decorate($('recently-closed-menu-button'), ntp.RecentMenuButton); |
| 119 chrome.send('getRecentlyClosedTabs'); | 113 chrome.send('getRecentlyClosedTabs'); |
| 120 | 114 |
| 121 if (templateData.showOtherSessionsMenu) { | 115 if (loadTimeData.getBoolean('showOtherSessionsMenu')) { |
| 122 otherSessionsButton = getRequiredElement('other-sessions-menu-button'); | 116 otherSessionsButton = getRequiredElement('other-sessions-menu-button'); |
| 123 cr.ui.decorate(otherSessionsButton, ntp.OtherSessionsMenuButton); | 117 cr.ui.decorate(otherSessionsButton, ntp.OtherSessionsMenuButton); |
| 124 otherSessionsButton.initialize(templateData.isUserSignedIn); | 118 otherSessionsButton.initialize(loadTimeData.getBoolean('isUserSignedIn')); |
| 125 } | 119 } |
| 126 | 120 |
| 127 var mostVisited = new ntp.MostVisitedPage(); | 121 var mostVisited = new ntp.MostVisitedPage(); |
| 128 // Move the footer into the most visited page if we are in "bare minimum" | 122 // Move the footer into the most visited page if we are in "bare minimum" |
| 129 // mode. | 123 // mode. |
| 130 if (document.body.classList.contains('bare-minimum')) | 124 if (document.body.classList.contains('bare-minimum')) |
| 131 mostVisited.appendFooter(getRequiredElement('footer')); | 125 mostVisited.appendFooter(getRequiredElement('footer')); |
| 132 newTabView.appendTilePage(mostVisited, | 126 newTabView.appendTilePage(mostVisited, |
| 133 localStrings.getString('mostvisited'), | 127 loadTimeData.getString('mostvisited'), |
| 134 false); | 128 false); |
| 135 chrome.send('getMostVisited'); | 129 chrome.send('getMostVisited'); |
| 136 | 130 |
| 137 if (templateData.isSuggestionsPageEnabled) { | 131 if (loadTimeData.getBoolean('isSuggestionsPageEnabled')) { |
| 138 var suggestions_script = document.createElement('script'); | 132 var suggestions_script = document.createElement('script'); |
| 139 suggestions_script.src = 'suggestions_page.js'; | 133 suggestions_script.src = 'suggestions_page.js'; |
| 140 suggestions_script.onload = function() { | 134 suggestions_script.onload = function() { |
| 141 newTabView.appendTilePage(new ntp.SuggestionsPage(), | 135 newTabView.appendTilePage(new ntp.SuggestionsPage(), |
| 142 localStrings.getString('suggestions'), | 136 loadTimeData.getString('suggestions'), |
| 143 false, | 137 false, |
| 144 (newTabView.appsPages.length > 0) ? | 138 (newTabView.appsPages.length > 0) ? |
| 145 newTabView.appsPages[0] : null); | 139 newTabView.appsPages[0] : null); |
| 146 chrome.send('getSuggestions'); | 140 chrome.send('getSuggestions'); |
| 147 }; | 141 }; |
| 148 document.querySelector('head').appendChild(suggestions_script); | 142 document.querySelector('head').appendChild(suggestions_script); |
| 149 } | 143 } |
| 150 | 144 |
| 151 var webstoreLink = localStrings.getString('webStoreLink'); | 145 var webStoreLink = loadTimeData.getString('webStoreLink'); |
| 152 if (templateData.isWebStoreExperimentEnabled) { | 146 if (loadTimeData.getBoolean('isWebStoreExperimentEnabled')) { |
| 153 var url = appendParam(webstoreLink, 'utm_source', 'chrome-ntp-launcher'); | 147 var url = appendParam(webStoreLink, 'utm_source', 'chrome-ntp-launcher'); |
| 154 $('chrome-web-store-href').href = url; | 148 $('chrome-web-store-href').href = url; |
| 155 $('chrome-web-store-href').addEventListener('click', | 149 $('chrome-web-store-href').addEventListener('click', |
| 156 onChromeWebStoreButtonClick); | 150 onChromeWebStoreButtonClick); |
| 157 | 151 |
| 158 $('footer-content').classList.add('enable-cws-experiment'); | 152 $('footer-content').classList.add('enable-cws-experiment'); |
| 159 } | 153 } |
| 160 | 154 |
| 161 if (templateData.appInstallHintEnabled) { | 155 if (loadTimeData.getBoolean('appInstallHintEnabled')) { |
| 162 var url = appendParam(webstoreLink, 'utm_source', 'chrome-ntp-plus-icon'); | 156 var url = appendParam(webStoreLink, 'utm_source', 'chrome-ntp-plus-icon'); |
| 163 $('app-install-hint-template').href = url; | 157 $('app-install-hint-template').href = url; |
| 164 } | 158 } |
| 165 | 159 |
| 166 if (localStrings.getString('login_status_message')) { | 160 if (loadTimeData.getString('login_status_message')) { |
| 167 loginBubble = new cr.ui.Bubble; | 161 loginBubble = new cr.ui.Bubble; |
| 168 loginBubble.anchorNode = $('login-container'); | 162 loginBubble.anchorNode = $('login-container'); |
| 169 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); | 163 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); |
| 170 loginBubble.bubbleAlignment = | 164 loginBubble.bubbleAlignment = |
| 171 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; | 165 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; |
| 172 loginBubble.deactivateToDismissDelay = 2000; | 166 loginBubble.deactivateToDismissDelay = 2000; |
| 173 loginBubble.setCloseButtonVisible(false); | 167 loginBubble.setCloseButtonVisible(false); |
| 174 | 168 |
| 175 $('login-status-learn-more').href = | |
| 176 localStrings.getString('login_status_url'); | |
| 177 $('login-status-advanced').onclick = function() { | 169 $('login-status-advanced').onclick = function() { |
| 178 chrome.send('showAdvancedLoginUI'); | 170 chrome.send('showAdvancedLoginUI'); |
| 179 }; | 171 }; |
| 180 $('login-status-dismiss').onclick = loginBubble.hide.bind(loginBubble); | 172 $('login-status-dismiss').onclick = loginBubble.hide.bind(loginBubble); |
| 181 | 173 |
| 182 var bubbleContent = $('login-status-bubble-contents'); | 174 var bubbleContent = $('login-status-bubble-contents'); |
| 183 loginBubble.content = bubbleContent; | 175 loginBubble.content = bubbleContent; |
| 184 | 176 |
| 185 // The anchor node won't be updated until updateLogin is called so don't | 177 // The anchor node won't be updated until updateLogin is called so don't |
| 186 // show the bubble yet. | 178 // show the bubble yet. |
| 187 shouldShowLoginBubble = true; | 179 shouldShowLoginBubble = true; |
| 188 } else if (localStrings.getString('ntp4_intro_message')) { | 180 } else if (loadTimeData.valueExists('ntp4_intro_message')) { |
| 189 infoBubble = new cr.ui.Bubble; | 181 infoBubble = new cr.ui.Bubble; |
| 190 infoBubble.anchorNode = newTabView.mostVisitedPage.navigationDot; | 182 infoBubble.anchorNode = newTabView.mostVisitedPage.navigationDot; |
| 191 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); | 183 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); |
| 192 infoBubble.handleCloseEvent = function() { | 184 infoBubble.handleCloseEvent = function() { |
| 193 this.hide(); | 185 this.hide(); |
| 194 chrome.send('introMessageDismissed'); | 186 chrome.send('introMessageDismissed'); |
| 195 }; | 187 }; |
| 196 | 188 |
| 197 var bubbleContent = $('ntp4-intro-bubble-contents'); | 189 var bubbleContent = $('ntp4-intro-bubble-contents'); |
| 198 infoBubble.content = bubbleContent; | 190 infoBubble.content = bubbleContent; |
| 199 | 191 |
| 200 var learnMoreLink = infoBubble.querySelector('a'); | 192 bubbleContent.querySelector('div > div').innerHTML = |
| 201 learnMoreLink.href = localStrings.getString('ntp4_intro_url'); | 193 loadTimeData.getString('ntp4_intro_message'); |
| 194 |
| 195 var learnMoreLink = bubbleContent.querySelector('a'); |
| 196 learnMoreLink.href = loadTimeData.getString('ntp4_intro_url'); |
| 202 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); | 197 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); |
| 203 | 198 |
| 204 infoBubble.show(); | 199 infoBubble.show(); |
| 205 chrome.send('introMessageSeen'); | 200 chrome.send('introMessageSeen'); |
| 206 } | 201 } |
| 207 | 202 |
| 208 var loginContainer = getRequiredElement('login-container'); | 203 var loginContainer = getRequiredElement('login-container'); |
| 209 loginContainer.addEventListener('click', showSyncLoginUI); | 204 loginContainer.addEventListener('click', showSyncLoginUI); |
| 210 chrome.send('initializeSyncLogin'); | 205 chrome.send('initializeSyncLogin'); |
| 211 | 206 |
| 212 doWhenAllSectionsReady(function() { | 207 doWhenAllSectionsReady(function() { |
| 213 // Tell the slider about the pages. | 208 // Tell the slider about the pages. |
| 214 newTabView.updateSliderCards(); | 209 newTabView.updateSliderCards(); |
| 215 // Mark the current page. | 210 // Mark the current page. |
| 216 newTabView.cardSlider.currentCardValue.navigationDot.classList.add( | 211 newTabView.cardSlider.currentCardValue.navigationDot.classList.add( |
| 217 'selected'); | 212 'selected'); |
| 218 | 213 |
| 219 var promo = localStrings.getString('serverpromo'); | 214 if (loadTimeData.valueExists('serverpromo')) { |
| 220 if (promo) { | 215 var promo = loadTimeData.getString('serverpromo'); |
| 221 var tags = ['IMG']; | 216 var tags = ['IMG']; |
| 222 var attrs = { | 217 var attrs = { |
| 223 src: function(node, value) { | 218 src: function(node, value) { |
| 224 return node.tagName == 'IMG' && | 219 return node.tagName == 'IMG' && |
| 225 /^data\:image\/(?:png|gif|jpe?g)/.test(value); | 220 /^data\:image\/(?:png|gif|jpe?g)/.test(value); |
| 226 }, | 221 }, |
| 227 }; | 222 }; |
| 228 showNotification(parseHtmlSubset(promo, tags, attrs), [], function() { | 223 showNotification(parseHtmlSubset(promo, tags, attrs), [], function() { |
| 229 chrome.send('closeNotificationPromo'); | 224 chrome.send('closeNotificationPromo'); |
| 230 }, 60000); | 225 }, 60000); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 else | 279 else |
| 285 window.setTimeout(callback, 0); // Do soon after, but asynchronously. | 280 window.setTimeout(callback, 0); // Do soon after, but asynchronously. |
| 286 } | 281 } |
| 287 | 282 |
| 288 /** | 283 /** |
| 289 * Fills in an invisible div with the 'Most Visited' string so that | 284 * Fills in an invisible div with the 'Most Visited' string so that |
| 290 * its length may be measured and the nav dots sized accordingly. | 285 * its length may be measured and the nav dots sized accordingly. |
| 291 */ | 286 */ |
| 292 function measureNavDots() { | 287 function measureNavDots() { |
| 293 var measuringDiv = $('fontMeasuringDiv'); | 288 var measuringDiv = $('fontMeasuringDiv'); |
| 294 measuringDiv.textContent = localStrings.getString('mostvisited'); | 289 measuringDiv.textContent = loadTimeData.getString('mostvisited'); |
| 295 // The 4 is for border and padding. | 290 // The 4 is for border and padding. |
| 296 var pxWidth = Math.max(measuringDiv.clientWidth * 1.15 + 4, 80); | 291 var pxWidth = Math.max(measuringDiv.clientWidth * 1.15 + 4, 80); |
| 297 | 292 |
| 298 var styleElement = document.createElement('style'); | 293 var styleElement = document.createElement('style'); |
| 299 styleElement.type = 'text/css'; | 294 styleElement.type = 'text/css'; |
| 300 // max-width is used because if we run out of space, the nav dots will be | 295 // max-width is used because if we run out of space, the nav dots will be |
| 301 // shrunk. | 296 // shrunk. |
| 302 styleElement.textContent = '.dot { max-width: ' + pxWidth + 'px; }'; | 297 styleElement.textContent = '.dot { max-width: ' + pxWidth + 'px; }'; |
| 303 document.querySelector('head').appendChild(styleElement); | 298 document.querySelector('head').appendChild(styleElement); |
| 304 } | 299 } |
| 305 | 300 |
| 306 function themeChanged(opt_hasAttribution) { | 301 function themeChanged(opt_hasAttribution) { |
| 307 $('themecss').href = 'chrome://theme/css/new_tab_theme.css?' + Date.now(); | 302 $('themecss').href = 'chrome://theme/css/new_tab_theme.css?' + Date.now(); |
| 308 | 303 |
| 309 if (typeof opt_hasAttribution != 'undefined') { | 304 if (typeof opt_hasAttribution != 'undefined') { |
| 310 document.documentElement.setAttribute('hasattribution', | 305 document.documentElement.setAttribute('hasattribution', |
| 311 opt_hasAttribution); | 306 opt_hasAttribution); |
| 312 } | 307 } |
| 313 | 308 |
| 314 updateLogo(); | |
| 315 updateAttribution(); | 309 updateAttribution(); |
| 316 } | 310 } |
| 317 | 311 |
| 318 function setBookmarkBarAttached(attached) { | 312 function setBookmarkBarAttached(attached) { |
| 319 document.documentElement.setAttribute('bookmarkbarattached', attached); | 313 document.documentElement.setAttribute('bookmarkbarattached', attached); |
| 320 } | 314 } |
| 321 | 315 |
| 322 /** | 316 /** |
| 323 * Sets the proper image for the logo at the bottom left. | |
| 324 */ | |
| 325 function updateLogo() { | |
| 326 var imageId = 'IDR_PRODUCT_LOGO'; | |
| 327 if (document.documentElement.getAttribute('customlogo') == 'true') | |
| 328 imageId = 'IDR_CUSTOM_PRODUCT_LOGO'; | |
| 329 | |
| 330 $('logo-img').src = 'chrome://theme/' + imageId + '?' + Date.now(); | |
| 331 } | |
| 332 | |
| 333 /** | |
| 334 * Attributes the attribution image at the bottom left. | 317 * Attributes the attribution image at the bottom left. |
| 335 */ | 318 */ |
| 336 function updateAttribution() { | 319 function updateAttribution() { |
| 337 var attribution = $('attribution'); | 320 var attribution = $('attribution'); |
| 338 if (document.documentElement.getAttribute('hasattribution') == 'true') { | 321 if (document.documentElement.getAttribute('hasattribution') == 'true') { |
| 339 $('attribution-img').src = | 322 $('attribution-img').src = |
| 340 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' + Date.now(); | 323 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' + Date.now(); |
| 341 attribution.hidden = false; | 324 attribution.hidden = false; |
| 342 } else { | 325 } else { |
| 343 attribution.hidden = true; | 326 attribution.hidden = true; |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 setSuggestionsPages: setSuggestionsPages, | 599 setSuggestionsPages: setSuggestionsPages, |
| 617 setRecentlyClosedTabs: setRecentlyClosedTabs, | 600 setRecentlyClosedTabs: setRecentlyClosedTabs, |
| 618 setStripeColor: setStripeColor, | 601 setStripeColor: setStripeColor, |
| 619 showNotification: showNotification, | 602 showNotification: showNotification, |
| 620 themeChanged: themeChanged, | 603 themeChanged: themeChanged, |
| 621 updateLogin: updateLogin | 604 updateLogin: updateLogin |
| 622 }; | 605 }; |
| 623 }); | 606 }); |
| 624 | 607 |
| 625 document.addEventListener('DOMContentLoaded', ntp.onLoad); | 608 document.addEventListener('DOMContentLoaded', ntp.onLoad); |
| OLD | NEW |