| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 * Javascript for omnibox.html, served from chrome://omnibox/ | 6 * Javascript for omnibox.html, served from chrome://omnibox/ |
| 7 * This is used to debug omnibox ranking. The user enters some text | 7 * This is used to debug omnibox ranking. The user enters some text |
| 8 * into a box, submits it, and then sees lots of debug information | 8 * into a box, submits it, and then sees lots of debug information |
| 9 * from the autocompleter that shows what omnibox would do with that | 9 * from the autocompleter that shows what omnibox would do with that |
| 10 * input. | 10 * input. |
| 11 * | 11 * |
| 12 * The simple object defined in this javascript file listens for | 12 * The simple object defined in this javascript file listens for |
| 13 * certain events on omnibox.html, sends (when appropriate) the | 13 * certain events on omnibox.html, sends (when appropriate) the |
| 14 * input text to C++ code to start the omnibox autcomplete controller | 14 * input text to C++ code to start the omnibox autcomplete controller |
| 15 * working, and listens from callbacks from the C++ code saying that | 15 * working, and listens from callbacks from the C++ code saying that |
| 16 * results are available. When results (possibly intermediate ones) | 16 * results are available. When results (possibly intermediate ones) |
| 17 * are available, the Javascript formats them and displays them. | 17 * are available, the Javascript formats them and displays them. |
| 18 */ | 18 */ |
| 19 | 19 |
| 20 (function() { | 20 (function() { |
| 21 /** | 21 /** |
| 22 * Register our event handlers. | 22 * Register our event handlers. |
| 23 */ | 23 */ |
| 24 function initialize() { | 24 function initialize() { |
| 25 $('omnibox-input-form').addEventListener( | 25 $('omnibox-input-form').addEventListener('submit', startOmniboxQuery, false); |
| 26 'submit', startOmniboxQuery, false); | 26 $('prevent-inline-autocomplete') |
| 27 $('prevent-inline-autocomplete').addEventListener( | 27 .addEventListener('change', startOmniboxQuery); |
| 28 'change', startOmniboxQuery); | 28 $('prefer-keyword').addEventListener('change', startOmniboxQuery); |
| 29 $('prefer-keyword').addEventListener('change', startOmniboxQuery); | 29 $('page-classification').addEventListener('change', startOmniboxQuery); |
| 30 $('page-classification').addEventListener('change', startOmniboxQuery); | 30 $('show-details').addEventListener('change', refresh); |
| 31 $('show-details').addEventListener('change', refresh); | 31 $('show-incomplete-results').addEventListener('change', refresh); |
| 32 $('show-incomplete-results').addEventListener('change', refresh); | 32 $('show-all-providers').addEventListener('change', refresh); |
| 33 $('show-all-providers').addEventListener('change', refresh); | 33 } |
| 34 } | 34 |
| 35 | 35 /** |
| 36 /** | 36 * @type {OmniboxResultMojo} an array of all autocomplete results we've seen |
| 37 * @type {OmniboxResultMojo} an array of all autocomplete results we've seen | 37 * for this query. We append to this list once for every call to |
| 38 * for this query. We append to this list once for every call to | 38 * handleNewAutocompleteResult. See omnibox.mojom for details.. |
| 39 * handleNewAutocompleteResult. See omnibox.mojom for details.. | 39 */ |
| 40 */ | 40 var progressiveAutocompleteResults = []; |
| 41 var progressiveAutocompleteResults = []; | 41 |
| 42 | 42 /** |
| 43 /** | 43 * @type {number} the value for cursor position we sent with the most |
| 44 * @type {number} the value for cursor position we sent with the most | 44 * recent request. We need to remember this in order to display it |
| 45 * recent request. We need to remember this in order to display it | 45 * in the output; otherwise it's hard or impossible to determine |
| 46 * in the output; otherwise it's hard or impossible to determine | 46 * from screen captures or print-to-PDFs. |
| 47 * from screen captures or print-to-PDFs. | 47 */ |
| 48 */ | 48 var cursorPositionUsed = -1; |
| 49 var cursorPositionUsed = -1; | 49 |
| 50 | 50 /** |
| 51 /** | 51 * Extracts the input text from the text field and sends it to the |
| 52 * Extracts the input text from the text field and sends it to the | 52 * C++ portion of chrome to handle. The C++ code will iteratively |
| 53 * C++ portion of chrome to handle. The C++ code will iteratively | 53 * call handleNewAutocompleteResult as results come in. |
| 54 * call handleNewAutocompleteResult as results come in. | 54 */ |
| 55 */ | 55 function startOmniboxQuery(event) { |
| 56 function startOmniboxQuery(event) { | 56 // First, clear the results of past calls (if any). |
| 57 // First, clear the results of past calls (if any). | 57 progressiveAutocompleteResults = []; |
| 58 progressiveAutocompleteResults = []; | 58 // Then, call chrome with a five-element list: |
| 59 // Then, call chrome with a five-element list: | 59 // - first element: the value in the text box |
| 60 // - first element: the value in the text box | 60 // - second element: the location of the cursor in the text box |
| 61 // - second element: the location of the cursor in the text box | 61 // - third element: the value of prevent-inline-autocomplete |
| 62 // - third element: the value of prevent-inline-autocomplete | 62 // - forth element: the value of prefer-keyword |
| 63 // - forth element: the value of prefer-keyword | 63 // - fifth element: the value of page-classification |
| 64 // - fifth element: the value of page-classification | 64 cursorPositionUsed = $('input-text').selectionEnd; |
| 65 cursorPositionUsed = $('input-text').selectionEnd; | 65 browserProxy.startOmniboxQuery( |
| 66 browserProxy.startOmniboxQuery( | 66 $('input-text').value, cursorPositionUsed, |
| 67 $('input-text').value, | 67 $('prevent-inline-autocomplete').checked, $('prefer-keyword').checked, |
| 68 cursorPositionUsed, | 68 parseInt($('page-classification').value)); |
| 69 $('prevent-inline-autocomplete').checked, | 69 // Cancel the submit action. i.e., don't submit the form. (We handle |
| 70 $('prefer-keyword').checked, | 70 // display the results solely with Javascript.) |
| 71 parseInt($('page-classification').value)); | 71 event.preventDefault(); |
| 72 // Cancel the submit action. i.e., don't submit the form. (We handle | 72 } |
| 73 // display the results solely with Javascript.) | 73 |
| 74 event.preventDefault(); | 74 /** |
| 75 } | 75 * Returns a simple object with information about how to display an |
| 76 | 76 * autocomplete result data field. |
| 77 /** | 77 * @param {string} header the label for the top of the column/table. |
| 78 * Returns a simple object with information about how to display an | 78 * @param {string} urlLabelForHeader the URL that the header should point |
| 79 * autocomplete result data field. | 79 * to (if non-empty). |
| 80 * @param {string} header the label for the top of the column/table. | 80 * @param {string} propertyName the name of the property in the autocomplete |
| 81 * @param {string} urlLabelForHeader the URL that the header should point | 81 * result record that we lookup. |
| 82 * to (if non-empty). | 82 * @param {boolean} displayAlways whether the property should be displayed |
| 83 * @param {string} propertyName the name of the property in the autocomplete | 83 * regardless of whether we're in detailed more. |
| 84 * result record that we lookup. | 84 * @param {string} tooltip a description of the property that will be |
| 85 * @param {boolean} displayAlways whether the property should be displayed | 85 * presented as a tooltip when the mouse is hovered over the column title. |
| 86 * regardless of whether we're in detailed more. | 86 * @constructor |
| 87 * @param {string} tooltip a description of the property that will be | 87 */ |
| 88 * presented as a tooltip when the mouse is hovered over the column title. | 88 function PresentationInfoRecord( |
| 89 * @constructor | 89 header, url, propertyName, displayAlways, tooltip) { |
| 90 */ | 90 this.header = header; |
| 91 function PresentationInfoRecord(header, url, propertyName, displayAlways, | 91 this.urlLabelForHeader = url; |
| 92 tooltip) { | 92 this.propertyName = propertyName; |
| 93 this.header = header; | 93 this.displayAlways = displayAlways; |
| 94 this.urlLabelForHeader = url; | 94 this.tooltip = tooltip; |
| 95 this.propertyName = propertyName; | 95 } |
| 96 this.displayAlways = displayAlways; | 96 |
| 97 this.tooltip = tooltip; | 97 /** |
| 98 } | 98 * A constant that's used to decide what autocomplete result |
| 99 | 99 * properties to output in what order. This is an array of |
| 100 /** | 100 * PresentationInfoRecord() objects; for details see that |
| 101 * A constant that's used to decide what autocomplete result | 101 * function. |
| 102 * properties to output in what order. This is an array of | 102 * @type {Array<Object>} |
| 103 * PresentationInfoRecord() objects; for details see that | 103 * @const |
| 104 * function. | 104 */ |
| 105 * @type {Array<Object>} | 105 var PROPERTY_OUTPUT_ORDER = [ |
| 106 * @const | 106 new PresentationInfoRecord( |
| 107 */ | 107 'Provider', '', 'providerName', true, |
| 108 var PROPERTY_OUTPUT_ORDER = [ | 108 'The AutocompleteProvider suggesting this result.'), |
| 109 new PresentationInfoRecord('Provider', '', 'providerName', true, | 109 new PresentationInfoRecord( |
| 110 'The AutocompleteProvider suggesting this result.'), | 110 'Type', '', 'type', true, 'The type of the result.'), |
| 111 new PresentationInfoRecord('Type', '', 'type', true, | 111 new PresentationInfoRecord( |
| 112 'The type of the result.'), | 112 'Relevance', '', 'relevance', true, |
| 113 new PresentationInfoRecord('Relevance', '', 'relevance', true, | 113 'The result score. Higher is more relevant.'), |
| 114 'The result score. Higher is more relevant.'), | 114 new PresentationInfoRecord( |
| 115 new PresentationInfoRecord('Contents', '', 'contents', true, | 115 'Contents', '', 'contents', true, |
| 116 'The text that is presented identifying the result.'), | 116 'The text that is presented identifying the result.'), |
| 117 new PresentationInfoRecord( | 117 new PresentationInfoRecord( |
| 118 'Can Be Default', '', 'allowedToBeDefaultMatch', false, | 118 'Can Be Default', '', 'allowedToBeDefaultMatch', false, |
| 119 'A green checkmark indicates that the result can be the default ' + | 119 'A green checkmark indicates that the result can be the default ' + |
| 120 'match (i.e., can be the match that pressing enter in the omnibox ' + | 120 'match (i.e., can be the match that pressing enter in the omnibox ' + |
| 121 'navigates to).'), | 121 'navigates to).'), |
| 122 new PresentationInfoRecord('Starred', '', 'starred', false, | 122 new PresentationInfoRecord( |
| 123 'A green checkmark indicates that the result has been bookmarked.'), | 123 'Starred', '', 'starred', false, |
| 124 new PresentationInfoRecord('Description', '', 'description', false, | 124 'A green checkmark indicates that the result has been bookmarked.'), |
| 125 'The page title of the result.'), | 125 new PresentationInfoRecord( |
| 126 new PresentationInfoRecord('URL', '', 'destinationUrl', true, | 126 'Description', '', 'description', false, 'The page title of the result.'), |
| 127 'The URL for the result.'), | 127 new PresentationInfoRecord( |
| 128 new PresentationInfoRecord('Fill Into Edit', '', 'fillIntoEdit', false, | 128 'URL', '', 'destinationUrl', true, 'The URL for the result.'), |
| 129 'The text shown in the omnibox when the result is selected.'), | 129 new PresentationInfoRecord( |
| 130 new PresentationInfoRecord( | 130 'Fill Into Edit', '', 'fillIntoEdit', false, |
| 131 'Inline Autocompletion', '', 'inlineAutocompletion', false, | 131 'The text shown in the omnibox when the result is selected.'), |
| 132 'The text shown in the omnibox as a blue highlight selection ' + | 132 new PresentationInfoRecord( |
| 133 'following the cursor, if this match is shown inline.'), | 133 'Inline Autocompletion', '', 'inlineAutocompletion', false, |
| 134 new PresentationInfoRecord('Del', '', 'deletable', false, | 134 'The text shown in the omnibox as a blue highlight selection ' + |
| 135 'A green checkmark indicates that the result can be deleted from ' + | 135 'following the cursor, if this match is shown inline.'), |
| 136 'the visit history.'), | 136 new PresentationInfoRecord( |
| 137 new PresentationInfoRecord('Prev', '', 'fromPrevious', false, ''), | 137 'Del', '', 'deletable', false, |
| 138 new PresentationInfoRecord( | 138 'A green checkmark indicates that the result can be deleted from ' + |
| 139 'Tran', | 139 'the visit history.'), |
| 140 'http://code.google.com/codesearch#OAMlx_jo-ck/src/content/public/' + | 140 new PresentationInfoRecord('Prev', '', 'fromPrevious', false, ''), |
| 141 'common/page_transition_types.h&exact_package=chromium&l=24', | 141 new PresentationInfoRecord( |
| 142 'transition', false, | 142 'Tran', |
| 143 'How the user got to the result.'), | 143 'http://code.google.com/codesearch#OAMlx_jo-ck/src/content/public/' + |
| 144 new PresentationInfoRecord( | 144 'common/page_transition_types.h&exact_package=chromium&l=24', |
| 145 'Done', '', 'providerDone', false, | 145 'transition', false, 'How the user got to the result.'), |
| 146 'A green checkmark indicates that the provider is done looking for ' + | 146 new PresentationInfoRecord( |
| 147 'more results.'), | 147 'Done', '', 'providerDone', false, |
| 148 new PresentationInfoRecord( | 148 'A green checkmark indicates that the provider is done looking for ' + |
| 149 'Associated Keyword', '', 'associatedKeyword', false, | 149 'more results.'), |
| 150 'If non-empty, a "press tab to search" hint will be shown and will ' + | 150 new PresentationInfoRecord( |
| 151 'engage this keyword.'), | 151 'Associated Keyword', '', 'associatedKeyword', false, |
| 152 new PresentationInfoRecord( | 152 'If non-empty, a "press tab to search" hint will be shown and will ' + |
| 153 'Keyword', '', 'keyword', false, | 153 'engage this keyword.'), |
| 154 'The keyword of the search engine to be used.'), | 154 new PresentationInfoRecord( |
| 155 new PresentationInfoRecord( | 155 'Keyword', '', 'keyword', false, |
| 156 'Duplicates', '', 'duplicates', false, | 156 'The keyword of the search engine to be used.'), |
| 157 'The number of matches that have been marked as duplicates of this ' + | 157 new PresentationInfoRecord( |
| 158 'match.'), | 158 'Duplicates', '', 'duplicates', false, |
| 159 new PresentationInfoRecord( | 159 'The number of matches that have been marked as duplicates of this ' + |
| 160 'Additional Info', '', 'additionalInfo', false, | 160 'match.'), |
| 161 'Provider-specific information about the result.') | 161 new PresentationInfoRecord( |
| 162 ]; | 162 'Additional Info', '', 'additionalInfo', false, |
| 163 | 163 'Provider-specific information about the result.') |
| 164 /** | 164 ]; |
| 165 * Returns an HTML Element of type table row that contains the | 165 |
| 166 * headers we'll use for labeling the columns. If we're in | 166 /** |
| 167 * detailedMode, we use all the headers. If not, we only use ones | 167 * Returns an HTML Element of type table row that contains the |
| 168 * marked displayAlways. | 168 * headers we'll use for labeling the columns. If we're in |
| 169 */ | 169 * detailedMode, we use all the headers. If not, we only use ones |
| 170 function createAutocompleteResultTableHeader() { | 170 * marked displayAlways. |
| 171 */ |
| 172 function createAutocompleteResultTableHeader() { |
| 173 var row = document.createElement('tr'); |
| 174 var inDetailedMode = $('show-details').checked; |
| 175 for (var i = 0; i < PROPERTY_OUTPUT_ORDER.length; i++) { |
| 176 if (inDetailedMode || PROPERTY_OUTPUT_ORDER[i].displayAlways) { |
| 177 var headerCell = document.createElement('th'); |
| 178 if (PROPERTY_OUTPUT_ORDER[i].urlLabelForHeader != '') { |
| 179 // Wrap header text in URL. |
| 180 var linkNode = document.createElement('a'); |
| 181 linkNode.href = PROPERTY_OUTPUT_ORDER[i].urlLabelForHeader; |
| 182 linkNode.textContent = PROPERTY_OUTPUT_ORDER[i].header; |
| 183 headerCell.appendChild(linkNode); |
| 184 } else { |
| 185 // Output header text without a URL. |
| 186 headerCell.textContent = PROPERTY_OUTPUT_ORDER[i].header; |
| 187 headerCell.className = 'table-header'; |
| 188 headerCell.title = PROPERTY_OUTPUT_ORDER[i].tooltip; |
| 189 } |
| 190 row.appendChild(headerCell); |
| 191 } |
| 192 } |
| 193 return row; |
| 194 } |
| 195 |
| 196 /** |
| 197 * @param {AutocompleteMatchMojo} autocompleteSuggestion the particular |
| 198 * autocomplete suggestion we're in the process of displaying. |
| 199 * @param {string} propertyName the particular property of the autocomplete |
| 200 * suggestion that should go in this cell. |
| 201 * @return {HTMLTableCellElement} that contains the value within this |
| 202 * autocompleteSuggestion associated with propertyName. |
| 203 */ |
| 204 function createCellForPropertyAndRemoveProperty( |
| 205 autocompleteSuggestion, propertyName) { |
| 206 var cell = document.createElement('td'); |
| 207 if (propertyName in autocompleteSuggestion) { |
| 208 if (propertyName == 'additionalInfo') { |
| 209 // |additionalInfo| embeds a two-column table of provider-specific data |
| 210 // within this cell. |additionalInfo| is an array of |
| 211 // AutocompleteAdditionalInfo. |
| 212 var additionalInfoTable = document.createElement('table'); |
| 213 for (var i = 0; i < autocompleteSuggestion[propertyName].length; i++) { |
| 214 var additionalInfo = autocompleteSuggestion[propertyName][i]; |
| 215 var additionalInfoRow = document.createElement('tr'); |
| 216 |
| 217 // Set the title (name of property) cell text. |
| 218 var propertyCell = document.createElement('td'); |
| 219 propertyCell.textContent = additionalInfo.key + ':'; |
| 220 propertyCell.className = 'additional-info-property'; |
| 221 additionalInfoRow.appendChild(propertyCell); |
| 222 |
| 223 // Set the value of the property cell text. |
| 224 var valueCell = document.createElement('td'); |
| 225 valueCell.textContent = additionalInfo.value; |
| 226 valueCell.className = 'additional-info-value'; |
| 227 additionalInfoRow.appendChild(valueCell); |
| 228 |
| 229 additionalInfoTable.appendChild(additionalInfoRow); |
| 230 } |
| 231 cell.appendChild(additionalInfoTable); |
| 232 } else if (typeof autocompleteSuggestion[propertyName] == 'boolean') { |
| 233 // If this is a boolean, display a checkmark or an X instead of |
| 234 // the strings true or false. |
| 235 if (autocompleteSuggestion[propertyName]) { |
| 236 cell.className = 'check-mark'; |
| 237 cell.textContent = '✔'; |
| 238 } else { |
| 239 cell.className = 'x-mark'; |
| 240 cell.textContent = '✗'; |
| 241 } |
| 242 } else { |
| 243 var text = String(autocompleteSuggestion[propertyName]); |
| 244 // If it's a URL wrap it in an href. |
| 245 var re = /^(http|https|ftp|chrome|file):\/\//; |
| 246 if (re.test(text)) { |
| 247 var aCell = document.createElement('a'); |
| 248 aCell.textContent = text; |
| 249 aCell.href = text; |
| 250 cell.appendChild(aCell); |
| 251 } else { |
| 252 // All other data types (integer, strings, etc.) display their |
| 253 // normal toString() output. |
| 254 cell.textContent = autocompleteSuggestion[propertyName]; |
| 255 } |
| 256 } |
| 257 } // else: if propertyName is undefined, we leave the cell blank |
| 258 return cell; |
| 259 } |
| 260 |
| 261 /** |
| 262 * Appends some human-readable information about the provided |
| 263 * autocomplete result to the HTML node with id omnibox-debug-text. |
| 264 * The current human-readable form is a few lines about general |
| 265 * autocomplete result statistics followed by a table with one line |
| 266 * for each autocomplete match. The input parameter is an OmniboxResultMojo. |
| 267 */ |
| 268 function addResultToOutput(result) { |
| 269 var output = $('omnibox-debug-text'); |
| 270 var inDetailedMode = $('show-details').checked; |
| 271 var showIncompleteResults = $('show-incomplete-results').checked; |
| 272 var showPerProviderResults = $('show-all-providers').checked; |
| 273 |
| 274 // Always output cursor position. |
| 275 var p = document.createElement('p'); |
| 276 p.textContent = 'cursor position = ' + cursorPositionUsed; |
| 277 output.appendChild(p); |
| 278 |
| 279 // Output the result-level features in detailed mode and in |
| 280 // show incomplete results mode. We do the latter because without |
| 281 // these result-level features, one can't make sense of each |
| 282 // batch of results. |
| 283 if (inDetailedMode || showIncompleteResults) { |
| 284 var p1 = document.createElement('p'); |
| 285 p1.textContent = |
| 286 'elapsed time = ' + result.timeSinceOmniboxStartedMs + 'ms'; |
| 287 output.appendChild(p1); |
| 288 var p2 = document.createElement('p'); |
| 289 p2.textContent = 'all providers done = ' + result.done; |
| 290 output.appendChild(p2); |
| 291 var p3 = document.createElement('p'); |
| 292 p3.textContent = 'host = ' + result.host; |
| 293 if ('isTypedHost' in result) { |
| 294 // Only output the isTypedHost information if available. (It may |
| 295 // be missing if the history database lookup failed.) |
| 296 p3.textContent = |
| 297 p3.textContent + ' has isTypedHost = ' + result.isTypedHost; |
| 298 } |
| 299 output.appendChild(p3); |
| 300 } |
| 301 |
| 302 // Combined results go after the lines below. |
| 303 var group = document.createElement('a'); |
| 304 group.className = 'group-separator'; |
| 305 group.textContent = 'Combined results.'; |
| 306 output.appendChild(group); |
| 307 |
| 308 // Add combined/merged result table. |
| 309 var p = document.createElement('p'); |
| 310 p.appendChild(addResultTableToOutput(result.combinedResults)); |
| 311 output.appendChild(p); |
| 312 |
| 313 // Move forward only if you want to display per provider results. |
| 314 if (!showPerProviderResults) { |
| 315 return; |
| 316 } |
| 317 |
| 318 // Individual results go after the lines below. |
| 319 var group = document.createElement('a'); |
| 320 group.className = 'group-separator'; |
| 321 group.textContent = 'Results for individual providers.'; |
| 322 output.appendChild(group); |
| 323 |
| 324 // Add the per-provider result tables with labels. We do not append the |
| 325 // combined/merged result table since we already have the per provider |
| 326 // results. |
| 327 for (var i = 0; i < result.resultsByProvider.length; i++) { |
| 328 var providerResults = result.resultsByProvider[i]; |
| 329 // If we have no results we do not display anything. |
| 330 if (providerResults.results.length == 0) { |
| 331 continue; |
| 332 } |
| 333 var p = document.createElement('p'); |
| 334 p.appendChild(addResultTableToOutput(providerResults.results)); |
| 335 output.appendChild(p); |
| 336 } |
| 337 } |
| 338 |
| 339 /** |
| 340 * @param {Object} result an array of AutocompleteMatchMojos. |
| 341 * @return {HTMLTableCellElement} that is a user-readable HTML |
| 342 * representation of this object. |
| 343 */ |
| 344 function addResultTableToOutput(result) { |
| 345 var inDetailedMode = $('show-details').checked; |
| 346 // Create a table to hold all the autocomplete items. |
| 347 var table = document.createElement('table'); |
| 348 table.className = 'autocomplete-results-table'; |
| 349 table.appendChild(createAutocompleteResultTableHeader()); |
| 350 // Loop over every autocomplete item and add it as a row in the table. |
| 351 for (var i = 0; i < result.length; i++) { |
| 352 var autocompleteSuggestion = result[i]; |
| 171 var row = document.createElement('tr'); | 353 var row = document.createElement('tr'); |
| 172 var inDetailedMode = $('show-details').checked; | 354 // Loop over all the columns/properties and output either them |
| 173 for (var i = 0; i < PROPERTY_OUTPUT_ORDER.length; i++) { | 355 // all (if we're in detailed mode) or only the ones marked displayAlways. |
| 174 if (inDetailedMode || PROPERTY_OUTPUT_ORDER[i].displayAlways) { | 356 // Keep track of which properties we displayed. |
| 175 var headerCell = document.createElement('th'); | 357 var displayedProperties = {}; |
| 176 if (PROPERTY_OUTPUT_ORDER[i].urlLabelForHeader != '') { | 358 for (var j = 0; j < PROPERTY_OUTPUT_ORDER.length; j++) { |
| 177 // Wrap header text in URL. | 359 if (inDetailedMode || PROPERTY_OUTPUT_ORDER[j].displayAlways) { |
| 178 var linkNode = document.createElement('a'); | 360 row.appendChild(createCellForPropertyAndRemoveProperty( |
| 179 linkNode.href = PROPERTY_OUTPUT_ORDER[i].urlLabelForHeader; | 361 autocompleteSuggestion, PROPERTY_OUTPUT_ORDER[j].propertyName)); |
| 180 linkNode.textContent = PROPERTY_OUTPUT_ORDER[i].header; | 362 displayedProperties[PROPERTY_OUTPUT_ORDER[j].propertyName] = true; |
| 181 headerCell.appendChild(linkNode); | 363 } |
| 182 } else { | 364 } |
| 183 // Output header text without a URL. | 365 |
| 184 headerCell.textContent = PROPERTY_OUTPUT_ORDER[i].header; | 366 // Now, if we're in detailed mode, add all the properties that |
| 185 headerCell.className = 'table-header'; | 367 // haven't already been output. (We know which properties have |
| 186 headerCell.title = PROPERTY_OUTPUT_ORDER[i].tooltip; | 368 // already been output because we delete the property when we output |
| 369 // it. The only way we have properties left at this point if |
| 370 // we're in detailed mode and we're getting back properties |
| 371 // not listed in PROPERTY_OUTPUT_ORDER. Perhaps someone added |
| 372 // something to the C++ code but didn't bother to update this |
| 373 // Javascript? In any case, we want to display them.) |
| 374 if (inDetailedMode) { |
| 375 for (var key in autocompleteSuggestion) { |
| 376 if (!displayedProperties[key] && |
| 377 typeof autocompleteSuggestion[key] != 'function') { |
| 378 var cell = document.createElement('td'); |
| 379 cell.textContent = key + '=' + autocompleteSuggestion[key]; |
| 380 row.appendChild(cell); |
| 187 } | 381 } |
| 188 row.appendChild(headerCell); | 382 } |
| 189 } | 383 } |
| 190 } | 384 |
| 191 return row; | 385 table.appendChild(row); |
| 192 } | 386 } |
| 193 | 387 return table; |
| 194 /** | 388 } |
| 195 * @param {AutocompleteMatchMojo} autocompleteSuggestion the particular | 389 |
| 196 * autocomplete suggestion we're in the process of displaying. | 390 /* Repaints the page based on the contents of the array |
| 197 * @param {string} propertyName the particular property of the autocomplete | 391 * progressiveAutocompleteResults, which represents consecutive |
| 198 * suggestion that should go in this cell. | 392 * autocomplete results. We only display the last (most recent) |
| 199 * @return {HTMLTableCellElement} that contains the value within this | 393 * entry unless we're asked to display incomplete results. For an |
| 200 * autocompleteSuggestion associated with propertyName. | 394 * example of the output, play with chrome://omnibox/ |
| 201 */ | 395 */ |
| 202 function createCellForPropertyAndRemoveProperty(autocompleteSuggestion, | 396 function refresh() { |
| 203 propertyName) { | 397 // Erase whatever is currently being displayed. |
| 204 var cell = document.createElement('td'); | 398 var output = $('omnibox-debug-text'); |
| 205 if (propertyName in autocompleteSuggestion) { | 399 output.innerHTML = ''; |
| 206 if (propertyName == 'additionalInfo') { | 400 |
| 207 // |additionalInfo| embeds a two-column table of provider-specific data | 401 if (progressiveAutocompleteResults.length > 0) { // if we have results |
| 208 // within this cell. |additionalInfo| is an array of | 402 // Display the results. |
| 209 // AutocompleteAdditionalInfo. | |
| 210 var additionalInfoTable = document.createElement('table'); | |
| 211 for (var i = 0; i < autocompleteSuggestion[propertyName].length; i++) { | |
| 212 var additionalInfo = autocompleteSuggestion[propertyName][i]; | |
| 213 var additionalInfoRow = document.createElement('tr'); | |
| 214 | |
| 215 // Set the title (name of property) cell text. | |
| 216 var propertyCell = document.createElement('td'); | |
| 217 propertyCell.textContent = additionalInfo.key + ':'; | |
| 218 propertyCell.className = 'additional-info-property'; | |
| 219 additionalInfoRow.appendChild(propertyCell); | |
| 220 | |
| 221 // Set the value of the property cell text. | |
| 222 var valueCell = document.createElement('td'); | |
| 223 valueCell.textContent = additionalInfo.value; | |
| 224 valueCell.className = 'additional-info-value'; | |
| 225 additionalInfoRow.appendChild(valueCell); | |
| 226 | |
| 227 additionalInfoTable.appendChild(additionalInfoRow); | |
| 228 } | |
| 229 cell.appendChild(additionalInfoTable); | |
| 230 } else if (typeof autocompleteSuggestion[propertyName] == 'boolean') { | |
| 231 // If this is a boolean, display a checkmark or an X instead of | |
| 232 // the strings true or false. | |
| 233 if (autocompleteSuggestion[propertyName]) { | |
| 234 cell.className = 'check-mark'; | |
| 235 cell.textContent = '✔'; | |
| 236 } else { | |
| 237 cell.className = 'x-mark'; | |
| 238 cell.textContent = '✗'; | |
| 239 } | |
| 240 } else { | |
| 241 var text = String(autocompleteSuggestion[propertyName]); | |
| 242 // If it's a URL wrap it in an href. | |
| 243 var re = /^(http|https|ftp|chrome|file):\/\//; | |
| 244 if (re.test(text)) { | |
| 245 var aCell = document.createElement('a'); | |
| 246 aCell.textContent = text; | |
| 247 aCell.href = text; | |
| 248 cell.appendChild(aCell); | |
| 249 } else { | |
| 250 // All other data types (integer, strings, etc.) display their | |
| 251 // normal toString() output. | |
| 252 cell.textContent = autocompleteSuggestion[propertyName]; | |
| 253 } | |
| 254 } | |
| 255 } // else: if propertyName is undefined, we leave the cell blank | |
| 256 return cell; | |
| 257 } | |
| 258 | |
| 259 /** | |
| 260 * Appends some human-readable information about the provided | |
| 261 * autocomplete result to the HTML node with id omnibox-debug-text. | |
| 262 * The current human-readable form is a few lines about general | |
| 263 * autocomplete result statistics followed by a table with one line | |
| 264 * for each autocomplete match. The input parameter is an OmniboxResultMojo. | |
| 265 */ | |
| 266 function addResultToOutput(result) { | |
| 267 var output = $('omnibox-debug-text'); | |
| 268 var inDetailedMode = $('show-details').checked; | |
| 269 var showIncompleteResults = $('show-incomplete-results').checked; | 403 var showIncompleteResults = $('show-incomplete-results').checked; |
| 270 var showPerProviderResults = $('show-all-providers').checked; | 404 var startIndex = |
| 271 | 405 showIncompleteResults ? 0 : progressiveAutocompleteResults.length - 1; |
| 272 // Always output cursor position. | 406 for (var i = startIndex; i < progressiveAutocompleteResults.length; i++) { |
| 273 var p = document.createElement('p'); | 407 addResultToOutput(progressiveAutocompleteResults[i]); |
| 274 p.textContent = 'cursor position = ' + cursorPositionUsed; | 408 } |
| 275 output.appendChild(p); | 409 } |
| 276 | 410 } |
| 277 // Output the result-level features in detailed mode and in | 411 |
| 278 // show incomplete results mode. We do the latter because without | 412 // NOTE: Need to keep a global reference to the |pageImpl| such that it is not |
| 279 // these result-level features, one can't make sense of each | 413 // garbage collected, which causes the pipe to close and future calls from C++ |
| 280 // batch of results. | 414 // to JS to get dropped. |
| 281 if (inDetailedMode || showIncompleteResults) { | 415 var pageImpl = null; |
| 282 var p1 = document.createElement('p'); | 416 var browserProxy = null; |
| 283 p1.textContent = 'elapsed time = ' + | 417 |
| 284 result.timeSinceOmniboxStartedMs + 'ms'; | 418 function initializeProxies() { |
| 285 output.appendChild(p1); | 419 browserProxy = new mojom.OmniboxPageHandlerPtr; |
| 286 var p2 = document.createElement('p'); | 420 Mojo.bindInterface( |
| 287 p2.textContent = 'all providers done = ' + result.done; | 421 mojom.OmniboxPageHandler.name, mojo.makeRequest(browserProxy).handle); |
| 288 output.appendChild(p2); | 422 |
| 289 var p3 = document.createElement('p'); | 423 /** @constructor */ |
| 290 p3.textContent = 'host = ' + result.host; | 424 var OmniboxPageImpl = function(request) { |
| 291 if ('isTypedHost' in result) { | 425 this.binding_ = new mojo.Binding(mojom.OmniboxPage, this, request); |
| 292 // Only output the isTypedHost information if available. (It may | 426 }; |
| 293 // be missing if the history database lookup failed.) | 427 |
| 294 p3.textContent = p3.textContent + ' has isTypedHost = ' + | 428 OmniboxPageImpl.prototype = { |
| 295 result.isTypedHost; | 429 /** @override */ |
| 296 } | 430 handleNewAutocompleteResult: function(result) { |
| 297 output.appendChild(p3); | 431 progressiveAutocompleteResults.push(result); |
| 298 } | 432 refresh(); |
| 299 | 433 }, |
| 300 // Combined results go after the lines below. | 434 }; |
| 301 var group = document.createElement('a'); | 435 |
| 302 group.className = 'group-separator'; | 436 var client = new mojom.OmniboxPagePtr; |
| 303 group.textContent = 'Combined results.'; | 437 pageImpl = new OmniboxPageImpl(mojo.makeRequest(client)); |
| 304 output.appendChild(group); | 438 browserProxy.setClientPage(client); |
| 305 | 439 } |
| 306 // Add combined/merged result table. | 440 |
| 307 var p = document.createElement('p'); | 441 document.addEventListener('DOMContentLoaded', function() { |
| 308 p.appendChild(addResultTableToOutput(result.combinedResults)); | 442 initializeProxies(); |
| 309 output.appendChild(p); | 443 initialize(); |
| 310 | 444 }); |
| 311 // Move forward only if you want to display per provider results. | |
| 312 if (!showPerProviderResults) { | |
| 313 return; | |
| 314 } | |
| 315 | |
| 316 // Individual results go after the lines below. | |
| 317 var group = document.createElement('a'); | |
| 318 group.className = 'group-separator'; | |
| 319 group.textContent = 'Results for individual providers.'; | |
| 320 output.appendChild(group); | |
| 321 | |
| 322 // Add the per-provider result tables with labels. We do not append the | |
| 323 // combined/merged result table since we already have the per provider | |
| 324 // results. | |
| 325 for (var i = 0; i < result.resultsByProvider.length; i++) { | |
| 326 var providerResults = result.resultsByProvider[i]; | |
| 327 // If we have no results we do not display anything. | |
| 328 if (providerResults.results.length == 0) { | |
| 329 continue; | |
| 330 } | |
| 331 var p = document.createElement('p'); | |
| 332 p.appendChild(addResultTableToOutput(providerResults.results)); | |
| 333 output.appendChild(p); | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 /** | |
| 338 * @param {Object} result an array of AutocompleteMatchMojos. | |
| 339 * @return {HTMLTableCellElement} that is a user-readable HTML | |
| 340 * representation of this object. | |
| 341 */ | |
| 342 function addResultTableToOutput(result) { | |
| 343 var inDetailedMode = $('show-details').checked; | |
| 344 // Create a table to hold all the autocomplete items. | |
| 345 var table = document.createElement('table'); | |
| 346 table.className = 'autocomplete-results-table'; | |
| 347 table.appendChild(createAutocompleteResultTableHeader()); | |
| 348 // Loop over every autocomplete item and add it as a row in the table. | |
| 349 for (var i = 0; i < result.length; i++) { | |
| 350 var autocompleteSuggestion = result[i]; | |
| 351 var row = document.createElement('tr'); | |
| 352 // Loop over all the columns/properties and output either them | |
| 353 // all (if we're in detailed mode) or only the ones marked displayAlways. | |
| 354 // Keep track of which properties we displayed. | |
| 355 var displayedProperties = {}; | |
| 356 for (var j = 0; j < PROPERTY_OUTPUT_ORDER.length; j++) { | |
| 357 if (inDetailedMode || PROPERTY_OUTPUT_ORDER[j].displayAlways) { | |
| 358 row.appendChild(createCellForPropertyAndRemoveProperty( | |
| 359 autocompleteSuggestion, PROPERTY_OUTPUT_ORDER[j].propertyName)); | |
| 360 displayedProperties[PROPERTY_OUTPUT_ORDER[j].propertyName] = true; | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 // Now, if we're in detailed mode, add all the properties that | |
| 365 // haven't already been output. (We know which properties have | |
| 366 // already been output because we delete the property when we output | |
| 367 // it. The only way we have properties left at this point if | |
| 368 // we're in detailed mode and we're getting back properties | |
| 369 // not listed in PROPERTY_OUTPUT_ORDER. Perhaps someone added | |
| 370 // something to the C++ code but didn't bother to update this | |
| 371 // Javascript? In any case, we want to display them.) | |
| 372 if (inDetailedMode) { | |
| 373 for (var key in autocompleteSuggestion) { | |
| 374 if (!displayedProperties[key] && | |
| 375 typeof autocompleteSuggestion[key] != 'function') { | |
| 376 var cell = document.createElement('td'); | |
| 377 cell.textContent = key + '=' + autocompleteSuggestion[key]; | |
| 378 row.appendChild(cell); | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 table.appendChild(row); | |
| 384 } | |
| 385 return table; | |
| 386 } | |
| 387 | |
| 388 /* Repaints the page based on the contents of the array | |
| 389 * progressiveAutocompleteResults, which represents consecutive | |
| 390 * autocomplete results. We only display the last (most recent) | |
| 391 * entry unless we're asked to display incomplete results. For an | |
| 392 * example of the output, play with chrome://omnibox/ | |
| 393 */ | |
| 394 function refresh() { | |
| 395 // Erase whatever is currently being displayed. | |
| 396 var output = $('omnibox-debug-text'); | |
| 397 output.innerHTML = ''; | |
| 398 | |
| 399 if (progressiveAutocompleteResults.length > 0) { // if we have results | |
| 400 // Display the results. | |
| 401 var showIncompleteResults = $('show-incomplete-results').checked; | |
| 402 var startIndex = showIncompleteResults ? 0 : | |
| 403 progressiveAutocompleteResults.length - 1; | |
| 404 for (var i = startIndex; i < progressiveAutocompleteResults.length; i++) { | |
| 405 addResultToOutput(progressiveAutocompleteResults[i]); | |
| 406 } | |
| 407 } | |
| 408 } | |
| 409 | |
| 410 // NOTE: Need to keep a global reference to the |pageImpl| such that it is not | |
| 411 // garbage collected, which causes the pipe to close and future calls from C++ | |
| 412 // to JS to get dropped. | |
| 413 var pageImpl = null; | |
| 414 var browserProxy = null; | |
| 415 | |
| 416 function initializeProxies() { | |
| 417 browserProxy = new mojom.OmniboxPageHandlerPtr; | |
| 418 Mojo.bindInterface(mojom.OmniboxPageHandler.name, | |
| 419 mojo.makeRequest(browserProxy).handle); | |
| 420 | |
| 421 /** @constructor */ | |
| 422 var OmniboxPageImpl = function(request) { | |
| 423 this.binding_ = new mojo.Binding(mojom.OmniboxPage, this, request); | |
| 424 }; | |
| 425 | |
| 426 OmniboxPageImpl.prototype = { | |
| 427 /** @override */ | |
| 428 handleNewAutocompleteResult: function(result) { | |
| 429 progressiveAutocompleteResults.push(result); | |
| 430 refresh(); | |
| 431 }, | |
| 432 }; | |
| 433 | |
| 434 var client = new mojom.OmniboxPagePtr; | |
| 435 pageImpl = new OmniboxPageImpl(mojo.makeRequest(client)); | |
| 436 browserProxy.setClientPage(client); | |
| 437 } | |
| 438 | |
| 439 document.addEventListener('DOMContentLoaded', function() { | |
| 440 initializeProxies(); | |
| 441 initialize(); | |
| 442 }); | |
| 443 })(); | 445 })(); |
| OLD | NEW |