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 BLACKLIST_BUTTON_INNER: 'mv-x-inner', |
31 DARK: 'dark', | 32 DARK: 'dark', |
32 DEFAULT_THEME: 'default-theme', | 33 DEFAULT_THEME: 'default-theme', |
33 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', | 34 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', |
34 DOT: 'dot', | 35 DOT: 'dot', |
35 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive | 36 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive |
36 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox | 37 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox |
37 // Applies drag focus style to the fakebox | 38 // Applies drag focus style to the fakebox |
38 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', | 39 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', |
39 FAVICON: 'mv-favicon', | 40 FAVICON: 'mv-favicon', |
40 FAVICON_FALLBACK: 'mv-favicon-fallback', | 41 FAVICON_FALLBACK: 'mv-favicon-fallback', |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 /** | 170 /** |
170 * True if a page has been blacklisted and we're waiting on the | 171 * True if a page has been blacklisted and we're waiting on the |
171 * onmostvisitedchange callback. See onMostVisitedChange() for how this | 172 * onmostvisitedchange callback. See onMostVisitedChange() for how this |
172 * is used. | 173 * is used. |
173 * @type {boolean} | 174 * @type {boolean} |
174 */ | 175 */ |
175 var isBlacklisting = false; | 176 var isBlacklisting = false; |
176 | 177 |
177 | 178 |
178 /** | 179 /** |
179 * Stores whether the current theme has a dark background. | |
180 * @type {boolean} | |
181 */ | |
182 var isBackgroundDark = false; | |
183 | |
184 | |
185 /** | |
186 * Current number of tiles columns shown based on the window width, including | 180 * Current number of tiles columns shown based on the window width, including |
187 * those that just contain filler. | 181 * those that just contain filler. |
188 * @type {number} | 182 * @type {number} |
189 */ | 183 */ |
190 var numColumnsShown = 0; | 184 var numColumnsShown = 0; |
191 | 185 |
192 | 186 |
193 /** | 187 /** |
194 * A flag to indicate Most Visited changed caused by user action. If true, then | 188 * A flag to indicate Most Visited changed caused by user action. If true, then |
195 * in onMostVisitedChange() tiles remain visible so no flickering occurs. | 189 * in onMostVisitedChange() tiles remain visible so no flickering occurs. |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 | 255 |
262 /** | 256 /** |
263 * The filename for a most visited iframe src which shows a thumbnail image. | 257 * The filename for a most visited iframe src which shows a thumbnail image. |
264 * @type {string} | 258 * @type {string} |
265 * @const | 259 * @const |
266 */ | 260 */ |
267 var MOST_VISITED_THUMBNAIL_IFRAME = 'thumbnail.html'; | 261 var MOST_VISITED_THUMBNAIL_IFRAME = 'thumbnail.html'; |
268 | 262 |
269 | 263 |
270 /** | 264 /** |
| 265 * The color of the title in RRGGBBAA format. |
| 266 * @type {?string} |
| 267 */ |
| 268 var titleColor = null; |
| 269 |
| 270 |
| 271 /** |
271 * Hide most visited tiles for at most this many milliseconds while painting. | 272 * Hide most visited tiles for at most this many milliseconds while painting. |
272 * @type {number} | 273 * @type {number} |
273 * @const | 274 * @const |
274 */ | 275 */ |
275 var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500; | 276 var MOST_VISITED_PAINT_TIMEOUT_MSEC = 500; |
276 | 277 |
277 | 278 |
278 /** | 279 /** |
279 * A Tile is either a rendering of a Most Visited page or "filler" used to | 280 * A Tile is either a rendering of a Most Visited page or "filler" used to |
280 * pad out the section when not enough pages exist. | 281 * pad out the section when not enough pages exist. |
(...skipping 18 matching lines...) Expand all Loading... |
299 | 300 |
300 /** @type {Element|undefined} */ | 301 /** @type {Element|undefined} */ |
301 this.thumbnailElem = opt_thumbnailElem; | 302 this.thumbnailElem = opt_thumbnailElem; |
302 | 303 |
303 /** @type {number|undefined} */ | 304 /** @type {number|undefined} */ |
304 this.rid = opt_rid; | 305 this.rid = opt_rid; |
305 } | 306 } |
306 | 307 |
307 | 308 |
308 /** | 309 /** |
309 * Determines whether a theme should be considered to have dark background. | 310 * Heuristic to determine whether a theme should be considered to be dark, so |
310 * @param {ThemeBackgroundInfo} info Theme background information. | 311 * the colors of various UI elements can be adjusted. |
311 * @return {boolean} Whether the theme has dark background. | 312 * @param {ThemeBackgroundInfo|undefined} info Theme background information. |
| 313 * @return {boolean} Whether the theme is dark. |
312 * @private | 314 * @private |
313 */ | 315 */ |
314 function getIsBackgroundDark(info) { | 316 function getIsThemeDark(info) { |
315 if (info.imageUrl) | 317 if (!info) |
316 return true; | 318 return false; |
317 var rgba = info.backgroundColorRgba; | 319 // Heuristic: light text implies dark theme. |
| 320 var rgba = info.textColorRgba; |
318 var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2]; | 321 var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2]; |
319 return luminance < 128; | 322 return luminance >= 128; |
320 } | 323 } |
321 | 324 |
322 | 325 |
323 /** | 326 /** |
324 * Updates the NTP based on the current theme. | 327 * Updates the NTP based on the current theme. |
325 * @private | 328 * @private |
326 */ | 329 */ |
327 function renderTheme() { | 330 function renderTheme() { |
| 331 var fakeboxText = $(IDS.FAKEBOX_TEXT); |
| 332 if (fakeboxText) { |
| 333 fakeboxText.innerHTML = ''; |
| 334 if (NTP_DESIGN.showFakeboxHint && |
| 335 configData.translatedStrings.searchboxPlaceholder) { |
| 336 fakeboxText.textContent = |
| 337 configData.translatedStrings.searchboxPlaceholder; |
| 338 } |
| 339 } |
| 340 |
328 var info = ntpApiHandle.themeBackgroundInfo; | 341 var info = ntpApiHandle.themeBackgroundInfo; |
| 342 var isThemeDark = getIsThemeDark(info); |
| 343 ntpContents.classList.toggle(CLASSES.DARK, isThemeDark); |
329 if (!info) { | 344 if (!info) { |
330 isBackgroundDark = false; | 345 titleColor = NTP_DESIGN.titleColor; |
331 return; | 346 return; |
332 } | 347 } |
333 | 348 |
334 isBackgroundDark = getIsBackgroundDark(info); | 349 if (!info.usingDefaultTheme && info.textColorRgba) { |
335 ntpContents.classList.toggle(CLASSES.DARK, isBackgroundDark); | 350 titleColor = convertToRRGGBBAAColor(info.textColorRgba); |
| 351 } else { |
| 352 titleColor = isThemeDark ? |
| 353 NTP_DESIGN.titleColorAgainstDark : NTP_DESIGN.titleColor; |
| 354 } |
336 | 355 |
337 var background = [convertToRGBAColor(info.backgroundColorRgba), | 356 var background = [convertToRGBAColor(info.backgroundColorRgba), |
338 info.imageUrl, | 357 info.imageUrl, |
339 info.imageTiling, | 358 info.imageTiling, |
340 info.imageHorizontalAlignment, | 359 info.imageHorizontalAlignment, |
341 info.imageVerticalAlignment].join(' ').trim(); | 360 info.imageVerticalAlignment].join(' ').trim(); |
| 361 |
342 document.body.style.background = background; | 362 document.body.style.background = background; |
343 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); | 363 document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo); |
344 updateThemeAttribution(info.attributionUrl); | 364 updateThemeAttribution(info.attributionUrl); |
345 setCustomThemeStyle(info); | 365 setCustomThemeStyle(info); |
346 } | 366 } |
347 | 367 |
348 | 368 |
349 /** | 369 /** |
350 * Updates the NTP based on the current theme, then rerenders all tiles. | 370 * Updates the NTP based on the current theme, then rerenders all tiles. |
351 * @private | 371 * @private |
352 */ | 372 */ |
353 function onThemeChange() { | 373 function onThemeChange() { |
354 renderTheme(); | 374 renderTheme(); |
355 tilesContainer.innerHTML = ''; | 375 tilesContainer.innerHTML = ''; |
356 renderAndShowTiles(); | 376 renderAndShowTiles(); |
357 } | 377 } |
358 | 378 |
359 | 379 |
360 /** | 380 /** |
361 * Updates the NTP style according to theme. | 381 * Updates the NTP style according to theme. |
362 * @param {Object=} opt_themeInfo The information about the theme. If it is | 382 * @param {Object=} opt_themeInfo The information about the theme. If it is |
363 * omitted the style will be reverted to the default. | 383 * omitted the style will be reverted to the default. |
364 * @private | 384 * @private |
365 */ | 385 */ |
366 function setCustomThemeStyle(opt_themeInfo) { | 386 function setCustomThemeStyle(opt_themeInfo) { |
367 var customStyleElement = $(IDS.CUSTOM_THEME_STYLE); | 387 var customStyleElement = $(IDS.CUSTOM_THEME_STYLE); |
368 var head = document.head; | 388 var head = document.head; |
369 | |
370 if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) { | 389 if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) { |
371 ntpContents.classList.remove(CLASSES.DEFAULT_THEME); | 390 ntpContents.classList.remove(CLASSES.DEFAULT_THEME); |
372 var themeStyle = | 391 var themeStyle = |
373 '#attribution {' + | 392 '#attribution {' + |
374 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' + | 393 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' + |
375 '}' + | 394 '}' + |
376 '#mv-msg {' + | 395 '#mv-msg {' + |
377 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorRgba) + ';' + | 396 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorRgba) + ';' + |
378 '}' + | 397 '}' + |
379 '#mv-notice-links span {' + | 398 '#mv-notice-links span {' + |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 * @private | 456 * @private |
438 */ | 457 */ |
439 function setAttributionVisibility_(show) { | 458 function setAttributionVisibility_(show) { |
440 if (attribution) { | 459 if (attribution) { |
441 attribution.style.display = show ? '' : 'none'; | 460 attribution.style.display = show ? '' : 'none'; |
442 } | 461 } |
443 } | 462 } |
444 | 463 |
445 | 464 |
446 /** | 465 /** |
| 466 * Converts an Array of color components into RRGGBBAA format. |
| 467 * @param {Array.<number>} color Array of rgba color components. |
| 468 * @return {string} Color string in RRGGBBAA format. |
| 469 * @private |
| 470 */ |
| 471 function convertToRRGGBBAAColor(color) { |
| 472 return color.map(function(t) { |
| 473 return ('0' + t.toString(16)).slice(-2); // To 2-digit, 0-padded hex. |
| 474 }).join(''); |
| 475 } |
| 476 |
| 477 |
| 478 /** |
447 * Converts an Array of color components into RGBA format "rgba(R,G,B,A)". | 479 * Converts an Array of color components into RGBA format "rgba(R,G,B,A)". |
448 * @param {Array.<number>} color Array of rgba color components. | 480 * @param {Array.<number>} color Array of rgba color components. |
449 * @return {string} CSS color in RGBA format. | 481 * @return {string} CSS color in RGBA format. |
450 * @private | 482 * @private |
451 */ | 483 */ |
452 function convertToRGBAColor(color) { | 484 function convertToRGBAColor(color) { |
453 return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + | 485 return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + |
454 color[3] / 255 + ')'; | 486 color[3] / 255 + ')'; |
455 } | 487 } |
456 | 488 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 | 610 |
579 /** | 611 /** |
580 * Builds a URL to display a most visited tile title in an iframe. | 612 * Builds a URL to display a most visited tile title in an iframe. |
581 * @param {number} rid The restricted ID. | 613 * @param {number} rid The restricted ID. |
582 * @param {number} position The position of the iframe in the UI. | 614 * @param {number} position The position of the iframe in the UI. |
583 * @return {string} An URL to display the most visited title in an iframe. | 615 * @return {string} An URL to display the most visited title in an iframe. |
584 */ | 616 */ |
585 function getMostVisitedTitleIframeUrl(rid, position) { | 617 function getMostVisitedTitleIframeUrl(rid, position) { |
586 var url = 'chrome-search://most-visited/' + | 618 var url = 'chrome-search://most-visited/' + |
587 encodeURIComponent(MOST_VISITED_TITLE_IFRAME); | 619 encodeURIComponent(MOST_VISITED_TITLE_IFRAME); |
588 var titleColor = isBackgroundDark ? NTP_DESIGN.titleColorAgainstDark : | |
589 NTP_DESIGN.titleColor; | |
590 var params = [ | 620 var params = [ |
591 'rid=' + encodeURIComponent(rid), | 621 'rid=' + encodeURIComponent(rid), |
592 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily), | 622 'f=' + encodeURIComponent(NTP_DESIGN.fontFamily), |
593 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize), | 623 'fs=' + encodeURIComponent(NTP_DESIGN.fontSize), |
594 'c=' + encodeURIComponent(titleColor), | 624 'c=' + encodeURIComponent(titleColor), |
595 'pos=' + encodeURIComponent(position)]; | 625 'pos=' + encodeURIComponent(position)]; |
596 if (NTP_DESIGN.titleTextAlign) | 626 if (NTP_DESIGN.titleTextAlign) |
597 params.push('ta=' + encodeURIComponent(NTP_DESIGN.titleTextAlign)); | 627 params.push('ta=' + encodeURIComponent(NTP_DESIGN.titleTextAlign)); |
598 if (NTP_DESIGN.titleTextFade) | 628 if (NTP_DESIGN.titleTextFade) |
599 params.push('tf=' + encodeURIComponent(NTP_DESIGN.titleTextFade)); | 629 params.push('tf=' + encodeURIComponent(NTP_DESIGN.titleTextFade)); |
(...skipping 25 matching lines...) Expand all Loading... |
625 /** | 655 /** |
626 * Creates a Tile with the specified page data. If no data is provided, a | 656 * Creates a Tile with the specified page data. If no data is provided, a |
627 * filler Tile is created. | 657 * filler Tile is created. |
628 * @param {Object} page The page data. | 658 * @param {Object} page The page data. |
629 * @param {number} position The position of the tile. | 659 * @param {number} position The position of the tile. |
630 * @return {Tile} The new Tile. | 660 * @return {Tile} The new Tile. |
631 */ | 661 */ |
632 function createTile(page, position) { | 662 function createTile(page, position) { |
633 var tileElem = document.createElement('div'); | 663 var tileElem = document.createElement('div'); |
634 tileElem.classList.add(CLASSES.TILE); | 664 tileElem.classList.add(CLASSES.TILE); |
| 665 // Prevent tile from being selected (and highlighted) when areas outside the |
| 666 // <iframe>s are clicked. |
| 667 tileElem.addEventListener('mousedown', function(e) { |
| 668 e.preventDefault(); |
| 669 }); |
635 var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER); | 670 var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER); |
636 | 671 |
637 if (page) { | 672 if (page) { |
638 var rid = page.rid; | 673 var rid = page.rid; |
639 tileElem.classList.add(CLASSES.PAGE); | 674 tileElem.classList.add(CLASSES.PAGE); |
640 | 675 |
641 var navigateFunction = function(e) { | 676 var navigateFunction = function(e) { |
642 e.preventDefault(); | 677 e.preventDefault(); |
643 ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); | 678 ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); |
644 }; | 679 }; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 thumbnailElem.tabIndex = '-1'; | 722 thumbnailElem.tabIndex = '-1'; |
688 // Keep this ID here. See comment above. | 723 // Keep this ID here. See comment above. |
689 thumbnailElem.id = 'thumb-' + rid; | 724 thumbnailElem.id = 'thumb-' + rid; |
690 thumbnailElem.className = CLASSES.THUMBNAIL; | 725 thumbnailElem.className = CLASSES.THUMBNAIL; |
691 thumbnailElem.src = getMostVisitedThumbnailIframeUrl(rid, position); | 726 thumbnailElem.src = getMostVisitedThumbnailIframeUrl(rid, position); |
692 innerElem.appendChild(thumbnailElem); | 727 innerElem.appendChild(thumbnailElem); |
693 | 728 |
694 // The button used to blacklist this page. | 729 // The button used to blacklist this page. |
695 var blacklistButton = createAndAppendElement( | 730 var blacklistButton = createAndAppendElement( |
696 innerElem, 'div', CLASSES.BLACKLIST_BUTTON); | 731 innerElem, 'div', CLASSES.BLACKLIST_BUTTON); |
| 732 createAndAppendElement( |
| 733 blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); |
697 var blacklistFunction = generateBlacklistFunction(rid); | 734 var blacklistFunction = generateBlacklistFunction(rid); |
698 blacklistButton.addEventListener('click', blacklistFunction); | 735 blacklistButton.addEventListener('click', blacklistFunction); |
699 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; | 736 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; |
700 | 737 |
701 // A helper mask on top of the tile that is used to create hover border | 738 // A helper mask on top of the tile that is used to create hover border |
702 // and/or to darken the thumbnail on focus. | 739 // and/or to darken the thumbnail on focus. |
703 var maskElement = createAndAppendElement( | 740 var maskElement = createAndAppendElement( |
704 innerElem, 'div', CLASSES.THUMBNAIL_MASK); | 741 innerElem, 'div', CLASSES.THUMBNAIL_MASK); |
705 | 742 |
706 // When a tile is focused, have delete also blacklist the page. | 743 // When a tile is focused, have delete also blacklist the page. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 notification.scrollTop; | 787 notification.scrollTop; |
751 notification.classList.add(CLASSES.DELAYED_HIDE_NOTIFICATION); | 788 notification.classList.add(CLASSES.DELAYED_HIDE_NOTIFICATION); |
752 } | 789 } |
753 | 790 |
754 | 791 |
755 /** | 792 /** |
756 * Hides the blacklist notification. | 793 * Hides the blacklist notification. |
757 */ | 794 */ |
758 function hideNotification() { | 795 function hideNotification() { |
759 notification.classList.add(CLASSES.HIDE_NOTIFICATION); | 796 notification.classList.add(CLASSES.HIDE_NOTIFICATION); |
| 797 notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION); |
760 } | 798 } |
761 | 799 |
762 | 800 |
763 /** | 801 /** |
764 * Handles a click on the notification undo link by hiding the notification and | 802 * Handles a click on the notification undo link by hiding the notification and |
765 * informing Chrome. | 803 * informing Chrome. |
766 */ | 804 */ |
767 function onUndo() { | 805 function onUndo() { |
768 userInitiatedMostVisitedChange = true; | 806 userInitiatedMostVisitedChange = true; |
769 hideNotification(); | 807 hideNotification(); |
770 var lastBlacklistedRID = lastBlacklistedTile.rid; | 808 var lastBlacklistedRID = lastBlacklistedTile.rid; |
771 if (typeof lastBlacklistedRID != 'undefined') | 809 if (typeof lastBlacklistedRID != 'undefined') |
772 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedRID); | 810 ntpApiHandle.undoMostVisitedDeletion(lastBlacklistedRID); |
773 } | 811 } |
774 | 812 |
775 | 813 |
776 /** | 814 /** |
777 * Handles a click on the restore all notification link by hiding the | 815 * Handles a click on the restore all notification link by hiding the |
778 * notification and informing Chrome. | 816 * notification and informing Chrome. |
779 */ | 817 */ |
780 function onRestoreAll() { | 818 function onRestoreAll() { |
781 userInitiatedMostVisitedChange = true; | 819 userInitiatedMostVisitedChange = true; |
782 hideNotification(); | 820 hideNotification(); |
783 ntpApiHandle.undoAllMostVisitedDeletions(); | 821 ntpApiHandle.undoAllMostVisitedDeletions(); |
784 } | 822 } |
785 | 823 |
786 | 824 |
787 /** | 825 /** |
788 * Resizes elements because the number of tile columns may need to change in | 826 * Recomputes the number of tile columns, and width of various contents based |
789 * response to resizing. Also shows or hides extra tiles tiles according to the | 827 * on the width of the window. |
790 * new width of the page. | 828 * @return {boolean} Whether the number of tile columns has changed. |
791 */ | 829 */ |
792 function onResize() { | 830 function updateContentWidth() { |
793 var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin; | 831 var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin; |
794 // If innerWidth is zero, then use the maximum snap size. | 832 // If innerWidth is zero, then use the maximum snap size. |
795 var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth - | 833 var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth - |
796 NTP_DESIGN.tileMargin + MIN_TOTAL_HORIZONTAL_PADDING; | 834 NTP_DESIGN.tileMargin + MIN_TOTAL_HORIZONTAL_PADDING; |
797 var innerWidth = window.innerWidth || maxSnapSize; | 835 var innerWidth = window.innerWidth || maxSnapSize; |
798 // Each tile has left and right margins that sum to NTP_DESIGN.tileMargin. | 836 // Each tile has left and right margins that sum to NTP_DESIGN.tileMargin. |
799 var availableWidth = innerWidth + NTP_DESIGN.tileMargin - | 837 var availableWidth = innerWidth + NTP_DESIGN.tileMargin - |
800 MIN_TOTAL_HORIZONTAL_PADDING; | 838 MIN_TOTAL_HORIZONTAL_PADDING; |
801 var newNumColumns = Math.floor(availableWidth / tileRequiredWidth); | 839 var newNumColumns = Math.floor(availableWidth / tileRequiredWidth); |
802 if (newNumColumns < MIN_NUM_COLUMNS) | 840 if (newNumColumns < MIN_NUM_COLUMNS) |
803 newNumColumns = MIN_NUM_COLUMNS; | 841 newNumColumns = MIN_NUM_COLUMNS; |
804 else if (newNumColumns > MAX_NUM_COLUMNS) | 842 else if (newNumColumns > MAX_NUM_COLUMNS) |
805 newNumColumns = MAX_NUM_COLUMNS; | 843 newNumColumns = MAX_NUM_COLUMNS; |
806 | 844 |
807 if (numColumnsShown != newNumColumns) { | 845 if (numColumnsShown === newNumColumns) |
808 numColumnsShown = newNumColumns; | 846 return false; |
809 var tilesContainerWidth = numColumnsShown * tileRequiredWidth; | 847 |
810 tilesContainer.style.width = tilesContainerWidth + 'px'; | 848 numColumnsShown = newNumColumns; |
811 if (fakebox) { | 849 var tilesContainerWidth = numColumnsShown * tileRequiredWidth; |
812 fakebox.style.width = // -2 to account for border. | 850 tilesContainer.style.width = tilesContainerWidth + 'px'; |
813 (tilesContainerWidth - NTP_DESIGN.tileMargin - 2) + 'px'; | 851 if (fakebox) { |
814 } | 852 // -2 to account for border. |
| 853 var fakeboxWidth = (tilesContainerWidth - NTP_DESIGN.tileMargin - 2); |
| 854 fakebox.style.width = fakeboxWidth + 'px'; |
| 855 } |
| 856 return true; |
| 857 } |
| 858 |
| 859 |
| 860 /** |
| 861 * Resizes elements because the number of tile columns may need to change in |
| 862 * response to resizing. Also shows or hides extra tiles tiles according to the |
| 863 * new width of the page. |
| 864 */ |
| 865 function onResize() { |
| 866 if (updateContentWidth()) { |
815 // Render without clearing tiles. | 867 // Render without clearing tiles. |
816 renderAndShowTiles(); | 868 renderAndShowTiles(); |
817 } | 869 } |
818 } | 870 } |
819 | 871 |
820 | 872 |
821 /** | 873 /** |
822 * Returns the tile corresponding to the specified page RID. | 874 * Returns the tile corresponding to the specified page RID. |
823 * @param {number} rid The page RID being looked up. | 875 * @param {number} rid The page RID being looked up. |
824 * @return {Tile} The corresponding tile. | 876 * @return {Tile} The corresponding tile. |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 | 1045 |
994 if (configData.isGooglePage) { | 1046 if (configData.isGooglePage) { |
995 var logo = document.createElement('div'); | 1047 var logo = document.createElement('div'); |
996 logo.id = IDS.LOGO; | 1048 logo.id = IDS.LOGO; |
997 | 1049 |
998 fakebox = document.createElement('div'); | 1050 fakebox = document.createElement('div'); |
999 fakebox.id = IDS.FAKEBOX; | 1051 fakebox.id = IDS.FAKEBOX; |
1000 var fakeboxHtml = []; | 1052 var fakeboxHtml = []; |
1001 fakeboxHtml.push('<input id="' + IDS.FAKEBOX_INPUT + | 1053 fakeboxHtml.push('<input id="' + IDS.FAKEBOX_INPUT + |
1002 '" autocomplete="off" tabindex="-1" aria-hidden="true">'); | 1054 '" autocomplete="off" tabindex="-1" aria-hidden="true">'); |
1003 if (NTP_DESIGN.showFakeboxHint && | 1055 fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '"></div>'); |
1004 configData.translatedStrings.searchboxPlaceholder) { | |
1005 fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '">' + | |
1006 configData.translatedStrings.searchboxPlaceholder + '</div>'); | |
1007 } | |
1008 fakeboxHtml.push('<div id="cursor"></div>'); | 1056 fakeboxHtml.push('<div id="cursor"></div>'); |
1009 fakebox.innerHTML = fakeboxHtml.join(''); | 1057 fakebox.innerHTML = fakeboxHtml.join(''); |
1010 | 1058 |
1011 ntpContents.insertBefore(fakebox, ntpContents.firstChild); | 1059 ntpContents.insertBefore(fakebox, ntpContents.firstChild); |
1012 ntpContents.insertBefore(logo, ntpContents.firstChild); | 1060 ntpContents.insertBefore(logo, ntpContents.firstChild); |
1013 } else { | 1061 } else { |
1014 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE); | 1062 document.body.classList.add(CLASSES.NON_GOOGLE_PAGE); |
1015 } | 1063 } |
1016 | 1064 |
| 1065 // Hide notifications after fade out, so we can't focus on links via keyboard. |
| 1066 notification.addEventListener('webkitTransitionEnd', hideNotification); |
| 1067 |
1017 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); | 1068 var notificationMessage = $(IDS.NOTIFICATION_MESSAGE); |
1018 notificationMessage.textContent = | 1069 notificationMessage.textContent = |
1019 configData.translatedStrings.thumbnailRemovedNotification; | 1070 configData.translatedStrings.thumbnailRemovedNotification; |
1020 | 1071 |
1021 var undoLink = $(IDS.UNDO_LINK); | 1072 var undoLink = $(IDS.UNDO_LINK); |
1022 undoLink.addEventListener('click', onUndo); | 1073 undoLink.addEventListener('click', onUndo); |
1023 registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo); | 1074 registerKeyHandler(undoLink, KEYCODE.ENTER, onUndo); |
1024 undoLink.textContent = configData.translatedStrings.undoThumbnailRemove; | 1075 undoLink.textContent = configData.translatedStrings.undoThumbnailRemove; |
1025 | 1076 |
1026 var restoreAllLink = $(IDS.RESTORE_ALL_LINK); | 1077 var restoreAllLink = $(IDS.RESTORE_ALL_LINK); |
1027 restoreAllLink.addEventListener('click', onRestoreAll); | 1078 restoreAllLink.addEventListener('click', onRestoreAll); |
1028 registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo); | 1079 registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onUndo); |
1029 restoreAllLink.textContent = | 1080 restoreAllLink.textContent = |
1030 configData.translatedStrings.restoreThumbnailsShort; | 1081 configData.translatedStrings.restoreThumbnailsShort; |
1031 | 1082 |
1032 $(IDS.ATTRIBUTION_TEXT).textContent = | 1083 $(IDS.ATTRIBUTION_TEXT).textContent = |
1033 configData.translatedStrings.attributionIntro; | 1084 configData.translatedStrings.attributionIntro; |
1034 | 1085 |
1035 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON); | 1086 var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON); |
| 1087 createAndAppendElement( |
| 1088 notificationCloseButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); |
1036 notificationCloseButton.addEventListener('click', hideNotification); | 1089 notificationCloseButton.addEventListener('click', hideNotification); |
1037 | 1090 |
1038 window.addEventListener('resize', onResize); | 1091 window.addEventListener('resize', onResize); |
1039 onResize(); | 1092 updateContentWidth(); |
1040 | 1093 |
1041 var topLevelHandle = getEmbeddedSearchApiHandle(); | 1094 var topLevelHandle = getEmbeddedSearchApiHandle(); |
1042 | 1095 |
1043 ntpApiHandle = topLevelHandle.newTabPage; | 1096 ntpApiHandle = topLevelHandle.newTabPage; |
1044 ntpApiHandle.onthemechange = onThemeChange; | 1097 ntpApiHandle.onthemechange = onThemeChange; |
1045 ntpApiHandle.onmostvisitedchange = onMostVisitedChange; | 1098 ntpApiHandle.onmostvisitedchange = onMostVisitedChange; |
1046 | 1099 |
1047 ntpApiHandle.oninputstart = onInputStart; | 1100 ntpApiHandle.oninputstart = onInputStart; |
1048 ntpApiHandle.oninputcancel = restoreNtp; | 1101 ntpApiHandle.oninputcancel = restoreNtp; |
1049 | 1102 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1110 | 1163 |
1111 return { | 1164 return { |
1112 init: init, | 1165 init: init, |
1113 listen: listen | 1166 listen: listen |
1114 }; | 1167 }; |
1115 } | 1168 } |
1116 | 1169 |
1117 if (!window.localNTPUnitTest) { | 1170 if (!window.localNTPUnitTest) { |
1118 LocalNTP().listen(); | 1171 LocalNTP().listen(); |
1119 } | 1172 } |
OLD | NEW |