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

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: rebase 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) {
223 readyCallbacks.shift()();
224 }
225 }
226 });
227
228 /**
229 * This is used to simulate a fire-once event (i.e. $(document).ready() in
230 * jQuery or Y.on('domready') in YUI. If all sections are ready, the callback
231 * is fired right away. If all pages are not ready yet, the function is queued
232 * for later execution.
233 * @param {function} callback The work to be done when ready.
234 */
235 function doWhenAllSectionsReady(callback) {
236 assert(typeof callback == 'function');
237 if (sectionsToWaitFor > 0)
238 readyCallbacks.push(callback);
239 else
240 window.setTimeout(callback, 0); // Do soon after, but asynchronously.
241 }
242
197 /** 243 /**
198 * Fills in an invisible div with the 'Most Visited' string so that 244 * Fills in an invisible div with the 'Most Visited' string so that
199 * its length may be measured and the nav dots sized accordingly. 245 * its length may be measured and the nav dots sized accordingly.
200 */ 246 */
201 function measureNavDots() { 247 function measureNavDots() {
202 var measuringDiv = $('fontMeasuringDiv'); 248 var measuringDiv = $('fontMeasuringDiv');
203 measuringDiv.textContent = localStrings.getString('mostvisited'); 249 measuringDiv.textContent = localStrings.getString('mostvisited');
204 var pxWidth = Math.max(measuringDiv.clientWidth * 1.15, 80); 250 var pxWidth = Math.max(measuringDiv.clientWidth * 1.15, 80);
205 251
206 var styleElement = document.createElement('style'); 252 var styleElement = document.createElement('style');
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 attribution.hidden = false; 288 attribution.hidden = false;
243 } else { 289 } else {
244 attribution.hidden = true; 290 attribution.hidden = true;
245 } 291 }
246 } 292 }
247 293
248 /** 294 /**
249 * Timeout ID. 295 * Timeout ID.
250 * @type {number} 296 * @type {number}
251 */ 297 */
252 var notificationTimeout_ = 0; 298 var notificationTimeout = 0;
253 299
254 /** 300 /**
255 * Shows the notification bubble. 301 * Shows the notification bubble.
256 * @param {string|Node} message The notification message or node to use as 302 * @param {string|Node} message The notification message or node to use as
257 * message. 303 * message.
258 * @param {Array.<{text: string, action: function()}>} links An array of 304 * @param {Array.<{text: string, action: function()}>} links An array of
259 * records describing the links in the notification. Each record should 305 * records describing the links in the notification. Each record should
260 * have a 'text' attribute (the display string) and an 'action' attribute 306 * have a 'text' attribute (the display string) and an 'action' attribute
261 * (a function to run when the link is activated). 307 * (a function to run when the link is activated).
262 * @param {Function} opt_closeHandler The callback invoked if the user 308 * @param {Function} opt_closeHandler The callback invoked if the user
263 * manually dismisses the notification. 309 * manually dismisses the notification.
264 */ 310 */
265 function showNotification(message, links, opt_closeHandler, opt_timeout) { 311 function showNotification(message, links, opt_closeHandler, opt_timeout) {
266 window.clearTimeout(notificationTimeout_); 312 window.clearTimeout(notificationTimeout);
267 313
268 var span = document.querySelector('#notification > span'); 314 var span = document.querySelector('#notification > span');
269 if (typeof message == 'string') { 315 if (typeof message == 'string') {
270 span.textContent = message; 316 span.textContent = message;
271 } else { 317 } else {
272 span.textContent = ''; // Remove all children. 318 span.textContent = ''; // Remove all children.
273 span.appendChild(message); 319 span.appendChild(message);
274 } 320 }
275 321
276 var linksBin = $('notificationLinks'); 322 var linksBin = $('notificationLinks');
277 linksBin.textContent = ''; 323 linksBin.textContent = '';
278 for (var i = 0; i < links.length; i++) { 324 for (var i = 0; i < links.length; i++) {
279 var link = linksBin.ownerDocument.createElement('div'); 325 var link = linksBin.ownerDocument.createElement('div');
280 link.textContent = links[i].text; 326 link.textContent = links[i].text;
281 link.action = links[i].action; 327 link.action = links[i].action;
282 link.onclick = function() { 328 link.onclick = function() {
283 this.action(); 329 this.action();
284 hideNotification(); 330 hideNotification();
285 } 331 };
286 link.setAttribute('role', 'button'); 332 link.setAttribute('role', 'button');
287 link.setAttribute('tabindex', 0); 333 link.setAttribute('tabindex', 0);
288 link.className = 'link-button'; 334 link.className = 'link-button';
289 linksBin.appendChild(link); 335 linksBin.appendChild(link);
290 } 336 }
291 337
292 document.querySelector('#notification button').onclick = function(e) { 338 function closeFunc(e) {
293 if (opt_closeHandler) 339 if (opt_closeHandler)
294 opt_closeHandler(); 340 opt_closeHandler();
295 hideNotification(); 341 hideNotification();
296 }; 342 }
343
344 document.querySelector('#notification button').onclick = closeFunc;
345 document.addEventListener('dragstart', closeFunc);
346
347 notificationContainer.hidden = false;
348 showNotificationOnCurrentPage();
349
350 newTabView.cardSlider.frame.addEventListener(
351 'cardSlider:card_change_ended', onCardChangeEnded);
297 352
298 var timeout = opt_timeout || 10000; 353 var timeout = opt_timeout || 10000;
299 notificationContainer.hidden = false; 354 notificationTimeout = window.setTimeout(hideNotification, timeout);
300 notificationContainer.classList.remove('inactive');
301 notificationTimeout_ = window.setTimeout(hideNotification, timeout);
302 } 355 }
303 356
304 /** 357 /**
305 * Hide the notification bubble. 358 * Hide the notification bubble.
306 */ 359 */
307 function hideNotification() { 360 function hideNotification() {
308 notificationContainer.classList.add('inactive'); 361 notificationContainer.classList.add('inactive');
362
363 newTabView.cardSlider.frame.removeEventListener(
364 'cardSlider:card_change_ended', onCardChangeEnded);
365 }
366
367 /**
368 * Happens when 1 or more consecutive card changes end.
369 * @param {Event} e The cardSlider:card_change_ended event.
370 */
371 function onCardChangeEnded(e) {
372 // If we ended on the same page as we started, ignore.
373 if (newTabView.cardSlider.currentCardValue.notification)
374 return;
375
376 // Hide the notification the old page.
377 notificationContainer.classList.add('card-changed');
378
379 showNotificationOnCurrentPage();
380 }
381
382 /**
383 * Move and show the notification on the current page.
384 */
385 function showNotificationOnCurrentPage() {
386 var page = newTabView.cardSlider.currentCardValue;
387 doWhenAllSectionsReady(function() {
388 if (page != newTabView.cardSlider.currentCardValue)
389 return;
390
391 // NOTE: This moves the notification to inside of the current page.
392 page.notification = notificationContainer;
393
394 // Reveal the notification and instruct it to hide itself if ignored.
395 notificationContainer.classList.remove('inactive');
396
397 // Gives the browser time to apply this rule before we remove it (causing
398 // a transition).
399 window.setTimeout(function() {
400 notificationContainer.classList.remove('card-changed');
401 }, 0);
402 });
309 } 403 }
310 404
311 /** 405 /**
312 * When done fading out, set hidden to true so the notification can't be 406 * When done fading out, set hidden to true so the notification can't be
313 * tabbed to or clicked. 407 * tabbed to or clicked.
408 * @param {Event} e The webkitTransitionEnd event.
314 */ 409 */
315 function onNotificationTransitionEnd(e) { 410 function onNotificationTransitionEnd(e) {
316 if (notificationContainer.classList.contains('inactive')); 411 if (notificationContainer.classList.contains('inactive'))
317 notificationContainer.hidden = true; 412 notificationContainer.hidden = true;
318 } 413 }
319 414
320 function setRecentlyClosedTabs(dataItems) { 415 function setRecentlyClosedTabs(dataItems) {
321 $('recently-closed-menu-button').dataItems = dataItems; 416 $('recently-closed-menu-button').dataItems = dataItems;
322 } 417 }
323 418
324 function setMostVisitedPages(data, hasBlacklistedUrls) { 419 function setMostVisitedPages(data, hasBlacklistedUrls) {
325 newTabView.mostVisitedPage.data = data; 420 newTabView.mostVisitedPage.data = data;
421 cr.dispatchSimpleEvent(document, 'sectionready', true, true);
326 } 422 }
327 423
328 /** 424 /**
329 * Set the dominant color for a node. This will be called in response to 425 * 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 426 * getFaviconDominantColor. The node represented by |id| better have a setter
331 * for stripeColor. 427 * for stripeColor.
332 * @param {string} id The ID of a node. 428 * @param {string} id The ID of a node.
333 * @param {string} color The color represented as a CSS string. 429 * @param {string} color The color represented as a CSS string.
334 */ 430 */
335 function setStripeColor(id, color) { 431 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 543 // TODO(estade): update the content handlers to use ntp namespace instead of
448 // making these global. 544 // making these global.
449 var getAppsCallback = ntp4.getAppsCallback; 545 var getAppsCallback = ntp4.getAppsCallback;
450 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback; 546 var appsPrefChangeCallback = ntp4.appsPrefChangeCallback;
451 var themeChanged = ntp4.themeChanged; 547 var themeChanged = ntp4.themeChanged;
452 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs; 548 var recentlyClosedTabs = ntp4.setRecentlyClosedTabs;
453 var setMostVisitedPages = ntp4.setMostVisitedPages; 549 var setMostVisitedPages = ntp4.setMostVisitedPages;
454 var updateLogin = ntp4.updateLogin; 550 var updateLogin = ntp4.updateLogin;
455 551
456 document.addEventListener('DOMContentLoaded', ntp4.onLoad); 552 document.addEventListener('DOMContentLoaded', ntp4.onLoad);
OLDNEW
« no previous file with comments | « chrome/browser/resources/ntp4/new_tab.css ('k') | chrome/browser/resources/ntp4/page_list_view.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698