*/
function LocalNTP() {
<include src="../../../../ui/webui/resources/js/assert.js">
+<include src="local_ntp_design.js">
+<include src="local_ntp_util.js">
<include src="window_disposition_util.js">
ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme
BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation
BLACKLIST_BUTTON: 'mv-x',
+ DARK: 'dark',
+ DEFAULT_THEME: 'default-theme',
DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide',
+ DOT: 'dot',
FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive
FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox
// Applies drag focus style to the fakebox
FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused',
FAVICON: 'mv-favicon',
+ FAVICON_FALLBACK: 'mv-favicon-fallback',
HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation
HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo',
HIDE_NOTIFICATION: 'mv-notice-hide',
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_FALLBACK: 'mv-thumb-fallback',
THUMBNAIL_MASK: 'mv-mask',
TILE: 'mv-tile',
+ TILE_INNER: 'mv-tile-inner',
TITLE: 'mv-title'
};
CUSTOM_THEME_STYLE: 'ct-style',
FAKEBOX: 'fakebox',
FAKEBOX_INPUT: 'fakebox-input',
+ FAKEBOX_TEXT: 'fakebox-text',
LOGO: 'logo',
NOTIFICATION: 'mv-notice',
NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x',
/**
+ * Specifications for the NTP design.
+ * @const {NtpDesign}
+ */
+var NTP_DESIGN = getNtpDesign(configData.ntpDesignName);
+
+
+/**
* The container for the tile elements.
* @type {Element}
*/
/**
+ * Stores whether the current theme has a dark background.
+ * @type {boolean}
+ */
+var isBackgroundDark = false;
+
+
+/**
* Current number of tiles columns shown based on the window width, including
* those that just contain filler.
* @type {number}
/**
- * True if the user initiated the current most visited change and false
- * otherwise.
+ * A flag to indicate Most Visited changed caused by user action. If true, then
+ * in onMostVisitedChange() tiles remain visible so no flickering occurs.
* @type {boolean}
*/
var userInitiatedMostVisitedChange = false;
var fakeboxInputBehavior = NTP_DISPOSE_STATE.HIDE_FAKEBOX_AND_LOGO;
-/**
- * Total tile width. Should be equal to mv-tile's width + 2 * border-width.
- * @private {number}
- * @const
- */
-var TILE_WIDTH = 140;
-
-
-/**
- * Margin between tiles. Should be equal to mv-tile's -webkit-margin-start.
- * @private {number}
- * @const
- */
-var TILE_MARGIN_START = 20;
-
-
/** @type {number} @const */
var MAX_NUM_TILES_TO_SHOW = 8;
/**
- * The hex color for most visited tile elements.
- * @type {string}
- * @const
- */
-var MOST_VISITED_COLOR = '777777';
-
-
-/**
- * The font family for most visited tile elements.
- * @type {string}
- * @const
- */
-var MOST_VISITED_FONT_FAMILY = 'arial, sans-serif';
-
-
-/**
- * The font size for most visited tile elements.
- * @type {number}
- * @const
- */
-var MOST_VISITED_FONT_SIZE = 11;
-
-
-/**
* Hide most visited tiles for at most this many milliseconds while painting.
* @type {number}
* @const
* pad out the section when not enough pages exist.
*
* @param {Element} elem The element for rendering the tile.
+ * @param {Element=} opt_innerElem The element for contents of tile.
+ * @param {Element=} opt_titleElem The element for rendering the title.
+ * @param {Element=} opt_thumbnailElem The element for rendering the thumbnail.
* @param {number=} opt_rid The RID for the corresponding Most Visited page.
* Should only be left unspecified when creating a filler tile.
* @constructor
*/
-function Tile(elem, opt_rid) {
+function Tile(elem, opt_innerElem, opt_titleElem, opt_thumbnailElem, opt_rid) {
/** @type {Element} */
this.elem = elem;
+ /** @type {Element|undefined} */
+ this.innerElem = opt_innerElem;
+
+ /** @type {Element|undefined} */
+ this.titleElem = opt_titleElem;
+
+ /** @type {Element|undefined} */
+ this.thumbnailElem = opt_thumbnailElem;
+
/** @type {number|undefined} */
this.rid = opt_rid;
}
/**
+ * Determines whether a theme should be considered to have dark background.
+ * @param {ThemeBackgroundInfo} info Theme background information.
+ * @return {boolean} Whether the theme has dark background.
+ * @private
+ */
+function getIsBackgroundDark(info) {
+ if (info.imageUrl)
+ return true;
+ var rgba = info.backgroundColorRgba;
+ var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2];
+ return luminance < 128;
+}
+
+
+/**
* Updates the NTP based on the current theme.
* @private
*/
-function onThemeChange() {
+function renderTheme() {
var info = ntpApiHandle.themeBackgroundInfo;
- if (!info)
+ if (!info) {
+ isBackgroundDark = false;
return;
+ }
+
+ isBackgroundDark = getIsBackgroundDark(info);
+ ntpContents.classList.toggle(CLASSES.DARK, isBackgroundDark);
var background = [convertToRGBAColor(info.backgroundColorRgba),
info.imageUrl,
document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo);
updateThemeAttribution(info.attributionUrl);
setCustomThemeStyle(info);
- renderTiles();
+}
+
+
+/**
+ * Updates the NTP based on the current theme, then rerenders all tiles.
+ * @private
+ */
+function onThemeChange() {
+ renderTheme();
+ tilesContainer.innerHTML = '';
+ renderAndShowTiles();
}
var head = document.head;
if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) {
+ ntpContents.classList.remove(CLASSES.DEFAULT_THEME);
var themeStyle =
'#attribution {' +
' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' +
' -webkit-filter: drop-shadow(0 0 0 ' +
convertToRGBAColor(opt_themeInfo.textColorRgba) + ');' +
'}' +
- '.mv-page-ready {' +
+ '.mv-page-ready .mv-mask {' +
' border: 1px solid ' +
- convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' +
+ convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' +
'}' +
- '.mv-page-ready:hover, .mv-page-ready:focus {' +
+ '.mv-page-ready:hover .mv-mask, .mv-page-ready:focus .mv-mask {' +
' border-color: ' +
convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' +
'}';
head.appendChild(customStyleElement);
}
- } else if (customStyleElement) {
- head.removeChild(customStyleElement);
+ } else {
+ ntpContents.classList.add(CLASSES.DEFAULT_THEME);
+ if (customStyleElement)
+ head.removeChild(customStyleElement);
}
}
* 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.
- var lastBlacklistedTileElement = lastBlacklistedTile.elem;
- lastBlacklistedTileElement.addEventListener(
+ // Trigger the blacklist animation, which then triggers reloadAllTiles().
+ var lastBlacklistedTileElem = lastBlacklistedTile.elem;
+ lastBlacklistedTileElem.addEventListener(
'webkitTransitionEnd', blacklistAnimationDone);
- lastBlacklistedTileElement.classList.add(CLASSES.BLACKLIST);
-
+ lastBlacklistedTileElem.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;
- 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 = [];
+ for (var i = 0; i < MAX_NUM_TILES_TO_SHOW; ++i)
+ tiles.push(createTile(pages[i], i));
+
+ tilesContainer.innerHTML = '';
+ renderAndShowTiles();
+}
+
+
+/**
+ * Binds onload events for a tile's internal <iframe> elements.
+ * @param {Tile} tile The main tile to bind events to.
+ * @param {Barrier} tileVisibilityBarrier A barrier to make all tiles visible
+ * the moment all tiles are loaded.
+ */
+function bindTileOnloadEvents(tile, tileVisibilityBarrier) {
+ if (tile.titleElem) {
+ tileVisibilityBarrier.add();
+ tile.titleElem.onload = function() {
+ tileVisibilityBarrier.remove();
+ };
+ }
+ if (tile.thumbnailElem) {
+ tileVisibilityBarrier.add();
+ tile.thumbnailElem.onload = function() {
+ tile.elem.classList.add(CLASSES.PAGE_READY);
+ tileVisibilityBarrier.remove();
+ };
}
}
/**
- * Shows most visited tiles if all child iframes are loaded, and hides them
- * otherwise.
+ * Renders the current list of visible tiles to DOM, and hides tiles that are
+ * already in the DOM but should not be seen.
*/
-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;
+function renderAndShowTiles() {
+ var numExisting = tilesContainer.querySelectorAll('.' + CLASSES.TILE).length;
+ // Only add visible tiles to the DOM, to avoid creating invisible tiles that
+ // produce meaningless impression metrics. However, if a tile becomes
+ // invisible then we leave it in DOM to prevent reload if it's shown again.
+ var numDesired = Math.min(tiles.length, numColumnsShown * NUM_ROWS);
+
+ // If we need to render new tiles, manage the visibility to hide intermediate
+ // load states of the <iframe>s.
+ if (numExisting < numDesired) {
+ var showAll = function() {
+ for (var i = 0; i < numDesired; ++i) {
+ if (tiles[i].titleElem || tiles[i].thumbnailElem)
+ tiles[i].elem.classList.add(CLASSES.PAGE_READY);
+ }
+ };
+ var tileVisibilityBarrier = new Barrier(showAll);
+
+ if (!userInitiatedMostVisitedChange) {
+ // Make titleContainer invisible, but still taking up space.
+ // titleContainer becomes visible again (1) on timeout, or (2) when all
+ // tiles finish loading (using tileVisibilityBarrier).
+ window.setTimeout(function() {
+ tileVisibilityBarrier.cancel();
+ showAll();
+ }, MOST_VISITED_PAINT_TIMEOUT_MSEC);
}
- }
- if (ready) {
- tilesContainer.hidden = false;
userInitiatedMostVisitedChange = false;
+
+ for (var i = numExisting; i < numDesired; ++i) {
+ bindTileOnloadEvents(tiles[i], tileVisibilityBarrier);
+ tilesContainer.appendChild(tiles[i].elem);
+ }
}
+
+ // Show only the desired tiles. Note that .hidden does not work for
+ // inline-block elements like tiles[i].elem.
+ for (var i = 0; i < numDesired; ++i)
+ tiles[i].elem.style.display = 'inline-block';
+ // If |numDesired| < |numExisting| then hide extra tiles (e.g., this occurs
+ // when window is downsized).
+ for (; i < numExisting; ++i)
+ tiles[i].elem.style.display = 'none';
}
/**
- * Builds a URL to display a most visited tile component in an iframe.
- * @param {string} filename The desired most visited component filename.
+ * Builds a URL to display a most visited tile title in an iframe.
* @param {number} rid The restricted ID.
- * @param {string} color The text color for text in the iframe.
- * @param {string} fontFamily The font family for text in the iframe.
- * @param {number} fontSize The font size for text in the iframe.
* @param {number} position The position of the iframe in the UI.
- * @return {string} An URL to display the most visited component in an iframe.
- */
-function getMostVisitedIframeUrl(filename, rid, color, fontFamily, fontSize,
- position) {
- return 'chrome-search://most-visited/' + encodeURIComponent(filename) + '?' +
- ['rid=' + encodeURIComponent(rid),
- 'c=' + encodeURIComponent(color),
- 'f=' + encodeURIComponent(fontFamily),
- 'fs=' + encodeURIComponent(fontSize),
- 'pos=' + encodeURIComponent(position)].join('&');
+ * @return {string} An URL to display the most visited title in an iframe.
+ */
+function getMostVisitedTitleIframeUrl(rid, position) {
+ var url = 'chrome-search://most-visited/' +
+ encodeURIComponent(MOST_VISITED_TITLE_IFRAME);
+ var titleColor = isBackgroundDark ? NTP_DESIGN.titleColorAgainstDark :
+ NTP_DESIGN.titleColor;
+ var params = [
+ 'rid=' + encodeURIComponent(rid),
+ 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily),
+ 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize),
+ 'c=' + encodeURIComponent(titleColor),
+ 'pos=' + encodeURIComponent(position)];
+ if (NTP_DESIGN.titleTextAlign)
+ params.push('ta=' + encodeURIComponent(NTP_DESIGN.titleTextAlign));
+ if (NTP_DESIGN.titleTextFade)
+ params.push('tf=' + encodeURIComponent(NTP_DESIGN.titleTextFade));
+ return url + '?' + params.join('&');
+}
+
+
+/**
+ * Builds a URL to display a most visited tile thumbnail in an iframe.
+ * @param {number} rid The restricted ID.
+ * @param {number} position The position of the iframe in the UI.
+ * @return {string} An URL to display the most visited thumbnail in an iframe.
+ */
+function getMostVisitedThumbnailIframeUrl(rid, position) {
+ var url = 'chrome-search://most-visited/' +
+ encodeURIComponent(MOST_VISITED_THUMBNAIL_IFRAME);
+ var params = [
+ 'rid=' + encodeURIComponent(rid),
+ 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily),
+ 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize),
+ 'c=' + encodeURIComponent(NTP_DESIGN.thumbnailTextColor),
+ 'pos=' + encodeURIComponent(position)];
+ if (NTP_DESIGN.thumbnailFallback)
+ params.push('etfb=1');
+ return url + '?' + params.join('&');
}
* @return {Tile} The new Tile.
*/
function createTile(page, position) {
- var tileElement = document.createElement('div');
- tileElement.classList.add(CLASSES.TILE);
+ var tileElem = document.createElement('div');
+ tileElem.classList.add(CLASSES.TILE);
+ var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER);
if (page) {
var rid = page.rid;
- tileElement.classList.add(CLASSES.PAGE);
+ tileElem.classList.add(CLASSES.PAGE);
var navigateFunction = function(e) {
e.preventDefault();
};
// The click handler for navigating to the page identified by the RID.
- tileElement.addEventListener('click', navigateFunction);
+ tileElem.addEventListener('click', navigateFunction);
// Make thumbnails tab-accessible.
- tileElement.setAttribute('tabindex', '1');
- registerKeyHandler(tileElement, KEYCODE.ENTER, navigateFunction);
+ tileElem.setAttribute('tabindex', '1');
+ registerKeyHandler(tileElem, KEYCODE.ENTER, navigateFunction);
// The iframe which renders the page title.
- var titleElement = document.createElement('iframe');
- titleElement.tabIndex = '-1';
+ var titleElem = document.createElement('iframe');
+ titleElem.tabIndex = '-1';
// Why iframes have IDs:
//
//
// 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.hidden = true;
- titleElement.onload = function() {
- titleElement.hidden = false;
- updateMostVisitedVisibility();
- };
- titleElement.className = CLASSES.TITLE;
- tileElement.appendChild(titleElement);
+ // Keep this ID here. See comment above.
+ titleElem.id = 'title-' + rid;
+ titleElem.className = CLASSES.TITLE;
+ titleElem.src = getMostVisitedTitleIframeUrl(rid, position);
+ innerElem.appendChild(titleElem);
+
+ // A fallback element for missing thumbnails.
+ if (NTP_DESIGN.thumbnailFallback) {
+ var fallbackElem = createAndAppendElement(
+ innerElem, 'div', CLASSES.THUMBNAIL_FALLBACK);
+ if (NTP_DESIGN.thumbnailFallback === THUMBNAIL_FALLBACK.DOT)
+ createAndAppendElement(fallbackElem, 'div', CLASSES.DOT);
+ }
// 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.hidden = true;
- thumbnailElement.onload = function() {
- thumbnailElement.hidden = false;
- tileElement.classList.add(CLASSES.PAGE_READY);
- updateMostVisitedVisibility();
- };
- thumbnailElement.className = CLASSES.THUMBNAIL;
- tileElement.appendChild(thumbnailElement);
-
- // A mask to darken the thumbnail on focus.
- var maskElement = createAndAppendElement(
- tileElement, 'div', CLASSES.THUMBNAIL_MASK);
+ var thumbnailElem = document.createElement('iframe');
+ thumbnailElem.tabIndex = '-1';
+ // Keep this ID here. See comment above.
+ thumbnailElem.id = 'thumb-' + rid;
+ thumbnailElem.className = CLASSES.THUMBNAIL;
+ thumbnailElem.src = getMostVisitedThumbnailIframeUrl(rid, position);
+ innerElem.appendChild(thumbnailElem);
// The button used to blacklist this page.
var blacklistButton = createAndAppendElement(
- tileElement, 'div', CLASSES.BLACKLIST_BUTTON);
+ innerElem, 'div', CLASSES.BLACKLIST_BUTTON);
var blacklistFunction = generateBlacklistFunction(rid);
blacklistButton.addEventListener('click', blacklistFunction);
blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip;
+ // A helper mask on top of the tile that is used to create hover border
+ // and/or to darken the thumbnail on focus.
+ var maskElement = createAndAppendElement(
+ innerElem, 'div', CLASSES.THUMBNAIL_MASK);
+
// When a tile is focused, have delete also blacklist the page.
- registerKeyHandler(tileElement, KEYCODE.DELETE, blacklistFunction);
-
- // The page favicon, if any.
- var faviconUrl = page.faviconUrl;
- if (faviconUrl) {
- var favicon = createAndAppendElement(
- tileElement, 'div', CLASSES.FAVICON);
- favicon.style.backgroundImage = 'url(' + faviconUrl + ')';
+ registerKeyHandler(tileElem, KEYCODE.DELETE, blacklistFunction);
+
+ // The page favicon, or a fallback.
+ var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON);
+ if (page.faviconUrl) {
+ favicon.style.backgroundImage = 'url(' + page.faviconUrl + ')';
+ } else {
+ favicon.classList.add(CLASSES.FAVICON_FALLBACK);
}
- return new Tile(tileElement, rid);
+ return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid);
} else {
- return new Tile(tileElement);
+ return new Tile(tileElem);
}
}
/**
- * 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.
*/
/**
- * 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 to resizing. Also shows or hides extra tiles tiles according to the
+ * new width of the page.
*/
function onResize() {
+ var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin;
// 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) {
- 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 -
+ var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth -
+ NTP_DESIGN.tileMargin + MIN_TOTAL_HORIZONTAL_PADDING;
+ var innerWidth = window.innerWidth || maxSnapSize;
+ // Each tile has left and right margins that sum to NTP_DESIGN.tileMargin.
+ var availableWidth = innerWidth + NTP_DESIGN.tileMargin -
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();
+ var newNumColumns = Math.floor(availableWidth / tileRequiredWidth);
+ if (newNumColumns < MIN_NUM_COLUMNS)
+ newNumColumns = MIN_NUM_COLUMNS;
+ else if (newNumColumns > MAX_NUM_COLUMNS)
+ newNumColumns = MAX_NUM_COLUMNS;
+
+ if (numColumnsShown != newNumColumns) {
+ numColumnsShown = newNumColumns;
+ var tilesContainerWidth = numColumnsShown * tileRequiredWidth;
+ tilesContainer.style.width = tilesContainerWidth + 'px';
+ if (fakebox) {
+ fakebox.style.width = // -2 to account for border.
+ (tilesContainerWidth - NTP_DESIGN.tileMargin - 2) + 'px';
+ }
+ // Render without clearing tiles.
+ renderAndShowTiles();
}
}
/**
- * Removes all the child nodes on a DOM node.
- * @param {Node} node Node to remove children from.
- */
-function removeChildren(node) {
- node.innerHTML = '';
-}
-
-
-/**
* @param {!Element} element The element to register the handler for.
* @param {number} keycode The keycode of the key to register.
* @param {!Function} handler The key handler to register.
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;
fakebox = document.createElement('div');
fakebox.id = IDS.FAKEBOX;
- fakebox.innerHTML =
- '<input id="' + IDS.FAKEBOX_INPUT +
- '" autocomplete="off" tabindex="-1" aria-hidden="true">' +
- '<div id=cursor></div>';
+ var fakeboxHtml = [];
+ fakeboxHtml.push('<input id="' + IDS.FAKEBOX_INPUT +
+ '" autocomplete="off" tabindex="-1" aria-hidden="true">');
+ if (NTP_DESIGN.showFakeboxHint &&
+ configData.translatedStrings.searchboxPlaceholder) {
+ fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '">' +
+ configData.translatedStrings.searchboxPlaceholder + '</div>');
+ }
+ fakeboxHtml.push('<div id="cursor"></div>');
+ fakebox.innerHTML = fakeboxHtml.join('');
ntpContents.insertBefore(fakebox, ntpContents.firstChild);
ntpContents.insertBefore(logo, ntpContents.firstChild);
var notificationMessage = $(IDS.NOTIFICATION_MESSAGE);
notificationMessage.textContent =
configData.translatedStrings.thumbnailRemovedNotification;
+
var undoLink = $(IDS.UNDO_LINK);
undoLink.addEventListener('click', onUndo);
registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo);
undoLink.textContent = configData.translatedStrings.undoThumbnailRemove;
+
var restoreAllLink = $(IDS.RESTORE_ALL_LINK);
restoreAllLink.addEventListener('click', onRestoreAll);
registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo);
restoreAllLink.textContent =
configData.translatedStrings.restoreThumbnailsShort;
+
$(IDS.ATTRIBUTION_TEXT).textContent =
configData.translatedStrings.attributionIntro;
var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
notificationCloseButton.addEventListener('click', hideNotification);
- userInitiatedMostVisitedChange = false;
window.addEventListener('resize', onResize);
onResize();
if (ntpApiHandle.isInputInProgress)
onInputStart();
- onThemeChange();
+ renderTheme();
onMostVisitedChange();
searchboxApiHandle = topLevelHandle.searchBox;
if (searchboxApiHandle.rtl) {
$(IDS.NOTIFICATION).dir = 'rtl';
+ document.body.setAttribute('dir', 'rtl');
// Add class for setting alignments based on language directionality.
document.body.classList.add(CLASSES.RTL);
$(IDS.TILES).dir = 'rtl';