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

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

Powered by Google App Engine
This is Rietveld 408576698