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

Side by Side Diff: chrome/browser/resources/local_ntp/local_ntp.js

Issue 412073002: Local NTP: prevent tiles from reloading on resize by moving them into single <div>. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Moving tile visibility logic to renderAndShowTiles(), using per-session Barrier. Created 6 years, 4 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 /** 6 /**
7 * @fileoverview The local InstantExtended NTP. 7 * @fileoverview The local InstantExtended NTP.
8 */ 8 */
9 9
10 10
11 /** 11 /**
12 * Controls rendering the new tab page for InstantExtended. 12 * Controls rendering the new tab page for InstantExtended.
13 * @return {Object} A limited interface for testing the local NTP. 13 * @return {Object} A limited interface for testing the local NTP.
14 */ 14 */
15 function LocalNTP() { 15 function LocalNTP() {
16 <include src="../../../../ui/webui/resources/js/assert.js"> 16 <include src="../../../../ui/webui/resources/js/assert.js">
17 <include src="local_ntp_util.js">
17 <include src="window_disposition_util.js"> 18 <include src="window_disposition_util.js">
18 19
19 20
20 /** 21 /**
21 * Enum for classnames. 22 * Enum for classnames.
22 * @enum {string} 23 * @enum {string}
23 * @const 24 * @const
24 */ 25 */
25 var CLASSES = { 26 var CLASSES = {
26 ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme 27 ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme
27 BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation 28 BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation
28 BLACKLIST_BUTTON: 'mv-x', 29 BLACKLIST_BUTTON: 'mv-x',
29 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', 30 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide',
30 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive 31 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive
31 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox 32 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox
32 // Applies drag focus style to the fakebox 33 // Applies drag focus style to the fakebox
33 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', 34 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused',
34 FAVICON: 'mv-favicon', 35 FAVICON: 'mv-favicon',
35 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation 36 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation
36 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo', 37 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo',
37 HIDE_NOTIFICATION: 'mv-notice-hide', 38 HIDE_NOTIFICATION: 'mv-notice-hide',
38 // Vertically centers the most visited section for a non-Google provided page. 39 // Vertically centers the most visited section for a non-Google provided page.
39 NON_GOOGLE_PAGE: 'non-google-page', 40 NON_GOOGLE_PAGE: 'non-google-page',
40 PAGE: 'mv-page', // page tiles 41 PAGE: 'mv-page', // page tiles
41 PAGE_READY: 'mv-page-ready', // page tile when ready 42 PAGE_READY: 'mv-page-ready', // page tile when ready
42 ROW: 'mv-row', // tile row
43 RTL: 'rtl', // Right-to-left language text. 43 RTL: 'rtl', // Right-to-left language text.
44 THUMBNAIL: 'mv-thumb', 44 THUMBNAIL: 'mv-thumb',
45 THUMBNAIL_MASK: 'mv-mask', 45 THUMBNAIL_MASK: 'mv-mask',
46 TILE: 'mv-tile', 46 TILE: 'mv-tile',
47 TITLE: 'mv-title' 47 TITLE: 'mv-title'
48 }; 48 };
49 49
50 50
51 /** 51 /**
52 * Enum for HTML element ids. 52 * Enum for HTML element ids.
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 162
163 /** 163 /**
164 * Current number of tiles columns shown based on the window width, including 164 * Current number of tiles columns shown based on the window width, including
165 * those that just contain filler. 165 * those that just contain filler.
166 * @type {number} 166 * @type {number}
167 */ 167 */
168 var numColumnsShown = 0; 168 var numColumnsShown = 0;
169 169
170 170
171 /** 171 /**
172 * True if the user initiated the current most visited change and false 172 * A flag to indicate Most Visited changed caused by user action. If true, then
173 * otherwise. 173 * in onMostVisitedChange() tiles remain visible so no flickering occurs.
174 * @type {boolean} 174 * @type {boolean}
175 */ 175 */
176 var userInitiatedMostVisitedChange = false; 176 var userInitiatedMostVisitedChange = false;
177 177
178 178
179 /** 179 /**
180 * The browser embeddedSearch.newTabPage object. 180 * The browser embeddedSearch.newTabPage object.
181 * @type {Object} 181 * @type {Object}
182 */ 182 */
183 var ntpApiHandle; 183 var ntpApiHandle;
(...skipping 22 matching lines...) Expand all
206 206
207 /** 207 /**
208 * Total tile width. Should be equal to mv-tile's width + 2 * border-width. 208 * Total tile width. Should be equal to mv-tile's width + 2 * border-width.
209 * @private {number} 209 * @private {number}
210 * @const 210 * @const
211 */ 211 */
212 var TILE_WIDTH = 140; 212 var TILE_WIDTH = 140;
213 213
214 214
215 /** 215 /**
216 * Margin between tiles. Should be equal to mv-tile's -webkit-margin-start. 216 * Margin between tiles. Should be equal to mv-tile's total horizontal margin.
217 * @private {number} 217 * @private {number}
218 * @const 218 * @const
219 */ 219 */
220 var TILE_MARGIN_START = 20; 220 var TILE_MARGIN = 20;
221 221
222 222
223 /** @type {number} @const */ 223 /** @type {number} @const */
224 var MAX_NUM_TILES_TO_SHOW = 8; 224 var MAX_NUM_TILES_TO_SHOW = 8;
225 225
226 226
227 /** @type {number} @const */ 227 /** @type {number} @const */
228 var MIN_NUM_COLUMNS = 2; 228 var MIN_NUM_COLUMNS = 2;
229 229
230 230
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 * @const 291 * @const
292 */ 292 */
293 var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500; 293 var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500;
294 294
295 295
296 /** 296 /**
297 * A Tile is either a rendering of a Most Visited page or "filler" used to 297 * A Tile is either a rendering of a Most Visited page or "filler" used to
298 * pad out the section when not enough pages exist. 298 * pad out the section when not enough pages exist.
299 * 299 *
300 * @param {Element} elem The element for rendering the tile. 300 * @param {Element} elem The element for rendering the tile.
301 * @param {Element=} opt_titleElem The element for rendering the title.
302 * @param {Element=} opt_thumbnailElem The element for rendering the thumbnail.
301 * @param {number=} opt_rid The RID for the corresponding Most Visited page. 303 * @param {number=} opt_rid The RID for the corresponding Most Visited page.
302 * Should only be left unspecified when creating a filler tile. 304 * Should only be left unspecified when creating a filler tile.
303 * @constructor 305 * @constructor
304 */ 306 */
305 function Tile(elem, opt_rid) { 307 function Tile(elem, opt_titleElem, opt_thumbnailElem, opt_rid) {
306 /** @type {Element} */ 308 /** @type {Element} */
307 this.elem = elem; 309 this.elem = elem;
308 310
311 /** @type {Element|undefined} */
312 this.titleElem = opt_titleElem;
313
314 /** @type {Element|undefined} */
315 this.thumbnailElem = opt_thumbnailElem;
316
309 /** @type {number|undefined} */ 317 /** @type {number|undefined} */
310 this.rid = opt_rid; 318 this.rid = opt_rid;
311 } 319 }
312 320
313 321
314 /** 322 /**
315 * Updates the NTP based on the current theme. 323 * Updates the NTP based on the current theme.
316 * @private 324 * @private
317 */ 325 */
318 function onThemeChange() { 326 function onThemeChange() {
319 var info = ntpApiHandle.themeBackgroundInfo; 327 var info = ntpApiHandle.themeBackgroundInfo;
320 if (!info) 328 if (!info)
321 return; 329 return;
322 330
323 var background = [convertToRGBAColor(info.backgroundColorRgba), 331 var background = [convertToRGBAColor(info.backgroundColorRgba),
324 info.imageUrl, 332 info.imageUrl,
325 info.imageTiling, 333 info.imageTiling,
326 info.imageHorizontalAlignment, 334 info.imageHorizontalAlignment,
327 info.imageVerticalAlignment].join(' ').trim(); 335 info.imageVerticalAlignment].join(' ').trim();
328 document.body.style.background = background; 336 document.body.style.background = background;
329 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); 337 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo);
330 updateThemeAttribution(info.attributionUrl); 338 updateThemeAttribution(info.attributionUrl);
331 setCustomThemeStyle(info); 339 setCustomThemeStyle(info);
332 renderTiles(); 340
341 tilesContainer.innerHTML = '';
342 renderAndShowTiles();
333 } 343 }
334 344
335 345
336 /** 346 /**
337 * Updates the NTP style according to theme. 347 * Updates the NTP style according to theme.
338 * @param {Object=} opt_themeInfo The information about the theme. If it is 348 * @param {Object=} opt_themeInfo The information about the theme. If it is
339 * omitted the style will be reverted to the default. 349 * omitted the style will be reverted to the default.
340 * @private 350 * @private
341 */ 351 */
342 function setCustomThemeStyle(opt_themeInfo) { 352 function setCustomThemeStyle(opt_themeInfo) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 function convertToRGBAColor(color) { 435 function convertToRGBAColor(color) {
426 return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + 436 return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' +
427 color[3] / 255 + ')'; 437 color[3] / 255 + ')';
428 } 438 }
429 439
430 440
431 /** 441 /**
432 * Handles a new set of Most Visited page data. 442 * Handles a new set of Most Visited page data.
433 */ 443 */
434 function onMostVisitedChange() { 444 function onMostVisitedChange() {
435 var pages = ntpApiHandle.mostVisited;
436
437 if (isBlacklisting) { 445 if (isBlacklisting) {
438 // Trigger the blacklist animation and re-render the tiles when it 446 // Trigger the blacklist animation, which then triggers reloadAllTiles().
439 // completes.
440 var lastBlacklistedTileElement = lastBlacklistedTile.elem; 447 var lastBlacklistedTileElement = lastBlacklistedTile.elem;
441 lastBlacklistedTileElement.addEventListener( 448 lastBlacklistedTileElement.addEventListener(
442 'webkitTransitionEnd', blacklistAnimationDone); 449 'webkitTransitionEnd', blacklistAnimationDone);
443 lastBlacklistedTileElement.classList.add(CLASSES.BLACKLIST); 450 lastBlacklistedTileElement.classList.add(CLASSES.BLACKLIST);
444
445 } else { 451 } else {
446 // Otherwise render the tiles using the new data without animation. 452 reloadAllTiles();
447 tiles = [];
448 for (var i = 0; i < MAX_NUM_TILES_TO_SHOW; ++i) {
449 tiles.push(createTile(pages[i], i));
450 }
451 if (!userInitiatedMostVisitedChange) {
452 tilesContainer.hidden = true;
453 window.setTimeout(function() {
454 if (tilesContainer) {
455 tilesContainer.hidden = false;
456 }
457 }, MOST_VISITED_PAINT_TIMEOUT_MSEC);
458 }
459 renderTiles();
460 } 453 }
461 } 454 }
462 455
463 456
464 /** 457 /**
465 * Renders the current set of tiles. 458 * Handles the end of the blacklist animation by showing the notification and
459 * re-rendering the new set of tiles.
466 */ 460 */
467 function renderTiles() { 461 function blacklistAnimationDone() {
468 var rows = tilesContainer.children; 462 showNotification();
469 for (var i = 0; i < rows.length; ++i) { 463 isBlacklisting = false;
470 removeChildren(rows[i]); 464 tilesContainer.classList.remove(CLASSES.HIDE_BLACKLIST_BUTTON);
465 lastBlacklistedTile.elem.removeEventListener(
466 'webkitTransitionEnd', blacklistAnimationDone);
467 // Need to call explicitly to re-render the tiles, since the initial
468 // onmostvisitedchange issued by the blacklist function only triggered
469 // the animation.
470 reloadAllTiles();
471 }
472
473
474 /**
475 * Fetches new data, creates, and renders tiles.
476 */
477 function reloadAllTiles() {
478 var pages = ntpApiHandle.mostVisited;
479
480 tiles = [];
481 for (var i = 0; i < MAX_NUM_TILES_TO_SHOW; ++i)
482 tiles.push(createTile(pages[i], i));
483
484 tilesContainer.innerHTML = '';
485 renderAndShowTiles();
486 }
487
488
489 /**
490 * Binds onload events for a tile's internal <iframe> elements.
491 * @param {Tile} tile The main tile to bind events to.
492 * @param {Barrier} tileVisibilityBarrier A barrier to make tile visible the
493 * moment all tiles are loaded.
494 */
495 function bindTileOnloadEvents(tile, tileVisibilityBarrier) {
496 if (tile.titleElem) {
497 tileVisibilityBarrier.add();
498 tile.titleElem.onload = function() {
499 tile.titleElem.hidden = false;
500 tileVisibilityBarrier.remove();
501 };
471 } 502 }
472 503
473 for (var i = 0, length = tiles.length; 504 if (tile.thumbnailElem) {
474 i < Math.min(length, numColumnsShown * NUM_ROWS); ++i) { 505 tileVisibilityBarrier.add();
475 rows[Math.floor(i / numColumnsShown)].appendChild(tiles[i].elem); 506 tile.thumbnailElem.onload = function() {
507 tile.thumbnailElem.hidden = false;
508 tile.elem.classList.add(CLASSES.PAGE_READY);
509 tileVisibilityBarrier.remove();
510 };
476 } 511 }
477 } 512 }
478 513
479 514
480 /** 515 /**
481 * Shows most visited tiles if all child iframes are loaded, and hides them 516 * Renders the current list of visible tiles to DOM, and hides tiles that are
482 * otherwise. 517 * already in the DOM but should not be seen.
483 */ 518 */
484 function updateMostVisitedVisibility() { 519 function renderAndShowTiles() {
485 var iframes = tilesContainer.querySelectorAll('iframe'); 520 var numExisting = tilesContainer.querySelectorAll('.' + CLASSES.TILE).length;
486 var ready = true; 521 // Only add visible tiles to the DOM, to avoid creating invisible tiles that
487 for (var i = 0, numIframes = iframes.length; i < numIframes; i++) { 522 // produce meaningless impression metrics. However, if a tile becomes
488 if (iframes[i].hidden) { 523 // invisible then we leave it in DOM to prevent reload if they're shown again.
Jered 2014/08/01 15:07:15 nit: they're -> it's
huangs 2014/08/01 15:42:16 Done.
489 ready = false; 524 var numDesired = Math.min(tiles.length, numColumnsShown * NUM_ROWS);
490 break; 525
526 // If we need to render new tiles, manage the visibility to hide intermediate
527 // load states of the <iframe>s.
528 if (numExisting < numDesired) {
529 var tileVisibilityBarrier = new Barrier(function() {
530 tilesContainer.style.visibility = 'visible';
531 });
532
533 if (!userInitiatedMostVisitedChange) {
534 // Make titleContainer invisible, but still taking up space.
535 // titleContainer becomes visible again (1) on timeout, or (2) when all
536 // tiles finish loading (using tileVisibilityBarrier).
537 tilesContainer.style.visibility = 'hidden';
538 window.setTimeout(function() {
539 tileVisibilityBarrier.cancel();
540 tilesContainer.style.visibility = 'visible';
541 }, MOST_VISITED_PAINT_TIMEOUT_MSEC);
542 }
543 userInitiatedMostVisitedChange = false;
544
545 for (var i = numExisting; i < numDesired; ++i) {
546 bindTileOnloadEvents(tiles[i], tileVisibilityBarrier);
547 tilesContainer.appendChild(tiles[i].elem);
491 } 548 }
492 } 549 }
493 if (ready) { 550
494 tilesContainer.hidden = false; 551 // Show only the desired tiles. Not using .hidden because it does not work
495 userInitiatedMostVisitedChange = false; 552 // for inline-block elements.
496 } 553 for (i = 0; i < numDesired; ++i)
Jered 2014/08/01 15:07:15 nit: still write var i here for clarity :-)
huangs 2014/08/01 15:42:16 Done.
554 tiles[i].elem.style.display = 'inline-block';
555 // If |numDesired| < |numExisting| then hide extra tiles (e.g., this occurs
556 // when window is downsized).
557 for (; i < numExisting; ++i)
558 tiles[i].elem.style.display = 'none';
497 } 559 }
498 560
499 561
500 /** 562 /**
501 * Builds a URL to display a most visited tile component in an iframe. 563 * Builds a URL to display a most visited tile component in an iframe.
502 * @param {string} filename The desired most visited component filename. 564 * @param {string} filename The desired most visited component filename.
503 * @param {number} rid The restricted ID. 565 * @param {number} rid The restricted ID.
504 * @param {string} color The text color for text in the iframe. 566 * @param {string} color The text color for text in the iframe.
505 * @param {string} fontFamily The font family for text in the iframe. 567 * @param {string} fontFamily The font family for text in the iframe.
506 * @param {number} fontSize The font size for text in the iframe. 568 * @param {number} fontSize The font size for text in the iframe.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get 618 // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get
557 // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. 619 // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1.
558 // Now due to crbug.com/68841, Chrome incorrectly loads the content for the 620 // Now due to crbug.com/68841, Chrome incorrectly loads the content for the
559 // first set of iframes into the most recent set of iframes. 621 // first set of iframes into the most recent set of iframes.
560 // 622 //
561 // Giving iframes distinct ids seems to cause some invalidation and prevent 623 // Giving iframes distinct ids seems to cause some invalidation and prevent
562 // associating the incorrect data. 624 // associating the incorrect data.
563 // 625 //
564 // TODO(jered): Find and fix the root (probably Blink) bug. 626 // TODO(jered): Find and fix the root (probably Blink) bug.
565 627
628 // Keep this ID here. See comment above.
629 titleElement.id = 'title-' + rid;
630 titleElement.className = CLASSES.TITLE;
631 titleElement.hidden = true;
566 titleElement.src = getMostVisitedIframeUrl( 632 titleElement.src = getMostVisitedIframeUrl(
567 MOST_VISITED_TITLE_IFRAME, rid, MOST_VISITED_COLOR, 633 MOST_VISITED_TITLE_IFRAME, rid, MOST_VISITED_COLOR,
568 MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position); 634 MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position);
569
570 // Keep this id here. See comment above.
571 titleElement.id = 'title-' + rid;
572 titleElement.hidden = true;
573 titleElement.onload = function() {
574 titleElement.hidden = false;
575 updateMostVisitedVisibility();
576 };
577 titleElement.className = CLASSES.TITLE;
578 tileElement.appendChild(titleElement); 635 tileElement.appendChild(titleElement);
579 636
580 // The iframe which renders either a thumbnail or domain element. 637 // The iframe which renders either a thumbnail or domain element.
581 var thumbnailElement = document.createElement('iframe'); 638 var thumbnailElement = document.createElement('iframe');
582 thumbnailElement.tabIndex = '-1'; 639 thumbnailElement.tabIndex = '-1';
640 // Keep this ID here. See comment above.
641 thumbnailElement.id = 'thumb-' + rid;
642 thumbnailElement.className = CLASSES.THUMBNAIL;
643 thumbnailElement.hidden = true;
583 thumbnailElement.src = getMostVisitedIframeUrl( 644 thumbnailElement.src = getMostVisitedIframeUrl(
584 MOST_VISITED_THUMBNAIL_IFRAME, rid, MOST_VISITED_COLOR, 645 MOST_VISITED_THUMBNAIL_IFRAME, rid, MOST_VISITED_COLOR,
585 MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position); 646 MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position);
586
587 // Keep this id here. See comment above.
588 thumbnailElement.id = 'thumb-' + rid;
589 thumbnailElement.hidden = true;
590 thumbnailElement.onload = function() {
591 thumbnailElement.hidden = false;
592 tileElement.classList.add(CLASSES.PAGE_READY);
593 updateMostVisitedVisibility();
594 };
595 thumbnailElement.className = CLASSES.THUMBNAIL;
596 tileElement.appendChild(thumbnailElement); 647 tileElement.appendChild(thumbnailElement);
597 648
598 // A mask to darken the thumbnail on focus. 649 // A mask to darken the thumbnail on focus.
599 var maskElement = createAndAppendElement( 650 var maskElement = createAndAppendElement(
600 tileElement, 'div', CLASSES.THUMBNAIL_MASK); 651 tileElement, 'div', CLASSES.THUMBNAIL_MASK);
601 652
602 // The button used to blacklist this page. 653 // The button used to blacklist this page.
603 var blacklistButton = createAndAppendElement( 654 var blacklistButton = createAndAppendElement(
604 tileElement, 'div', CLASSES.BLACKLIST_BUTTON); 655 tileElement, 'div', CLASSES.BLACKLIST_BUTTON);
605 var blacklistFunction = generateBlacklistFunction(rid); 656 var blacklistFunction = generateBlacklistFunction(rid);
606 blacklistButton.addEventListener('click', blacklistFunction); 657 blacklistButton.addEventListener('click', blacklistFunction);
607 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; 658 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip;
608 659
609 // When a tile is focused, have delete also blacklist the page. 660 // When a tile is focused, have delete also blacklist the page.
610 registerKeyHandler(tileElement, KEYCODE.DELETE, blacklistFunction); 661 registerKeyHandler(tileElement, KEYCODE.DELETE, blacklistFunction);
611 662
612 // The page favicon, if any. 663 // The page favicon, if any.
613 var faviconUrl = page.faviconUrl; 664 var faviconUrl = page.faviconUrl;
614 if (faviconUrl) { 665 if (faviconUrl) {
615 var favicon = createAndAppendElement( 666 var favicon = createAndAppendElement(tileElement, 'div', CLASSES.FAVICON);
616 tileElement, 'div', CLASSES.FAVICON);
617 favicon.style.backgroundImage = 'url(' + faviconUrl + ')'; 667 favicon.style.backgroundImage = 'url(' + faviconUrl + ')';
618 } 668 }
619 return new Tile(tileElement, rid); 669 return new Tile(tileElement, titleElement, thumbnailElement, rid);
620 } else { 670 } else {
621 return new Tile(tileElement); 671 return new Tile(tileElement);
622 } 672 }
623 } 673 }
624 674
625 675
626 /** 676 /**
627 * Generates a function to be called when the page with the corresponding RID 677 * Generates a function to be called when the page with the corresponding RID
628 * is blacklisted. 678 * is blacklisted.
629 * @param {number} rid The RID of the page being blacklisted. 679 * @param {number} rid The RID of the page being blacklisted.
(...skipping 27 matching lines...) Expand all
657 707
658 /** 708 /**
659 * Hides the blacklist notification. 709 * Hides the blacklist notification.
660 */ 710 */
661 function hideNotification() { 711 function hideNotification() {
662 notification.classList.add(CLASSES.HIDE_NOTIFICATION); 712 notification.classList.add(CLASSES.HIDE_NOTIFICATION);
663 } 713 }
664 714
665 715
666 /** 716 /**
667 * Handles the end of the blacklist animation by showing the notification and
668 * re-rendering the new set of tiles.
669 */
670 function blacklistAnimationDone() {
671 showNotification();
672 isBlacklisting = false;
673 tilesContainer.classList.remove(CLASSES.HIDE_BLACKLIST_BUTTON);
674 lastBlacklistedTile.elem.removeEventListener(
675 'webkitTransitionEnd', blacklistAnimationDone);
676 // Need to call explicitly to re-render the tiles, since the initial
677 // onmostvisitedchange issued by the blacklist function only triggered
678 // the animation.
679 onMostVisitedChange();
680 }
681
682
683 /**
684 * Handles a click on the notification undo link by hiding the notification and 717 * Handles a click on the notification undo link by hiding the notification and
685 * informing Chrome. 718 * informing Chrome.
686 */ 719 */
687 function onUndo() { 720 function onUndo() {
688 userInitiatedMostVisitedChange = true; 721 userInitiatedMostVisitedChange = true;
689 hideNotification(); 722 hideNotification();
690 var lastBlacklistedRID = lastBlacklistedTile.rid; 723 var lastBlacklistedRID = lastBlacklistedTile.rid;
691 if (typeof lastBlacklistedRID != 'undefined') 724 if (typeof lastBlacklistedRID != 'undefined')
692 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedRID); 725 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedRID);
693 } 726 }
694 727
695 728
696 /** 729 /**
697 * Handles a click on the restore all notification link by hiding the 730 * Handles a click on the restore all notification link by hiding the
698 * notification and informing Chrome. 731 * notification and informing Chrome.
699 */ 732 */
700 function onRestoreAll() { 733 function onRestoreAll() {
701 userInitiatedMostVisitedChange = true; 734 userInitiatedMostVisitedChange = true;
702 hideNotification(); 735 hideNotification();
703 ntpApiHandle.undoAllMostVisitedDeletions(); 736 ntpApiHandle.undoAllMostVisitedDeletions();
704 } 737 }
705 738
706 739
707 /** 740 /**
708 * Re-renders the tiles if the number of columns has changed. As a temporary 741 * Resizes elements because the number of tile columns may need to change in
709 * fix for crbug/240510, updates the width of the fakebox and most visited tiles 742 * response to resizing. Also shows or hides extra tiles tiles according to the
710 * container. 743 * new width of the page.
711 */ 744 */
712 function onResize() { 745 function onResize() {
713 // If innerWidth is zero, then use the maximum snap size. 746 // If innerWidth is zero, then use the maximum snap size.
714 var innerWidth = window.innerWidth || 820; 747 var innerWidth = window.innerWidth || 820;
748 // Each tile has left and right margins that sum to TILE_MARGIN.
749 var tileRequiredWidth = TILE_WIDTH + TILE_MARGIN;
750 var availableWidth = innerWidth + TILE_MARGIN - MIN_TOTAL_HORIZONTAL_PADDING;
751 var newNumColumns = Math.floor(availableWidth / tileRequiredWidth);
752 if (newNumColumns < MIN_NUM_COLUMNS)
753 newNumColumns = MIN_NUM_COLUMNS;
754 else if (newNumColumns > MAX_NUM_COLUMNS)
755 newNumColumns = MAX_NUM_COLUMNS;
715 756
716 // These values should remain in sync with local_ntp.css. 757 if (numColumnsShown != newNumColumns) {
717 // TODO(jeremycho): Delete once the root cause of crbug/240510 is resolved. 758 numColumnsShown = newNumColumns;
718 var setWidths = function(tilesContainerWidth) { 759 var tilesContainerWidth = numColumnsShown * tileRequiredWidth;
719 tilesContainer.style.width = tilesContainerWidth + 'px'; 760 tilesContainer.style.width = tilesContainerWidth + 'px';
720 if (fakebox) 761 if (fakebox) // -2 to account for border.
721 fakebox.style.width = (tilesContainerWidth - 2) + 'px'; 762 fakebox.style.width = (tilesContainerWidth - TILE_MARGIN - 2) + 'px';
722 }; 763 // Render without clearing tiles.
723 if (innerWidth >= 820) 764 renderAndShowTiles();
724 setWidths(620);
725 else if (innerWidth >= 660)
726 setWidths(460);
727 else
728 setWidths(300);
729
730 var tileRequiredWidth = TILE_WIDTH + TILE_MARGIN_START;
731 // Adds margin-start to the available width to compensate the extra margin
732 // counted above for the first tile (which does not have a margin-start).
733 var availableWidth = innerWidth + TILE_MARGIN_START -
734 MIN_TOTAL_HORIZONTAL_PADDING;
735 var numColumnsToShow = Math.floor(availableWidth / tileRequiredWidth);
736 numColumnsToShow = Math.max(MIN_NUM_COLUMNS,
737 Math.min(MAX_NUM_COLUMNS, numColumnsToShow));
738 if (numColumnsToShow != numColumnsShown) {
739 numColumnsShown = numColumnsToShow;
740 renderTiles();
741 } 765 }
742 } 766 }
743 767
744 768
745 /** 769 /**
746 * Returns the tile corresponding to the specified page RID. 770 * Returns the tile corresponding to the specified page RID.
747 * @param {number} rid The page RID being looked up. 771 * @param {number} rid The page RID being looked up.
748 * @return {Tile} The corresponding tile. 772 * @return {Tile} The corresponding tile.
749 */ 773 */
750 function getTileByRid(rid) { 774 function getTileByRid(rid) {
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 /** 897 /**
874 * Removes a node from its parent. 898 * Removes a node from its parent.
875 * @param {Node} node The node to remove. 899 * @param {Node} node The node to remove.
876 */ 900 */
877 function removeNode(node) { 901 function removeNode(node) {
878 node.parentNode.removeChild(node); 902 node.parentNode.removeChild(node);
879 } 903 }
880 904
881 905
882 /** 906 /**
883 * Removes all the child nodes on a DOM node.
884 * @param {Node} node Node to remove children from.
885 */
886 function removeChildren(node) {
887 node.innerHTML = '';
888 }
889
890
891 /**
892 * @param {!Element} element The element to register the handler for. 907 * @param {!Element} element The element to register the handler for.
893 * @param {number} keycode The keycode of the key to register. 908 * @param {number} keycode The keycode of the key to register.
894 * @param {!Function} handler The key handler to register. 909 * @param {!Function} handler The key handler to register.
895 */ 910 */
896 function registerKeyHandler(element, keycode, handler) { 911 function registerKeyHandler(element, keycode, handler) {
897 element.addEventListener('keydown', function(event) { 912 element.addEventListener('keydown', function(event) {
898 if (event.keyCode == keycode) 913 if (event.keyCode == keycode)
899 handler(event); 914 handler(event);
900 }); 915 });
901 } 916 }
(...skipping 15 matching lines...) Expand all
917 * Prepares the New Tab Page by adding listeners, rendering the current 932 * Prepares the New Tab Page by adding listeners, rendering the current
918 * theme, the most visited pages section, and Google-specific elements for a 933 * theme, the most visited pages section, and Google-specific elements for a
919 * Google-provided page. 934 * Google-provided page.
920 */ 935 */
921 function init() { 936 function init() {
922 tilesContainer = $(IDS.TILES); 937 tilesContainer = $(IDS.TILES);
923 notification = $(IDS.NOTIFICATION); 938 notification = $(IDS.NOTIFICATION);
924 attribution = $(IDS.ATTRIBUTION); 939 attribution = $(IDS.ATTRIBUTION);
925 ntpContents = $(IDS.NTP_CONTENTS); 940 ntpContents = $(IDS.NTP_CONTENTS);
926 941
927 for (var i = 0; i < NUM_ROWS; i++) {
928 var row = document.createElement('div');
929 row.classList.add(CLASSES.ROW);
930 tilesContainer.appendChild(row);
931 }
932
933 if (configData.isGooglePage) { 942 if (configData.isGooglePage) {
934 var logo = document.createElement('div'); 943 var logo = document.createElement('div');
935 logo.id = IDS.LOGO; 944 logo.id = IDS.LOGO;
936 945
937 fakebox = document.createElement('div'); 946 fakebox = document.createElement('div');
938 fakebox.id = IDS.FAKEBOX; 947 fakebox.id = IDS.FAKEBOX;
939 fakebox.innerHTML = 948 fakebox.innerHTML =
940 '<input id="' + IDS.FAKEBOX_INPUT + 949 '<input id="' + IDS.FAKEBOX_INPUT +
941 '" autocomplete="off" tabindex="-1" aria-hidden="true">' + 950 '" autocomplete="off" tabindex="-1" aria-hidden="true">' +
942 '<div id=cursor></div>'; 951 '<div id="cursor"></div>';
943 952
944 ntpContents.insertBefore(fakebox, ntpContents.firstChild); 953 ntpContents.insertBefore(fakebox, ntpContents.firstChild);
945 ntpContents.insertBefore(logo, ntpContents.firstChild); 954 ntpContents.insertBefore(logo, ntpContents.firstChild);
946 } else { 955 } else {
947 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE); 956 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE);
948 } 957 }
949 958
950 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); 959 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE);
951 notificationMessage.textContent = 960 notificationMessage.textContent =
952 configData.translatedStrings.thumbnailRemovedNotification; 961 configData.translatedStrings.thumbnailRemovedNotification;
953 var undoLink = $(IDS.UNDO_LINK); 962 var undoLink = $(IDS.UNDO_LINK);
954 undoLink.addEventListener('click', onUndo); 963 undoLink.addEventListener('click', onUndo);
955 registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo); 964 registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo);
956 undoLink.textContent = configData.translatedStrings.undoThumbnailRemove; 965 undoLink.textContent = configData.translatedStrings.undoThumbnailRemove;
957 var restoreAllLink = $(IDS.RESTORE_ALL_LINK); 966 var restoreAllLink = $(IDS.RESTORE_ALL_LINK);
958 restoreAllLink.addEventListener('click', onRestoreAll); 967 restoreAllLink.addEventListener('click', onRestoreAll);
959 registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo); 968 registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo);
960 restoreAllLink.textContent = 969 restoreAllLink.textContent =
961 configData.translatedStrings.restoreThumbnailsShort; 970 configData.translatedStrings.restoreThumbnailsShort;
962 $(IDS.ATTRIBUTION_TEXT).textContent = 971 $(IDS.ATTRIBUTION_TEXT).textContent =
963 configData.translatedStrings.attributionIntro; 972 configData.translatedStrings.attributionIntro;
964 973
965 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON); 974 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
966 notificationCloseButton.addEventListener('click', hideNotification); 975 notificationCloseButton.addEventListener('click', hideNotification);
967 976
968 userInitiatedMostVisitedChange = false;
969 window.addEventListener('resize', onResize); 977 window.addEventListener('resize', onResize);
970 onResize(); 978 onResize();
971 979
972 var topLevelHandle = getEmbeddedSearchApiHandle(); 980 var topLevelHandle = getEmbeddedSearchApiHandle();
973 981
974 ntpApiHandle = topLevelHandle.newTabPage; 982 ntpApiHandle = topLevelHandle.newTabPage;
975 ntpApiHandle.onthemechange = onThemeChange; 983 ntpApiHandle.onthemechange = onThemeChange;
976 ntpApiHandle.onmostvisitedchange = onMostVisitedChange; 984 ntpApiHandle.onmostvisitedchange = onMostVisitedChange;
977 985
978 ntpApiHandle.oninputstart = onInputStart; 986 ntpApiHandle.oninputstart = onInputStart;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1040 1048
1041 return { 1049 return {
1042 init: init, 1050 init: init,
1043 listen: listen 1051 listen: listen
1044 }; 1052 };
1045 } 1053 }
1046 1054
1047 if (!window.localNTPUnitTest) { 1055 if (!window.localNTPUnitTest) {
1048 LocalNTP().listen(); 1056 LocalNTP().listen();
1049 } 1057 }
OLDNEW
« no previous file with comments | « chrome/browser/resources/local_ntp/local_ntp.css ('k') | chrome/browser/resources/local_ntp/local_ntp_util.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698