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

Unified 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: Switching back to userInitiatedMostVisitedChange; hiding tiles using visibility. Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/resources/local_ntp/local_ntp.css ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/resources/local_ntp/local_ntp.js
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index fb8b873216619a004c19a623ce170a4cb6d0796b..0786439f118445a2a1708ce59c00bbf7373b6cd8 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -39,7 +39,6 @@ var CLASSES = {
NON_GOOGLE_PAGE: 'non-google-page',
PAGE: 'mv-page', // page tiles
PAGE_READY: 'mv-page-ready', // page tile when ready
- ROW: 'mv-row', // tile row
RTL: 'rtl', // Right-to-left language text.
THUMBNAIL: 'mv-thumb',
THUMBNAIL_MASK: 'mv-mask',
@@ -169,14 +168,23 @@ var numColumnsShown = 0;
/**
- * True if the user initiated the current most visited change and false
- * otherwise.
+ * A flag to indicate Most Visit changed cuased by user action. If true, then
Mathieu 2014/07/25 00:19:17 nit: extra space, and correct to "Most Visited"
Mathieu 2014/07/25 00:19:17 *caused
huangs 2014/07/25 20:12:17 Done.
huangs 2014/07/25 20:12:18 Done.
+ * in onMostVisitedChange() tiles remain visible, to avoid flickering.
* @type {boolean}
*/
var userInitiatedMostVisitedChange = false;
/**
+ * A barrier to make tiles visible the moment all tiles are loaded.
+ * @type {Barrier}
+ */
+var tileVisibilityBarrier = new Barrier(function() {
+ tilesContainer.style.visibility = 'visible';
+});
+
+
+/**
* The browser embeddedSearch.newTabPage object.
* @type {Object}
*/
@@ -213,11 +221,11 @@ var TILE_WIDTH = 140;
/**
- * Margin between tiles. Should be equal to mv-tile's -webkit-margin-start.
+ * Margin between tiles. Should be equal to mv-tile's total horizontal margin.
* @private {number}
* @const
*/
-var TILE_MARGIN_START = 20;
+var TILE_MARGIN = 20;
/** @type {number} @const */
@@ -312,6 +320,41 @@ function Tile(elem, opt_rid) {
/**
+ * A counter with a callback that gets executed on the 1-to-0 transition.
+ *
+ * @param {Function} callback The callback to be executed.
+ * @constructor
+ */
+function Barrier(callback) {
Mathieu 2014/07/25 00:19:17 Could be in a util file included at the top of thi
huangs 2014/07/25 20:12:18 I think the change is short enough to not require
+ /** @type {Function} */
+ this.callback = callback;
+
+ /** @private {number} */
+ this.count_ = 0;
+}
+
+
+/**
+ * Increments count of the Barrier.
+ */
+Barrier.prototype.lock = function() {
+ ++this.count_;
+};
+
+
+/**
+ * Decrements count of the Barrier, and executes callback on 1-to-0 transition.
+ */
+Barrier.prototype.release = function() {
+ if (this.count_ === 0) // Guards against underflow.
+ return;
+ --this.count_;
+ if (this.count_ === 0)
+ this.callback();
+};
+
+
+/**
* Updates the NTP based on the current theme.
* @private
*/
@@ -329,6 +372,7 @@ function onThemeChange() {
document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo);
updateThemeAttribution(info.attributionUrl);
setCustomThemeStyle(info);
+
renderTiles();
}
@@ -432,67 +476,73 @@ function convertToRGBAColor(color) {
* Handles a new set of Most Visited page data.
*/
function onMostVisitedChange() {
- var pages = ntpApiHandle.mostVisited;
-
if (isBlacklisting) {
- // Trigger the blacklist animation and re-render the tiles when it
- // completes.
+ // Trigger the blacklist animation, which then triggers reloadAllTiles().
var lastBlacklistedTileElement = lastBlacklistedTile.elem;
lastBlacklistedTileElement.addEventListener(
'webkitTransitionEnd', blacklistAnimationDone);
lastBlacklistedTileElement.classList.add(CLASSES.BLACKLIST);
-
} else {
- // Otherwise render the tiles using the new data without animation.
- tiles = [];
- for (var i = 0; i < MAX_NUM_TILES_TO_SHOW; ++i) {
- tiles.push(createTile(pages[i], i));
- }
- if (!userInitiatedMostVisitedChange) {
- tilesContainer.hidden = true;
- window.setTimeout(function() {
- if (tilesContainer) {
- tilesContainer.hidden = false;
- }
- }, MOST_VISITED_PAINT_TIMEOUT_MSEC);
- }
- renderTiles();
+ reloadAllTiles();
}
}
/**
- * Renders the current set of tiles.
+ * Handles the end of the blacklist animation by showing the notification and
+ * re-rendering the new set of tiles.
*/
-function renderTiles() {
- var rows = tilesContainer.children;
- for (var i = 0; i < rows.length; ++i) {
- removeChildren(rows[i]);
+function blacklistAnimationDone() {
+ showNotification();
+ isBlacklisting = false;
+ tilesContainer.classList.remove(CLASSES.HIDE_BLACKLIST_BUTTON);
+ lastBlacklistedTile.elem.removeEventListener(
+ 'webkitTransitionEnd', blacklistAnimationDone);
+ // Need to call explicitly to re-render the tiles, since the initial
+ // onmostvisitedchange issued by the blacklist function only triggered
+ // the animation.
+ reloadAllTiles();
+}
+
+
+/**
+ * Fetches new data, creates, and renders tiles.
+ */
+function reloadAllTiles() {
+ var pages = ntpApiHandle.mostVisited;
+
+ if (!userInitiatedMostVisitedChange) {
+ // Temporarily hide titleContainer, then show it (1) on timeout, or (2) when
+ // all tiles finish loading (using tileVisibilityBarrier).
+ tilesContainer.style.visibility = 'hidden';
+ window.setTimeout(function() {
+ if (tilesContainer) {
+ tilesContainer.style.visibility = 'visible';
+ }
+ }, MOST_VISITED_PAINT_TIMEOUT_MSEC);
}
+ userInitiatedMostVisitedChange = false;
- for (var i = 0, length = tiles.length;
- i < Math.min(length, numColumnsShown * NUM_ROWS); ++i) {
- rows[Math.floor(i / numColumnsShown)].appendChild(tiles[i].elem);
+ tiles = [];
+ // Increment barrier to guard against race conditions.
+ tileVisibilityBarrier.lock();
+ for (var i = 0; i < MAX_NUM_TILES_TO_SHOW; ++i) {
+ tiles.push(createTile(pages[i], i));
}
+ renderTiles();
+ tileVisibilityBarrier.release();
}
/**
- * Shows most visited tiles if all child iframes are loaded, and hides them
- * otherwise.
+ * Adds the current list of tiles to DOM.
*/
-function updateMostVisitedVisibility() {
- var iframes = tilesContainer.querySelectorAll('iframe');
- var ready = true;
- for (var i = 0, numIframes = iframes.length; i < numIframes; i++) {
- if (iframes[i].hidden) {
- ready = false;
- break;
- }
- }
- if (ready) {
- tilesContainer.hidden = false;
- userInitiatedMostVisitedChange = false;
+function renderTiles() {
+ removeChildren(tilesContainer);
+ var renderedList = tilesContainer.querySelectorAll('.mv-tile');
+ var size = Math.min(tiles.length, numColumnsShown * NUM_ROWS);
+ for (var i = 0; i < size; ++i) {
+ tilesContainer.appendChild(tiles[i].elem);
}
}
@@ -563,36 +613,36 @@ function createTile(page, position) {
//
// TODO(jered): Find and fix the root (probably Blink) bug.
- titleElement.src = getMostVisitedIframeUrl(
- MOST_VISITED_TITLE_IFRAME, rid, MOST_VISITED_COLOR,
- MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position);
-
// Keep this id here. See comment above.
titleElement.id = 'title-' + rid;
+ titleElement.className = CLASSES.TITLE;
titleElement.hidden = true;
+ tileVisibilityBarrier.lock();
Mathieu 2014/07/25 00:19:17 I don't really like "lock". Wouldn't add, acquire
huangs 2014/07/25 20:12:18 Renamed to add() and remove().
titleElement.onload = function() {
titleElement.hidden = false;
- updateMostVisitedVisibility();
+ tileVisibilityBarrier.release();
};
- titleElement.className = CLASSES.TITLE;
+ titleElement.src = getMostVisitedIframeUrl(
+ MOST_VISITED_TITLE_IFRAME, rid, MOST_VISITED_COLOR,
+ MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position);
tileElement.appendChild(titleElement);
// The iframe which renders either a thumbnail or domain element.
var thumbnailElement = document.createElement('iframe');
thumbnailElement.tabIndex = '-1';
- thumbnailElement.src = getMostVisitedIframeUrl(
- MOST_VISITED_THUMBNAIL_IFRAME, rid, MOST_VISITED_COLOR,
- MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position);
-
// Keep this id here. See comment above.
thumbnailElement.id = 'thumb-' + rid;
+ thumbnailElement.className = CLASSES.THUMBNAIL;
thumbnailElement.hidden = true;
+ tileVisibilityBarrier.lock();
thumbnailElement.onload = function() {
thumbnailElement.hidden = false;
tileElement.classList.add(CLASSES.PAGE_READY);
- updateMostVisitedVisibility();
+ tileVisibilityBarrier.release();
};
- thumbnailElement.className = CLASSES.THUMBNAIL;
+ thumbnailElement.src = getMostVisitedIframeUrl(
+ MOST_VISITED_THUMBNAIL_IFRAME, rid, MOST_VISITED_COLOR,
+ MOST_VISITED_FONT_FAMILY, MOST_VISITED_FONT_SIZE, position);
tileElement.appendChild(thumbnailElement);
// A mask to darken the thumbnail on focus.
@@ -664,23 +714,6 @@ function hideNotification() {
/**
- * Handles the end of the blacklist animation by showing the notification and
- * re-rendering the new set of tiles.
- */
-function blacklistAnimationDone() {
- showNotification();
- isBlacklisting = false;
- tilesContainer.classList.remove(CLASSES.HIDE_BLACKLIST_BUTTON);
- lastBlacklistedTile.elem.removeEventListener(
- 'webkitTransitionEnd', blacklistAnimationDone);
- // Need to call explicitly to re-render the tiles, since the initial
- // onmostvisitedchange issued by the blacklist function only triggered
- // the animation.
- onMostVisitedChange();
-}
-
-
-/**
* Handles a click on the notification undo link by hiding the notification and
* informing Chrome.
*/
@@ -705,39 +738,31 @@ function onRestoreAll() {
/**
- * Re-renders the tiles if the number of columns has changed. As a temporary
- * fix for crbug/240510, updates the width of the fakebox and most visited tiles
- * container.
+ * Resizes elements because the number of tile columns may need to change in
+ * response resizing. Also shows or hides extra tiles beyond the bottommost row.
Mathieu 2014/07/25 00:19:17 response *to resizing
Mathieu 2014/07/25 00:19:17 instead of "beyond the bottommost row", how about
huangs 2014/07/25 20:12:18 Done.
huangs 2014/07/25 20:12:18 Done.
*/
function onResize() {
// If innerWidth is zero, then use the maximum snap size.
var innerWidth = window.innerWidth || 820;
-
- // These values should remain in sync with local_ntp.css.
- // TODO(jeremycho): Delete once the root cause of crbug/240510 is resolved.
- var setWidths = function(tilesContainerWidth) {
+ // Each tile is has left and right margins that sum to TILE_MARGIN.
Mathieu 2014/07/25 00:19:17 Each tile *has
huangs 2014/07/25 20:12:18 Done.
+ var tileRequiredWidth = TILE_WIDTH + TILE_MARGIN;
+ var availableWidth = innerWidth + TILE_MARGIN - MIN_TOTAL_HORIZONTAL_PADDING;
+ var newNumColumns = Math.floor(availableWidth / tileRequiredWidth);
+ newNumColumns =
+ Math.max(MIN_NUM_COLUMNS, Math.min(newNumColumns, MAX_NUM_COLUMNS));
+ if (numColumnsShown != newNumColumns) {
+ numColumnsShown = newNumColumns;
+ var tilesContainerWidth = numColumnsShown * tileRequiredWidth;
tilesContainer.style.width = tilesContainerWidth + 'px';
- if (fakebox)
- fakebox.style.width = (tilesContainerWidth - 2) + 'px';
- };
- if (innerWidth >= 820)
- setWidths(620);
- else if (innerWidth >= 660)
- setWidths(460);
- else
- setWidths(300);
-
- var tileRequiredWidth = TILE_WIDTH + TILE_MARGIN_START;
- // Adds margin-start to the available width to compensate the extra margin
- // counted above for the first tile (which does not have a margin-start).
- var availableWidth = innerWidth + TILE_MARGIN_START -
- MIN_TOTAL_HORIZONTAL_PADDING;
- var numColumnsToShow = Math.floor(availableWidth / tileRequiredWidth);
- numColumnsToShow = Math.max(MIN_NUM_COLUMNS,
- Math.min(MAX_NUM_COLUMNS, numColumnsToShow));
- if (numColumnsToShow != numColumnsShown) {
- numColumnsShown = numColumnsToShow;
- renderTiles();
+ if (fakebox) // -2 to account for border.
+ fakebox.style.width = (tilesContainerWidth - TILE_MARGIN - 2) + 'px';
+ // Shows only rendered tiles in the first NUM_ROWS rows.
+ var renderedList = tilesContainer.querySelectorAll('.mv-tile');
+ var numVisible = Math.min(tiles.length, numColumnsShown * NUM_ROWS);
+ // Not using .hidden becomes it does not work for inline-block elements.
Mathieu 2014/07/25 00:19:17 *because
huangs 2014/07/25 20:12:17 Done.
+ for (var i = 0; i < renderedList.length; ++i) {
+ renderedList[i].style.display = i < numVisible ? 'inline-block' : 'none';
+ }
}
}
@@ -924,12 +949,6 @@ function init() {
attribution = $(IDS.ATTRIBUTION);
ntpContents = $(IDS.NTP_CONTENTS);
- for (var i = 0; i < NUM_ROWS; i++) {
- var row = document.createElement('div');
- row.classList.add(CLASSES.ROW);
- tilesContainer.appendChild(row);
- }
-
if (configData.isGooglePage) {
var logo = document.createElement('div');
logo.id = IDS.LOGO;
@@ -939,7 +958,7 @@ function init() {
fakebox.innerHTML =
'<input id="' + IDS.FAKEBOX_INPUT +
'" autocomplete="off" tabindex="-1" aria-hidden="true">' +
- '<div id=cursor></div>';
+ '<div id="cursor"></div>';
ntpContents.insertBefore(fakebox, ntpContents.firstChild);
ntpContents.insertBefore(logo, ntpContents.firstChild);
@@ -965,7 +984,6 @@ function init() {
var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
notificationCloseButton.addEventListener('click', hideNotification);
- userInitiatedMostVisitedChange = false;
window.addEventListener('resize', onResize);
onResize();
« no previous file with comments | « chrome/browser/resources/local_ntp/local_ntp.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698