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

Unified Diff: chrome/browser/resources/local_ntp/local_ntp.js

Issue 473583002: [Local NTP] Implementing Material Design styling (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixing comments. 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 side-by-side diff with in-line comments
Download patch
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 9aaa9a814bb1b7410f2e92e39f7db5a0e03bb55f..ba193ba55287e85565d6e8173d7a56cd1e58b854 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -28,12 +28,16 @@ var CLASSES = {
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',
@@ -43,8 +47,10 @@ var CLASSES = {
PAGE_READY: 'mv-page-ready', // page tile when ready
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'
};
@@ -60,6 +66,7 @@ var IDS = {
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',
@@ -169,6 +176,13 @@ var isBlacklisting = false;
/**
+ * 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}
@@ -266,17 +280,21 @@ var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500;
* 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_titleElem, opt_thumbnailElem, 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} */
@@ -288,13 +306,33 @@ function Tile(elem, opt_titleElem, opt_thumbnailElem, 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,
@@ -305,7 +343,15 @@ function onThemeChange() {
document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo);
updateThemeAttribution(info.attributionUrl);
setCustomThemeStyle(info);
+}
+
+/**
+ * Updates the NTP based on the current theme, then rerenders all tiles.
+ * @private
+ */
+function onThemeChange() {
+ renderTheme();
tilesContainer.innerHTML = '';
renderAndShowTiles();
}
@@ -322,6 +368,7 @@ function setCustomThemeStyle(opt_themeInfo) {
var head = document.head;
if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) {
+ ntpContents.classList.remove(CLASSES.DEFAULT_THEME);
var themeStyle =
'#attribution {' +
' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' +
@@ -336,11 +383,11 @@ function setCustomThemeStyle(opt_themeInfo) {
' -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) + ';' +
'}' +
- '.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) + ';' +
'}';
@@ -355,8 +402,10 @@ function setCustomThemeStyle(opt_themeInfo) {
head.appendChild(customStyleElement);
}
- } else if (customStyleElement) {
- head.removeChild(customStyleElement);
+ } else {
+ ntpContents.classList.add(CLASSES.DEFAULT_THEME);
+ if (customStyleElement)
+ head.removeChild(customStyleElement);
}
}
@@ -412,10 +461,10 @@ function convertToRGBAColor(color) {
function onMostVisitedChange() {
if (isBlacklisting) {
// Trigger the blacklist animation, which then triggers reloadAllTiles().
- var lastBlacklistedTileElement = lastBlacklistedTile.elem;
- lastBlacklistedTileElement.addEventListener(
+ var lastBlacklistedTileElem = lastBlacklistedTile.elem;
+ lastBlacklistedTileElem.addEventListener(
'webkitTransitionEnd', blacklistAnimationDone);
- lastBlacklistedTileElement.classList.add(CLASSES.BLACKLIST);
+ lastBlacklistedTileElem.classList.add(CLASSES.BLACKLIST);
} else {
reloadAllTiles();
}
@@ -457,22 +506,19 @@ function reloadAllTiles() {
/**
* 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 tile visible the
- * moment all tiles are loaded.
+ * @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() {
- tile.titleElem.hidden = false;
tileVisibilityBarrier.remove();
};
}
-
if (tile.thumbnailElem) {
tileVisibilityBarrier.add();
tile.thumbnailElem.onload = function() {
- tile.thumbnailElem.hidden = false;
tile.elem.classList.add(CLASSES.PAGE_READY);
tileVisibilityBarrier.remove();
};
@@ -494,18 +540,21 @@ function renderAndShowTiles() {
// If we need to render new tiles, manage the visibility to hide intermediate
// load states of the <iframe>s.
if (numExisting < numDesired) {
- var tileVisibilityBarrier = new Barrier(function() {
- tilesContainer.style.visibility = 'visible';
- });
+ 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).
- tilesContainer.style.visibility = 'hidden';
window.setTimeout(function() {
tileVisibilityBarrier.cancel();
- tilesContainer.style.visibility = 'visible';
+ showAll();
}, MOST_VISITED_PAINT_TIMEOUT_MSEC);
}
userInitiatedMostVisitedChange = false;
@@ -516,8 +565,8 @@ function renderAndShowTiles() {
}
}
- // Show only the desired tiles. Not using .hidden because it does not work for
- // inline-block elements.
+ // 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
@@ -536,11 +585,13 @@ function renderAndShowTiles() {
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(NTP_DESIGN.titleColor),
+ 'c=' + encodeURIComponent(titleColor),
'pos=' + encodeURIComponent(position)];
if (NTP_DESIGN.titleTextAlign)
params.push('ta=' + encodeURIComponent(NTP_DESIGN.titleTextAlign));
@@ -565,6 +616,8 @@ function getMostVisitedThumbnailIframeUrl(rid, position) {
'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('&');
}
@@ -577,12 +630,13 @@ function getMostVisitedThumbnailIframeUrl(rid, position) {
* @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();
@@ -590,15 +644,15 @@ function createTile(page, position) {
};
// 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:
//
@@ -615,45 +669,53 @@ function createTile(page, position) {
// TODO(jered): Find and fix the root (probably Blink) bug.
// Keep this ID here. See comment above.
- titleElement.id = 'title-' + rid;
- titleElement.className = CLASSES.TITLE;
- titleElement.hidden = true;
- titleElement.src = getMostVisitedTitleIframeUrl(rid, position);
- tileElement.appendChild(titleElement);
+ 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';
+ var thumbnailElem = document.createElement('iframe');
+ thumbnailElem.tabIndex = '-1';
// Keep this ID here. See comment above.
- thumbnailElement.id = 'thumb-' + rid;
- thumbnailElement.className = CLASSES.THUMBNAIL;
- thumbnailElement.hidden = true;
- thumbnailElement.src = getMostVisitedThumbnailIframeUrl(rid, position);
- tileElement.appendChild(thumbnailElement);
-
- // A mask to darken the thumbnail on focus.
- var maskElement = createAndAppendElement(
- tileElement, 'div', CLASSES.THUMBNAIL_MASK);
+ 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);
+ registerKeyHandler(tileElem, 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 + ')';
+ // 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, titleElement, thumbnailElement, rid);
+ return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid);
} else {
- return new Tile(tileElement);
+ return new Tile(tileElem);
}
}
@@ -747,8 +809,7 @@ function onResize() {
var tilesContainerWidth = numColumnsShown * tileRequiredWidth;
tilesContainer.style.width = tilesContainerWidth + 'px';
if (fakebox) {
- // -2 to account for border.
- fakebox.style.width =
+ fakebox.style.width = // -2 to account for border.
(tilesContainerWidth - NTP_DESIGN.tileMargin - 2) + 'px';
}
// Render without clearing tiles.
@@ -936,10 +997,15 @@ function init() {
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.searchboxPlaceholder) {
+ fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '">' +
+ configData.searchboxPlaceholder + '</div>');
+ }
+ fakeboxHtml.push('<div id="cursor"></div>');
+ fakebox.innerHTML = fakeboxHtml.join('');
ntpContents.insertBefore(fakebox, ntpContents.firstChild);
ntpContents.insertBefore(logo, ntpContents.firstChild);
@@ -983,7 +1049,7 @@ function init() {
if (ntpApiHandle.isInputInProgress)
onInputStart();
- onThemeChange();
+ renderTheme();
onMostVisitedChange();
searchboxApiHandle = topLevelHandle.searchBox;
« no previous file with comments | « chrome/browser/resources/local_ntp/local_ntp.css ('k') | chrome/browser/resources/local_ntp/local_ntp_design.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698