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

Side by Side Diff: chrome/browser/resources/local_ntp/local_ntp.js

Issue 2600683002: Run tools/clang-format-js on some of chrome/browser/resources/ (Closed)
Patch Set: hackhackhack Created 3 years, 11 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 5
6 /** 6 /**
7 * @fileoverview The local InstantExtended NTP. 7 * @fileoverview The local InstantExtended NTP.
8 */ 8 */
9 9
10 10
11 /** 11 /**
12 * Controls rendering the new tab page for InstantExtended. 12 * Controls rendering the new tab page for InstantExtended.
13 * @return {Object} A limited interface for testing the local NTP. 13 * @return {Object} A limited interface for testing the local NTP.
14 */ 14 */
15 function LocalNTP() { 15 function LocalNTP() {
16 'use strict'; 16 'use strict';
17 17
18 18
19 /** 19 /**
20 * Alias for document.getElementById. 20 * Alias for document.getElementById.
21 * @param {string} id The ID of the element to find. 21 * @param {string} id The ID of the element to find.
22 * @return {HTMLElement} The found element or null if not found. 22 * @return {HTMLElement} The found element or null if not found.
23 */ 23 */
24 function $(id) { 24 function $(id) {
25 return document.getElementById(id); 25 return document.getElementById(id);
26 } 26 }
27 27
28 28
29 /** 29 /**
30 * Specifications for an NTP design (not comprehensive). 30 * Specifications for an NTP design (not comprehensive).
31 * 31 *
32 * fakeboxWingSize: Extra distance for fakebox to extend beyond beyond the list 32 * fakeboxWingSize: Extra distance for fakebox to extend beyond beyond the
33 * of tiles. 33 * list
34 * fontFamily: Font family to use for title and thumbnail iframes. 34 * of tiles.
35 * fontSize: Font size to use for the iframes, in px. 35 * fontFamily: Font family to use for title and thumbnail iframes.
36 * mainClass: Class applied to #ntp-contents to control CSS. 36 * fontSize: Font size to use for the iframes, in px.
37 * numTitleLines: Number of lines to display in titles. 37 * mainClass: Class applied to #ntp-contents to control CSS.
38 * showFavicon: Whether to show favicon. 38 * numTitleLines: Number of lines to display in titles.
39 * thumbnailTextColor: The 4-component color that thumbnail iframe may use to 39 * showFavicon: Whether to show favicon.
40 * display text message in place of missing thumbnail. 40 * thumbnailTextColor: The 4-component color that thumbnail iframe may use to
41 * thumbnailFallback: (Optional) A value in THUMBNAIL_FALLBACK to specify the 41 * display text message in place of missing thumbnail.
42 * thumbnail fallback strategy. If unassigned, then the thumbnail.html 42 * thumbnailFallback: (Optional) A value in THUMBNAIL_FALLBACK to specify the
43 * iframe would handle the fallback. 43 * thumbnail fallback strategy. If unassigned, then the thumbnail.html
44 * tileWidth: The width of each suggestion tile, in px. 44 * iframe would handle the fallback.
45 * tileMargin: Spacing between successive tiles, in px. 45 * tileWidth: The width of each suggestion tile, in px.
46 * titleColor: The 4-component color of title text. 46 * tileMargin: Spacing between successive tiles, in px.
47 * titleColorAgainstDark: The 4-component color of title text against a dark 47 * titleColor: The 4-component color of title text.
48 * theme. 48 * titleColorAgainstDark: The 4-component color of title text against a dark
49 * titleTextAlign: (Optional) The alignment of title text. If unspecified, the 49 * theme.
50 * default value is 'center'. 50 * titleTextAlign: (Optional) The alignment of title text. If unspecified, the
51 * titleTextFade: (Optional) The number of pixels beyond which title 51 * default value is 'center'.
52 * text begins to fade. This overrides the default ellipsis style. 52 * titleTextFade: (Optional) The number of pixels beyond which title
53 * 53 * text begins to fade. This overrides the default ellipsis style.
54 * @type {{ 54 *
55 * fakeboxWingSize: number, 55 * @type {{
56 * fontFamily: string, 56 * fakeboxWingSize: number,
57 * fontSize: number, 57 * fontFamily: string,
58 * mainClass: string, 58 * fontSize: number,
59 * numTitleLines: number, 59 * mainClass: string,
60 * showFavicon: boolean, 60 * numTitleLines: number,
61 * thumbnailTextColor: string, 61 * showFavicon: boolean,
62 * thumbnailFallback: string|null|undefined, 62 * thumbnailTextColor: string,
63 * tileWidth: number, 63 * thumbnailFallback: string|null|undefined,
64 * tileMargin: number, 64 * tileWidth: number,
65 * titleColor: string, 65 * tileMargin: number,
66 * titleColorAgainstDark: string, 66 * titleColor: string,
67 * titleTextAlign: string|null|undefined, 67 * titleColorAgainstDark: string,
68 * titleTextFade: number|null|undefined 68 * titleTextAlign: string|null|undefined,
69 * }} 69 * titleTextFade: number|null|undefined
70 */ 70 * }}
71 var NTP_DESIGN = { 71 */
72 fakeboxWingSize: 0, 72 var NTP_DESIGN = {
73 fontFamily: 'arial, sans-serif', 73 fakeboxWingSize: 0,
74 fontSize: 12, 74 fontFamily: 'arial, sans-serif',
75 mainClass: 'thumb-ntp', 75 fontSize: 12,
76 numTitleLines: 1, 76 mainClass: 'thumb-ntp',
77 showFavicon: true, 77 numTitleLines: 1,
78 thumbnailTextColor: [50, 50, 50, 255], 78 showFavicon: true,
79 thumbnailFallback: 'dot', // Draw single dot. 79 thumbnailTextColor: [50, 50, 50, 255],
80 tileWidth: 154, 80 thumbnailFallback: 'dot', // Draw single dot.
81 tileMargin: 16, 81 tileWidth: 154,
82 titleColor: [50, 50, 50, 255], 82 tileMargin: 16,
83 titleColorAgainstDark: [210, 210, 210, 255], 83 titleColor: [50, 50, 50, 255],
84 titleTextAlign: 'inherit', 84 titleColorAgainstDark: [210, 210, 210, 255],
85 titleTextFade: 122 - 36 // 112px wide title with 32 pixel fade at end. 85 titleTextAlign: 'inherit',
86 }; 86 titleTextFade: 122 - 36 // 112px wide title with 32 pixel fade at end.
87 87 };
88 88
89 /** 89
90 * Modifies NTP_DESIGN parameters for icon NTP. 90 /**
91 */ 91 * Modifies NTP_DESIGN parameters for icon NTP.
92 function modifyNtpDesignForIcons() { 92 */
93 NTP_DESIGN.fakeboxWingSize = 132; 93 function modifyNtpDesignForIcons() {
94 NTP_DESIGN.mainClass = 'icon-ntp'; 94 NTP_DESIGN.fakeboxWingSize = 132;
95 NTP_DESIGN.numTitleLines = 2; 95 NTP_DESIGN.mainClass = 'icon-ntp';
96 NTP_DESIGN.showFavicon = false; 96 NTP_DESIGN.numTitleLines = 2;
97 NTP_DESIGN.thumbnailFallback = null; 97 NTP_DESIGN.showFavicon = false;
98 NTP_DESIGN.tileWidth = 48 + 2 * 18; 98 NTP_DESIGN.thumbnailFallback = null;
99 NTP_DESIGN.tileMargin = 60 - 18 * 2; 99 NTP_DESIGN.tileWidth = 48 + 2 * 18;
100 NTP_DESIGN.titleColor = [120, 120, 120, 255]; 100 NTP_DESIGN.tileMargin = 60 - 18 * 2;
101 NTP_DESIGN.titleColorAgainstDark = [210, 210, 210, 255]; 101 NTP_DESIGN.titleColor = [120, 120, 120, 255];
102 NTP_DESIGN.titleTextAlign = 'center'; 102 NTP_DESIGN.titleColorAgainstDark = [210, 210, 210, 255];
103 delete NTP_DESIGN.titleTextFade; 103 NTP_DESIGN.titleTextAlign = 'center';
104 } 104 delete NTP_DESIGN.titleTextFade;
105 105 }
106 106
107 /** 107
108 * Enum for classnames. 108 /**
109 * @enum {string} 109 * Enum for classnames.
110 * @const 110 * @enum {string}
111 */ 111 * @const
112 var CLASSES = { 112 */
113 ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme 113 var CLASSES = {
114 DARK: 'dark', 114 ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme
115 DEFAULT_THEME: 'default-theme', 115 DARK: 'dark',
116 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', 116 DEFAULT_THEME: 'default-theme',
117 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive 117 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide',
118 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox 118 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive
119 // Applies drag focus style to the fakebox 119 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox
120 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', 120 // Applies drag focus style to the fakebox
121 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo', 121 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused',
122 HIDE_NOTIFICATION: 'mv-notice-hide', 122 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo',
123 LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution', 123 HIDE_NOTIFICATION: 'mv-notice-hide',
124 // Vertically centers the most visited section for a non-Google provided page. 124 LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution',
125 NON_GOOGLE_PAGE: 'non-google-page', 125 // Vertically centers the most visited section for a non-Google provided
126 RTL: 'rtl' // Right-to-left language text. 126 // page.
127 }; 127 NON_GOOGLE_PAGE: 'non-google-page',
128 128 RTL: 'rtl' // Right-to-left language text.
129 129 };
130 /** 130
131 * Enum for HTML element ids. 131
132 * @enum {string} 132 /**
133 * @const 133 * Enum for HTML element ids.
134 */ 134 * @enum {string}
135 var IDS = { 135 * @const
136 ATTRIBUTION: 'attribution', 136 */
137 ATTRIBUTION_TEXT: 'attribution-text', 137 var IDS = {
138 CUSTOM_THEME_STYLE: 'ct-style', 138 ATTRIBUTION: 'attribution',
139 FAKEBOX: 'fakebox', 139 ATTRIBUTION_TEXT: 'attribution-text',
140 FAKEBOX_INPUT: 'fakebox-input', 140 CUSTOM_THEME_STYLE: 'ct-style',
141 FAKEBOX_TEXT: 'fakebox-text', 141 FAKEBOX: 'fakebox',
142 LOGO: 'logo', 142 FAKEBOX_INPUT: 'fakebox-input',
143 NOTIFICATION: 'mv-notice', 143 FAKEBOX_TEXT: 'fakebox-text',
144 NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x', 144 LOGO: 'logo',
145 NOTIFICATION_MESSAGE: 'mv-msg', 145 NOTIFICATION: 'mv-notice',
146 NTP_CONTENTS: 'ntp-contents', 146 NOTIFICATION_CLOSE_BUTTON: 'mv-notice-x',
147 RESTORE_ALL_LINK: 'mv-restore', 147 NOTIFICATION_MESSAGE: 'mv-msg',
148 TILES: 'mv-tiles', 148 NTP_CONTENTS: 'ntp-contents',
149 UNDO_LINK: 'mv-undo' 149 RESTORE_ALL_LINK: 'mv-restore',
150 }; 150 TILES: 'mv-tiles',
151 151 UNDO_LINK: 'mv-undo'
152 152 };
153 /** 153
154 * Enum for keycodes. 154
155 * @enum {number} 155 /**
156 * @const 156 * Enum for keycodes.
157 */ 157 * @enum {number}
158 var KEYCODE = { 158 * @const
159 ENTER: 13 159 */
160 }; 160 var KEYCODE = {ENTER: 13};
161 161
162 162
163 /** 163 /**
164 * Enum for the state of the NTP when it is disposed. 164 * Enum for the state of the NTP when it is disposed.
165 * @enum {number} 165 * @enum {number}
166 * @const 166 * @const
167 */ 167 */
168 var NTP_DISPOSE_STATE = { 168 var NTP_DISPOSE_STATE = {
169 NONE: 0, // Preserve the NTP appearance and functionality 169 NONE: 0, // Preserve the NTP appearance and functionality
170 DISABLE_FAKEBOX: 1, 170 DISABLE_FAKEBOX: 1,
171 HIDE_FAKEBOX_AND_LOGO: 2 171 HIDE_FAKEBOX_AND_LOGO: 2
172 }; 172 };
173 173
174 174
175 /** 175 /**
176 * The notification displayed when a page is blacklisted. 176 * The notification displayed when a page is blacklisted.
177 * @type {Element} 177 * @type {Element}
178 */ 178 */
179 var notification; 179 var notification;
180 180
181 181
182 /** 182 /**
183 * The container for the theme attribution. 183 * The container for the theme attribution.
184 * @type {Element} 184 * @type {Element}
185 */ 185 */
186 var attribution; 186 var attribution;
187 187
188 188
189 /** 189 /**
190 * The "fakebox" - an input field that looks like a regular searchbox. When it 190 * The "fakebox" - an input field that looks like a regular searchbox. When
191 * is focused, any text the user types goes directly into the omnibox. 191 * it
192 * @type {Element} 192 * is focused, any text the user types goes directly into the omnibox.
193 */ 193 * @type {Element}
194 var fakebox; 194 */
195 195 var fakebox;
196 196
197 /** 197
198 * The container for NTP elements. 198 /**
199 * @type {Element} 199 * The container for NTP elements.
200 */ 200 * @type {Element}
201 var ntpContents; 201 */
202 202 var ntpContents;
203 203
204 /** 204
205 * The last blacklisted tile rid if any, which by definition should not be 205 /**
206 * filler. 206 * The last blacklisted tile rid if any, which by definition should not be
207 * @type {?number} 207 * filler.
208 */ 208 * @type {?number}
209 var lastBlacklistedTile = null; 209 */
210 210 var lastBlacklistedTile = null;
211 211
212 /** 212
213 * Current number of tiles columns shown based on the window width, including 213 /**
214 * those that just contain filler. 214 * Current number of tiles columns shown based on the window width, including
215 * @type {number} 215 * those that just contain filler.
216 */ 216 * @type {number}
217 var numColumnsShown = 0; 217 */
218 218 var numColumnsShown = 0;
219 219
220 /** 220
221 * The browser embeddedSearch.newTabPage object. 221 /**
222 * @type {Object} 222 * The browser embeddedSearch.newTabPage object.
223 */ 223 * @type {Object}
224 var ntpApiHandle; 224 */
225 225 var ntpApiHandle;
226 226
227 /** 227
228 * The browser embeddedSearch.searchBox object. 228 /**
229 * @type {Object} 229 * The browser embeddedSearch.searchBox object.
230 */ 230 * @type {Object}
231 var searchboxApiHandle; 231 */
232 232 var searchboxApiHandle;
233 233
234 /** 234
235 * The state of the NTP when a query is entered into the Omnibox. 235 /**
236 * @type {NTP_DISPOSE_STATE} 236 * The state of the NTP when a query is entered into the Omnibox.
237 */ 237 * @type {NTP_DISPOSE_STATE}
238 var omniboxInputBehavior = NTP_DISPOSE_STATE.NONE; 238 */
239 239 var omniboxInputBehavior = NTP_DISPOSE_STATE.NONE;
240 240
241 /** 241
242 * The state of the NTP when a query is entered into the Fakebox. 242 /**
243 * @type {NTP_DISPOSE_STATE} 243 * The state of the NTP when a query is entered into the Fakebox.
244 */ 244 * @type {NTP_DISPOSE_STATE}
245 var fakeboxInputBehavior = NTP_DISPOSE_STATE.HIDE_FAKEBOX_AND_LOGO; 245 */
246 246 var fakeboxInputBehavior = NTP_DISPOSE_STATE.HIDE_FAKEBOX_AND_LOGO;
247 247
248 /** @type {number} @const */ 248
249 var MAX_NUM_TILES_TO_SHOW = 8; 249 /** @type {number} @const */
250 250 var MAX_NUM_TILES_TO_SHOW = 8;
251 251
252 /** @type {number} @const */ 252
253 var MIN_NUM_COLUMNS = 2; 253 /** @type {number} @const */
254 254 var MIN_NUM_COLUMNS = 2;
255 255
256 /** @type {number} @const */ 256
257 var MAX_NUM_COLUMNS = 4; 257 /** @type {number} @const */
258 258 var MAX_NUM_COLUMNS = 4;
259 259
260 /** @type {number} @const */ 260
261 var NUM_ROWS = 2; 261 /** @type {number} @const */
262 262 var NUM_ROWS = 2;
263 263
264 /** 264
265 * Minimum total padding to give to the left and right of the most visited 265 /**
266 * section. Used to determine how many tiles to show. 266 * Minimum total padding to give to the left and right of the most visited
267 * @type {number} 267 * section. Used to determine how many tiles to show.
268 * @const 268 * @type {number}
269 */ 269 * @const
270 var MIN_TOTAL_HORIZONTAL_PADDING = 200; 270 */
271 271 var MIN_TOTAL_HORIZONTAL_PADDING = 200;
272 272
273 /** 273
274 /**
274 * Heuristic to determine whether a theme should be considered to be dark, so 275 * Heuristic to determine whether a theme should be considered to be dark, so
275 * the colors of various UI elements can be adjusted. 276 * the colors of various UI elements can be adjusted.
276 * @param {ThemeBackgroundInfo|undefined} info Theme background information. 277 * @param {ThemeBackgroundInfo|undefined} info Theme background information.
277 * @return {boolean} Whether the theme is dark. 278 * @return {boolean} Whether the theme is dark.
278 * @private 279 * @private
279 */ 280 */
280 function getIsThemeDark(info) { 281 function getIsThemeDark(info) {
281 if (!info) 282 if (!info)
282 return false; 283 return false;
283 // Heuristic: light text implies dark theme. 284 // Heuristic: light text implies dark theme.
284 var rgba = info.textColorRgba; 285 var rgba = info.textColorRgba;
285 var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2]; 286 var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2];
286 return luminance >= 128; 287 return luminance >= 128;
287 } 288 }
288 289
289 290
290 /** 291 /**
291 * Updates the NTP based on the current theme. 292 * Updates the NTP based on the current theme.
292 * @private 293 * @private
293 */ 294 */
294 function renderTheme() { 295 function renderTheme() {
295 var fakeboxText = $(IDS.FAKEBOX_TEXT); 296 var fakeboxText = $(IDS.FAKEBOX_TEXT);
296 if (fakeboxText) { 297 if (fakeboxText) {
297 fakeboxText.innerHTML = ''; 298 fakeboxText.innerHTML = '';
298 if (configData.translatedStrings.searchboxPlaceholder) { 299 if (configData.translatedStrings.searchboxPlaceholder) {
299 fakeboxText.textContent = 300 fakeboxText.textContent =
300 configData.translatedStrings.searchboxPlaceholder; 301 configData.translatedStrings.searchboxPlaceholder;
301 } 302 }
302 } 303 }
303 304
304 var info = ntpApiHandle.themeBackgroundInfo; 305 var info = ntpApiHandle.themeBackgroundInfo;
305 var isThemeDark = getIsThemeDark(info); 306 var isThemeDark = getIsThemeDark(info);
306 ntpContents.classList.toggle(CLASSES.DARK, isThemeDark); 307 ntpContents.classList.toggle(CLASSES.DARK, isThemeDark);
307 if (!info) { 308 if (!info) {
308 return; 309 return;
309 } 310 }
310 311
311 var background = [convertToRGBAColor(info.backgroundColorRgba), 312 var background = [
312 info.imageUrl, 313 convertToRGBAColor(info.backgroundColorRgba), info.imageUrl,
313 info.imageTiling, 314 info.imageTiling, info.imageHorizontalAlignment,
314 info.imageHorizontalAlignment, 315 info.imageVerticalAlignment
315 info.imageVerticalAlignment].join(' ').trim(); 316 ].join(' ').trim();
316 317
317 document.body.style.background = background; 318 document.body.style.background = background;
318 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); 319 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo);
319 updateThemeAttribution(info.attributionUrl, info.imageHorizontalAlignment); 320 updateThemeAttribution(info.attributionUrl, info.imageHorizontalAlignment);
320 setCustomThemeStyle(info); 321 setCustomThemeStyle(info);
321 322
322 var themeinfo = {cmd: 'updateTheme'}; 323 var themeinfo = {cmd: 'updateTheme'};
323 if (!info.usingDefaultTheme) { 324 if (!info.usingDefaultTheme) {
324 themeinfo.tileBorderColor = convertToRGBAColor(info.sectionBorderColorRgba); 325 themeinfo.tileBorderColor =
325 themeinfo.tileHoverBorderColor = convertToRGBAColor(info.headerColorRgba); 326 convertToRGBAColor(info.sectionBorderColorRgba);
326 } 327 themeinfo.tileHoverBorderColor = convertToRGBAColor(info.headerColorRgba);
327 themeinfo.isThemeDark = isThemeDark; 328 }
328 329 themeinfo.isThemeDark = isThemeDark;
329 var titleColor = NTP_DESIGN.titleColor; 330
330 if (!info.usingDefaultTheme && info.textColorRgba) { 331 var titleColor = NTP_DESIGN.titleColor;
331 titleColor = info.textColorRgba; 332 if (!info.usingDefaultTheme && info.textColorRgba) {
332 } else if (isThemeDark) { 333 titleColor = info.textColorRgba;
333 titleColor = NTP_DESIGN.titleColorAgainstDark; 334 } else if (isThemeDark) {
334 } 335 titleColor = NTP_DESIGN.titleColorAgainstDark;
335 themeinfo.tileTitleColor = convertToRGBAColor(titleColor); 336 }
336 337 themeinfo.tileTitleColor = convertToRGBAColor(titleColor);
337 $('mv-single').contentWindow.postMessage(themeinfo, '*'); 338
338 } 339 $('mv-single').contentWindow.postMessage(themeinfo, '*');
339 340 }
340 341
341 /** 342
342 * Updates the NTP based on the current theme, then rerenders all tiles. 343 /**
343 * @private 344 * Updates the NTP based on the current theme, then rerenders all tiles.
344 */ 345 * @private
345 function onThemeChange() { 346 */
346 renderTheme(); 347 function onThemeChange() {
347 } 348 renderTheme();
348 349 }
349 350
350 /** 351
351 * Updates the NTP style according to theme. 352 /**
352 * @param {Object=} opt_themeInfo The information about the theme. If it is 353 * Updates the NTP style according to theme.
353 * omitted the style will be reverted to the default. 354 * @param {Object=} opt_themeInfo The information about the theme. If it is
354 * @private 355 * omitted the style will be reverted to the default.
355 */ 356 * @private
356 function setCustomThemeStyle(opt_themeInfo) { 357 */
357 var customStyleElement = $(IDS.CUSTOM_THEME_STYLE); 358 function setCustomThemeStyle(opt_themeInfo) {
358 var head = document.head; 359 var customStyleElement = $(IDS.CUSTOM_THEME_STYLE);
359 if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) { 360 var head = document.head;
360 ntpContents.classList.remove(CLASSES.DEFAULT_THEME); 361 if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) {
361 var themeStyle = 362 ntpContents.classList.remove(CLASSES.DEFAULT_THEME);
362 '#attribution {' + 363 var themeStyle = '#attribution {' +
363 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' + 364 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) +
364 '}' + 365 ';' +
365 '#mv-msg {' + 366 '}' +
366 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorRgba) + ';' + 367 '#mv-msg {' +
367 '}' + 368 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorRgba) + ';' +
368 '#mv-notice-links span {' + 369 '}' +
369 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' + 370 '#mv-notice-links span {' +
370 '}' + 371 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) +
371 '#mv-notice-x {' + 372 ';' +
372 ' -webkit-filter: drop-shadow(0 0 0 ' + 373 '}' +
374 '#mv-notice-x {' +
375 ' -webkit-filter: drop-shadow(0 0 0 ' +
373 convertToRGBAColor(opt_themeInfo.textColorRgba) + ');' + 376 convertToRGBAColor(opt_themeInfo.textColorRgba) + ');' +
374 '}' + 377 '}' +
375 '.mv-page-ready .mv-mask {' + 378 '.mv-page-ready .mv-mask {' +
376 ' border: 1px solid ' + 379 ' border: 1px solid ' +
377 convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' + 380 convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' +
378 '}' + 381 '}' +
379 '.mv-page-ready:hover .mv-mask, .mv-page-ready .mv-focused ~ .mv-mask {' + 382 '.mv-page-ready:hover .mv-mask, ' +
380 ' border-color: ' + 383 '.mv-page-ready .mv-focused ~ .mv-mask {' +
384 ' border-color: ' +
381 convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' + 385 convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' +
382 '}'; 386 '}';
383 387
384 if (customStyleElement) { 388 if (customStyleElement) {
385 customStyleElement.textContent = themeStyle; 389 customStyleElement.textContent = themeStyle;
390 } else {
391 customStyleElement = document.createElement('style');
392 customStyleElement.type = 'text/css';
393 customStyleElement.id = IDS.CUSTOM_THEME_STYLE;
394 customStyleElement.textContent = themeStyle;
395 head.appendChild(customStyleElement);
396 }
397
386 } else { 398 } else {
387 customStyleElement = document.createElement('style'); 399 ntpContents.classList.add(CLASSES.DEFAULT_THEME);
388 customStyleElement.type = 'text/css'; 400 if (customStyleElement)
389 customStyleElement.id = IDS.CUSTOM_THEME_STYLE; 401 head.removeChild(customStyleElement);
390 customStyleElement.textContent = themeStyle; 402 }
391 head.appendChild(customStyleElement); 403 }
392 } 404
393 405
394 } else { 406 /**
395 ntpContents.classList.add(CLASSES.DEFAULT_THEME); 407 * Renders the attribution if the URL is present, otherwise hides it.
396 if (customStyleElement) 408 * @param {string} url The URL of the attribution image, if any.
397 head.removeChild(customStyleElement); 409 * @param {string} themeBackgroundAlignment The alignment of the theme
398 } 410 * background image. This is used to compute the attribution's alignment.
399 } 411 * @private
400 412 */
401 413 function updateThemeAttribution(url, themeBackgroundAlignment) {
402 /** 414 if (!url) {
403 * Renders the attribution if the URL is present, otherwise hides it. 415 setAttributionVisibility_(false);
404 * @param {string} url The URL of the attribution image, if any. 416 return;
405 * @param {string} themeBackgroundAlignment The alignment of the theme 417 }
406 * background image. This is used to compute the attribution's alignment. 418
407 * @private 419 var attributionImage = attribution.querySelector('img');
408 */ 420 if (!attributionImage) {
409 function updateThemeAttribution(url, themeBackgroundAlignment) { 421 attributionImage = new Image();
410 if (!url) { 422 attribution.appendChild(attributionImage);
411 setAttributionVisibility_(false); 423 }
412 return; 424 attributionImage.style.content = url;
413 } 425
414 426 // To avoid conflicts, place the attribution on the left for themes that
415 var attributionImage = attribution.querySelector('img'); 427 // right align their background images.
416 if (!attributionImage) { 428 attribution.classList.toggle(
417 attributionImage = new Image(); 429 CLASSES.LEFT_ALIGN_ATTRIBUTION, themeBackgroundAlignment == 'right');
418 attribution.appendChild(attributionImage); 430 setAttributionVisibility_(true);
419 } 431 }
420 attributionImage.style.content = url; 432
421 433
422 // To avoid conflicts, place the attribution on the left for themes that 434 /**
423 // right align their background images. 435 * Sets the visibility of the theme attribution.
424 attribution.classList.toggle(CLASSES.LEFT_ALIGN_ATTRIBUTION, 436 * @param {boolean} show True to show the attribution.
425 themeBackgroundAlignment == 'right'); 437 * @private
426 setAttributionVisibility_(true); 438 */
427 } 439 function setAttributionVisibility_(show) {
428 440 if (attribution) {
429 441 attribution.style.display = show ? '' : 'none';
430 /** 442 }
431 * Sets the visibility of the theme attribution. 443 }
432 * @param {boolean} show True to show the attribution. 444
433 * @private 445
434 */ 446 /**
435 function setAttributionVisibility_(show) {
436 if (attribution) {
437 attribution.style.display = show ? '' : 'none';
438 }
439 }
440
441
442 /**
443 * Converts an Array of color components into RRGGBBAA format. 447 * Converts an Array of color components into RRGGBBAA format.
444 * @param {Array<number>} color Array of rgba color components. 448 * @param {Array<number>} color Array of rgba color components.
445 * @return {string} Color string in RRGGBBAA format. 449 * @return {string} Color string in RRGGBBAA format.
446 * @private 450 * @private
447 */ 451 */
448 function convertToRRGGBBAAColor(color) { 452 function convertToRRGGBBAAColor(color) {
449 return color.map(function(t) { 453 return color
450 return ('0' + t.toString(16)).slice(-2); // To 2-digit, 0-padded hex. 454 .map(function(t) {
451 }).join(''); 455 return ('0' + t.toString(16)).slice(-2); // To 2-digit, 0-padded hex.
452 } 456 })
453 457 .join('');
454 458 }
455 /** 459
460
461 /**
456 * Converts an Array of color components into RGBA format "rgba(R,G,B,A)". 462 * Converts an Array of color components into RGBA format "rgba(R,G,B,A)".
457 * @param {Array<number>} color Array of rgba color components. 463 * @param {Array<number>} color Array of rgba color components.
458 * @return {string} CSS color in RGBA format. 464 * @return {string} CSS color in RGBA format.
459 * @private 465 * @private
460 */ 466 */
461 function convertToRGBAColor(color) { 467 function convertToRGBAColor(color) {
462 return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + 468 return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' +
463 color[3] / 255 + ')'; 469 color[3] / 255 + ')';
464 } 470 }
465 471
466 472
467 /** 473 /**
468 * Called when page data change. 474 * Called when page data change.
469 */ 475 */
470 function onMostVisitedChange() { 476 function onMostVisitedChange() {
471 reloadTiles(); 477 reloadTiles();
472 } 478 }
473 479
474 480
475 /** 481 /**
476 * Fetches new data, creates, and renders tiles. 482 * Fetches new data, creates, and renders tiles.
477 */ 483 */
478 function reloadTiles() { 484 function reloadTiles() {
479 var pages = ntpApiHandle.mostVisited; 485 var pages = ntpApiHandle.mostVisited;
480 var cmds = []; 486 var cmds = [];
481 for (var i = 0; i < Math.min(MAX_NUM_TILES_TO_SHOW, pages.length); ++i) { 487 for (var i = 0; i < Math.min(MAX_NUM_TILES_TO_SHOW, pages.length); ++i) {
482 cmds.push({cmd: 'tile', rid: pages[i].rid}); 488 cmds.push({cmd: 'tile', rid: pages[i].rid});
483 } 489 }
484 cmds.push({cmd: 'show', maxVisible: numColumnsShown * NUM_ROWS}); 490 cmds.push({cmd: 'show', maxVisible: numColumnsShown * NUM_ROWS});
485 491
486 $('mv-single').contentWindow.postMessage(cmds, '*'); 492 $('mv-single').contentWindow.postMessage(cmds, '*');
487 } 493 }
488 494
489 495
490 /** 496 /**
491 * Shows the blacklist notification and triggers a delay to hide it. 497 * Shows the blacklist notification and triggers a delay to hide it.
492 */ 498 */
493 function showNotification() { 499 function showNotification() {
494 notification.classList.remove(CLASSES.HIDE_NOTIFICATION); 500 notification.classList.remove(CLASSES.HIDE_NOTIFICATION);
495 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION); 501 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION);
496 notification.scrollTop; 502 notification.scrollTop;
497 notification.classList.add(CLASSES.DELAYED_HIDE_NOTIFICATION); 503 notification.classList.add(CLASSES.DELAYED_HIDE_NOTIFICATION);
498 } 504 }
499 505
500 506
501 /** 507 /**
502 * Hides the blacklist notification. 508 * Hides the blacklist notification.
503 */ 509 */
504 function hideNotification() { 510 function hideNotification() {
505 notification.classList.add(CLASSES.HIDE_NOTIFICATION); 511 notification.classList.add(CLASSES.HIDE_NOTIFICATION);
506 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION); 512 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION);
507 } 513 }
508 514
509 515
510 /** 516 /**
511 * Handles a click on the notification undo link by hiding the notification and 517 * Handles a click on the notification undo link by hiding the notification
512 * informing Chrome. 518 * and
513 */ 519 * informing Chrome.
514 function onUndo() { 520 */
515 hideNotification(); 521 function onUndo() {
516 if (lastBlacklistedTile != null) { 522 hideNotification();
517 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedTile); 523 if (lastBlacklistedTile != null) {
518 } 524 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedTile);
519 } 525 }
520 526 }
521 527
522 /** 528
523 * Handles a click on the restore all notification link by hiding the 529 /**
524 * notification and informing Chrome. 530 * Handles a click on the restore all notification link by hiding the
525 */ 531 * notification and informing Chrome.
526 function onRestoreAll() { 532 */
527 hideNotification(); 533 function onRestoreAll() {
528 ntpApiHandle.undoAllMostVisitedDeletions(); 534 hideNotification();
529 } 535 ntpApiHandle.undoAllMostVisitedDeletions();
530 536 }
531 537
532 /** 538
539 /**
533 * Recomputes the number of tile columns, and width of various contents based 540 * Recomputes the number of tile columns, and width of various contents based
534 * on the width of the window. 541 * on the width of the window.
535 * @return {boolean} Whether the number of tile columns has changed. 542 * @return {boolean} Whether the number of tile columns has changed.
536 */ 543 */
537 function updateContentWidth() { 544 function updateContentWidth() {
538 var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin; 545 var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin;
539 // If innerWidth is zero, then use the maximum snap size. 546 // If innerWidth is zero, then use the maximum snap size.
540 var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth - 547 var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth -
541 NTP_DESIGN.tileMargin + MIN_TOTAL_HORIZONTAL_PADDING; 548 NTP_DESIGN.tileMargin + MIN_TOTAL_HORIZONTAL_PADDING;
542 var innerWidth = window.innerWidth || maxSnapSize; 549 var innerWidth = window.innerWidth || maxSnapSize;
543 // Each tile has left and right margins that sum to NTP_DESIGN.tileMargin. 550 // Each tile has left and right margins that sum to NTP_DESIGN.tileMargin.
544 var availableWidth = innerWidth + NTP_DESIGN.tileMargin - 551 var availableWidth = innerWidth + NTP_DESIGN.tileMargin -
545 NTP_DESIGN.fakeboxWingSize * 2 - MIN_TOTAL_HORIZONTAL_PADDING; 552 NTP_DESIGN.fakeboxWingSize * 2 - MIN_TOTAL_HORIZONTAL_PADDING;
546 var newNumColumns = Math.floor(availableWidth / tileRequiredWidth); 553 var newNumColumns = Math.floor(availableWidth / tileRequiredWidth);
547 if (newNumColumns < MIN_NUM_COLUMNS) 554 if (newNumColumns < MIN_NUM_COLUMNS)
548 newNumColumns = MIN_NUM_COLUMNS; 555 newNumColumns = MIN_NUM_COLUMNS;
549 else if (newNumColumns > MAX_NUM_COLUMNS) 556 else if (newNumColumns > MAX_NUM_COLUMNS)
550 newNumColumns = MAX_NUM_COLUMNS; 557 newNumColumns = MAX_NUM_COLUMNS;
551 558
552 if (numColumnsShown === newNumColumns) 559 if (numColumnsShown === newNumColumns)
553 return false; 560 return false;
554 561
555 numColumnsShown = newNumColumns; 562 numColumnsShown = newNumColumns;
556 // We add an extra pixel because rounding errors on different zooms can 563 // We add an extra pixel because rounding errors on different zooms can
557 // make the width shorter than it should be. 564 // make the width shorter than it should be.
558 var tilesContainerWidth = Math.ceil(numColumnsShown * tileRequiredWidth) + 1; 565 var tilesContainerWidth =
559 $(IDS.TILES).style.width = tilesContainerWidth + 'px'; 566 Math.ceil(numColumnsShown * tileRequiredWidth) + 1;
560 if (fakebox) { 567 $(IDS.TILES).style.width = tilesContainerWidth + 'px';
561 // -2 to account for border. 568 if (fakebox) {
562 var fakeboxWidth = (tilesContainerWidth - NTP_DESIGN.tileMargin - 2); 569 // -2 to account for border.
563 fakeboxWidth += NTP_DESIGN.fakeboxWingSize * 2; 570 var fakeboxWidth = (tilesContainerWidth - NTP_DESIGN.tileMargin - 2);
564 fakebox.style.width = fakeboxWidth + 'px'; 571 fakeboxWidth += NTP_DESIGN.fakeboxWingSize * 2;
565 } 572 fakebox.style.width = fakeboxWidth + 'px';
566 return true; 573 }
567 } 574 return true;
568 575 }
569 576
570 /** 577
571 * Resizes elements because the number of tile columns may need to change in 578 /**
572 * response to resizing. Also shows or hides extra tiles tiles according to the 579 * Resizes elements because the number of tile columns may need to change in
573 * new width of the page. 580 * response to resizing. Also shows or hides extra tiles tiles according to
574 */ 581 * the
575 function onResize() { 582 * new width of the page.
576 updateContentWidth(); 583 */
577 $('mv-single').contentWindow.postMessage( 584 function onResize() {
578 {cmd: 'tilesVisible', maxVisible: numColumnsShown * NUM_ROWS}, '*'); 585 updateContentWidth();
579 } 586 $('mv-single')
580 587 .contentWindow.postMessage(
581 588 {cmd: 'tilesVisible', maxVisible: numColumnsShown * NUM_ROWS}, '*');
582 /** 589 }
583 * Handles new input by disposing the NTP, according to where the input was 590
584 * entered. 591
585 */ 592 /**
586 function onInputStart() { 593 * Handles new input by disposing the NTP, according to where the input was
587 if (fakebox && isFakeboxFocused()) { 594 * entered.
588 setFakeboxFocus(false); 595 */
589 setFakeboxDragFocus(false); 596 function onInputStart() {
590 disposeNtp(true); 597 if (fakebox && isFakeboxFocused()) {
591 } else if (!isFakeboxFocused()) { 598 setFakeboxFocus(false);
592 disposeNtp(false); 599 setFakeboxDragFocus(false);
593 } 600 disposeNtp(true);
594 } 601 } else if (!isFakeboxFocused()) {
595 602 disposeNtp(false);
596 603 }
597 /** 604 }
598 * Disposes the NTP, according to where the input was entered. 605
599 * @param {boolean} wasFakeboxInput True if the input was in the fakebox. 606
600 */ 607 /**
601 function disposeNtp(wasFakeboxInput) { 608 * Disposes the NTP, according to where the input was entered.
602 var behavior = wasFakeboxInput ? fakeboxInputBehavior : omniboxInputBehavior; 609 * @param {boolean} wasFakeboxInput True if the input was in the fakebox.
603 if (behavior == NTP_DISPOSE_STATE.DISABLE_FAKEBOX) 610 */
604 setFakeboxActive(false); 611 function disposeNtp(wasFakeboxInput) {
605 else if (behavior == NTP_DISPOSE_STATE.HIDE_FAKEBOX_AND_LOGO) 612 var behavior =
606 setFakeboxAndLogoVisibility(false); 613 wasFakeboxInput ? fakeboxInputBehavior : omniboxInputBehavior;
607 } 614 if (behavior == NTP_DISPOSE_STATE.DISABLE_FAKEBOX)
608 615 setFakeboxActive(false);
609 616 else if (behavior == NTP_DISPOSE_STATE.HIDE_FAKEBOX_AND_LOGO)
610 /** 617 setFakeboxAndLogoVisibility(false);
611 * Restores the NTP (re-enables the fakebox and unhides the logo.) 618 }
612 */ 619
613 function restoreNtp() { 620
614 setFakeboxActive(true); 621 /**
615 setFakeboxAndLogoVisibility(true); 622 * Restores the NTP (re-enables the fakebox and unhides the logo.)
616 } 623 */
617 624 function restoreNtp() {
618 625 setFakeboxActive(true);
619 /** 626 setFakeboxAndLogoVisibility(true);
620 * @param {boolean} focus True to focus the fakebox. 627 }
621 */ 628
622 function setFakeboxFocus(focus) { 629
623 document.body.classList.toggle(CLASSES.FAKEBOX_FOCUS, focus); 630 /**
624 } 631 * @param {boolean} focus True to focus the fakebox.
625 632 */
626 /** 633 function setFakeboxFocus(focus) {
627 * @param {boolean} focus True to show a dragging focus to the fakebox. 634 document.body.classList.toggle(CLASSES.FAKEBOX_FOCUS, focus);
628 */ 635 }
629 function setFakeboxDragFocus(focus) { 636
630 document.body.classList.toggle(CLASSES.FAKEBOX_DRAG_FOCUS, focus); 637 /**
631 } 638 * @param {boolean} focus True to show a dragging focus to the fakebox.
632 639 */
633 /** 640 function setFakeboxDragFocus(focus) {
641 document.body.classList.toggle(CLASSES.FAKEBOX_DRAG_FOCUS, focus);
642 }
643
644 /**
634 * @return {boolean} True if the fakebox has focus. 645 * @return {boolean} True if the fakebox has focus.
635 */ 646 */
636 function isFakeboxFocused() { 647 function isFakeboxFocused() {
637 return document.body.classList.contains(CLASSES.FAKEBOX_FOCUS) || 648 return document.body.classList.contains(CLASSES.FAKEBOX_FOCUS) ||
638 document.body.classList.contains(CLASSES.FAKEBOX_DRAG_FOCUS); 649 document.body.classList.contains(CLASSES.FAKEBOX_DRAG_FOCUS);
639 } 650 }
640 651
641 652
642 /** 653 /**
643 * @param {boolean} enable True to enable the fakebox. 654 * @param {boolean} enable True to enable the fakebox.
644 */ 655 */
645 function setFakeboxActive(enable) { 656 function setFakeboxActive(enable) {
646 document.body.classList.toggle(CLASSES.FAKEBOX_DISABLE, !enable); 657 document.body.classList.toggle(CLASSES.FAKEBOX_DISABLE, !enable);
647 } 658 }
648 659
649 660
650 /** 661 /**
651 * @param {!Event} event The click event. 662 * @param {!Event} event The click event.
652 * @return {boolean} True if the click occurred in an enabled fakebox. 663 * @return {boolean} True if the click occurred in an enabled fakebox.
653 */ 664 */
654 function isFakeboxClick(event) { 665 function isFakeboxClick(event) {
655 return fakebox.contains(event.target) && 666 return fakebox.contains(event.target) &&
656 !document.body.classList.contains(CLASSES.FAKEBOX_DISABLE); 667 !document.body.classList.contains(CLASSES.FAKEBOX_DISABLE);
657 } 668 }
658 669
659 670
660 /** 671 /**
661 * @param {boolean} show True to show the fakebox and logo. 672 * @param {boolean} show True to show the fakebox and logo.
662 */ 673 */
663 function setFakeboxAndLogoVisibility(show) { 674 function setFakeboxAndLogoVisibility(show) {
664 document.body.classList.toggle(CLASSES.HIDE_FAKEBOX_AND_LOGO, !show); 675 document.body.classList.toggle(CLASSES.HIDE_FAKEBOX_AND_LOGO, !show);
665 } 676 }
666 677
667 678
668 /** 679 /**
669 * Shortcut for document.getElementById. 680 * Shortcut for document.getElementById.
670 * @param {string} id of the element. 681 * @param {string} id of the element.
671 * @return {HTMLElement} with the id. 682 * @return {HTMLElement} with the id.
672 */ 683 */
673 function $(id) { 684 function $(id) {
674 return document.getElementById(id); 685 return document.getElementById(id);
675 } 686 }
676 687
677 688
678 /** 689 /**
679 * Utility function which creates an element with an optional classname and 690 * Utility function which creates an element with an optional classname and
680 * appends it to the specified parent. 691 * appends it to the specified parent.
681 * @param {Element} parent The parent to append the new element. 692 * @param {Element} parent The parent to append the new element.
682 * @param {string} name The name of the new element. 693 * @param {string} name The name of the new element.
683 * @param {string=} opt_class The optional classname of the new element. 694 * @param {string=} opt_class The optional classname of the new element.
684 * @return {Element} The new element. 695 * @return {Element} The new element.
685 */ 696 */
686 function createAndAppendElement(parent, name, opt_class) { 697 function createAndAppendElement(parent, name, opt_class) {
687 var child = document.createElement(name); 698 var child = document.createElement(name);
688 if (opt_class) 699 if (opt_class)
689 child.classList.add(opt_class); 700 child.classList.add(opt_class);
690 parent.appendChild(child); 701 parent.appendChild(child);
691 return child; 702 return child;
692 } 703 }
693 704
694 705
695 /** 706 /**
696 * @param {!Element} element The element to register the handler for. 707 * @param {!Element} element The element to register the handler for.
697 * @param {number} keycode The keycode of the key to register. 708 * @param {number} keycode The keycode of the key to register.
698 * @param {!Function} handler The key handler to register. 709 * @param {!Function} handler The key handler to register.
699 */ 710 */
700 function registerKeyHandler(element, keycode, handler) { 711 function registerKeyHandler(element, keycode, handler) {
701 element.addEventListener('keydown', function(event) { 712 element.addEventListener('keydown', function(event) {
702 if (event.keyCode == keycode) 713 if (event.keyCode == keycode)
703 handler(event); 714 handler(event);
704 }); 715 });
705 } 716 }
706 717
707 718
708 /** 719 /**
709 * @return {Object} the handle to the embeddedSearch API. 720 * @return {Object} the handle to the embeddedSearch API.
710 */ 721 */
711 function getEmbeddedSearchApiHandle() { 722 function getEmbeddedSearchApiHandle() {
712 if (window.cideb) 723 if (window.cideb)
713 return window.cideb; 724 return window.cideb;
714 if (window.chrome && window.chrome.embeddedSearch) 725 if (window.chrome && window.chrome.embeddedSearch)
715 return window.chrome.embeddedSearch; 726 return window.chrome.embeddedSearch;
716 return null; 727 return null;
728 }
729
730
731 /**
732 * Event handler for the focus changed and blacklist messages on link
733 * elements.
734 * Used to toggle visual treatment on the tiles (depending on the message).
735 * @param {Event} event Event received.
736 */
737 function handlePostMessage(event) {
738 var cmd = event.data.cmd;
739 var args = event.data;
740 if (cmd == 'tileBlacklisted') {
741 showNotification();
742 lastBlacklistedTile = args.tid;
743
744 ntpApiHandle.deleteMostVisitedItem(args.tid);
745 }
746 }
747
748
749 /**
750 * Prepares the New Tab Page by adding listeners, rendering the current
751 * theme, the most visited pages section, and Google-specific elements for a
752 * Google-provided page.
753 */
754 function init() {
755 notification = $(IDS.NOTIFICATION);
756 attribution = $(IDS.ATTRIBUTION);
757 ntpContents = $(IDS.NTP_CONTENTS);
758
759 if (configData.isGooglePage) {
760 var logo = document.createElement('div');
761 logo.id = IDS.LOGO;
762 logo.title = 'Google';
763
764 fakebox = document.createElement('div');
765 fakebox.id = IDS.FAKEBOX;
766 var fakeboxHtml = [];
767 fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '"></div>');
768 fakeboxHtml.push(
769 '<input id="' + IDS.FAKEBOX_INPUT +
770 '" autocomplete="off" tabindex="-1" type="url" aria-hidden="true">');
771 fakeboxHtml.push('<div id="cursor"></div>');
772 fakebox.innerHTML = fakeboxHtml.join('');
773
774 ntpContents.insertBefore(fakebox, ntpContents.firstChild);
775 ntpContents.insertBefore(logo, ntpContents.firstChild);
776 } else {
777 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE);
778 }
779
780 // Modify design for experimental icon NTP, if specified.
781 if (configData.useIcons)
782 modifyNtpDesignForIcons();
783 document.querySelector('#ntp-contents').classList.add(NTP_DESIGN.mainClass);
784
785 // Hide notifications after fade out, so we can't focus on links via
786 // keyboard.
787 notification.addEventListener('webkitTransitionEnd', hideNotification);
788
789 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE);
790 notificationMessage.textContent =
791 configData.translatedStrings.thumbnailRemovedNotification;
792
793 var undoLink = $(IDS.UNDO_LINK);
794 undoLink.addEventListener('click', onUndo);
795 registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo);
796 undoLink.textContent = configData.translatedStrings.undoThumbnailRemove;
797
798 var restoreAllLink = $(IDS.RESTORE_ALL_LINK);
799 restoreAllLink.addEventListener('click', onRestoreAll);
800 registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo);
801 restoreAllLink.textContent =
802 configData.translatedStrings.restoreThumbnailsShort;
803
804 $(IDS.ATTRIBUTION_TEXT).textContent =
805 configData.translatedStrings.attributionIntro;
806
807 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
808 createAndAppendElement(
809 notificationCloseButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER);
810 notificationCloseButton.addEventListener('click', hideNotification);
811
812 window.addEventListener('resize', onResize);
813 updateContentWidth();
814
815 var topLevelHandle = getEmbeddedSearchApiHandle();
816
817 ntpApiHandle = topLevelHandle.newTabPage;
818 ntpApiHandle.onthemechange = onThemeChange;
819 ntpApiHandle.onmostvisitedchange = onMostVisitedChange;
820
821 ntpApiHandle.oninputstart = onInputStart;
822 ntpApiHandle.oninputcancel = restoreNtp;
823
824 if (ntpApiHandle.isInputInProgress)
825 onInputStart();
826
827 searchboxApiHandle = topLevelHandle.searchBox;
828
829 if (fakebox) {
830 // Listener for updating the key capture state.
831 document.body.onmousedown = function(event) {
832 if (isFakeboxClick(event))
833 searchboxApiHandle.startCapturingKeyStrokes();
834 else if (isFakeboxFocused())
835 searchboxApiHandle.stopCapturingKeyStrokes();
836 };
837 searchboxApiHandle.onkeycapturechange = function() {
838 setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled);
839 };
840 var inputbox = $(IDS.FAKEBOX_INPUT);
841 if (inputbox) {
842 inputbox.onpaste = function(event) {
843 event.preventDefault();
844 // Send pasted text to Omnibox.
845 var text = event.clipboardData.getData('text/plain');
846 if (text)
847 searchboxApiHandle.paste(text);
848 };
849 inputbox.ondrop = function(event) {
850 event.preventDefault();
851 var text = event.dataTransfer.getData('text/plain');
852 if (text) {
853 searchboxApiHandle.paste(text);
854 }
855 setFakeboxDragFocus(false);
856 };
857 inputbox.ondragenter = function() {
858 setFakeboxDragFocus(true);
859 };
860 inputbox.ondragleave = function() {
861 setFakeboxDragFocus(false);
862 };
863 }
864
865 // Update the fakebox style to match the current key capturing state.
866 setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled);
867 }
868
869 if (searchboxApiHandle.rtl) {
870 $(IDS.NOTIFICATION).dir = 'rtl';
871 // Grabbing the root HTML element.
872 document.documentElement.setAttribute('dir', 'rtl');
873 // Add class for setting alignments based on language directionality.
874 document.documentElement.classList.add(CLASSES.RTL);
875 }
876
877 var iframe = document.createElement('iframe');
878 // Change the order of tabbing the page to start with NTP tiles.
879 iframe.setAttribute('tabindex', '1');
880 iframe.id = 'mv-single';
881
882 var args = [];
883
884 if (searchboxApiHandle.rtl)
885 args.push('rtl=1');
886 if (window.configData.useIcons)
887 args.push('icons=1');
888 if (NTP_DESIGN.numTitleLines > 1)
889 args.push('ntl=' + NTP_DESIGN.numTitleLines);
890
891 args.push(
892 'removeTooltip=' +
893 encodeURIComponent(
894 configData.translatedStrings.removeThumbnailTooltip));
895
896 iframe.src = '//most-visited/single.html?' + args.join('&');
897 $(IDS.TILES).appendChild(iframe);
898
899 iframe.onload = function() {
900 reloadTiles();
901 renderTheme();
902 };
903
904 window.addEventListener('message', handlePostMessage);
905 }
906
907
908 /**
909 * Binds event listeners.
910 */
911 function listen() {
912 document.addEventListener('DOMContentLoaded', init);
913 }
914
915 return {init: init, listen: listen};
717 } 916 }
718 917
719
720 /**
721 * Event handler for the focus changed and blacklist messages on link elements.
722 * Used to toggle visual treatment on the tiles (depending on the message).
723 * @param {Event} event Event received.
724 */
725 function handlePostMessage(event) {
726 var cmd = event.data.cmd;
727 var args = event.data;
728 if (cmd == 'tileBlacklisted') {
729 showNotification();
730 lastBlacklistedTile = args.tid;
731
732 ntpApiHandle.deleteMostVisitedItem(args.tid);
733 }
734 }
735
736
737 /**
738 * Prepares the New Tab Page by adding listeners, rendering the current
739 * theme, the most visited pages section, and Google-specific elements for a
740 * Google-provided page.
741 */
742 function init() {
743 notification = $(IDS.NOTIFICATION);
744 attribution = $(IDS.ATTRIBUTION);
745 ntpContents = $(IDS.NTP_CONTENTS);
746
747 if (configData.isGooglePage) {
748 var logo = document.createElement('div');
749 logo.id = IDS.LOGO;
750 logo.title = 'Google';
751
752 fakebox = document.createElement('div');
753 fakebox.id = IDS.FAKEBOX;
754 var fakeboxHtml = [];
755 fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '"></div>');
756 fakeboxHtml.push('<input id="' + IDS.FAKEBOX_INPUT +
757 '" autocomplete="off" tabindex="-1" type="url" aria-hidden="true">');
758 fakeboxHtml.push('<div id="cursor"></div>');
759 fakebox.innerHTML = fakeboxHtml.join('');
760
761 ntpContents.insertBefore(fakebox, ntpContents.firstChild);
762 ntpContents.insertBefore(logo, ntpContents.firstChild);
763 } else {
764 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE);
765 }
766
767 // Modify design for experimental icon NTP, if specified.
768 if (configData.useIcons)
769 modifyNtpDesignForIcons();
770 document.querySelector('#ntp-contents').classList.add(NTP_DESIGN.mainClass);
771
772 // Hide notifications after fade out, so we can't focus on links via keyboard.
773 notification.addEventListener('webkitTransitionEnd', hideNotification);
774
775 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE);
776 notificationMessage.textContent =
777 configData.translatedStrings.thumbnailRemovedNotification;
778
779 var undoLink = $(IDS.UNDO_LINK);
780 undoLink.addEventListener('click', onUndo);
781 registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo);
782 undoLink.textContent = configData.translatedStrings.undoThumbnailRemove;
783
784 var restoreAllLink = $(IDS.RESTORE_ALL_LINK);
785 restoreAllLink.addEventListener('click', onRestoreAll);
786 registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo);
787 restoreAllLink.textContent =
788 configData.translatedStrings.restoreThumbnailsShort;
789
790 $(IDS.ATTRIBUTION_TEXT).textContent =
791 configData.translatedStrings.attributionIntro;
792
793 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
794 createAndAppendElement(
795 notificationCloseButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER);
796 notificationCloseButton.addEventListener('click', hideNotification);
797
798 window.addEventListener('resize', onResize);
799 updateContentWidth();
800
801 var topLevelHandle = getEmbeddedSearchApiHandle();
802
803 ntpApiHandle = topLevelHandle.newTabPage;
804 ntpApiHandle.onthemechange = onThemeChange;
805 ntpApiHandle.onmostvisitedchange = onMostVisitedChange;
806
807 ntpApiHandle.oninputstart = onInputStart;
808 ntpApiHandle.oninputcancel = restoreNtp;
809
810 if (ntpApiHandle.isInputInProgress)
811 onInputStart();
812
813 searchboxApiHandle = topLevelHandle.searchBox;
814
815 if (fakebox) {
816 // Listener for updating the key capture state.
817 document.body.onmousedown = function(event) {
818 if (isFakeboxClick(event))
819 searchboxApiHandle.startCapturingKeyStrokes();
820 else if (isFakeboxFocused())
821 searchboxApiHandle.stopCapturingKeyStrokes();
822 };
823 searchboxApiHandle.onkeycapturechange = function() {
824 setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled);
825 };
826 var inputbox = $(IDS.FAKEBOX_INPUT);
827 if (inputbox) {
828 inputbox.onpaste = function(event) {
829 event.preventDefault();
830 // Send pasted text to Omnibox.
831 var text = event.clipboardData.getData('text/plain');
832 if (text)
833 searchboxApiHandle.paste(text);
834 };
835 inputbox.ondrop = function(event) {
836 event.preventDefault();
837 var text = event.dataTransfer.getData('text/plain');
838 if (text) {
839 searchboxApiHandle.paste(text);
840 }
841 setFakeboxDragFocus(false);
842 };
843 inputbox.ondragenter = function() {
844 setFakeboxDragFocus(true);
845 };
846 inputbox.ondragleave = function() {
847 setFakeboxDragFocus(false);
848 };
849 }
850
851 // Update the fakebox style to match the current key capturing state.
852 setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled);
853 }
854
855 if (searchboxApiHandle.rtl) {
856 $(IDS.NOTIFICATION).dir = 'rtl';
857 // Grabbing the root HTML element.
858 document.documentElement.setAttribute('dir', 'rtl');
859 // Add class for setting alignments based on language directionality.
860 document.documentElement.classList.add(CLASSES.RTL);
861 }
862
863 var iframe = document.createElement('iframe');
864 // Change the order of tabbing the page to start with NTP tiles.
865 iframe.setAttribute('tabindex', '1');
866 iframe.id = 'mv-single';
867
868 var args = [];
869
870 if (searchboxApiHandle.rtl)
871 args.push('rtl=1');
872 if (window.configData.useIcons)
873 args.push('icons=1');
874 if (NTP_DESIGN.numTitleLines > 1)
875 args.push('ntl=' + NTP_DESIGN.numTitleLines);
876
877 args.push('removeTooltip=' +
878 encodeURIComponent(configData.translatedStrings.removeThumbnailTooltip));
879
880 iframe.src = '//most-visited/single.html?' + args.join('&');
881 $(IDS.TILES).appendChild(iframe);
882
883 iframe.onload = function() {
884 reloadTiles();
885 renderTheme();
886 };
887
888 window.addEventListener('message', handlePostMessage);
889 }
890
891
892 /**
893 * Binds event listeners.
894 */
895 function listen() {
896 document.addEventListener('DOMContentLoaded', init);
897 }
898
899 return {
900 init: init,
901 listen: listen
902 };
903 }
904
905 if (!window.localNTPUnitTest) { 918 if (!window.localNTPUnitTest) {
906 LocalNTP().listen(); 919 LocalNTP().listen();
907 } 920 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698