Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: chrome/renderer/searchbox_extension.cc

Issue 10809063: Adding Javascript support for the Extended Searchbox API. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Remove test for older API, removed in this CL. Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include "chrome/renderer/searchbox_extension.h" 5 #include "chrome/renderer/searchbox_extension.h"
6 6
7 #include <ctype.h>
7 #include <string> 8 #include <string>
8 #include <vector> 9 #include <vector>
9 10
10 #include "base/basictypes.h" 11 #include "base/basictypes.h"
11 #include "base/command_line.h" 12 #include "base/string_number_conversions.h"
13 #include "base/string_piece.h"
12 #include "base/string_split.h" 14 #include "base/string_split.h"
13 #include "base/stringprintf.h" 15 #include "base/stringprintf.h"
16 #include "chrome/common/chrome_switches.h"
14 #include "chrome/renderer/searchbox.h" 17 #include "chrome/renderer/searchbox.h"
15 #include "content/public/renderer/render_view.h" 18 #include "content/public/renderer/render_view.h"
16 #include "grit/renderer_resources.h" 19 #include "grit/renderer_resources.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" 23 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLReques t.h"
20 #include "ui/base/resource/resource_bundle.h" 25 #include "ui/base/resource/resource_bundle.h"
21 #include "v8/include/v8.h" 26 #include "v8/include/v8.h"
22 27
23 using WebKit::WebFrame; 28 using WebKit::WebFrame;
24 using WebKit::WebScriptSource; 29 using WebKit::WebScriptSource;
25 using WebKit::WebString; 30 using WebKit::WebString;
26 using WebKit::WebView; 31 using WebKit::WebView;
27 32
33 namespace {
34
35 // Splits the string in |number| into two pieces, a leading number token (saved
36 // in |number|) and the rest (saved in |suffix|). Either piece may become empty,
37 // depending on whether the input had no digits or only digits. Neither argument
38 // may be NULL.
39 void SplitLeadingNumberToken(std::string* number, std::string* suffix) {
40 size_t i = 0;
41 while (i < number->size() && isdigit((*number)[i]))
42 ++i;
43 suffix->assign(*number, i, number->size() - i);
44 number->resize(i);
45 }
46
47 } // namespace
48
28 namespace extensions_v8 { 49 namespace extensions_v8 {
29 50
30 static const char kSearchBoxExtensionName[] = "v8/SearchBox"; 51 static const char kSearchBoxExtensionName[] = "v8/SearchBox";
31 52
32 static const char kDispatchChangeEventScript[] = 53 static const char kDispatchChangeEventScript[] =
33 "if (window.chrome &&" 54 "if (window.chrome &&"
34 " window.chrome.searchBox &&" 55 " window.chrome.searchBox &&"
35 " window.chrome.searchBox.onchange &&" 56 " window.chrome.searchBox.onchange &&"
36 " typeof window.chrome.searchBox.onchange == 'function') {" 57 " typeof window.chrome.searchBox.onchange == 'function') {"
37 " window.chrome.searchBox.onchange();" 58 " window.chrome.searchBox.onchange();"
(...skipping 20 matching lines...) Expand all
58 79
59 static const char kDispatchResizeEventScript[] = 80 static const char kDispatchResizeEventScript[] =
60 "if (window.chrome &&" 81 "if (window.chrome &&"
61 " window.chrome.searchBox &&" 82 " window.chrome.searchBox &&"
62 " window.chrome.searchBox.onresize &&" 83 " window.chrome.searchBox.onresize &&"
63 " typeof window.chrome.searchBox.onresize == 'function') {" 84 " typeof window.chrome.searchBox.onresize == 'function') {"
64 " window.chrome.searchBox.onresize();" 85 " window.chrome.searchBox.onresize();"
65 " true;" 86 " true;"
66 "}"; 87 "}";
67 88
68 // Deprecated API support. 89 // Extended API.
69 // TODO(tonyg): Remove these when they are no longer used.
70 // ----------------------------------------------------------------------------
71 // Script sent as the user is typing and the provider supports instant.
72 // Params:
73 // . the text the user typed.
74 // '46' forces the server to give us verbatim results.
75 static const char kUserInputScript[] =
76 "if (window.chrome.userInput)"
77 " window.chrome.userInput("
78 " window.chrome.searchBox.value,"
79 " window.chrome.searchBox.verbatim ? 46 : 0,"
80 " window.chrome.searchBox.selectionStart);";
81 90
82 // Script sent when the page is committed and the provider supports instant. 91 static const char kDispatchNativeSuggestionsEventScript[] =
83 // Params: 92 "if (window.chrome &&"
84 // . the text the user typed. 93 " window.chrome.searchBox &&"
85 // . boolean indicating if the user pressed enter to accept the text. 94 " window.chrome.searchBox.onnativesuggestions &&"
86 static const char kUserDoneScript[] = 95 " typeof window.chrome.searchBox.onnativesuggestions == 'function') {"
87 "if (window.chrome.userWantsQuery)" 96 " window.chrome.searchBox.onnativesuggestions();"
88 " window.chrome.userWantsQuery(" 97 " true;"
89 " window.chrome.searchBox.value," 98 "}";
90 " window.chrome.searchBox.verbatim);";
91 99
92 // Script sent when the bounds of the omnibox changes and the provider supports 100 static const char kDispatchKeyPressEventScript[] =
93 // instant. The params are the bounds relative to the origin of the preview 101 "if (window.chrome &&"
94 // (x, y, width, height). 102 " window.chrome.searchBox &&"
95 static const char kSetOmniboxBoundsScript[] = 103 " window.chrome.searchBox.onkeypress &&"
96 "if (window.chrome.setDropdownDimensions)" 104 " typeof window.chrome.searchBox.onkeypress == 'function') {"
97 " window.chrome.setDropdownDimensions(" 105 " window.chrome.searchBox.onkeypress("
98 " window.chrome.searchBox.x," 106 " {keyCode:window.chrome.searchBox.keyCode});"
99 " window.chrome.searchBox.y," 107 " true;"
100 " window.chrome.searchBox.width," 108 "}";
101 " window.chrome.searchBox.height);"; 109
110 static const char kDispatchFocusEventScript[] =
111 "if (window.chrome &&"
112 " window.chrome.searchBox &&"
113 " window.chrome.searchBox.onfocus &&"
114 " typeof window.chrome.searchBox.onfocus == 'function') {"
115 " window.chrome.searchBox.onfocus();"
116 " true;"
117 "}";
118
119 static const char kDispatchBlurEventScript[] =
120 "if (window.chrome &&"
121 " window.chrome.searchBox &&"
122 " window.chrome.searchBox.onblur &&"
123 " typeof window.chrome.searchBox.onblur == 'function') {"
124 " window.chrome.searchBox.onblur();"
125 " true;"
126 "}";
102 127
103 // We first send this script down to determine if the page supports instant. 128 // We first send this script down to determine if the page supports instant.
104 static const char kSupportsInstantScript[] = 129 static const char kSupportsInstantScript[] =
105 "if (window.chrome.sv) true; else false;"; 130 "if (window.chrome &&"
106 131 " window.chrome.searchBox &&"
107 // The google.y.first array is a list of functions which are to be executed 132 " window.chrome.searchBox.onsubmit &&"
108 // after the external JavaScript used by Google web search loads. The deprecated 133 " typeof window.chrome.searchBox.onsubmit == 'function') {"
109 // API requires setDropdownDimensions and userInput to be invoked after 134 " true;"
110 // the external JavaScript loads. So if they are not already registered, we add 135 "} else {"
111 // them to the array of functions the page will execute after load. This tight 136 " false;"
112 // coupling discourages proliferation of the deprecated API. 137 "}";
113 static const char kInitScript[] =
114 "(function() {"
115 "var initScript = function(){%s%s};"
116 "if (window.chrome.setDropdownDimensions)"
117 " initScript();"
118 "else if (window.google && window.google.y)"
119 " window.google.y.first.push(initScript);"
120 "})();";
121 // ----------------------------------------------------------------------------
122 138
123 class SearchBoxExtensionWrapper : public v8::Extension { 139 class SearchBoxExtensionWrapper : public v8::Extension {
124 public: 140 public:
125 explicit SearchBoxExtensionWrapper(const base::StringPiece& code); 141 explicit SearchBoxExtensionWrapper(const base::StringPiece& code);
126 142
127 // Allows v8's javascript code to call the native functions defined 143 // Allows v8's javascript code to call the native functions defined
128 // in this class for window.chrome. 144 // in this class for window.chrome.
129 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 145 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
130 v8::Handle<v8::String> name); 146 v8::Handle<v8::String> name);
131 147
(...skipping 21 matching lines...) Expand all
153 // Gets the y coordinate (relative to |window|) of the right edge of the 169 // Gets the y coordinate (relative to |window|) of the right edge of the
154 // region of the search box that overlaps the window. 170 // region of the search box that overlaps the window.
155 static v8::Handle<v8::Value> GetY(const v8::Arguments& args); 171 static v8::Handle<v8::Value> GetY(const v8::Arguments& args);
156 172
157 // Gets the width of the region of the search box that overlaps the window. 173 // Gets the width of the region of the search box that overlaps the window.
158 static v8::Handle<v8::Value> GetWidth(const v8::Arguments& args); 174 static v8::Handle<v8::Value> GetWidth(const v8::Arguments& args);
159 175
160 // Gets the height of the region of the search box that overlaps the window. 176 // Gets the height of the region of the search box that overlaps the window.
161 static v8::Handle<v8::Value> GetHeight(const v8::Arguments& args); 177 static v8::Handle<v8::Value> GetHeight(const v8::Arguments& args);
162 178
179 // Gets the native suggestions from search box.
180 static v8::Handle<v8::Value> GetNativeSuggestions(const v8::Arguments& args);
181
182 // Gets the last key code entered in search box.
183 static v8::Handle<v8::Value> GetKeyCode(const v8::Arguments& args);
184
185 // Gets some info about the last search session committed in the search box.
186 static v8::Handle<v8::Value> GetSessionContext(const v8::Arguments& args);
187
188 // Gets whether the search box currently has keyboard focus or not.
189 static v8::Handle<v8::Value> GetIsFocused(const v8::Arguments& args);
190
163 // Sets ordered suggestions. Valid for current |value|. 191 // Sets ordered suggestions. Valid for current |value|.
164 static v8::Handle<v8::Value> SetSuggestions(const v8::Arguments& args); 192 static v8::Handle<v8::Value> SetSuggestions(const v8::Arguments& args);
165 193
194 // Sets the text to be autocompleted into the search box.
195 static v8::Handle<v8::Value> SetAutocompleteText(const v8::Arguments& args);
196
197 // Like |SetAutocompleteText| but uses a restricted ID to identify the text.
198 static v8::Handle<v8::Value> SetRestrictedAutocompleteText(
199 const v8::Arguments& args);
200
201 // Sets the search box text, completely replacing what the user typed.
202 static v8::Handle<v8::Value> SetValue(const v8::Arguments& args);
203
204 // Like |SetValue| but uses a restricted ID to identify the text.
205 static v8::Handle<v8::Value> SetRestrictedValue(const v8::Arguments& args);
206
207 // Resize the preview to the given height.
208 static v8::Handle<v8::Value> SetNonNativeDropdownHeight(
209 const v8::Arguments& args);
210
211 // Navigate the window to the URL identified by a restricted ID.
212 static v8::Handle<v8::Value> NavigateContentWindow(const v8::Arguments& args);
213
214
166 private: 215 private:
167 DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper); 216 DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper);
168 }; 217 };
169 218
170 SearchBoxExtensionWrapper::SearchBoxExtensionWrapper( 219 SearchBoxExtensionWrapper::SearchBoxExtensionWrapper(
171 const base::StringPiece& code) 220 const base::StringPiece& code)
172 : v8::Extension(kSearchBoxExtensionName, code.data(), 0, 0, code.size()) {} 221 : v8::Extension(kSearchBoxExtensionName, code.data(), 0, 0, code.size()) {}
173 222
174 v8::Handle<v8::FunctionTemplate> SearchBoxExtensionWrapper::GetNativeFunction( 223 v8::Handle<v8::FunctionTemplate> SearchBoxExtensionWrapper::GetNativeFunction(
175 v8::Handle<v8::String> name) { 224 v8::Handle<v8::String> name) {
176 if (name->Equals(v8::String::New("GetValue"))) { 225 if (name->Equals(v8::String::New("GetValue"))) {
177 return v8::FunctionTemplate::New(GetValue); 226 return v8::FunctionTemplate::New(GetValue);
178 } else if (name->Equals(v8::String::New("GetVerbatim"))) { 227 } else if (name->Equals(v8::String::New("GetVerbatim"))) {
179 return v8::FunctionTemplate::New(GetVerbatim); 228 return v8::FunctionTemplate::New(GetVerbatim);
180 } else if (name->Equals(v8::String::New("GetSelectionStart"))) { 229 } else if (name->Equals(v8::String::New("GetSelectionStart"))) {
181 return v8::FunctionTemplate::New(GetSelectionStart); 230 return v8::FunctionTemplate::New(GetSelectionStart);
182 } else if (name->Equals(v8::String::New("GetSelectionEnd"))) { 231 } else if (name->Equals(v8::String::New("GetSelectionEnd"))) {
183 return v8::FunctionTemplate::New(GetSelectionEnd); 232 return v8::FunctionTemplate::New(GetSelectionEnd);
184 } else if (name->Equals(v8::String::New("GetX"))) { 233 } else if (name->Equals(v8::String::New("GetX"))) {
185 return v8::FunctionTemplate::New(GetX); 234 return v8::FunctionTemplate::New(GetX);
186 } else if (name->Equals(v8::String::New("GetY"))) { 235 } else if (name->Equals(v8::String::New("GetY"))) {
187 return v8::FunctionTemplate::New(GetY); 236 return v8::FunctionTemplate::New(GetY);
188 } else if (name->Equals(v8::String::New("GetWidth"))) { 237 } else if (name->Equals(v8::String::New("GetWidth"))) {
189 return v8::FunctionTemplate::New(GetWidth); 238 return v8::FunctionTemplate::New(GetWidth);
190 } else if (name->Equals(v8::String::New("GetHeight"))) { 239 } else if (name->Equals(v8::String::New("GetHeight"))) {
191 return v8::FunctionTemplate::New(GetHeight); 240 return v8::FunctionTemplate::New(GetHeight);
241 } else if (name->Equals(v8::String::New("GetNativeSuggestions"))) {
242 return v8::FunctionTemplate::New(GetNativeSuggestions);
243 } else if (name->Equals(v8::String::New("GetKeyCode"))) {
244 return v8::FunctionTemplate::New(GetKeyCode);
245 } else if (name->Equals(v8::String::New("GetSessionContext"))) {
246 return v8::FunctionTemplate::New(GetSessionContext);
247 } else if (name->Equals(v8::String::New("GetIsFocused"))) {
248 return v8::FunctionTemplate::New(GetIsFocused);
192 } else if (name->Equals(v8::String::New("SetSuggestions"))) { 249 } else if (name->Equals(v8::String::New("SetSuggestions"))) {
193 return v8::FunctionTemplate::New(SetSuggestions); 250 return v8::FunctionTemplate::New(SetSuggestions);
251 } else if (name->Equals(v8::String::New("SetAutocompleteText"))) {
252 return v8::FunctionTemplate::New(SetAutocompleteText);
253 } else if (name->Equals(v8::String::New("SetRestrictedAutocompleteText"))) {
254 return v8::FunctionTemplate::New(SetRestrictedAutocompleteText);
255 } else if (name->Equals(v8::String::New("SetValue"))) {
256 return v8::FunctionTemplate::New(SetValue);
257 } else if (name->Equals(v8::String::New("SetRestrictedValue"))) {
258 return v8::FunctionTemplate::New(SetRestrictedValue);
259 } else if (name->Equals(v8::String::New("SetNonNativeDropdownHeight"))) {
260 return v8::FunctionTemplate::New(SetNonNativeDropdownHeight);
261 } else if (name->Equals(v8::String::New("NavigateContentWindow"))) {
262 return v8::FunctionTemplate::New(NavigateContentWindow);
194 } 263 }
195 return v8::Handle<v8::FunctionTemplate>(); 264 return v8::Handle<v8::FunctionTemplate>();
196 } 265 }
197 266
198 // static 267 // static
199 content::RenderView* SearchBoxExtensionWrapper::GetRenderView() { 268 content::RenderView* SearchBoxExtensionWrapper::GetRenderView() {
200 WebFrame* webframe = WebFrame::frameForEnteredContext(); 269 WebFrame* webframe = WebFrame::frameForEnteredContext();
201 DCHECK(webframe) << "There should be an active frame since we just got " 270 DCHECK(webframe) << "There should be an active frame since we just got "
202 "a native function called."; 271 "a native function called.";
203 if (!webframe) return NULL; 272 if (!webframe) return NULL;
204 273
205 WebView* webview = webframe->view(); 274 WebView* webview = webframe->view();
206 if (!webview) return NULL; // can happen during closing 275 if (!webview) return NULL; // can happen during closing
207 276
208 return content::RenderView::FromWebView(webview); 277 return content::RenderView::FromWebView(webview);
209 } 278 }
210 279
211 // static 280 // static
212 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetValue( 281 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetValue(
213 const v8::Arguments& args) { 282 const v8::Arguments& args) {
214 content::RenderView* render_view = GetRenderView(); 283 content::RenderView* render_view = GetRenderView();
215 if (!render_view) return v8::Undefined(); 284 if (!render_view) return v8::Undefined();
216 return v8::String::New( 285 return v8::String::New(
217 reinterpret_cast<const uint16_t*>( 286 reinterpret_cast<const uint16_t*>(
218 SearchBox::Get(render_view)->value().c_str()), 287 SearchBox::Get(render_view)->value().c_str()),
219 SearchBox::Get(render_view)->value().length()); 288 SearchBox::Get(render_view)->value().length());
220 } 289 }
221 290
222 // static 291 // static
223 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetVerbatim( 292 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetVerbatim(
224 const v8::Arguments& args) { 293 const v8::Arguments& args) {
225 content::RenderView* render_view = GetRenderView(); 294 content::RenderView* render_view = GetRenderView();
226 if (!render_view) return v8::Undefined(); 295 if (!render_view) return v8::Undefined();
227 return v8::Boolean::New(SearchBox::Get(render_view)->verbatim()); 296 return v8::Boolean::New(SearchBox::Get(render_view)->verbatim());
228 } 297 }
229 298
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 } 337 }
269 338
270 // static 339 // static
271 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetHeight( 340 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetHeight(
272 const v8::Arguments& args) { 341 const v8::Arguments& args) {
273 content::RenderView* render_view = GetRenderView(); 342 content::RenderView* render_view = GetRenderView();
274 if (!render_view) return v8::Undefined(); 343 if (!render_view) return v8::Undefined();
275 return v8::Int32::New(SearchBox::Get(render_view)->GetRect().height()); 344 return v8::Int32::New(SearchBox::Get(render_view)->GetRect().height());
276 } 345 }
277 346
278 // Accepts a single argument in form: 347 // static
279 // { 348 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetNativeSuggestions(
280 // suggestions: [ 349 const v8::Arguments& args) {
281 // { 350 content::RenderView* render_view = GetRenderView();
282 // value: "..." 351 if (!render_view) return v8::Undefined();
283 // } 352 const std::vector<InstantNativeSuggestionsParts>& suggestions =
284 // ] 353 SearchBox::Get(render_view)->native_suggestions();
285 // } 354 const int rid_base = SearchBox::Get(render_view)->rid_base();
355 v8::Handle<v8::Array> suggestions_array(v8::Array::New(suggestions.size()));
356 for (size_t i = 0; i < suggestions.size(); ++i) {
357 v8::Handle<v8::Object> suggestion(v8::Object::New());
358 suggestion->Set(v8::String::New("provider"),
359 v8::String::New(suggestions[i].provider.c_str()));
360 suggestion->Set(v8::String::New("contents"),
361 v8::String::New(suggestions[i].contents.c_str()));
362 suggestion->Set(v8::String::New("destination_url"),
363 v8::String::New(suggestions[i].destination_url.spec().c_str()));
364 suggestion->Set(v8::String::New("rid"), v8::Uint32::New(rid_base + i));
365
366 v8::Handle<v8::Object> ranking_data(v8::Object::New());
367 ranking_data->Set(v8::String::New("relevance"),
368 v8::Int32::New(suggestions[i].relevance));
369 suggestion->Set(v8::String::New("rankingData"), ranking_data);
370
371 suggestions_array->Set(i, suggestion);
372 }
373
374 return suggestions_array;
375 }
376
377 // static
378 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetKeyCode(
379 const v8::Arguments& args) {
380 content::RenderView* render_view = GetRenderView();
381 if (!render_view) return v8::Undefined();
382 return v8::Int32::New(SearchBox::Get(render_view)->key_code());
383 }
384
385 // static
386 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetSessionContext(
387 const v8::Arguments& args) {
388 content::RenderView* render_view = GetRenderView();
389 if (!render_view) return v8::Undefined();
390 v8::Handle<v8::Object> session_context(v8::Object::New());
391 session_context->Set(v8::String::New("lastSearchQuery"),
392 v8::String::New(SearchBox::Get(render_view)->last_query().c_str()));
393 // NOTE: SECURITY RISK -- Providing the current url in this way is insecure.
394 session_context->Set(v8::String::New("currentUrl"),
395 v8::String::New(SearchBox::Get(render_view)->current_url().c_str()));
396 return session_context;
397 }
398
399 // static
400 v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetIsFocused(
401 const v8::Arguments& args) {
402 content::RenderView* render_view = GetRenderView();
403 if (!render_view) return v8::Undefined();
404 return v8::Boolean::New(SearchBox::Get(render_view)->is_focused());
405 }
406
286 // static 407 // static
287 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestions( 408 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestions(
288 const v8::Arguments& args) { 409 const v8::Arguments& args) {
289 std::vector<std::string> suggestions; 410 std::vector<InstantSuggestion> suggestions;
290 InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; 411
291 412 if (args.Length() && args[0]->IsObject()) {
292 if (args.Length() && args[0]->IsArray()) { 413 v8::Local<v8::Object> suggestion_json(args[0]->ToObject());
293 // For backwards compatibility, also accept an array of strings. 414
294 // TODO(tonyg): Remove this when it is confirmed to be unused. 415 InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW;
295 v8::Local<v8::Array> suggestions_array = 416 InstantSuggestionType type = INSTANT_SUGGESTION_SEARCH;
296 v8::Local<v8::Array>::Cast(args[0]); 417 v8::Local<v8::Value> complete_value(
297 uint32_t length = suggestions_array->Length(); 418 suggestion_json->Get(v8::String::New("complete_behavior")));
298 for (uint32_t i = 0; i < length; i++) { 419 if (complete_value->IsString()) {
299 std::string suggestion = *v8::String::Utf8Value( 420 if (complete_value->Equals(v8::String::New("now"))) {
300 suggestions_array->Get(v8::Integer::New(i))->ToString()); 421 behavior = INSTANT_COMPLETE_NOW;
301 if (!suggestion.length()) continue; 422 } else if (complete_value->Equals(v8::String::New("never"))) {
302 suggestions.push_back(suggestion); 423 behavior = INSTANT_COMPLETE_NEVER;
303 } 424 } else if (complete_value->Equals(v8::String::New("delayed"))) {
304 } else if (args.Length() && args[0]->IsObject()) { 425 behavior = INSTANT_COMPLETE_DELAYED;
305 // Standard version, object argument. 426 } else if (complete_value->Equals(v8::String::New("replace"))) {
306 v8::Local<v8::Object> suggestion_json = 427 behavior = INSTANT_COMPLETE_REPLACE;
307 v8::Local<v8::Object>::Cast(args[0]); 428 } else {
308 v8::Local<v8::Value> suggestions_field = 429 VLOG(1) << "Unsupported complete behavior '"
309 suggestion_json->Get(v8::String::New("suggestions")); 430 << *v8::String::Utf8Value(complete_value) << "'";
310 431 }
432 }
433
434 v8::Local<v8::Value> suggestions_field(
435 suggestion_json->Get(v8::String::New("suggestions")));
311 if (suggestions_field->IsArray()) { 436 if (suggestions_field->IsArray()) {
312 v8::Local<v8::Array> suggestions_array = 437 v8::Local<v8::Array> suggestions_array(
313 suggestions_field.As<v8::Array>(); 438 suggestions_field.As<v8::Array>());
314 439 size_t length = suggestions_array->Length();
315 uint32_t length = suggestions_array->Length(); 440 for (size_t i = 0; i < length; i++) {
316 for (uint32_t i = 0; i < length; i++) { 441 v8::Local<v8::Value> suggestion_value(suggestions_array->Get(i));
317 v8::Local<v8::Value> suggestion_value =
318 suggestions_array->Get(v8::Integer::New(i));
319 if (!suggestion_value->IsObject()) continue; 442 if (!suggestion_value->IsObject()) continue;
320 443
321 v8::Local<v8::Object> suggestion_object = 444 v8::Local<v8::Object> suggestion_object(suggestion_value->ToObject());
322 suggestion_value.As<v8::Object>(); 445 v8::Local<v8::Value> suggestion_object_value(
323 v8::Local<v8::Value> suggestion_object_value = 446 suggestion_object->Get(v8::String::New("value")));
324 suggestion_object->Get(v8::String::New("value"));
325 if (!suggestion_object_value->IsString()) continue; 447 if (!suggestion_object_value->IsString()) continue;
326 448
327 std::string suggestion = *v8::String::Utf8Value( 449 std::string text = *v8::String::Utf8Value(suggestion_object_value);
328 suggestion_object_value->ToString()); 450
329 if (!suggestion.length()) continue; 451 suggestions.push_back(InstantSuggestion(text, behavior, type));
330 suggestions.push_back(suggestion);
331 }
332 }
333 if (suggestion_json->Has(v8::String::New("complete_behavior"))) {
334 v8::Local<v8::Value> complete_value =
335 suggestion_json->Get(v8::String::New("complete_behavior"));
336 if (complete_value->IsString()) {
337 if (complete_value->Equals(v8::String::New("never")))
338 behavior = INSTANT_COMPLETE_NEVER;
339 else if (complete_value->Equals(v8::String::New("delayed")))
340 behavior = INSTANT_COMPLETE_DELAYED;
341 } 452 }
342 } 453 }
343 } 454 }
344 455
345 if (content::RenderView* render_view = GetRenderView()) 456 if (content::RenderView* render_view = GetRenderView())
346 SearchBox::Get(render_view)->SetSuggestions(suggestions, behavior); 457 SearchBox::Get(render_view)->SetSuggestions(suggestions);
347 return v8::Undefined(); 458 return v8::Undefined();
348 } 459 }
349 460
350 // static 461 // static
351 void Dispatch(WebFrame* frame, 462 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetAutocompleteText(
352 WebString event_dispatch_script, 463 const v8::Arguments& args) {
353 WebString no_event_handler_script) { 464 if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) {
465 std::string text = *v8::String::Utf8Value(args[0]);
466 InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW;
467 InstantSuggestionType type = INSTANT_SUGGESTION_URL;
468
469 if (args.Length() >= 2 && args[1]->Uint32Value() == 2) {
470 behavior = INSTANT_COMPLETE_NEVER;
471 // TODO(sreeram): The page should really set the type explicitly.
472 type = INSTANT_SUGGESTION_SEARCH;
473 }
474
475 if (content::RenderView* render_view = GetRenderView()) {
476 std::vector<InstantSuggestion> suggestions;
477 suggestions.push_back(InstantSuggestion(text, behavior, type));
478 SearchBox::Get(render_view)->SetSuggestions(suggestions);
479 }
480 }
481 return v8::Undefined();
482 }
483
484 // static
485 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetRestrictedAutocompleteText(
486 const v8::Arguments& args) {
487 content::RenderView* render_view = GetRenderView();
488 if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsNumber() &&
489 render_view) {
490 const int rid = args[0]->Uint32Value();
491 const int rid_base = SearchBox::Get(render_view)->rid_base();
492 // Note that stale rids, less than the current rid_base, will wrap.
493 const size_t index = rid - rid_base;
494 const std::vector<InstantNativeSuggestionsParts>& suggestions =
495 SearchBox::Get(render_view)->native_suggestions();
496 if (index < suggestions.size()) {
497 std::string text = suggestions[index].destination_url.spec();
498 InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW;
499 InstantSuggestionType type = INSTANT_SUGGESTION_URL;
500
501 if (args.Length() >= 2 && args[1]->Uint32Value() == 2)
502 behavior = INSTANT_COMPLETE_NEVER;
503
504 if (suggestions[index].is_search) {
505 text = suggestions[index].contents;
506 type = INSTANT_SUGGESTION_SEARCH;
507 }
508
509 std::vector<InstantSuggestion> suggestions;
510 suggestions.push_back(InstantSuggestion(text, behavior, type));
511 SearchBox::Get(render_view)->SetSuggestions(suggestions);
512 } else {
513 VLOG(1) << "Invalid rid " << rid << "; "
514 << "rid_base is " << rid_base << ".";
515 }
516 }
517 return v8::Undefined();
518 }
519
520 // static
521 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetValue(
522 const v8::Arguments& args) {
523 // TODO(sreeram): Make the second argument (type) mandatory.
524 if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) {
525 std::string text = *v8::String::Utf8Value(args[0]);
526 InstantCompleteBehavior behavior = INSTANT_COMPLETE_REPLACE;
527 InstantSuggestionType type = INSTANT_SUGGESTION_SEARCH;
528
529 if (args.Length() >= 2 && args[1]->Uint32Value() == 1)
530 type = INSTANT_SUGGESTION_URL;
531
532 if (content::RenderView* render_view = GetRenderView()) {
533 std::vector<InstantSuggestion> suggestions;
534 suggestions.push_back(InstantSuggestion(text, behavior, type));
535 SearchBox::Get(render_view)->SetSuggestions(suggestions);
536 }
537 }
538 return v8::Undefined();
539 }
540
541 // static
542 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetRestrictedValue(
543 const v8::Arguments& args) {
544 content::RenderView* render_view = GetRenderView();
545 if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsNumber() &&
546 render_view) {
547 const int rid = args[0]->Uint32Value();
548 const int rid_base = SearchBox::Get(render_view)->rid_base();
549 // Note that stale rids, less than the current rid_base, will wrap.
550 const size_t index = rid - rid_base;
551 const std::vector<InstantNativeSuggestionsParts>& suggestions =
552 SearchBox::Get(render_view)->native_suggestions();
553 if (index < suggestions.size()) {
554 std::string text = suggestions[index].destination_url.spec();
555 InstantCompleteBehavior behavior = INSTANT_COMPLETE_REPLACE;
556 InstantSuggestionType type = INSTANT_SUGGESTION_URL;
557
558 if ((args.Length() >= 2 && args[1]->Uint32Value() == 0) ||
559 (args.Length() < 2 && suggestions[index].is_search)) {
560 text = suggestions[index].contents;
561 type = INSTANT_SUGGESTION_SEARCH;
562 }
563
564 std::vector<InstantSuggestion> suggestions;
565 suggestions.push_back(InstantSuggestion(text, behavior, type));
566 SearchBox::Get(render_view)->SetSuggestions(suggestions);
567 } else {
568 VLOG(1) << "Invalid rid " << rid << "; "
569 << "rid_base is " << rid_base << ".";
570 }
571 }
572 return v8::Undefined();
573 }
574
575 // static
576 v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetNonNativeDropdownHeight(
577 const v8::Arguments& args) {
578 if (args.Length() == 1) {
579 int height = 0;
580 InstantSizeUnits units = INSTANT_SIZE_PIXELS;
581 if (args[0]->IsInt32()) {
582 height = args[0]->Int32Value();
583 } else if (args[0]->IsString()) {
584 std::string height_str = *v8::String::Utf8Value(args[0]);
585 std::string units_str;
586 SplitLeadingNumberToken(&height_str, &units_str);
587 if (!base::StringToInt(height_str, &height))
588 return v8::Undefined();
589 if (units_str == "%") {
590 units = INSTANT_SIZE_PERCENT;
591 } else if (!units_str.empty() && units_str != "px") {
592 return v8::Undefined();
593 }
594 } else {
595 return v8::Undefined();
596 }
597 content::RenderView* render_view = GetRenderView();
598 if (render_view && height >= 0)
599 SearchBox::Get(render_view)->SetInstantPreviewHeight(height, units);
600 }
601 return v8::Undefined();
602 }
603
604 // static
605 v8::Handle<v8::Value> SearchBoxExtensionWrapper::NavigateContentWindow(
606 const v8::Arguments& args) {
607 content::RenderView* render_view = GetRenderView();
608 if (args.Length() == 1 && args[0]->IsNumber() && render_view) {
609 const int rid = args[0]->Uint32Value();
610 const int rid_base = SearchBox::Get(render_view)->rid_base();
611 // Note that stale rids, less than the current rid_base, will wrap.
612 const size_t index = rid - rid_base;
613 const std::vector<InstantNativeSuggestionsParts>& suggestions =
614 SearchBox::Get(render_view)->native_suggestions();
615 if (index < suggestions.size()) {
616 // Navigate directly to the selected URL.
617 // TODO(sreeram): SECURITY RISK! Disconnect the InstantLoader and call
618 // SearchBox::Reset to not leak sensitive data to the new page.
619 WebKit::WebURLRequest request(suggestions[index].destination_url);
620 render_view->GetWebView()->mainFrame()->loadRequest(request);
621 } else {
622 VLOG(1) << "Invalid rid " << rid << "; "
623 << "rid_base is " << rid_base << ".";
624 }
625 }
626 return v8::Undefined();
627 }
628
629 // static
630 void Dispatch(WebFrame* frame, WebString event_dispatch_script) {
354 DCHECK(frame) << "Dispatch requires frame"; 631 DCHECK(frame) << "Dispatch requires frame";
355 if (!frame) 632 if (!frame) return;
356 return; 633 frame->executeScript(WebScriptSource(event_dispatch_script));
357
358 v8::Handle<v8::Value> result = frame->executeScriptAndReturnValue(
359 WebScriptSource(event_dispatch_script));
360 if (result.IsEmpty() || result->IsUndefined() || result->IsNull() ||
361 result->IsFalse()) {
362 frame->executeScript(WebScriptSource(no_event_handler_script));
363 }
364 } 634 }
365 635
366 // static 636 // static
367 void SearchBoxExtension::DispatchChange(WebFrame* frame) { 637 void SearchBoxExtension::DispatchChange(WebFrame* frame) {
368 Dispatch(frame, kDispatchChangeEventScript, kUserInputScript); 638 Dispatch(frame, kDispatchChangeEventScript);
369 } 639 }
370 640
371 // static 641 // static
372 void SearchBoxExtension::DispatchSubmit(WebFrame* frame) { 642 void SearchBoxExtension::DispatchSubmit(WebFrame* frame) {
373 Dispatch(frame, kDispatchSubmitEventScript, kUserDoneScript); 643 Dispatch(frame, kDispatchSubmitEventScript);
374 } 644 }
375 645
376 // static 646 // static
377 void SearchBoxExtension::DispatchCancel(WebFrame* frame) { 647 void SearchBoxExtension::DispatchCancel(WebFrame* frame) {
378 Dispatch(frame, kDispatchCancelEventScript, kUserDoneScript); 648 Dispatch(frame, kDispatchCancelEventScript);
379 } 649 }
380 650
381 // static 651 // static
382 void SearchBoxExtension::DispatchResize(WebFrame* frame) { 652 void SearchBoxExtension::DispatchResize(WebFrame* frame) {
383 Dispatch(frame, kDispatchResizeEventScript, kSetOmniboxBoundsScript); 653 Dispatch(frame, kDispatchResizeEventScript);
384 } 654 }
385 655
386 // static 656 // static
657 void SearchBoxExtension::DispatchNativeSuggestions(WebFrame* frame) {
658 Dispatch(frame, kDispatchNativeSuggestionsEventScript);
659 }
660
661 // static
662 void SearchBoxExtension::DispatchKeyPress(WebFrame* frame) {
663 Dispatch(frame, kDispatchKeyPressEventScript);
664 }
665
666 // static
667 void SearchBoxExtension::DispatchFocus(WebFrame* frame) {
668 Dispatch(frame, kDispatchFocusEventScript);
669 }
670
671 // static
672 void SearchBoxExtension::DispatchBlur(WebFrame* frame) {
673 Dispatch(frame, kDispatchBlurEventScript);
674 }
675
676 // static
387 bool SearchBoxExtension::PageSupportsInstant(WebFrame* frame) { 677 bool SearchBoxExtension::PageSupportsInstant(WebFrame* frame) {
388 DCHECK(frame) << "PageSupportsInstant requires frame"; 678 DCHECK(frame) << "PageSupportsInstant requires frame";
389 if (!frame) return false; 679 if (!frame) return false;
390 680
391 v8::Handle<v8::Value> v = frame->executeScriptAndReturnValue( 681 v8::Handle<v8::Value> v = frame->executeScriptAndReturnValue(
392 WebScriptSource(kSupportsInstantScript)); 682 WebScriptSource(kSupportsInstantScript));
393 bool supports_deprecated_api = !v.IsEmpty() && v->BooleanValue(); 683 if (!v.IsEmpty() && v->BooleanValue()) {
394 // TODO(tonyg): Add way of detecting instant support to SearchBox API. 684 // Send a resize message to tell the page that Chrome is actively using
395 bool supports_searchbox_api = supports_deprecated_api; 685 // the searchbox API with it. The page uses the message to transition from
396 686 // "homepage" mode to "search" mode.
397 // The deprecated API needs to notify the page of events it may have missed. 687 DispatchResize(frame);
398 // This isn't necessary in the SearchBox API, since the page can query the 688 return true;
399 // API at any time.
400 CR_DEFINE_STATIC_LOCAL(std::string, init_script,
401 (StringPrintf(kInitScript, kSetOmniboxBoundsScript, kUserInputScript)));
402 if (supports_deprecated_api) {
403 frame->executeScript(WebScriptSource(WebString::fromUTF8(init_script)));
404 } 689 }
405 690 return false;
406 return supports_searchbox_api || supports_deprecated_api;
407 } 691 }
408 692
409 // static 693 // static
410 v8::Extension* SearchBoxExtension::Get() { 694 v8::Extension* SearchBoxExtension::Get() {
411 const base::StringPiece code = 695 const base::StringPiece code =
412 ResourceBundle::GetSharedInstance().GetRawDataResource( 696 ResourceBundle::GetSharedInstance().GetRawDataResource(
413 IDR_SEARCHBOX_API, ui::SCALE_FACTOR_NONE); 697 IDR_SEARCHBOX_API, ui::SCALE_FACTOR_NONE);
414 return new SearchBoxExtensionWrapper(code); 698 return new SearchBoxExtensionWrapper(code);
415 } 699 }
416 700
417 } // namespace extensions_v8 701 } // namespace extensions_v8
OLDNEW
« chrome/common/instant_types.cc ('K') | « chrome/renderer/searchbox_extension.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698