OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 |
(...skipping 10 matching lines...) Expand all Loading... | |
21 | 21 |
22 /** | 22 /** |
23 * Enum for classnames. | 23 * Enum for classnames. |
24 * @enum {string} | 24 * @enum {string} |
25 * @const | 25 * @const |
26 */ | 26 */ |
27 var CLASSES = { | 27 var CLASSES = { |
28 ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme | 28 ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme |
29 BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation | 29 BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation |
30 BLACKLIST_BUTTON: 'mv-x', | 30 BLACKLIST_BUTTON: 'mv-x', |
31 DARK: 'dark', | |
31 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', | 32 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', |
33 DOT: 'dot', | |
32 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive | 34 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive |
33 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox | 35 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox |
34 // Applies drag focus style to the fakebox | 36 // Applies drag focus style to the fakebox |
35 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', | 37 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', |
36 FAVICON: 'mv-favicon', | 38 FAVICON: 'mv-favicon', |
37 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation | 39 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation |
38 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo', | 40 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo', |
39 HIDE_NOTIFICATION: 'mv-notice-hide', | 41 HIDE_NOTIFICATION: 'mv-notice-hide', |
40 // Vertically centers the most visited section for a non-Google provided page. | 42 // Vertically centers the most visited section for a non-Google provided page. |
41 NON_GOOGLE_PAGE: 'non-google-page', | 43 NON_GOOGLE_PAGE: 'non-google-page', |
42 PAGE: 'mv-page', // page tiles | 44 PAGE: 'mv-page', // page tiles |
43 PAGE_READY: 'mv-page-ready', // page tile when ready | 45 PAGE_READY: 'mv-page-ready', // page tile when ready |
44 RTL: 'rtl', // Right-to-left language text. | 46 RTL: 'rtl', // Right-to-left language text. |
45 THUMBNAIL: 'mv-thumb', | 47 THUMBNAIL: 'mv-thumb', |
48 THUMBNAIL_FALLBACK: 'mv-thumb-fallback', | |
46 THUMBNAIL_MASK: 'mv-mask', | 49 THUMBNAIL_MASK: 'mv-mask', |
47 TILE: 'mv-tile', | 50 TILE: 'mv-tile', |
51 TILE_INNER: 'mv-tile-inner', | |
48 TITLE: 'mv-title' | 52 TITLE: 'mv-title' |
49 }; | 53 }; |
50 | 54 |
51 | 55 |
52 /** | 56 /** |
53 * Enum for HTML element ids. | 57 * Enum for HTML element ids. |
54 * @enum {string} | 58 * @enum {string} |
55 * @const | 59 * @const |
56 */ | 60 */ |
57 var IDS = { | 61 var IDS = { |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 /** | 166 /** |
163 * True if a page has been blacklisted and we're waiting on the | 167 * True if a page has been blacklisted and we're waiting on the |
164 * onmostvisitedchange callback. See onMostVisitedChange() for how this | 168 * onmostvisitedchange callback. See onMostVisitedChange() for how this |
165 * is used. | 169 * is used. |
166 * @type {boolean} | 170 * @type {boolean} |
167 */ | 171 */ |
168 var isBlacklisting = false; | 172 var isBlacklisting = false; |
169 | 173 |
170 | 174 |
171 /** | 175 /** |
176 * Stores whether the current theme has a dark background. | |
177 * @type {boolean} | |
178 */ | |
179 var isBackgroundDark = false; | |
180 | |
181 | |
182 /** | |
172 * Current number of tiles columns shown based on the window width, including | 183 * Current number of tiles columns shown based on the window width, including |
173 * those that just contain filler. | 184 * those that just contain filler. |
174 * @type {number} | 185 * @type {number} |
175 */ | 186 */ |
176 var numColumnsShown = 0; | 187 var numColumnsShown = 0; |
177 | 188 |
178 | 189 |
179 /** | 190 /** |
180 * A flag to indicate Most Visited changed caused by user action. If true, then | 191 * A flag to indicate Most Visited changed caused by user action. If true, then |
181 * in onMostVisitedChange() tiles remain visible so no flickering occurs. | 192 * in onMostVisitedChange() tiles remain visible so no flickering occurs. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
259 * @const | 270 * @const |
260 */ | 271 */ |
261 var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500; | 272 var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500; |
262 | 273 |
263 | 274 |
264 /** | 275 /** |
265 * A Tile is either a rendering of a Most Visited page or "filler" used to | 276 * A Tile is either a rendering of a Most Visited page or "filler" used to |
266 * pad out the section when not enough pages exist. | 277 * pad out the section when not enough pages exist. |
267 * | 278 * |
268 * @param {Element} elem The element for rendering the tile. | 279 * @param {Element} elem The element for rendering the tile. |
280 * @param {Element=} opt_innerElem The element for contents of tile. | |
269 * @param {Element=} opt_titleElem The element for rendering the title. | 281 * @param {Element=} opt_titleElem The element for rendering the title. |
270 * @param {Element=} opt_thumbnailElem The element for rendering the thumbnail. | 282 * @param {Element=} opt_thumbnailElem The element for rendering the thumbnail. |
271 * @param {number=} opt_rid The RID for the corresponding Most Visited page. | 283 * @param {number=} opt_rid The RID for the corresponding Most Visited page. |
272 * Should only be left unspecified when creating a filler tile. | 284 * Should only be left unspecified when creating a filler tile. |
273 * @constructor | 285 * @constructor |
274 */ | 286 */ |
275 function Tile(elem, opt_titleElem, opt_thumbnailElem, opt_rid) { | 287 function Tile(elem, opt_innerElem, opt_titleElem, opt_thumbnailElem, opt_rid) { |
276 /** @type {Element} */ | 288 /** @type {Element} */ |
277 this.elem = elem; | 289 this.elem = elem; |
278 | 290 |
279 /** @type {Element|undefined} */ | 291 /** @type {Element|undefined} */ |
292 this.innerElem = opt_innerElem; | |
293 | |
294 /** @type {Element|undefined} */ | |
280 this.titleElem = opt_titleElem; | 295 this.titleElem = opt_titleElem; |
281 | 296 |
282 /** @type {Element|undefined} */ | 297 /** @type {Element|undefined} */ |
283 this.thumbnailElem = opt_thumbnailElem; | 298 this.thumbnailElem = opt_thumbnailElem; |
284 | 299 |
285 /** @type {number|undefined} */ | 300 /** @type {number|undefined} */ |
286 this.rid = opt_rid; | 301 this.rid = opt_rid; |
287 } | 302 } |
288 | 303 |
289 | 304 |
290 /** | 305 /** |
306 * Determines whether a theme should be considered to have dark background. | |
307 * @param {ThemeBackgroundInfo} info Theme background information. | |
308 * @return {boolean} Whether the theme has dark background. | |
309 * @private | |
310 */ | |
311 function getIsBackgroundDark(info) { | |
Mathieu
2014/08/13 20:09:29
rename to isThemeBackgroundDark?
huangs
2014/08/13 21:34:08
Inlined this into renderTheme(), since predominate
| |
312 if (info.imageUrl) | |
313 return true; | |
314 var rgba = info.backgroundColorRgba; | |
315 var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2]; | |
316 return luminance < 128; | |
317 } | |
318 | |
319 | |
320 /** | |
291 * Updates the NTP based on the current theme. | 321 * Updates the NTP based on the current theme. |
292 * @private | 322 * @private |
293 */ | 323 */ |
294 function onThemeChange() { | 324 function renderTheme() { |
295 var info = ntpApiHandle.themeBackgroundInfo; | 325 var info = ntpApiHandle.themeBackgroundInfo; |
296 if (!info) | 326 if (!info) { |
327 isBackgroundDark = false; | |
297 return; | 328 return; |
329 } | |
330 | |
331 isBackgroundDark = getIsBackgroundDark(info); | |
332 ntpContents.classList.toggle(CLASSES.DARK, isBackgroundDark); | |
298 | 333 |
299 var background = [convertToRGBAColor(info.backgroundColorRgba), | 334 var background = [convertToRGBAColor(info.backgroundColorRgba), |
300 info.imageUrl, | 335 info.imageUrl, |
301 info.imageTiling, | 336 info.imageTiling, |
302 info.imageHorizontalAlignment, | 337 info.imageHorizontalAlignment, |
303 info.imageVerticalAlignment].join(' ').trim(); | 338 info.imageVerticalAlignment].join(' ').trim(); |
304 document.body.style.background = background; | 339 document.body.style.background = background; |
305 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); | 340 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); |
306 updateThemeAttribution(info.attributionUrl); | 341 updateThemeAttribution(info.attributionUrl); |
307 setCustomThemeStyle(info); | 342 setCustomThemeStyle(info); |
343 } | |
308 | 344 |
345 | |
346 /** | |
347 * Updates the NTP based on the current theme, then rerenders all tiles. | |
348 * @private | |
349 */ | |
350 function onThemeChange() { | |
351 renderTheme(); | |
309 tilesContainer.innerHTML = ''; | 352 tilesContainer.innerHTML = ''; |
310 renderAndShowTiles(); | 353 renderAndShowTiles(); |
311 } | 354 } |
312 | 355 |
313 | 356 |
314 /** | 357 /** |
315 * Updates the NTP style according to theme. | 358 * Updates the NTP style according to theme. |
316 * @param {Object=} opt_themeInfo The information about the theme. If it is | 359 * @param {Object=} opt_themeInfo The information about the theme. If it is |
317 * omitted the style will be reverted to the default. | 360 * omitted the style will be reverted to the default. |
318 * @private | 361 * @private |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
405 color[3] / 255 + ')'; | 448 color[3] / 255 + ')'; |
406 } | 449 } |
407 | 450 |
408 | 451 |
409 /** | 452 /** |
410 * Handles a new set of Most Visited page data. | 453 * Handles a new set of Most Visited page data. |
411 */ | 454 */ |
412 function onMostVisitedChange() { | 455 function onMostVisitedChange() { |
413 if (isBlacklisting) { | 456 if (isBlacklisting) { |
414 // Trigger the blacklist animation, which then triggers reloadAllTiles(). | 457 // Trigger the blacklist animation, which then triggers reloadAllTiles(). |
415 var lastBlacklistedTileElement = lastBlacklistedTile.elem; | 458 var lastBlacklistedTileElem = lastBlacklistedTile.elem; |
416 lastBlacklistedTileElement.addEventListener( | 459 lastBlacklistedTileElem.addEventListener( |
417 'webkitTransitionEnd', blacklistAnimationDone); | 460 'webkitTransitionEnd', blacklistAnimationDone); |
418 lastBlacklistedTileElement.classList.add(CLASSES.BLACKLIST); | 461 lastBlacklistedTileElem.classList.add(CLASSES.BLACKLIST); |
419 } else { | 462 } else { |
420 reloadAllTiles(); | 463 reloadAllTiles(); |
421 } | 464 } |
422 } | 465 } |
423 | 466 |
424 | 467 |
425 /** | 468 /** |
426 * Handles the end of the blacklist animation by showing the notification and | 469 * Handles the end of the blacklist animation by showing the notification and |
427 * re-rendering the new set of tiles. | 470 * re-rendering the new set of tiles. |
428 */ | 471 */ |
(...skipping 21 matching lines...) Expand all Loading... | |
450 tiles.push(createTile(pages[i], i)); | 493 tiles.push(createTile(pages[i], i)); |
451 | 494 |
452 tilesContainer.innerHTML = ''; | 495 tilesContainer.innerHTML = ''; |
453 renderAndShowTiles(); | 496 renderAndShowTiles(); |
454 } | 497 } |
455 | 498 |
456 | 499 |
457 /** | 500 /** |
458 * Binds onload events for a tile's internal <iframe> elements. | 501 * Binds onload events for a tile's internal <iframe> elements. |
459 * @param {Tile} tile The main tile to bind events to. | 502 * @param {Tile} tile The main tile to bind events to. |
460 * @param {Barrier} tileVisibilityBarrier A barrier to make tile visible the | 503 * @param {Barrier} tileVisibilityBarrier A barrier to make all tiles visible |
461 * moment all tiles are loaded. | 504 * the moment all tiles are loaded. |
462 */ | 505 */ |
463 function bindTileOnloadEvents(tile, tileVisibilityBarrier) { | 506 function bindTileOnloadEvents(tile, tileVisibilityBarrier) { |
464 if (tile.titleElem) { | 507 if (tile.titleElem) { |
465 tileVisibilityBarrier.add(); | 508 tileVisibilityBarrier.add(); |
466 tile.titleElem.onload = function() { | 509 tile.titleElem.onload = function() { |
467 tile.titleElem.hidden = false; | |
468 tileVisibilityBarrier.remove(); | 510 tileVisibilityBarrier.remove(); |
469 }; | 511 }; |
470 } | 512 } |
471 | |
472 if (tile.thumbnailElem) { | 513 if (tile.thumbnailElem) { |
473 tileVisibilityBarrier.add(); | 514 tileVisibilityBarrier.add(); |
474 tile.thumbnailElem.onload = function() { | 515 tile.thumbnailElem.onload = function() { |
475 tile.thumbnailElem.hidden = false; | |
476 tile.elem.classList.add(CLASSES.PAGE_READY); | 516 tile.elem.classList.add(CLASSES.PAGE_READY); |
477 tileVisibilityBarrier.remove(); | 517 tileVisibilityBarrier.remove(); |
478 }; | 518 }; |
479 } | 519 } |
480 } | 520 } |
481 | 521 |
482 | 522 |
483 /** | 523 /** |
484 * Renders the current list of visible tiles to DOM, and hides tiles that are | 524 * Renders the current list of visible tiles to DOM, and hides tiles that are |
485 * already in the DOM but should not be seen. | 525 * already in the DOM but should not be seen. |
486 */ | 526 */ |
487 function renderAndShowTiles() { | 527 function renderAndShowTiles() { |
488 var numExisting = tilesContainer.querySelectorAll('.' + CLASSES.TILE).length; | 528 var numExisting = tilesContainer.querySelectorAll('.' + CLASSES.TILE).length; |
489 // Only add visible tiles to the DOM, to avoid creating invisible tiles that | 529 // Only add visible tiles to the DOM, to avoid creating invisible tiles that |
490 // produce meaningless impression metrics. However, if a tile becomes | 530 // produce meaningless impression metrics. However, if a tile becomes |
491 // invisible then we leave it in DOM to prevent reload if it's shown again. | 531 // invisible then we leave it in DOM to prevent reload if it's shown again. |
492 var numDesired = Math.min(tiles.length, numColumnsShown * NUM_ROWS); | 532 var numDesired = Math.min(tiles.length, numColumnsShown * NUM_ROWS); |
493 | 533 |
494 // If we need to render new tiles, manage the visibility to hide intermediate | 534 // If we need to render new tiles, manage the visibility to hide intermediate |
495 // load states of the <iframe>s. | 535 // load states of the <iframe>s. |
496 if (numExisting < numDesired) { | 536 if (numExisting < numDesired) { |
497 var tileVisibilityBarrier = new Barrier(function() { | 537 var showAll = function() { |
498 tilesContainer.style.visibility = 'visible'; | 538 for (var i = 0; i < numDesired; ++i) { |
499 }); | 539 if (tiles[i].titleElem || tiles[i].thumbnailElem) |
540 tiles[i].elem.classList.add(CLASSES.PAGE_READY); | |
541 } | |
542 }; | |
543 var tileVisibilityBarrier = new Barrier(showAll); | |
500 | 544 |
501 if (!userInitiatedMostVisitedChange) { | 545 if (!userInitiatedMostVisitedChange) { |
502 // Make titleContainer invisible, but still taking up space. | 546 // Make titleContainer invisible, but still taking up space. |
503 // titleContainer becomes visible again (1) on timeout, or (2) when all | 547 // titleContainer becomes visible again (1) on timeout, or (2) when all |
504 // tiles finish loading (using tileVisibilityBarrier). | 548 // tiles finish loading (using tileVisibilityBarrier). |
505 tilesContainer.style.visibility = 'hidden'; | |
506 window.setTimeout(function() { | 549 window.setTimeout(function() { |
507 tileVisibilityBarrier.cancel(); | 550 tileVisibilityBarrier.cancel(); |
508 tilesContainer.style.visibility = 'visible'; | 551 showAll(); |
509 }, MOST_VISITED_PAINT_TIMEOUT_MSEC); | 552 }, MOST_VISITED_PAINT_TIMEOUT_MSEC); |
510 } | 553 } |
511 userInitiatedMostVisitedChange = false; | 554 userInitiatedMostVisitedChange = false; |
512 | 555 |
513 for (var i = numExisting; i < numDesired; ++i) { | 556 for (var i = numExisting; i < numDesired; ++i) { |
514 bindTileOnloadEvents(tiles[i], tileVisibilityBarrier); | 557 bindTileOnloadEvents(tiles[i], tileVisibilityBarrier); |
515 tilesContainer.appendChild(tiles[i].elem); | 558 tilesContainer.appendChild(tiles[i].elem); |
516 } | 559 } |
517 } | 560 } |
518 | 561 |
519 // Show only the desired tiles. Not using .hidden because it does not work for | 562 // Show only the desired tiles. Note that .hidden does not work for |
520 // inline-block elements. | 563 // inline-block elements like tiles[i].elem. |
521 for (var i = 0; i < numDesired; ++i) | 564 for (var i = 0; i < numDesired; ++i) |
522 tiles[i].elem.style.display = 'inline-block'; | 565 tiles[i].elem.style.display = 'inline-block'; |
523 // If |numDesired| < |numExisting| then hide extra tiles (e.g., this occurs | 566 // If |numDesired| < |numExisting| then hide extra tiles (e.g., this occurs |
524 // when window is downsized). | 567 // when window is downsized). |
525 for (; i < numExisting; ++i) | 568 for (; i < numExisting; ++i) |
526 tiles[i].elem.style.display = 'none'; | 569 tiles[i].elem.style.display = 'none'; |
527 } | 570 } |
528 | 571 |
529 | 572 |
530 /** | 573 /** |
531 * Builds a URL to display a most visited tile title in an iframe. | 574 * Builds a URL to display a most visited tile title in an iframe. |
532 * @param {number} rid The restricted ID. | 575 * @param {number} rid The restricted ID. |
533 * @param {number} position The position of the iframe in the UI. | 576 * @param {number} position The position of the iframe in the UI. |
534 * @return {string} An URL to display the most visited title in an iframe. | 577 * @return {string} An URL to display the most visited title in an iframe. |
535 */ | 578 */ |
536 function getMostVisitedTitleIframeUrl(rid, position) { | 579 function getMostVisitedTitleIframeUrl(rid, position) { |
537 var url = 'chrome-search://most-visited/' + | 580 var url = 'chrome-search://most-visited/' + |
538 encodeURIComponent(MOST_VISITED_TITLE_IFRAME); | 581 encodeURIComponent(MOST_VISITED_TITLE_IFRAME); |
582 var titleColor = isBackgroundDark ? NTP_DESIGN.titleColorAgainstDark : | |
583 NTP_DESIGN.titleColor; | |
539 var params = [ | 584 var params = [ |
540 'rid=' + encodeURIComponent(rid), | 585 'rid=' + encodeURIComponent(rid), |
541 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily), | 586 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily), |
542 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize), | 587 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize), |
543 'c=' + encodeURIComponent(NTP_DESIGN.titleColor), | 588 'c=' + encodeURIComponent(titleColor), |
544 'pos=' + encodeURIComponent(position)]; | 589 'pos=' + encodeURIComponent(position)]; |
545 if (NTP_DESIGN.titleTextAlign) | 590 if (NTP_DESIGN.titleTextAlign) |
546 params.push('ta=' + encodeURIComponent(NTP_DESIGN.titleTextAlign)); | 591 params.push('ta=' + encodeURIComponent(NTP_DESIGN.titleTextAlign)); |
547 if (NTP_DESIGN.titleTextFade) | 592 if (NTP_DESIGN.titleTextFade) |
548 params.push('tf=' + encodeURIComponent(NTP_DESIGN.titleTextFade)); | 593 params.push('tf=' + encodeURIComponent(NTP_DESIGN.titleTextFade)); |
549 return url + '?' + params.join('&'); | 594 return url + '?' + params.join('&'); |
550 } | 595 } |
551 | 596 |
552 | 597 |
553 /** | 598 /** |
554 * Builds a URL to display a most visited tile thumbnail in an iframe. | 599 * Builds a URL to display a most visited tile thumbnail in an iframe. |
555 * @param {number} rid The restricted ID. | 600 * @param {number} rid The restricted ID. |
556 * @param {number} position The position of the iframe in the UI. | 601 * @param {number} position The position of the iframe in the UI. |
557 * @return {string} An URL to display the most visited thumbnail in an iframe. | 602 * @return {string} An URL to display the most visited thumbnail in an iframe. |
558 */ | 603 */ |
559 function getMostVisitedThumbnailIframeUrl(rid, position) { | 604 function getMostVisitedThumbnailIframeUrl(rid, position) { |
560 var url = 'chrome-search://most-visited/' + | 605 var url = 'chrome-search://most-visited/' + |
561 encodeURIComponent(MOST_VISITED_THUMBNAIL_IFRAME); | 606 encodeURIComponent(MOST_VISITED_THUMBNAIL_IFRAME); |
562 var params = [ | 607 var params = [ |
563 'rid=' + encodeURIComponent(rid), | 608 'rid=' + encodeURIComponent(rid), |
564 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily), | 609 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily), |
565 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize), | 610 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize), |
566 'c=' + encodeURIComponent(NTP_DESIGN.thumbnailTextColor), | 611 'c=' + encodeURIComponent(NTP_DESIGN.thumbnailTextColor), |
567 'pos=' + encodeURIComponent(position)]; | 612 'pos=' + encodeURIComponent(position)]; |
613 if (NTP_DESIGN.thumbnailFallback) | |
614 params.push('tfb=1'); | |
568 return url + '?' + params.join('&'); | 615 return url + '?' + params.join('&'); |
569 } | 616 } |
570 | 617 |
571 | 618 |
572 /** | 619 /** |
573 * Creates a Tile with the specified page data. If no data is provided, a | 620 * Creates a Tile with the specified page data. If no data is provided, a |
574 * filler Tile is created. | 621 * filler Tile is created. |
575 * @param {Object} page The page data. | 622 * @param {Object} page The page data. |
576 * @param {number} position The position of the tile. | 623 * @param {number} position The position of the tile. |
577 * @return {Tile} The new Tile. | 624 * @return {Tile} The new Tile. |
578 */ | 625 */ |
579 function createTile(page, position) { | 626 function createTile(page, position) { |
580 var tileElement = document.createElement('div'); | 627 var tileElem = document.createElement('div'); |
581 tileElement.classList.add(CLASSES.TILE); | 628 tileElem.classList.add(CLASSES.TILE); |
629 var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER); | |
582 | 630 |
583 if (page) { | 631 if (page) { |
584 var rid = page.rid; | 632 var rid = page.rid; |
585 tileElement.classList.add(CLASSES.PAGE); | 633 tileElem.classList.add(CLASSES.PAGE); |
586 | 634 |
587 var navigateFunction = function(e) { | 635 var navigateFunction = function(e) { |
588 e.preventDefault(); | 636 e.preventDefault(); |
589 ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); | 637 ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); |
590 }; | 638 }; |
591 | 639 |
592 // The click handler for navigating to the page identified by the RID. | 640 // The click handler for navigating to the page identified by the RID. |
593 tileElement.addEventListener('click', navigateFunction); | 641 tileElem.addEventListener('click', navigateFunction); |
594 | 642 |
595 // Make thumbnails tab-accessible. | 643 // Make thumbnails tab-accessible. |
596 tileElement.setAttribute('tabindex', '1'); | 644 tileElem.setAttribute('tabindex', '1'); |
597 registerKeyHandler(tileElement, KEYCODE.ENTER, navigateFunction); | 645 registerKeyHandler(tileElem, KEYCODE.ENTER, navigateFunction); |
598 | 646 |
599 // The iframe which renders the page title. | 647 // The iframe which renders the page title. |
600 var titleElement = document.createElement('iframe'); | 648 var titleElem = document.createElement('iframe'); |
601 titleElement.tabIndex = '-1'; | 649 titleElem.tabIndex = '-1'; |
602 | 650 |
603 // Why iframes have IDs: | 651 // Why iframes have IDs: |
604 // | 652 // |
605 // On navigating back to the NTP we see several onmostvisitedchange() events | 653 // On navigating back to the NTP we see several onmostvisitedchange() events |
606 // in series with incrementing RIDs. After the first event, a set of iframes | 654 // in series with incrementing RIDs. After the first event, a set of iframes |
607 // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get | 655 // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get |
608 // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. | 656 // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. |
609 // Now due to crbug.com/68841, Chrome incorrectly loads the content for the | 657 // Now due to crbug.com/68841, Chrome incorrectly loads the content for the |
610 // first set of iframes into the most recent set of iframes. | 658 // first set of iframes into the most recent set of iframes. |
611 // | 659 // |
612 // Giving iframes distinct ids seems to cause some invalidation and prevent | 660 // Giving iframes distinct ids seems to cause some invalidation and prevent |
613 // associating the incorrect data. | 661 // associating the incorrect data. |
614 // | 662 // |
615 // TODO(jered): Find and fix the root (probably Blink) bug. | 663 // TODO(jered): Find and fix the root (probably Blink) bug. |
616 | 664 |
617 // Keep this ID here. See comment above. | 665 // Keep this ID here. See comment above. |
618 titleElement.id = 'title-' + rid; | 666 titleElem.id = 'title-' + rid; |
619 titleElement.className = CLASSES.TITLE; | 667 titleElem.className = CLASSES.TITLE; |
620 titleElement.hidden = true; | 668 titleElem.src = getMostVisitedTitleIframeUrl(rid, position); |
621 titleElement.src = getMostVisitedTitleIframeUrl(rid, position); | 669 innerElem.appendChild(titleElem); |
622 tileElement.appendChild(titleElement); | 670 |
671 // A fallback element for missing thumbnails. | |
672 if (NTP_DESIGN.thumbnailFallback) { | |
673 var fallbackElem = createAndAppendElement( | |
674 innerElem, 'div', CLASSES.THUMBNAIL_FALLBACK); | |
675 if (NTP_DESIGN.thumbnailFallback === THUMBNAIL_FALLBACK.DOT) | |
676 createAndAppendElement(fallbackElem, 'div', CLASSES.DOT); | |
677 } | |
623 | 678 |
624 // The iframe which renders either a thumbnail or domain element. | 679 // The iframe which renders either a thumbnail or domain element. |
625 var thumbnailElement = document.createElement('iframe'); | 680 var thumbnailElem = document.createElement('iframe'); |
626 thumbnailElement.tabIndex = '-1'; | 681 thumbnailElem.tabIndex = '-1'; |
627 // Keep this ID here. See comment above. | 682 // Keep this ID here. See comment above. |
628 thumbnailElement.id = 'thumb-' + rid; | 683 thumbnailElem.id = 'thumb-' + rid; |
629 thumbnailElement.className = CLASSES.THUMBNAIL; | 684 thumbnailElem.className = CLASSES.THUMBNAIL; |
630 thumbnailElement.hidden = true; | 685 thumbnailElem.src = getMostVisitedThumbnailIframeUrl(rid, position); |
631 thumbnailElement.src = getMostVisitedThumbnailIframeUrl(rid, position); | 686 innerElem.appendChild(thumbnailElem); |
632 tileElement.appendChild(thumbnailElement); | |
633 | |
634 // A mask to darken the thumbnail on focus. | |
635 var maskElement = createAndAppendElement( | |
636 tileElement, 'div', CLASSES.THUMBNAIL_MASK); | |
637 | 687 |
638 // The button used to blacklist this page. | 688 // The button used to blacklist this page. |
639 var blacklistButton = createAndAppendElement( | 689 var blacklistButton = createAndAppendElement( |
640 tileElement, 'div', CLASSES.BLACKLIST_BUTTON); | 690 innerElem, 'div', CLASSES.BLACKLIST_BUTTON); |
641 var blacklistFunction = generateBlacklistFunction(rid); | 691 var blacklistFunction = generateBlacklistFunction(rid); |
642 blacklistButton.addEventListener('click', blacklistFunction); | 692 blacklistButton.addEventListener('click', blacklistFunction); |
643 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; | 693 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; |
644 | 694 |
695 // A helper mask on top of the tile that is used to create hover border | |
696 // and/or to darken the thumbnail on focus. | |
697 var maskElement = createAndAppendElement( | |
698 innerElem, 'div', CLASSES.THUMBNAIL_MASK); | |
699 | |
645 // When a tile is focused, have delete also blacklist the page. | 700 // When a tile is focused, have delete also blacklist the page. |
646 registerKeyHandler(tileElement, KEYCODE.DELETE, blacklistFunction); | 701 registerKeyHandler(tileElem, KEYCODE.DELETE, blacklistFunction); |
647 | 702 |
648 // The page favicon, if any. | 703 // The page favicon, if any. |
649 var faviconUrl = page.faviconUrl; | 704 var faviconUrl = page.faviconUrl; |
650 if (faviconUrl) { | 705 if (faviconUrl) { |
651 var favicon = createAndAppendElement(tileElement, 'div', CLASSES.FAVICON); | 706 var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON); |
652 favicon.style.backgroundImage = 'url(' + faviconUrl + ')'; | 707 favicon.style.backgroundImage = 'url(' + faviconUrl + ')'; |
653 } | 708 } |
654 return new Tile(tileElement, titleElement, thumbnailElement, rid); | 709 return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid); |
655 } else { | 710 } else { |
656 return new Tile(tileElement); | 711 return new Tile(tileElem); |
657 } | 712 } |
658 } | 713 } |
659 | 714 |
660 | 715 |
661 /** | 716 /** |
662 * Generates a function to be called when the page with the corresponding RID | 717 * Generates a function to be called when the page with the corresponding RID |
663 * is blacklisted. | 718 * is blacklisted. |
664 * @param {number} rid The RID of the page being blacklisted. | 719 * @param {number} rid The RID of the page being blacklisted. |
665 * @return {function(Event)} A function which handles the blacklisting of the | 720 * @return {function(Event)} A function which handles the blacklisting of the |
666 * page by updating state variables and notifying Chrome. | 721 * page by updating state variables and notifying Chrome. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
740 if (newNumColumns < MIN_NUM_COLUMNS) | 795 if (newNumColumns < MIN_NUM_COLUMNS) |
741 newNumColumns = MIN_NUM_COLUMNS; | 796 newNumColumns = MIN_NUM_COLUMNS; |
742 else if (newNumColumns > MAX_NUM_COLUMNS) | 797 else if (newNumColumns > MAX_NUM_COLUMNS) |
743 newNumColumns = MAX_NUM_COLUMNS; | 798 newNumColumns = MAX_NUM_COLUMNS; |
744 | 799 |
745 if (numColumnsShown != newNumColumns) { | 800 if (numColumnsShown != newNumColumns) { |
746 numColumnsShown = newNumColumns; | 801 numColumnsShown = newNumColumns; |
747 var tilesContainerWidth = numColumnsShown * tileRequiredWidth; | 802 var tilesContainerWidth = numColumnsShown * tileRequiredWidth; |
748 tilesContainer.style.width = tilesContainerWidth + 'px'; | 803 tilesContainer.style.width = tilesContainerWidth + 'px'; |
749 if (fakebox) { | 804 if (fakebox) { |
750 // -2 to account for border. | 805 if (NTP_DESIGN.name === 'smallScreen1') { |
751 fakebox.style.width = | 806 // -2 to account for border. |
752 (tilesContainerWidth - NTP_DESIGN.tileMargin - 2) + 'px'; | 807 fakebox.style.width = (tilesContainerWidth - tileRequiredWidth - |
808 NTP_DESIGN.tileMargin - 2) + 'px'; | |
809 } else { | |
810 fakebox.style.width = | |
811 (tilesContainerWidth - NTP_DESIGN.tileMargin - 2) + 'px'; | |
812 } | |
753 } | 813 } |
754 // Render without clearing tiles. | 814 // Render without clearing tiles. |
755 renderAndShowTiles(); | 815 renderAndShowTiles(); |
756 } | 816 } |
757 } | 817 } |
758 | 818 |
759 | 819 |
760 /** | 820 /** |
761 * Returns the tile corresponding to the specified page RID. | 821 * Returns the tile corresponding to the specified page RID. |
762 * @param {number} rid The page RID being looked up. | 822 * @param {number} rid The page RID being looked up. |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
923 * Prepares the New Tab Page by adding listeners, rendering the current | 983 * Prepares the New Tab Page by adding listeners, rendering the current |
924 * theme, the most visited pages section, and Google-specific elements for a | 984 * theme, the most visited pages section, and Google-specific elements for a |
925 * Google-provided page. | 985 * Google-provided page. |
926 */ | 986 */ |
927 function init() { | 987 function init() { |
928 tilesContainer = $(IDS.TILES); | 988 tilesContainer = $(IDS.TILES); |
929 notification = $(IDS.NOTIFICATION); | 989 notification = $(IDS.NOTIFICATION); |
930 attribution = $(IDS.ATTRIBUTION); | 990 attribution = $(IDS.ATTRIBUTION); |
931 ntpContents = $(IDS.NTP_CONTENTS); | 991 ntpContents = $(IDS.NTP_CONTENTS); |
932 | 992 |
993 NTP_DESIGN.classToAdd.forEach(function(v, idx) { | |
Mathieu
2014/08/13 20:09:29
would rather not have this.
huangs
2014/08/13 21:34:08
Deleted; injecting "classical" from local_ntp_sour
| |
994 ntpContents.classList.add(v); | |
995 }); | |
996 | |
933 if (configData.isGooglePage) { | 997 if (configData.isGooglePage) { |
934 var logo = document.createElement('div'); | 998 var logo = document.createElement('div'); |
935 logo.id = IDS.LOGO; | 999 logo.id = IDS.LOGO; |
936 | 1000 |
937 fakebox = document.createElement('div'); | 1001 fakebox = document.createElement('div'); |
938 fakebox.id = IDS.FAKEBOX; | 1002 fakebox.id = IDS.FAKEBOX; |
939 fakebox.innerHTML = | 1003 var fakeboxHtml = []; |
940 '<input id="' + IDS.FAKEBOX_INPUT + | 1004 fakeboxHtml.push('<input id="' + IDS.FAKEBOX_INPUT + |
941 '" autocomplete="off" tabindex="-1" aria-hidden="true">' + | 1005 '" autocomplete="off" tabindex="-1" aria-hidden="true">'); |
942 '<div id="cursor"></div>'; | 1006 if (NTP_DESIGN.showFakeboxHint && configData.searchboxPlaceholder) { |
1007 fakeboxHtml.push('<div id="fakebox-text">' + | |
1008 configData.searchboxPlaceholder + '</div>'); | |
1009 } | |
1010 fakeboxHtml.push('<div id="cursor"></div>'); | |
1011 fakebox.innerHTML = fakeboxHtml.join(''); | |
943 | 1012 |
944 ntpContents.insertBefore(fakebox, ntpContents.firstChild); | 1013 ntpContents.insertBefore(fakebox, ntpContents.firstChild); |
945 ntpContents.insertBefore(logo, ntpContents.firstChild); | 1014 ntpContents.insertBefore(logo, ntpContents.firstChild); |
946 } else { | 1015 } else { |
947 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE); | 1016 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE); |
948 } | 1017 } |
949 | 1018 |
950 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); | 1019 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); |
951 notificationMessage.textContent = | 1020 notificationMessage.textContent = |
952 configData.translatedStrings.thumbnailRemovedNotification; | 1021 configData.translatedStrings.thumbnailRemovedNotification; |
(...skipping 23 matching lines...) Expand all Loading... | |
976 ntpApiHandle = topLevelHandle.newTabPage; | 1045 ntpApiHandle = topLevelHandle.newTabPage; |
977 ntpApiHandle.onthemechange = onThemeChange; | 1046 ntpApiHandle.onthemechange = onThemeChange; |
978 ntpApiHandle.onmostvisitedchange = onMostVisitedChange; | 1047 ntpApiHandle.onmostvisitedchange = onMostVisitedChange; |
979 | 1048 |
980 ntpApiHandle.oninputstart = onInputStart; | 1049 ntpApiHandle.oninputstart = onInputStart; |
981 ntpApiHandle.oninputcancel = restoreNtp; | 1050 ntpApiHandle.oninputcancel = restoreNtp; |
982 | 1051 |
983 if (ntpApiHandle.isInputInProgress) | 1052 if (ntpApiHandle.isInputInProgress) |
984 onInputStart(); | 1053 onInputStart(); |
985 | 1054 |
986 onThemeChange(); | 1055 renderTheme(); |
987 onMostVisitedChange(); | 1056 onMostVisitedChange(); |
988 | 1057 |
989 searchboxApiHandle = topLevelHandle.searchBox; | 1058 searchboxApiHandle = topLevelHandle.searchBox; |
990 | 1059 |
991 if (fakebox) { | 1060 if (fakebox) { |
992 // Listener for updating the key capture state. | 1061 // Listener for updating the key capture state. |
993 document.body.onmousedown = function(event) { | 1062 document.body.onmousedown = function(event) { |
994 if (isFakeboxClick(event)) | 1063 if (isFakeboxClick(event)) |
995 searchboxApiHandle.startCapturingKeyStrokes(); | 1064 searchboxApiHandle.startCapturingKeyStrokes(); |
996 else if (isFakeboxFocused()) | 1065 else if (isFakeboxFocused()) |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1043 | 1112 |
1044 return { | 1113 return { |
1045 init: init, | 1114 init: init, |
1046 listen: listen | 1115 listen: listen |
1047 }; | 1116 }; |
1048 } | 1117 } |
1049 | 1118 |
1050 if (!window.localNTPUnitTest) { | 1119 if (!window.localNTPUnitTest) { |
1051 LocalNTP().listen(); | 1120 LocalNTP().listen(); |
1052 } | 1121 } |
OLD | NEW |