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 26bf34eb8fa71b58fc06c858fd5b352fb07585bd..3dfdbe6df086c7bfabe5c09b3efbfffe1fddcca5 100644 |
--- a/chrome/browser/resources/local_ntp/local_ntp.js |
+++ b/chrome/browser/resources/local_ntp/local_ntp.js |
@@ -28,6 +28,7 @@ var CLASSES = { |
ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme |
BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation |
BLACKLIST_BUTTON: 'mv-x', |
+ BLACKLIST_BUTTON_INNER: 'mv-x-inner', |
DARK: 'dark', |
DEFAULT_THEME: 'default-theme', |
DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', |
@@ -176,13 +177,6 @@ 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} |
@@ -268,6 +262,13 @@ var MOST_VISITED_THUMBNAIL_IFRAME = 'thumbnail.html'; |
/** |
+ * The color of the title in RRGGBBAA format. |
+ * @type {?string} |
+ */ |
+var titleColor = null; |
+ |
+ |
+/** |
* Hide most visited tiles for at most this many milliseconds while painting. |
* @type {number} |
* @const |
@@ -306,17 +307,19 @@ function Tile(elem, opt_innerElem, 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. |
+ * Heuristic to determine whether a theme should be considered to be dark, so |
+ * the colors of various UI elements can be adjusted. |
+ * @param {ThemeBackgroundInfo|undefined} info Theme background information. |
+ * @return {boolean} Whether the theme is dark. |
* @private |
*/ |
-function getIsBackgroundDark(info) { |
- if (info.imageUrl) |
- return true; |
- var rgba = info.backgroundColorRgba; |
+function getIsThemeDark(info) { |
+ if (!info) |
+ return false; |
+ // Heuristic: bright text implies dark theme. |
+ var rgba = info.textColorRgba; |
var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2]; |
- return luminance < 128; |
+ return luminance >= 128; |
} |
@@ -325,20 +328,34 @@ function getIsBackgroundDark(info) { |
* @private |
*/ |
function renderTheme() { |
+ var fakeboxText = $(IDS.FAKEBOX_TEXT); |
+ fakeboxText.innerHTML = ''; |
+ if (NTP_DESIGN.showFakeboxHint && |
+ configData.translatedStrings.searchboxPlaceholder) { |
+ fakeboxText.textContent = configData.translatedStrings.searchboxPlaceholder; |
+ } |
+ |
var info = ntpApiHandle.themeBackgroundInfo; |
+ var isThemeDark = getIsThemeDark(info); |
+ ntpContents.classList.toggle(CLASSES.DARK, isThemeDark); |
if (!info) { |
- isBackgroundDark = false; |
+ titleColor = NTP_DESIGN.titleColor; |
return; |
} |
- isBackgroundDark = getIsBackgroundDark(info); |
- ntpContents.classList.toggle(CLASSES.DARK, isBackgroundDark); |
+ if (!info.usingDefaultTheme && info.textColorRgba) { |
+ titleColor = convertToRRGGBBAAColor(info.textColorRgba); |
+ } else { |
+ titleColor = isThemeDark ? |
+ NTP_DESIGN.titleColorAgainstDark : NTP_DESIGN.titleColor; |
+ } |
var background = [convertToRGBAColor(info.backgroundColorRgba), |
info.imageUrl, |
info.imageTiling, |
info.imageHorizontalAlignment, |
info.imageVerticalAlignment].join(' ').trim(); |
+ |
document.body.style.background = background; |
document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); |
updateThemeAttribution(info.attributionUrl); |
@@ -366,7 +383,6 @@ function onThemeChange() { |
function setCustomThemeStyle(opt_themeInfo) { |
var customStyleElement = $(IDS.CUSTOM_THEME_STYLE); |
var head = document.head; |
- |
if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) { |
ntpContents.classList.remove(CLASSES.DEFAULT_THEME); |
var themeStyle = |
@@ -444,6 +460,19 @@ function setAttributionVisibility_(show) { |
/** |
+ * Converts an Array of color components into RRGGBBAA format. |
+ * @param {Array.<number>} color Array of rgba color components. |
+ * @return {string} Color string in RRGGBBAA format. |
+ * @private |
+ */ |
+function convertToRRGGBBAAColor(color) { |
+ return color.map(function(t) { |
+ return ('0' + t.toString(16)).slice(-2); // To 2-digit, 0-padded hex. |
+ }).join(''); |
+} |
+ |
+ |
+ /** |
* Converts an Array of color components into RGBA format "rgba(R,G,B,A)". |
* @param {Array.<number>} color Array of rgba color components. |
* @return {string} CSS color in RGBA format. |
@@ -585,8 +614,6 @@ 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), |
@@ -632,6 +659,11 @@ function getMostVisitedThumbnailIframeUrl(rid, position) { |
function createTile(page, position) { |
var tileElem = document.createElement('div'); |
tileElem.classList.add(CLASSES.TILE); |
+ // Prevent tile from being selected (and highlighted) when areas outside the |
+ // <iframe>s are clicked. |
+ tileElem.addEventListener('mousedown', function(e) { |
+ e.preventDefault(); |
+ }); |
var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER); |
if (page) { |
@@ -694,6 +726,8 @@ function createTile(page, position) { |
// The button used to blacklist this page. |
var blacklistButton = createAndAppendElement( |
innerElem, 'div', CLASSES.BLACKLIST_BUTTON); |
+ createAndAppendElement( |
+ blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); |
var blacklistFunction = generateBlacklistFunction(rid); |
blacklistButton.addEventListener('click', blacklistFunction); |
blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; |
@@ -757,6 +791,7 @@ function showNotification() { |
*/ |
function hideNotification() { |
notification.classList.add(CLASSES.HIDE_NOTIFICATION); |
+ notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION); |
} |
@@ -785,11 +820,11 @@ function onRestoreAll() { |
/** |
- * 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. |
+ * Recomputes the number of tile columns, and width of various contents based |
+ * on the width of the window. |
+ * @return {boolean} Whether the number of tile columns has changed. |
*/ |
-function onResize() { |
+function updateContentWidth() { |
var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin; |
// If innerWidth is zero, then use the maximum snap size. |
var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth - |
@@ -804,14 +839,28 @@ function onResize() { |
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'; |
- } |
+ if (numColumnsShown === newNumColumns) |
+ return false; |
+ |
+ numColumnsShown = newNumColumns; |
+ var tilesContainerWidth = numColumnsShown * tileRequiredWidth; |
+ tilesContainer.style.width = tilesContainerWidth + 'px'; |
+ if (fakebox) { |
+ // -2 to account for border. |
+ var fakeboxWidth = (tilesContainerWidth - NTP_DESIGN.tileMargin - 2); |
+ fakebox.style.width = fakeboxWidth + 'px'; |
+ } |
+ return true; |
+} |
+ |
+ |
+/** |
+ * 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() { |
+ if (updateContentWidth()) { |
// Render without clearing tiles. |
renderAndShowTiles(); |
} |
@@ -1000,11 +1049,7 @@ function init() { |
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="' + IDS.FAKEBOX_TEXT + '"></div>'); |
fakeboxHtml.push('<div id="cursor"></div>'); |
fakebox.innerHTML = fakeboxHtml.join(''); |
@@ -1014,6 +1059,9 @@ function init() { |
document.body.classList.add(CLASSES.NON_GOOGLE_PAGE); |
} |
+ // Hide notifications after fade out, so we can't focus on links via keyboard. |
+ notification.addEventListener('webkitTransitionEnd', hideNotification); |
+ |
var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); |
notificationMessage.textContent = |
configData.translatedStrings.thumbnailRemovedNotification; |
@@ -1033,10 +1081,12 @@ function init() { |
configData.translatedStrings.attributionIntro; |
var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON); |
+ createAndAppendElement( |
+ notificationCloseButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); |
notificationCloseButton.addEventListener('click', hideNotification); |
window.addEventListener('resize', onResize); |
- onResize(); |
+ updateContentWidth(); |
var topLevelHandle = getEmbeddedSearchApiHandle(); |