OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 * @fileoverview Support for omnibox behavior in offline mode or when API | 6 * @fileoverview Support for omnibox behavior in offline mode or when API |
7 * features are not supported on the server. | 7 * features are not supported on the server. |
8 */ | 8 */ |
9 | 9 |
10 // ========================================================== | 10 // ========================================================== |
(...skipping 21 matching lines...) Expand all Loading... |
32 // ============================================================================= | 32 // ============================================================================= |
33 | 33 |
34 /** | 34 /** |
35 * The maximum number of suggestions to show. | 35 * The maximum number of suggestions to show. |
36 * @type {number} | 36 * @type {number} |
37 * @const | 37 * @const |
38 */ | 38 */ |
39 var MAX_SUGGESTIONS_TO_SHOW = 5; | 39 var MAX_SUGGESTIONS_TO_SHOW = 5; |
40 | 40 |
41 /** | 41 /** |
| 42 * Assume any native suggestion with a score higher than this value has been |
| 43 * inlined by the browser. |
| 44 * @type {number} |
| 45 * @const |
| 46 */ |
| 47 var INLINE_SUGGESTION_THRESHOLD = 1200; |
| 48 |
| 49 /** |
| 50 * Suggestion provider type corresponding to a verbatim URL suggestion. |
| 51 * @type {string} |
| 52 * @const |
| 53 */ |
| 54 var VERBATIM_URL_TYPE = 'url-what-you-typed'; |
| 55 |
| 56 /** |
42 * The omnibox input value during the last onnativesuggestions event. | 57 * The omnibox input value during the last onnativesuggestions event. |
43 * @type {string} | 58 * @type {string} |
44 */ | 59 */ |
45 var lastInputValue = ''; | 60 var lastInputValue = ''; |
46 | 61 |
47 /** | 62 /** |
48 * The ordered restricted ids of the currently displayed suggestions. Since the | 63 * The ordered restricted ids of the currently displayed suggestions. Since the |
49 * suggestions contain the user's personal data (browser history) the searchBox | 64 * suggestions contain the user's personal data (browser history) the searchBox |
50 * API embeds the content of the suggestion in a shadow dom, and assigns a | 65 * API embeds the content of the suggestion in a shadow dom, and assigns a |
51 * random restricted id to each suggestion which is accessible to the JS. | 66 * random restricted id to each suggestion which is accessible to the JS. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 * Renders the input suggestions. | 114 * Renders the input suggestions. |
100 * @param {Array} nativeSuggestions An array of native suggestions to render. | 115 * @param {Array} nativeSuggestions An array of native suggestions to render. |
101 */ | 116 */ |
102 function renderSuggestions(nativeSuggestions) { | 117 function renderSuggestions(nativeSuggestions) { |
103 var box = document.createElement('div'); | 118 var box = document.createElement('div'); |
104 box.id = 'suggestionsBox'; | 119 box.id = 'suggestionsBox'; |
105 $('suggestions-box-container').appendChild(box); | 120 $('suggestions-box-container').appendChild(box); |
106 | 121 |
107 for (var i = 0, length = nativeSuggestions.length; | 122 for (var i = 0, length = nativeSuggestions.length; |
108 i < Math.min(MAX_SUGGESTIONS_TO_SHOW, length); ++i) { | 123 i < Math.min(MAX_SUGGESTIONS_TO_SHOW, length); ++i) { |
109 // Select the first suggestion. | 124 addSuggestionToBox(nativeSuggestions[i], box, i == selectedIndex); |
110 addSuggestionToBox(nativeSuggestions[i], box, i == 0); | |
111 } | 125 } |
112 } | 126 } |
113 | 127 |
114 /** | 128 /** |
115 * Clears the suggestions being displayed. | 129 * Clears the suggestions being displayed. |
116 */ | 130 */ |
117 function clearSuggestions() { | 131 function clearSuggestions() { |
118 $('suggestions-box-container').innerHTML = ''; | 132 $('suggestions-box-container').innerHTML = ''; |
119 restrictedIds = []; | 133 restrictedIds = []; |
120 selectedIndex = -1; | 134 selectedIndex = -1; |
121 } | 135 } |
122 | 136 |
123 /** | 137 /** |
124 * @return {integer} The height of the dropdown. | 138 * @return {integer} The height of the dropdown. |
125 */ | 139 */ |
126 function getDropdownHeight() { | 140 function getDropdownHeight() { |
127 return $('suggestions-box-container').offsetHeight; | 141 return $('suggestions-box-container').offsetHeight; |
128 } | 142 } |
129 | 143 |
130 /** | 144 /** |
| 145 * @param {Object} suggestion A suggestion. |
| 146 * @param {boolean} inVerbatimMode Are we in verbatim mode? |
| 147 * @return {boolean} True if the suggestion should be selected. |
| 148 */ |
| 149 function shouldSelectSuggestion(suggestion, inVerbatimMode) { |
| 150 var isVerbatimUrl = suggestion.type == VERBATIM_URL_TYPE; |
| 151 var inlinableSuggestion = suggestion.rankingData.relevance > |
| 152 INLINE_SUGGESTION_THRESHOLD; |
| 153 // Verbatim URLs should always be selected. Otherwise, select suggestions |
| 154 // with a high enough score unless we are in verbatim mode (e.g. backspacing |
| 155 // away). |
| 156 return isVerbatimUrl || (!inVerbatimMode && inlinableSuggestion); |
| 157 } |
| 158 |
| 159 /** |
131 * Updates selectedIndex, bounding it between -1 and the total number of | 160 * Updates selectedIndex, bounding it between -1 and the total number of |
132 * of suggestions - 1 (looping as necessary), and selects the corresponding | 161 * of suggestions - 1 (looping as necessary), and selects the corresponding |
133 * suggestion. | 162 * suggestion. |
134 * @param {boolean} increment True to increment the selected suggestion, false | 163 * @param {boolean} increment True to increment the selected suggestion, false |
135 * to decrement. | 164 * to decrement. |
136 */ | 165 */ |
137 function updateSelectedSuggestion(increment) { | 166 function updateSelectedSuggestion(increment) { |
138 var numSuggestions = restrictedIds.length; | 167 var numSuggestions = restrictedIds.length; |
139 if (!numSuggestions) | 168 if (!numSuggestions) |
140 return; | 169 return; |
(...skipping 30 matching lines...) Expand all Loading... |
171 if (window.navigator && window.navigator.embeddedSearch && | 200 if (window.navigator && window.navigator.embeddedSearch && |
172 window.navigator.embeddedSearch.searchBox) | 201 window.navigator.embeddedSearch.searchBox) |
173 return window.navigator.embeddedSearch.searchBox; | 202 return window.navigator.embeddedSearch.searchBox; |
174 if (window.chrome && window.chrome.embeddedSearch && | 203 if (window.chrome && window.chrome.embeddedSearch && |
175 window.chrome.embeddedSearch.searchBox) | 204 window.chrome.embeddedSearch.searchBox) |
176 return window.chrome.embeddedSearch.searchBox; | 205 return window.chrome.embeddedSearch.searchBox; |
177 return null; | 206 return null; |
178 } | 207 } |
179 | 208 |
180 /** | 209 /** |
181 * chrome.searchBox.onnativesuggestions implementation. | 210 * Updates suggestions in response to a onchange or onnativesuggestions call. |
182 */ | 211 */ |
183 function handleNativeSuggestions() { | 212 function updateSuggestions() { |
184 var apiHandle = getApiObjectHandle(); | 213 var apiHandle = getApiObjectHandle(); |
185 | |
186 // Used to workaround repeated undesired asynchronous onnativesuggestions | |
187 // events and the fact that when a suggestion is clicked, the omnibox unfocus | |
188 // can cause onnativesuggestions to fire, preventing the suggestion onclick | |
189 // from registering. | |
190 if (lastInputValue == apiHandle.value && $('suggestionsBox')) { | |
191 return; | |
192 } | |
193 lastInputValue = apiHandle.value; | 214 lastInputValue = apiHandle.value; |
194 | 215 |
195 clearSuggestions(); | 216 clearSuggestions(); |
196 var nativeSuggestions = apiHandle.nativeSuggestions; | 217 var nativeSuggestions = apiHandle.nativeSuggestions; |
197 if (nativeSuggestions.length) { | 218 if (nativeSuggestions.length) { |
198 nativeSuggestions.sort(function(a, b) { | 219 nativeSuggestions.sort(function(a, b) { |
199 return b.rankingData.relevance - a.rankingData.relevance; | 220 return b.rankingData.relevance - a.rankingData.relevance; |
200 }); | 221 }); |
| 222 if (shouldSelectSuggestion(nativeSuggestions[0], apiHandle.verbatim)) { |
| 223 selectedIndex = 0; |
| 224 apiHandle.setRestrictedAutocompleteText( |
| 225 nativeSuggestions[selectedIndex].rid); |
| 226 } |
201 renderSuggestions(nativeSuggestions); | 227 renderSuggestions(nativeSuggestions); |
202 selectedIndex = 0; | |
203 apiHandle.setRestrictedAutocompleteText( | |
204 nativeSuggestions[selectedIndex].rid); | |
205 } | 228 } |
206 | 229 |
207 var height = getDropdownHeight(); | 230 var height = getDropdownHeight(); |
208 apiHandle.showOverlay(height); | 231 apiHandle.showOverlay(height); |
209 } | 232 } |
210 | 233 |
211 /** | 234 /** |
212 * Appends a style node for suggestion properties that depend on apiHandle. | 235 * Appends a style node for suggestion properties that depend on apiHandle. |
213 */ | 236 */ |
214 function appendSuggestionStyles() { | 237 function appendSuggestionStyles() { |
215 var apiHandle = getApiObjectHandle(); | 238 var apiHandle = getApiObjectHandle(); |
216 var style = document.createElement('style'); | 239 var style = document.createElement('style'); |
217 style.type = 'text/css'; | 240 style.type = 'text/css'; |
218 style.id = 'suggestionStyle'; | 241 style.id = 'suggestionStyle'; |
219 style.textContent = | 242 style.textContent = |
220 '.suggestion {' + | 243 '.suggestion {' + |
221 ' -webkit-margin-start: ' + apiHandle.startMargin + 'px;' + | 244 ' -webkit-margin-start: ' + apiHandle.startMargin + 'px;' + |
222 ' -webkit-margin-end: ' + apiHandle.endMargin + 'px;' + | 245 ' width: ' + apiHandle.width + 'px;' + |
223 ' font: ' + apiHandle.fontSize + 'px "' + apiHandle.font + '";' + | 246 ' font: ' + apiHandle.fontSize + 'px "' + apiHandle.font + '";' + |
224 '}'; | 247 '}'; |
225 document.querySelector('head').appendChild(style); | 248 document.querySelector('head').appendChild(style); |
226 } | 249 } |
227 | 250 |
228 /** | 251 /** |
229 * Extract the desired navigation behavior from a click event. | 252 * Extract the desired navigation behavior from a click event. |
230 * @param {Event} event The click event. | 253 * @param {Event} event The click event. |
231 * @return {WindowOpenDisposition} The desired behavior for | 254 * @return {WindowOpenDisposition} The desired behavior for |
232 * navigateContentWindow. | 255 * navigateContentWindow. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 * chrome.searchBox.embeddedSearch.onsubmit implementation. | 291 * chrome.searchBox.embeddedSearch.onsubmit implementation. |
269 */ | 292 */ |
270 function onSubmit() { | 293 function onSubmit() { |
271 } | 294 } |
272 | 295 |
273 /** | 296 /** |
274 * Sets up the searchBox API. | 297 * Sets up the searchBox API. |
275 */ | 298 */ |
276 function setUpApi() { | 299 function setUpApi() { |
277 var apiHandle = getApiObjectHandle(); | 300 var apiHandle = getApiObjectHandle(); |
278 apiHandle.onnativesuggestions = handleNativeSuggestions; | 301 apiHandle.onnativesuggestions = updateSuggestions; |
| 302 apiHandle.onchange = updateSuggestions; |
279 apiHandle.onkeypress = handleKeyPress; | 303 apiHandle.onkeypress = handleKeyPress; |
280 apiHandle.onsubmit = onSubmit; | 304 apiHandle.onsubmit = onSubmit; |
281 appendSuggestionStyles(); | 305 appendSuggestionStyles(); |
282 | 306 |
283 if (apiHandle.nativeSuggestions.length) | 307 if (apiHandle.nativeSuggestions.length) |
284 handleNativeSuggestions(); | 308 handleNativeSuggestions(); |
285 } | 309 } |
286 | 310 |
287 document.addEventListener('DOMContentLoaded', setUpApi); | 311 document.addEventListener('DOMContentLoaded', setUpApi); |
OLD | NEW |