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 21 matching lines...) Expand all Loading... |
32 DARK: 'dark', | 32 DARK: 'dark', |
33 DEFAULT_THEME: 'default-theme', | 33 DEFAULT_THEME: 'default-theme', |
34 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', | 34 DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide', |
35 DOT: 'dot', | 35 DOT: 'dot', |
36 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive | 36 FAKEBOX_DISABLE: 'fakebox-disable', // Makes fakebox non-interactive |
37 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox | 37 FAKEBOX_FOCUS: 'fakebox-focused', // Applies focus styles to the fakebox |
38 // Applies drag focus style to the fakebox | 38 // Applies drag focus style to the fakebox |
39 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', | 39 FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused', |
40 FAVICON: 'mv-favicon', | 40 FAVICON: 'mv-favicon', |
41 FAVICON_FALLBACK: 'mv-favicon-fallback', | 41 FAVICON_FALLBACK: 'mv-favicon-fallback', |
| 42 FOCUSED: 'mv-focused', |
42 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation | 43 HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation |
43 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo', | 44 HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo', |
44 HIDE_NOTIFICATION: 'mv-notice-hide', | 45 HIDE_NOTIFICATION: 'mv-notice-hide', |
45 // Vertically centers the most visited section for a non-Google provided page. | 46 // Vertically centers the most visited section for a non-Google provided page. |
46 NON_GOOGLE_PAGE: 'non-google-page', | 47 NON_GOOGLE_PAGE: 'non-google-page', |
47 PAGE: 'mv-page', // page tiles | 48 PAGE: 'mv-page', // page tiles |
48 PAGE_READY: 'mv-page-ready', // page tile when ready | 49 PAGE_READY: 'mv-page-ready', // page tile when ready |
49 RTL: 'rtl', // Right-to-left language text. | 50 RTL: 'rtl', // Right-to-left language text. |
50 THUMBNAIL: 'mv-thumb', | 51 THUMBNAIL: 'mv-thumb', |
51 THUMBNAIL_FALLBACK: 'mv-thumb-fallback', | 52 THUMBNAIL_FALLBACK: 'mv-thumb-fallback', |
(...skipping 26 matching lines...) Expand all Loading... |
78 UNDO_LINK: 'mv-undo' | 79 UNDO_LINK: 'mv-undo' |
79 }; | 80 }; |
80 | 81 |
81 | 82 |
82 /** | 83 /** |
83 * Enum for keycodes. | 84 * Enum for keycodes. |
84 * @enum {number} | 85 * @enum {number} |
85 * @const | 86 * @const |
86 */ | 87 */ |
87 var KEYCODE = { | 88 var KEYCODE = { |
88 DELETE: 46, | |
89 ENTER: 13 | 89 ENTER: 13 |
90 }; | 90 }; |
91 | 91 |
92 | 92 |
93 /** | 93 /** |
94 * Enum for the state of the NTP when it is disposed. | 94 * Enum for the state of the NTP when it is disposed. |
95 * @enum {number} | 95 * @enum {number} |
96 * @const | 96 * @const |
97 */ | 97 */ |
98 var NTP_DISPOSE_STATE = { | 98 var NTP_DISPOSE_STATE = { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 | 161 |
162 | 162 |
163 /** | 163 /** |
164 * The last blacklisted tile if any, which by definition should not be filler. | 164 * The last blacklisted tile if any, which by definition should not be filler. |
165 * @type {?Tile} | 165 * @type {?Tile} |
166 */ | 166 */ |
167 var lastBlacklistedTile = null; | 167 var lastBlacklistedTile = null; |
168 | 168 |
169 | 169 |
170 /** | 170 /** |
| 171 * The iframe element which is currently keyboard focused, or null. |
| 172 * @type {?Element} |
| 173 */ |
| 174 var focusedIframe = null; |
| 175 |
| 176 |
| 177 /** |
171 * True if a page has been blacklisted and we're waiting on the | 178 * True if a page has been blacklisted and we're waiting on the |
172 * onmostvisitedchange callback. See onMostVisitedChange() for how this | 179 * onmostvisitedchange callback. See onMostVisitedChange() for how this |
173 * is used. | 180 * is used. |
174 * @type {boolean} | 181 * @type {boolean} |
175 */ | 182 */ |
176 var isBlacklisting = false; | 183 var isBlacklisting = false; |
177 | 184 |
178 | 185 |
179 /** | 186 /** |
180 * Current number of tiles columns shown based on the window width, including | 187 * Current number of tiles columns shown based on the window width, including |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' + | 406 ' color: ' + convertToRGBAColor(opt_themeInfo.textColorLightRgba) + ';' + |
400 '}' + | 407 '}' + |
401 '#mv-notice-x {' + | 408 '#mv-notice-x {' + |
402 ' -webkit-filter: drop-shadow(0 0 0 ' + | 409 ' -webkit-filter: drop-shadow(0 0 0 ' + |
403 convertToRGBAColor(opt_themeInfo.textColorRgba) + ');' + | 410 convertToRGBAColor(opt_themeInfo.textColorRgba) + ');' + |
404 '}' + | 411 '}' + |
405 '.mv-page-ready .mv-mask {' + | 412 '.mv-page-ready .mv-mask {' + |
406 ' border: 1px solid ' + | 413 ' border: 1px solid ' + |
407 convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' + | 414 convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' + |
408 '}' + | 415 '}' + |
409 '.mv-page-ready:hover .mv-mask, .mv-page-ready:focus .mv-mask {' + | 416 '.mv-page-ready:hover .mv-mask, .mv-page-ready .mv-focused ~ .mv-mask {' + |
410 ' border-color: ' + | 417 ' border-color: ' + |
411 convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' + | 418 convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' + |
412 '}'; | 419 '}'; |
413 | 420 |
414 if (customStyleElement) { | 421 if (customStyleElement) { |
415 customStyleElement.textContent = themeStyle; | 422 customStyleElement.textContent = themeStyle; |
416 } else { | 423 } else { |
417 customStyleElement = document.createElement('style'); | 424 customStyleElement = document.createElement('style'); |
418 customStyleElement.type = 'text/css'; | 425 customStyleElement.type = 'text/css'; |
419 customStyleElement.id = IDS.CUSTOM_THEME_STYLE; | 426 customStyleElement.id = IDS.CUSTOM_THEME_STYLE; |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 tileElem.classList.add(CLASSES.PAGE); | 681 tileElem.classList.add(CLASSES.PAGE); |
675 | 682 |
676 var navigateFunction = function(e) { | 683 var navigateFunction = function(e) { |
677 e.preventDefault(); | 684 e.preventDefault(); |
678 ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); | 685 ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); |
679 }; | 686 }; |
680 | 687 |
681 // The click handler for navigating to the page identified by the RID. | 688 // The click handler for navigating to the page identified by the RID. |
682 tileElem.addEventListener('click', navigateFunction); | 689 tileElem.addEventListener('click', navigateFunction); |
683 | 690 |
684 // Make thumbnails tab-accessible. | |
685 tileElem.setAttribute('tabindex', '1'); | |
686 registerKeyHandler(tileElem, KEYCODE.ENTER, navigateFunction); | |
687 | |
688 // The iframe which renders the page title. | 691 // The iframe which renders the page title. |
689 var titleElem = document.createElement('iframe'); | 692 var titleElem = document.createElement('iframe'); |
690 titleElem.tabIndex = '-1'; | 693 // Enable tab navigation on the iframe, which will move the selection to the |
| 694 // link element (which also has a tabindex). |
| 695 titleElem.tabIndex = '0'; |
691 | 696 |
692 // Why iframes have IDs: | 697 // Why iframes have IDs: |
693 // | 698 // |
694 // On navigating back to the NTP we see several onmostvisitedchange() events | 699 // On navigating back to the NTP we see several onmostvisitedchange() events |
695 // in series with incrementing RIDs. After the first event, a set of iframes | 700 // in series with incrementing RIDs. After the first event, a set of iframes |
696 // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get | 701 // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get |
697 // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. | 702 // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. |
698 // Now due to crbug.com/68841, Chrome incorrectly loads the content for the | 703 // Now due to crbug.com/68841, Chrome incorrectly loads the content for the |
699 // first set of iframes into the most recent set of iframes. | 704 // first set of iframes into the most recent set of iframes. |
700 // | 705 // |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); | 738 blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); |
734 var blacklistFunction = generateBlacklistFunction(rid); | 739 var blacklistFunction = generateBlacklistFunction(rid); |
735 blacklistButton.addEventListener('click', blacklistFunction); | 740 blacklistButton.addEventListener('click', blacklistFunction); |
736 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; | 741 blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; |
737 | 742 |
738 // A helper mask on top of the tile that is used to create hover border | 743 // A helper mask on top of the tile that is used to create hover border |
739 // and/or to darken the thumbnail on focus. | 744 // and/or to darken the thumbnail on focus. |
740 var maskElement = createAndAppendElement( | 745 var maskElement = createAndAppendElement( |
741 innerElem, 'div', CLASSES.THUMBNAIL_MASK); | 746 innerElem, 'div', CLASSES.THUMBNAIL_MASK); |
742 | 747 |
743 // When a tile is focused, have delete also blacklist the page. | |
744 registerKeyHandler(tileElem, KEYCODE.DELETE, blacklistFunction); | |
745 | |
746 // The page favicon, or a fallback. | 748 // The page favicon, or a fallback. |
747 var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON); | 749 var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON); |
748 if (page.faviconUrl) { | 750 if (page.faviconUrl) { |
749 favicon.style.backgroundImage = 'url(' + page.faviconUrl + ')'; | 751 favicon.style.backgroundImage = 'url(' + page.faviconUrl + ')'; |
750 } else { | 752 } else { |
751 favicon.classList.add(CLASSES.FAVICON_FALLBACK); | 753 favicon.classList.add(CLASSES.FAVICON_FALLBACK); |
752 } | 754 } |
753 return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid); | 755 return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid); |
754 } else { | 756 } else { |
755 return new Tile(tileElem); | 757 return new Tile(tileElem); |
756 } | 758 } |
757 } | 759 } |
758 | 760 |
759 | 761 |
760 /** | 762 /** |
761 * Generates a function to be called when the page with the corresponding RID | 763 * Generates a function to be called when the page with the corresponding RID |
762 * is blacklisted. | 764 * is blacklisted. |
763 * @param {number} rid The RID of the page being blacklisted. | 765 * @param {number} rid The RID of the page being blacklisted. |
764 * @return {function(Event)} A function which handles the blacklisting of the | 766 * @return {function(!Event)} A function which handles the blacklisting of the |
765 * page by updating state variables and notifying Chrome. | 767 * page by updating state variables and notifying Chrome. |
766 */ | 768 */ |
767 function generateBlacklistFunction(rid) { | 769 function generateBlacklistFunction(rid) { |
768 return function(e) { | 770 return function(e) { |
769 // Prevent navigation when the page is being blacklisted. | 771 // Prevent navigation when the page is being blacklisted. |
770 e.stopPropagation(); | 772 if (e) |
| 773 e.stopPropagation(); |
771 | 774 |
772 userInitiatedMostVisitedChange = true; | 775 userInitiatedMostVisitedChange = true; |
773 isBlacklisting = true; | 776 isBlacklisting = true; |
774 tilesContainer.classList.add(CLASSES.HIDE_BLACKLIST_BUTTON); | 777 tilesContainer.classList.add(CLASSES.HIDE_BLACKLIST_BUTTON); |
775 lastBlacklistedTile = getTileByRid(rid); | 778 lastBlacklistedTile = getTileByRid(rid); |
776 ntpApiHandle.deleteMostVisitedItem(rid); | 779 ntpApiHandle.deleteMostVisitedItem(rid); |
777 }; | 780 }; |
778 } | 781 } |
779 | 782 |
780 | 783 |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 function getEmbeddedSearchApiHandle() { | 1029 function getEmbeddedSearchApiHandle() { |
1027 if (window.cideb) | 1030 if (window.cideb) |
1028 return window.cideb; | 1031 return window.cideb; |
1029 if (window.chrome && window.chrome.embeddedSearch) | 1032 if (window.chrome && window.chrome.embeddedSearch) |
1030 return window.chrome.embeddedSearch; | 1033 return window.chrome.embeddedSearch; |
1031 return null; | 1034 return null; |
1032 } | 1035 } |
1033 | 1036 |
1034 | 1037 |
1035 /** | 1038 /** |
| 1039 * Event handler for the focus changed and blacklist messages on link elements. |
| 1040 * Used to toggle visual treatment on the tiles (depending on the message). |
| 1041 * @param {Event} event Event received. |
| 1042 */ |
| 1043 function handlePostMessage(event) { |
| 1044 if (event.origin !== 'chrome-search://most-visited') |
| 1045 return; |
| 1046 |
| 1047 if (event.data === 'linkFocused') { |
| 1048 var activeElement = document.activeElement; |
| 1049 if (activeElement.classList.contains(CLASSES.TITLE)) { |
| 1050 activeElement.classList.add(CLASSES.FOCUSED); |
| 1051 focusedIframe = activeElement; |
| 1052 } |
| 1053 } else if (event.data === 'linkBlurred') { |
| 1054 if (focusedIframe) |
| 1055 focusedIframe.classList.remove(CLASSES.FOCUSED); |
| 1056 focusedIframe = null; |
| 1057 } else if (event.data.indexOf('tileBlacklisted') === 0) { |
| 1058 var tilePosition = event.data.split(',')[1]; |
| 1059 if (tilePosition) |
| 1060 generateBlacklistFunction(tiles[parseInt(tilePosition, 10)].rid)(); |
| 1061 } |
| 1062 } |
| 1063 |
| 1064 |
| 1065 /** |
1036 * Prepares the New Tab Page by adding listeners, rendering the current | 1066 * Prepares the New Tab Page by adding listeners, rendering the current |
1037 * theme, the most visited pages section, and Google-specific elements for a | 1067 * theme, the most visited pages section, and Google-specific elements for a |
1038 * Google-provided page. | 1068 * Google-provided page. |
1039 */ | 1069 */ |
1040 function init() { | 1070 function init() { |
1041 tilesContainer = $(IDS.TILES); | 1071 tilesContainer = $(IDS.TILES); |
1042 notification = $(IDS.NOTIFICATION); | 1072 notification = $(IDS.NOTIFICATION); |
1043 attribution = $(IDS.ATTRIBUTION); | 1073 attribution = $(IDS.ATTRIBUTION); |
1044 ntpContents = $(IDS.NTP_CONTENTS); | 1074 ntpContents = $(IDS.NTP_CONTENTS); |
1045 | 1075 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1144 setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled); | 1174 setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled); |
1145 } | 1175 } |
1146 | 1176 |
1147 if (searchboxApiHandle.rtl) { | 1177 if (searchboxApiHandle.rtl) { |
1148 $(IDS.NOTIFICATION).dir = 'rtl'; | 1178 $(IDS.NOTIFICATION).dir = 'rtl'; |
1149 document.body.setAttribute('dir', 'rtl'); | 1179 document.body.setAttribute('dir', 'rtl'); |
1150 // Add class for setting alignments based on language directionality. | 1180 // Add class for setting alignments based on language directionality. |
1151 document.body.classList.add(CLASSES.RTL); | 1181 document.body.classList.add(CLASSES.RTL); |
1152 $(IDS.TILES).dir = 'rtl'; | 1182 $(IDS.TILES).dir = 'rtl'; |
1153 } | 1183 } |
| 1184 |
| 1185 window.addEventListener('message', handlePostMessage); |
1154 } | 1186 } |
1155 | 1187 |
1156 | 1188 |
1157 /** | 1189 /** |
1158 * Binds event listeners. | 1190 * Binds event listeners. |
1159 */ | 1191 */ |
1160 function listen() { | 1192 function listen() { |
1161 document.addEventListener('DOMContentLoaded', init); | 1193 document.addEventListener('DOMContentLoaded', init); |
1162 } | 1194 } |
1163 | 1195 |
1164 return { | 1196 return { |
1165 init: init, | 1197 init: init, |
1166 listen: listen | 1198 listen: listen |
1167 }; | 1199 }; |
1168 } | 1200 } |
1169 | 1201 |
1170 if (!window.localNTPUnitTest) { | 1202 if (!window.localNTPUnitTest) { |
1171 LocalNTP().listen(); | 1203 LocalNTP().listen(); |
1172 } | 1204 } |
OLD | NEW |