Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: chrome/browser/resources/ntp4/new_tab.js

Issue 9318017: [NTP4] Redesign of notification promo. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes according to style guide Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END); 130 loginBubble.setArrowLocation(cr.ui.ArrowLocation.TOP_END);
131 loginBubble.bubbleAlignment = 131 loginBubble.bubbleAlignment =
132 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE; 132 cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE;
133 loginBubble.deactivateToDismissDelay = 2000; 133 loginBubble.deactivateToDismissDelay = 2000;
134 loginBubble.setCloseButtonVisible(false); 134 loginBubble.setCloseButtonVisible(false);
135 135
136 $('login-status-learn-more').href = 136 $('login-status-learn-more').href =
137 localStrings.getString('login_status_url'); 137 localStrings.getString('login_status_url');
138 $('login-status-advanced').onclick = function() { 138 $('login-status-advanced').onclick = function() {
139 chrome.send('showAdvancedLoginUI'); 139 chrome.send('showAdvancedLoginUI');
140 } 140 };
141 $('login-status-dismiss').onclick = loginBubble.hide.bind(loginBubble); 141 $('login-status-dismiss').onclick = loginBubble.hide.bind(loginBubble);
142 142
143 var bubbleContent = $('login-status-bubble-contents'); 143 var bubbleContent = $('login-status-bubble-contents');
144 loginBubble.content = bubbleContent; 144 loginBubble.content = bubbleContent;
145 145
146 // The anchor node won't be updated until updateLogin is called so don't 146 // The anchor node won't be updated until updateLogin is called so don't
147 // show the bubble yet. 147 // show the bubble yet.
148 shouldShowLoginBubble = true; 148 shouldShowLoginBubble = true;
149 } else if (localStrings.getString('ntp4_intro_message')) { 149 } else if (localStrings.getString('ntp4_intro_message')) {
150 infoBubble = new cr.ui.Bubble; 150 infoBubble = new cr.ui.Bubble;
151 infoBubble.anchorNode = newTabView.mostVisitedPage.navigationDot; 151 infoBubble.anchorNode = newTabView.mostVisitedPage.navigationDot;
152 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START); 152 infoBubble.setArrowLocation(cr.ui.ArrowLocation.BOTTOM_START);
153 infoBubble.handleCloseEvent = function() { 153 infoBubble.handleCloseEvent = function() {
154 this.hide(); 154 this.hide();
155 chrome.send('introMessageDismissed'); 155 chrome.send('introMessageDismissed');
156 } 156 };
157 157
158 var bubbleContent = $('ntp4-intro-bubble-contents'); 158 var bubbleContent = $('ntp4-intro-bubble-contents');
159 infoBubble.content = bubbleContent; 159 infoBubble.content = bubbleContent;
160 160
161 var learnMoreLink = infoBubble.querySelector('a'); 161 var learnMoreLink = infoBubble.querySelector('a');
162 learnMoreLink.href = localStrings.getString('ntp4_intro_url'); 162 learnMoreLink.href = localStrings.getString('ntp4_intro_url');
163 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble); 163 learnMoreLink.onclick = infoBubble.hide.bind(infoBubble);
164 164
165 infoBubble.show(); 165 infoBubble.show();
166 chrome.send('introMessageSeen'); 166 chrome.send('introMessageSeen');
167 } 167 }
168 168
169 var serverpromo = localStrings.getString('serverpromo'); 169 var promo = localStrings.getString('serverpromo');
170 if (serverpromo) { 170 if (promo) {
171 showNotification(parseHtmlSubset(serverpromo), [], function() { 171 var tags = ['IMG'];
172 var attrs = {
173 src: function(node, value) {
174 return node.tagName == 'IMG' &&
175 /^data\:image\/(?:png|gif|jpe?g)/.test(value);
176 },
177 };
178 showNotification(parseHtmlSubset(promo, tags, attrs), [], function() {
172 chrome.send('closeNotificationPromo'); 179 chrome.send('closeNotificationPromo');
173 }, 60000); 180 }, 60000);
174 chrome.send('notificationPromoViewed'); 181 chrome.send('notificationPromoViewed');
175 } 182 }
176 183
177 var loginContainer = getRequiredElement('login-container'); 184 var loginContainer = getRequiredElement('login-container');
178 loginContainer.addEventListener('click', function() { 185 loginContainer.addEventListener('click', function() {
179 var rect = loginContainer.getBoundingClientRect(); 186 var rect = loginContainer.getBoundingClientRect();
180 chrome.send('showSyncLoginUI', 187 chrome.send('showSyncLoginUI',
181 [rect.left, rect.top, rect.width, rect.height]); 188 [rect.left, rect.top, rect.width, rect.height]);
182 }); 189 });
183 chrome.send('initializeSyncLogin'); 190 chrome.send('initializeSyncLogin');
184 } 191 }
185 192
186 /** 193 /**
187 * Launches the chrome web store app with the chrome-ntp-launcher 194 * Launches the chrome web store app with the chrome-ntp-launcher
188 * source. 195 * source.
189 * @param {Event} e The click event. 196 * @param {Event} e The click event.
190 */ 197 */
191 function onChromeWebStoreButtonClick(e) { 198 function onChromeWebStoreButtonClick(e) {
192 chrome.send('recordAppLaunchByURL', 199 chrome.send('recordAppLaunchByURL',
193 [encodeURIComponent(this.href), 200 [encodeURIComponent(this.href),
194 ntp4.APP_LAUNCH.NTP_WEBSTORE_FOOTER]); 201 ntp4.APP_LAUNCH.NTP_WEBSTORE_FOOTER]);
195 } 202 }
196 203
204 /*
205 * The number of sections to wait on.
206 * @type {number}
207 */
208 var sectionsToWaitFor = 2;
209
210 /**
211 * Queued callbacks which lie in wait for all sections to be ready.
212 * @type {array}
213 */
214 var readyCallbacks = [];
215
216 /**
217 * Fired as each section of pages becomes ready.
218 * @param {Event} e Each page's synthetic DOM event.
219 */
220 document.addEventListener('sectionready', function(e) {
221 if (--sectionsToWaitFor <= 0) {
222 while (readyCallbacks.length)
Evan Stade 2012/02/07 01:07:21 I think curlies here
Dan Beam 2012/02/07 01:42:27 Done. (why are for/while treated differently, thou
223 readyCallbacks.shift()();
224 }
225 });
226
227 /**
228 * This is used to simulate a fire-once event (i.e. $(document).ready() in
229 * jQuery or Y.on('domready') in YUI. If all sections are ready, the callback
230 * is fired right away. If all pages are not ready yet, the function is queued
231 * for later execution.
232 * @param {function} callback The work to be done when ready.
233 */
234 function doWhenAllSectionsReady(callback) {
235 assert(typeof callback == 'function');
236 if (sectionsToWaitFor > 0)
237 readyCallbacks.push(callback);
238 else
239 window.setTimeout(callback, 0); // Do soon after, but asynchronously.
240 }
241
197 /** 242 /**
198 * Fills in an invisible div with the 'Most Visited' string so that 243 * Fills in an invisible div with the 'Most Visited' string so that
199 * its length may be measured and the nav dots sized accordingly. 244 * its length may be measured and the nav dots sized accordingly.
200 */ 245 */
201 function measureNavDots() { 246 function measureNavDots() {
202 var measuringDiv = $('fontMeasuringDiv'); 247 var measuringDiv = $('fontMeasuringDiv');
203 measuringDiv.textContent = localStrings.getString('mostvisited'); 248 measuringDiv.textContent = localStrings.getString('mostvisited');
204 var pxWidth = Math.max(measuringDiv.clientWidth * 1.15, 80); 249 var pxWidth = Math.max(measuringDiv.clientWidth * 1.15, 80);
205 250
206 var styleElement = document.createElement('style'); 251 var styleElement = document.createElement('style');
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 attribution.hidden = false; 287 attribution.hidden = false;
243 } else { 288 } else {
244 attribution.hidden = true; 289 attribution.hidden = true;
245 } 290 }
246 } 291 }
247 292
248 /** 293 /**
249 * Timeout ID. 294 * Timeout ID.
250 * @type {number} 295 * @type {number}
251 */ 296 */
252 var notificationTimeout_ = 0; 297 var notificationTimeout = 0;
253 298
254 /** 299 /**
255 * Shows the notification bubble. 300 * Shows the notification bubble.
256 * @param {string|Node} message The notification message or node to use as 301 * @param {string|Node} message The notification message or node to use as
257 * message. 302 * message.
258 * @param {Array.<{text: string, action: function()}>} links An array of 303 * @param {Array.<{text: string, action: function()}>} links An array of
259 * records describing the links in the notification. Each record should 304 * records describing the links in the notification. Each record should
260 * have a 'text' attribute (the display string) and an 'action' attribute 305 * have a 'text' attribute (the display string) and an 'action' attribute
261 * (a function to run when the link is activated). 306 * (a function to run when the link is activated).
262 * @param {Function} opt_closeHandler The callback invoked if the user 307 * @param {Function} opt_closeHandler The callback invoked if the user
263 * manually dismisses the notification. 308 * manually dismisses the notification.
264 */ 309 */
265 function showNotification(message, links, opt_closeHandler, opt_timeout) { 310 function showNotification(message, links, opt_closeHandler, opt_timeout) {
266 window.clearTimeout(notificationTimeout_); 311 window.clearTimeout(notificationTimeout);
267 312
268 var span = document.querySelector('#notification > span'); 313 var span = document.querySelector('#notification > span');
269 if (typeof message == 'string') { 314 if (typeof message == 'string') {
270 span.textContent = message; 315 span.textContent = message;
271 } else { 316 } else {
272 span.textContent = ''; // Remove all children. 317 span.textContent = ''; // Remove all children.
273 span.appendChild(message); 318 span.appendChild(message);
274 } 319 }
275 320
276 var linksBin = $('notificationLinks'); 321 var linksBin = $('notificationLinks');
277 linksBin.textContent = ''; 322 linksBin.textContent = '';
278 for (var i = 0; i < links.length; i++) { 323 for (var i = 0; i < links.length; i++) {
279 var link = linksBin.ownerDocument.createElement('div'); 324 var link = linksBin.ownerDocument.createElement('div');
280 link.textContent = links[i].text; 325 link.textContent = links[i].text;
281 link.action = links[i].action; 326 link.action = links[i].action;
282 link.onclick = function() { 327 link.onclick = function() {
283 this.action(); 328 this.action();
284 hideNotification(); 329 hideNotification();
285 } 330 };
286 link.setAttribute('role', 'button'); 331 link.setAttribute('role', 'button');
287 link.setAttribute('tabindex', 0); 332 link.setAttribute('tabindex', 0);
288 link.className = 'link-button'; 333 link.className = 'link-button';
289 linksBin.appendChild(link); 334 linksBin.appendChild(link);
290 } 335 }
291 336
292 document.querySelector('#notification button').onclick = function(e) { 337 function closeFunc(e) {
293 if (opt_closeHandler) 338 if (opt_closeHandler)
294 opt_closeHandler(); 339 opt_closeHandler();
295 hideNotification(); 340 hideNotification();
296 }; 341 }
342
343 document.querySelector('#notification button').onclick = closeFunc;
344 document.addEventListener('dragstart', closeFunc);
345
346 notificationContainer.hidden = false;
347 showNotificationOnCurrentPage();
348
349 newTabView.cardSlider.frame.addEventListener(
350 'cardSlider:card_change_ended', onCardChangeEnded);
297 351
298 var timeout = opt_timeout || 10000; 352 var timeout = opt_timeout || 10000;
299 notificationContainer.hidden = false; 353 notificationTimeout = window.setTimeout(hideNotification, timeout);
300 notificationContainer.classList.remove('inactive');
301 notificationTimeout_ = window.setTimeout(hideNotification, timeout);
302 } 354 }
303 355
304 /** 356 /**
305 * Hide the notification bubble. 357 * Hide the notification bubble.
306 */ 358 */
307 function hideNotification() { 359 function hideNotification() {
308 notificationContainer.classList.add('inactive'); 360 notificationContainer.classList.add('inactive');
361
362 newTabView.cardSlider.frame.removeEventListener(
363 'cardSlider:card_change_ended', onCardChangeEnded);
364 }
365
366 /**
367 * Happens when 1 or more consecutive card changes end.
368 * @param {Event} e The cardSlider:card_change_ended event.
369 */
370 function onCardChangeEnded(e) {
371 // If we ended on the same page as we started, ignore.
372 if (newTabView.cardSlider.currentCardValue.notification)
373 return;
374
375 // Hide the notification the old page.
376 notificationContainer.classList.add('card-changed');
377
378 showNotificationOnCurrentPage();
379 }
380
381 /**
382 * Move and show the notification on the current page.
383 */
384 function showNotificationOnCurrentPage() {
385 var page = newTabView.cardSlider.currentCardValue;
386 doWhenAllSectionsReady(function() {
387 if (page != newTabView.cardSlider.currentCardValue)
388 return;
389
390 // NOTE: This moves the notification to inside of the current page.
391 page.notification = notificationContainer;
392
393 // Reveal the notification and instruct it to hide itself if ignored.
394 notificationContainer.classList.remove('inactive');
395
396 // Gives the browser time to apply this rule before we remove it (causing
397 // a transition).
398 window.setTimeout(function() {
399 notificationContainer.classList.remove('card-changed');
400 }, 0);
401 });
309 } 402 }
310 403
311 /** 404 /**
312 * When done fading out, set hidden to true so the notification can't be 405 * When done fading out, set hidden to true so the notification can't be
313 * tabbed to or clicked. 406 * tabbed to or clicked.
407 * @param {Event} e The webkitTransitionEnd event.
314 */ 408 */
315 function onNotificationTransitionEnd(e) { 409 function onNotificationTransitionEnd(e) {
316 if (notificationContainer.classList.contains('inactive')); 410 if (notificationContainer.classList.contains('inactive'))
317 notificationContainer.hidden = true; 411 notificationContainer.hidden = true;
318 } 412 }
319 413
320 function setRecentlyClosedTabs(dataItems) { 414 function setRecentlyClosedTabs(dataItems) {
321 $('recently-closed-menu-button').dataItems = dataItems; 415 $('recently-closed-menu-button').dataItems = dataItems;
322 } 416 }
323 417
324 function setMostVisitedPages(data, hasBlacklistedUrls) { 418 function setMostVisitedPages(data, hasBlacklistedUrls) {
325 newTabView.mostVisitedPage.data = data; 419 newTabView.mostVisitedPage.data = data;
420 cr.dispatchSimpleEvent(document, 'sectionready', true, true);
326 } 421 }
327 422
328 /** 423 /**
329 * Set the dominant color for a node. This will be called in response to 424 * Set the dominant color for a node. This will be called in response to
330 * getFaviconDominantColor. The node represented by |id| better have a setter 425 * getFaviconDominantColor. The node represented by |id| better have a setter
331 * for stripeColor. 426 * for stripeColor.
332 * @param {string} id The ID of a node. 427 * @param {string} id The ID of a node.
333 * @param {string} color The color represented as a CSS string. 428 * @param {string} color The color represented as a CSS string.
334 */ 429 */
335 function setStripeColor(id, color) { 430 function setStripeColor(id, color) {
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 // TODO(estade): update the content handlers to use ntp namespace instead of 542 // TODO(estade): update the content handlers to use ntp namespace instead of
448 // making these global. 543 // making these global.
449 var getAppsCallback = ntp4.getAppsCallback; 544 var getAppsCallback = ntp4.getAppsCallback;
450 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback; 545 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback;
451 var themeChanged = ntp4.themeChanged; 546 var themeChanged = ntp4.themeChanged;
452 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs; 547 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs;
453 var setMostVisitedPages = ntp4.setMostVisitedPages; 548 var setMostVisitedPages = ntp4.setMostVisitedPages;
454 var updateLogin = ntp4.updateLogin; 549 var updateLogin = ntp4.updateLogin;
455 550
456 document.addEventListener('DOMContentLoaded', ntp4.onLoad); 551 document.addEventListener('DOMContentLoaded', ntp4.onLoad);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698