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 var chrome; | 5 var chrome; |
6 if (!chrome) | 6 if (!chrome) |
7 chrome = {}; | 7 chrome = {}; |
8 if (!chrome.searchBox) { | 8 if (!chrome.searchBox) { |
9 chrome.searchBox = new function() { | 9 chrome.searchBox = new function() { |
10 native function GetValue(); | 10 // ========================================================================= |
| 11 // Constants |
| 12 // ========================================================================= |
| 13 |
| 14 var MAX_CLIENT_SUGGESTIONS_TO_DEDUPE = 6; |
| 15 |
| 16 var HTTP_REGEX = /^https?:\/\//; |
| 17 |
| 18 var WWW_REGEX = /^www\./; |
| 19 |
| 20 // ========================================================================= |
| 21 // Private functions |
| 22 // ========================================================================= |
| 23 native function GetQuery(); |
11 native function GetVerbatim(); | 24 native function GetVerbatim(); |
12 native function GetSelectionStart(); | 25 native function GetSelectionStart(); |
13 native function GetSelectionEnd(); | 26 native function GetSelectionEnd(); |
14 native function GetX(); | 27 native function GetX(); |
15 native function GetY(); | 28 native function GetY(); |
16 native function GetWidth(); | 29 native function GetWidth(); |
17 native function GetHeight(); | 30 native function GetHeight(); |
| 31 native function GetAutocompleteResults(); |
| 32 native function GetKeyCode(); |
18 native function SetSuggestions(); | 33 native function SetSuggestions(); |
19 this.__defineGetter__('value', GetValue); | 34 native function SetQuerySuggestion(); |
| 35 native function SetQuerySuggestionFromAutocompleteResult(); |
| 36 native function SetQuery(); |
| 37 native function SetQueryFromAutocompleteResult(); |
| 38 native function SetPreviewHeight(); |
| 39 |
| 40 // Returns the |restrictedText| wrapped in a ShadowDOM. |
| 41 function SafeWrap(restrictedText) { |
| 42 var node = document.createElement('div'); |
| 43 var nodeShadow = new WebKitShadowRoot(node); |
| 44 nodeShadow.applyAuthorStyles = true; |
| 45 nodeShadow.innerHTML = |
| 46 '<div style="width:700px!important;' + |
| 47 ' height:22px!important;' + |
| 48 ' font-family:\'Chrome Droid Sans\',\'Arial\'!important;' + |
| 49 ' overflow:hidden!important;' + |
| 50 ' text-overflow:ellipsis!important">' + |
| 51 ' <nobr>' + restrictedText + '</nobr>' + |
| 52 '</div>'; |
| 53 return node; |
| 54 } |
| 55 |
| 56 // Wraps the AutocompleteResult query and URL into ShadowDOM nodes so that |
| 57 // the JS cannot access them and deletes the raw values. |
| 58 function GetAutocompleteResultsWrapper() { |
| 59 var autocompleteResults = DedupeAutcompleteResults( |
| 60 GetAutocompleteResults()); |
| 61 var userInput = GetQuery(); |
| 62 for (var i = 0; i < autocompleteResults.length; ++i) { |
| 63 var result = autocompleteResults[i]; |
| 64 var title = result.contents; |
| 65 var url = CleanUrl(result.destination_url, userInput); |
| 66 var combinedHtml = '<span class=chrome_url>' + url + '</span>'; |
| 67 if (title) { |
| 68 result.titleNode = SafeWrap(title); |
| 69 combinedHtml += '<span class=chrome_separator> – </span>' + |
| 70 '<span class=chrome_title>' + title + '</span>'; |
| 71 } |
| 72 result.urlNode = SafeWrap(url); |
| 73 result.combinedNode = SafeWrap(combinedHtml); |
| 74 delete result.contents; |
| 75 delete result.destination_url; |
| 76 } |
| 77 return autocompleteResults; |
| 78 } |
| 79 |
| 80 function CleanUrl(url, userInput) { |
| 81 if (url.indexOf(userInput) == 0) { |
| 82 return url; |
| 83 } |
| 84 url = url.replace(HTTP_REGEX, ''); |
| 85 if (url.indexOf(userInput) == 0) { |
| 86 return url; |
| 87 } |
| 88 return url.replace(WWW_REGEX, ''); |
| 89 } |
| 90 |
| 91 function CanonicalizeUrl(url) { |
| 92 return url.replace(HTTP_REGEX, '').replace(WWW_REGEX, ''); |
| 93 } |
| 94 |
| 95 // Removes duplicates from AutocompleteResults. |
| 96 // TODO(dcblack): Do this in C++ instead of JS. |
| 97 function DedupeAutcompleteResults(autocompleteResults) { |
| 98 var urlToResultMap = {}; |
| 99 for (var i = 0; i < autocompleteResults.length; ++i) { |
| 100 var result = autocompleteResults[i]; |
| 101 var url = CanonicalizeUrl(result.destination_url); |
| 102 if (url in urlToResultMap) { |
| 103 var oldRelevance = urlToResultMap[url].rankingData.relevance; |
| 104 var newRelevance = result.rankingData.relevance; |
| 105 if (newRelevance > oldRelevance) { |
| 106 urlToResultMap[url] = result; |
| 107 } |
| 108 } else { |
| 109 urlToResultMap[url] = result; |
| 110 } |
| 111 } |
| 112 var dedupedResults = []; |
| 113 for (url in urlToResultMap) { |
| 114 dedupedResults.push(urlToResultMap[url]); |
| 115 } |
| 116 return dedupedResults; |
| 117 } |
| 118 |
| 119 var lastPrefixQueriedForDuplicates = ''; |
| 120 |
| 121 function DedupeClientSuggestions(clientSuggestions) { |
| 122 var userInput = GetQuery(); |
| 123 if (userInput == lastPrefixQueriedForDuplicates) { |
| 124 // Request blocked for privacy reasons. |
| 125 // TODO(dcblack): This check is insufficient. We should have a check |
| 126 // such that it's only callable once per onnativesuggestions, not |
| 127 // once per prefix. |
| 128 return false; |
| 129 } |
| 130 lastPrefixQueriedForDuplicates = userInput; |
| 131 var autocompleteResults = GetAutocompleteResults(); |
| 132 var nativeUrls = {}; |
| 133 for (var i = 0; i < autocompleteResults.length; ++i) { |
| 134 var nativeUrl = CanonicalizeUrl(autocompleteResults[i].destination_url); |
| 135 nativeUrls[nativeUrl] = autocompleteResults[i].rid; |
| 136 } |
| 137 for (var i = 0; i < clientSuggestions.length && |
| 138 i < MAX_CLIENT_SUGGESTIONS_TO_DEDUPE; ++i) { |
| 139 var clientUrl = CanonicalizeUrl(clientSuggestions[i].url); |
| 140 if (clientUrl in nativeUrls) { |
| 141 clientSuggestions[i].duplicateOf = nativeUrls[clientUrl]; |
| 142 } |
| 143 } |
| 144 return true; |
| 145 } |
| 146 |
| 147 // ========================================================================= |
| 148 // Exported functions |
| 149 // ========================================================================= |
| 150 this.__defineGetter__('value', GetQuery); |
20 this.__defineGetter__('verbatim', GetVerbatim); | 151 this.__defineGetter__('verbatim', GetVerbatim); |
21 this.__defineGetter__('selectionStart', GetSelectionStart); | 152 this.__defineGetter__('selectionStart', GetSelectionStart); |
22 this.__defineGetter__('selectionEnd', GetSelectionEnd); | 153 this.__defineGetter__('selectionEnd', GetSelectionEnd); |
23 this.__defineGetter__('x', GetX); | 154 this.__defineGetter__('x', GetX); |
24 this.__defineGetter__('y', GetY); | 155 this.__defineGetter__('y', GetY); |
25 this.__defineGetter__('width', GetWidth); | 156 this.__defineGetter__('width', GetWidth); |
26 this.__defineGetter__('height', GetHeight); | 157 this.__defineGetter__('height', GetHeight); |
| 158 this.__defineGetter__('nativeSuggestions', GetAutocompleteResultsWrapper); |
| 159 this.__defineGetter__('keyCode', GetKeyCode); |
27 this.setSuggestions = function(text) { | 160 this.setSuggestions = function(text) { |
28 SetSuggestions(text); | 161 SetSuggestions(text); |
29 }; | 162 }; |
| 163 this.setAutocompleteText = function(text, behavior) { |
| 164 SetQuerySuggestion(text, behavior); |
| 165 }; |
| 166 this.setRestrictedAutocompleteText = function(resultId, behavior) { |
| 167 SetQuerySuggestionFromAutocompleteResult(resultId, behavior); |
| 168 }; |
| 169 this.setValue = function(text, type) { |
| 170 SetQuery(text, type); |
| 171 }; |
| 172 this.setRestrictedValue = function(resultId, behavior) { |
| 173 SetQueryFromAutocompleteResult(resultId, behavior); |
| 174 }; |
| 175 this.setNonNativeDropdownHeight = function(height) { |
| 176 SetPreviewHeight(height); |
| 177 }; |
| 178 this.markDuplicateSuggestions = function(clientSuggestions) { |
| 179 return DedupeClientSuggestions(clientSuggestions); |
| 180 }; |
30 this.onchange = null; | 181 this.onchange = null; |
31 this.onsubmit = null; | 182 this.onsubmit = null; |
32 this.oncancel = null; | 183 this.oncancel = null; |
33 this.onresize = null; | 184 this.onresize = null; |
| 185 this.onautocompleteresults = null; |
| 186 this.onkeypress = null; |
34 }; | 187 }; |
35 } | 188 } |
OLD | NEW |