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