| 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 |