**
* The container for the tile elements.
* @type {Element}
*/
var tilesContainer;
/**
* The notification displayed when a page is blacklisted.
* @type {Element}
*/
var notification;
/**
* The container for the theme attribution.
* @type {Element}
*/
var attribution;
/**
* The "fakebox" - an input field that looks like a regular searchbox. When it
* is focused, any text the user types goes directly into the omnibox.
* @type {Element}
*/
var fakebox;
/**
* The container for NTP elements.
* @type {Element}
*/
var ntpContents;
/**
* The array of rendered tiles, ordered by appearance.
* @type {!Array.}
*/
var tiles = [];
/**
* The last blacklisted tile if any, which by definition should not be filler.
* @type {?Tile}
*/
var lastBlacklistedTile = null;
/**
* The iframe element which is currently keyboard focused, or null.
* @type {?Element}
*/
var focusedIframe = null;
/**
* True if a page has been blacklisted and we're waiting on the
* onmostvisitedchange callback. See onMostVisitedChange() for how this
* is used.
* @type {boolean}
*/
var isBlacklisting = false;
/**
* Current number of tiles columns shown based on the window width, including
* those that just contain filler.
* @type {number}
*/
var numColumnsShown = 0;
/**
* 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;
/**
* The browser embeddedSearch.newTabPage object.
* @type {Object}
*/
var ntpApiHandle;
/**
* The browser embeddedSearch.searchBox object.
* @type {Object}
*/
var searchboxApiHandle;
/**
* The state of the NTP when a query is entered into the Omnibox.
* @type {NTP_DISPOSE_STATE}
*/
var omniboxInputBehavior = NTP_DISPOSE_STATE.NONE;
/**
* The state of the NTP when a query is entered into the Fakebox.
* @type {NTP_DISPOSE_STATE}
*/
var fakeboxInputBehavior = NTP_DISPOSE_STATE.HIDE_FAKEBOX_AND_LOGO;
/** @type {number} @const */
var MAX_NUM_TILES_TO_SHOW = 8;
/** @type {number} @const */
var MIN_NUM_COLUMNS = 2;
/** @type {number} @const */
var MAX_NUM_COLUMNS = 4;
/** @type {number} @const */
var NUM_ROWS = 2;
/**
* Minimum total padding to give to the left and right of the most visited
* section. Used to determine how many tiles to show.
* @type {number}
* @const
*/
var MIN_TOTAL_HORIZONTAL_PADDING = 200;
/**
* The filename for a most visited iframe src which shows a page title.
* @type {string}
* @const
*/
var MOST_VISITED_TITLE_IFRAME = 'title.html';
/**
* The filename for a most visited iframe src which shows a thumbnail image.
* @type {string}
* @const
*/
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
*/
var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500;
/**
* A Tile is either a rendering of a Most Visited page or "filler" used to
* 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_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;
}
/**
* 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 getIsThemeDark(info) {
if (!info)
return false;
// Heuristic: light 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;
}
/**
* Updates the NTP based on the current theme.
* @private
*/
function renderTheme() {
var fakeboxText = $(IDS.FAKEBOX_TEXT);
if (fakeboxText) {
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) {
titleColor = NTP_DESIGN.titleColor;
return;
}
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);
setCustomThemeStyle(info);
}
/**
* Updates the NTP based on the current theme, then rerenders all tiles.
* @private
*/
function onThemeChange() {
renderTheme();
tilesContainer.innerHTML = '';
renderAndShowTiles();
}
/**
* Updates the NTP style according to theme.
* @param {Object=} opt_themeInfo The information about the theme. If it is
* omitted the style will be reverted to the default.
* @private
*/
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 =
'#attribution {' +
' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' +
'}' +
'#mv-msg {' +
' color: ' + convertToRGBAColor(opt_themeInfo.textColorRgba) + ';' +
'}' +
'#mv-notice-links span {' +
' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' +
'}' +
'#mv-notice-x {' +
' -webkit-filter: drop-shadow(0 0 0 ' +
convertToRGBAColor(opt_themeInfo.textColorRgba) + ');' +
'}' +
'.mv-page-ready .mv-mask {' +
' border: 1px solid ' +
convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' +
'}' +
'.mv-page-ready:hover .mv-mask, .mv-page-ready .mv-focused ~ .mv-mask {' +
' border-color: ' +
convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' +
'}';