Index: chrome/renderer/searchbox_extension.cc |
diff --git a/chrome/renderer/searchbox_extension.cc b/chrome/renderer/searchbox_extension.cc |
index 29bddcfecf0669d5b96f5d5210f016fbc3dda72c..d15db22e21242ee8eecf7d3a40f3e4530ff7d9fc 100644 |
--- a/chrome/renderer/searchbox_extension.cc |
+++ b/chrome/renderer/searchbox_extension.cc |
@@ -8,15 +8,19 @@ |
#include <vector> |
#include "base/basictypes.h" |
-#include "base/command_line.h" |
+#include "base/string_number_conversions.h" |
+#include "base/string_piece.h" |
#include "base/string_split.h" |
#include "base/stringprintf.h" |
+#include "chrome/common/chrome_switches.h" |
#include "chrome/renderer/searchbox.h" |
#include "content/public/renderer/render_view.h" |
#include "grit/renderer_resources.h" |
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
#include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h" |
#include "ui/base/resource/resource_bundle.h" |
#include "v8/include/v8.h" |
@@ -25,6 +29,22 @@ using WebKit::WebScriptSource; |
using WebKit::WebString; |
using WebKit::WebView; |
+namespace { |
+ |
+// Splits the string in |number| into two pieces, a leading number token (saved |
+// in |number|) and the rest (saved in |suffix|). Either piece may become empty, |
+// depending on whether the input had no digits or only digits. Neither argument |
+// may be NULL. |
+void SplitLeadingNumberToken(std::string* number, std::string* suffix) { |
+ size_t i = 0; |
+ while (i < number->size() && isdigit((*number)[i])) |
+ ++i; |
+ suffix->assign(*number, i, number->size() - i); |
+ number->resize(i); |
+} |
+ |
+} // namespace |
+ |
namespace extensions_v8 { |
static const char kSearchBoxExtensionName[] = "v8/SearchBox"; |
@@ -65,60 +85,55 @@ static const char kDispatchResizeEventScript[] = |
" true;" |
"}"; |
-// Deprecated API support. |
-// TODO(tonyg): Remove these when they are no longer used. |
-// ---------------------------------------------------------------------------- |
-// Script sent as the user is typing and the provider supports instant. |
-// Params: |
-// . the text the user typed. |
-// '46' forces the server to give us verbatim results. |
-static const char kUserInputScript[] = |
- "if (window.chrome.userInput)" |
- " window.chrome.userInput(" |
- " window.chrome.searchBox.value," |
- " window.chrome.searchBox.verbatim ? 46 : 0," |
- " window.chrome.searchBox.selectionStart);"; |
- |
-// Script sent when the page is committed and the provider supports instant. |
-// Params: |
-// . the text the user typed. |
-// . boolean indicating if the user pressed enter to accept the text. |
-static const char kUserDoneScript[] = |
- "if (window.chrome.userWantsQuery)" |
- " window.chrome.userWantsQuery(" |
- " window.chrome.searchBox.value," |
- " window.chrome.searchBox.verbatim);"; |
- |
-// Script sent when the bounds of the omnibox changes and the provider supports |
-// instant. The params are the bounds relative to the origin of the preview |
-// (x, y, width, height). |
-static const char kSetOmniboxBoundsScript[] = |
- "if (window.chrome.setDropdownDimensions)" |
- " window.chrome.setDropdownDimensions(" |
- " window.chrome.searchBox.x," |
- " window.chrome.searchBox.y," |
- " window.chrome.searchBox.width," |
- " window.chrome.searchBox.height);"; |
+// Extended API. |
+ |
+static const char kDispatchNativeSuggestionsEventScript[] = |
+ "if (window.chrome &&" |
+ " window.chrome.searchBox &&" |
+ " window.chrome.searchBox.onnativesuggestions &&" |
+ " typeof window.chrome.searchBox.onnativesuggestions == 'function') {" |
+ " window.chrome.searchBox.onnativesuggestions();" |
+ " true;" |
+ "}"; |
+ |
+static const char kDispatchKeyPressEventScript[] = |
+ "if (window.chrome &&" |
+ " window.chrome.searchBox &&" |
+ " window.chrome.searchBox.onkeypress &&" |
+ " typeof window.chrome.searchBox.onkeypress == 'function') {" |
+ " window.chrome.searchBox.onkeypress(" |
+ " {keyCode:window.chrome.searchBox.keyCode});" |
+ " true;" |
+ "}"; |
+ |
+static const char kDispatchFocusEventScript[] = |
+ "if (window.chrome &&" |
+ " window.chrome.searchBox &&" |
+ " window.chrome.searchBox.onfocus &&" |
+ " typeof window.chrome.searchBox.onfocus == 'function') {" |
+ " window.chrome.searchBox.onfocus();" |
+ " true;" |
+ "}"; |
+ |
+static const char kDispatchBlurEventScript[] = |
+ "if (window.chrome &&" |
+ " window.chrome.searchBox &&" |
+ " window.chrome.searchBox.onblur &&" |
+ " typeof window.chrome.searchBox.onblur == 'function') {" |
+ " window.chrome.searchBox.onblur();" |
+ " true;" |
+ "}"; |
// We first send this script down to determine if the page supports instant. |
static const char kSupportsInstantScript[] = |
- "if (window.chrome.sv) true; else false;"; |
- |
-// The google.y.first array is a list of functions which are to be executed |
-// after the external JavaScript used by Google web search loads. The deprecated |
-// API requires setDropdownDimensions and userInput to be invoked after |
-// the external JavaScript loads. So if they are not already registered, we add |
-// them to the array of functions the page will execute after load. This tight |
-// coupling discourages proliferation of the deprecated API. |
-static const char kInitScript[] = |
- "(function() {" |
- "var initScript = function(){%s%s};" |
- "if (window.chrome.setDropdownDimensions)" |
- " initScript();" |
- "else if (window.google && window.google.y)" |
- " window.google.y.first.push(initScript);" |
- "})();"; |
-// ---------------------------------------------------------------------------- |
+ "if (window.chrome &&" |
+ " window.chrome.searchBox &&" |
+ " window.chrome.searchBox.onsubmit &&" |
+ " typeof window.chrome.searchBox.onsubmit == 'function') {" |
+ " true;" |
+ "} else {" |
+ " false;" |
+ "}"; |
class SearchBoxExtensionWrapper : public v8::Extension { |
public: |
@@ -160,9 +175,42 @@ class SearchBoxExtensionWrapper : public v8::Extension { |
// Gets the height of the region of the search box that overlaps the window. |
static v8::Handle<v8::Value> GetHeight(const v8::Arguments& args); |
+ // Gets the native suggestions from search box. |
+ static v8::Handle<v8::Value> GetNativeSuggestions(const v8::Arguments& args); |
+ |
+ // Gets the last key code entered in search box. |
+ static v8::Handle<v8::Value> GetKeyCode(const v8::Arguments& args); |
+ |
+ // Gets some info about the last search session committed in the search box. |
+ static v8::Handle<v8::Value> GetSessionContext(const v8::Arguments& args); |
+ |
+ // Gets whether the search box currently has keyboard focus or not. |
+ static v8::Handle<v8::Value> GetIsFocused(const v8::Arguments& args); |
+ |
// Sets ordered suggestions. Valid for current |value|. |
static v8::Handle<v8::Value> SetSuggestions(const v8::Arguments& args); |
+ // Sets the text to be autocompleted into the search box. |
+ static v8::Handle<v8::Value> SetAutocompleteText(const v8::Arguments& args); |
+ |
+ // Like |SetAutocompleteText| but uses a restricted ID to identify the text. |
+ static v8::Handle<v8::Value> SetRestrictedAutocompleteText( |
+ const v8::Arguments& args); |
+ |
+ // Sets the search box text, completely replacing what the user typed. |
+ static v8::Handle<v8::Value> SetValue(const v8::Arguments& args); |
+ |
+ // Like |SetValue| but uses a restricted ID to identify the text. |
+ static v8::Handle<v8::Value> SetRestrictedValue(const v8::Arguments& args); |
+ |
+ // Resize the preview to the given height. |
+ static v8::Handle<v8::Value> SetNonNativeDropdownHeight( |
+ const v8::Arguments& args); |
+ |
+ // Navigate the window to the URL identified by a restricted ID. |
+ static v8::Handle<v8::Value> NavigateContentWindow(const v8::Arguments& args); |
+ |
+ |
private: |
DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper); |
}; |
@@ -189,8 +237,28 @@ v8::Handle<v8::FunctionTemplate> SearchBoxExtensionWrapper::GetNativeFunction( |
return v8::FunctionTemplate::New(GetWidth); |
} else if (name->Equals(v8::String::New("GetHeight"))) { |
return v8::FunctionTemplate::New(GetHeight); |
+ } 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
|
+ return v8::FunctionTemplate::New(GetNativeSuggestions); |
+ } else if (name->Equals(v8::String::New("GetKeyCode"))) { |
+ return v8::FunctionTemplate::New(GetKeyCode); |
+ } else if (name->Equals(v8::String::New("GetSessionContext"))) { |
+ return v8::FunctionTemplate::New(GetSessionContext); |
+ } else if (name->Equals(v8::String::New("GetIsFocused"))) { |
+ return v8::FunctionTemplate::New(GetIsFocused); |
} else if (name->Equals(v8::String::New("SetSuggestions"))) { |
return v8::FunctionTemplate::New(SetSuggestions); |
+ } else if (name->Equals(v8::String::New("SetAutocompleteText"))) { |
+ return v8::FunctionTemplate::New(SetAutocompleteText); |
+ } else if (name->Equals(v8::String::New("SetRestrictedAutocompleteText"))) { |
+ return v8::FunctionTemplate::New(SetRestrictedAutocompleteText); |
+ } else if (name->Equals(v8::String::New("SetValue"))) { |
+ return v8::FunctionTemplate::New(SetValue); |
+ } else if (name->Equals(v8::String::New("SetRestrictedValue"))) { |
+ return v8::FunctionTemplate::New(SetRestrictedValue); |
+ } else if (name->Equals(v8::String::New("SetNonNativeDropdownHeight"))) { |
+ return v8::FunctionTemplate::New(SetNonNativeDropdownHeight); |
+ } else if (name->Equals(v8::String::New("NavigateContentWindow"))) { |
+ return v8::FunctionTemplate::New(NavigateContentWindow); |
} |
return v8::Handle<v8::FunctionTemplate>(); |
} |
@@ -199,7 +267,7 @@ v8::Handle<v8::FunctionTemplate> SearchBoxExtensionWrapper::GetNativeFunction( |
content::RenderView* SearchBoxExtensionWrapper::GetRenderView() { |
WebFrame* webframe = WebFrame::frameForEnteredContext(); |
DCHECK(webframe) << "There should be an active frame since we just got " |
- "a native function called."; |
+ "a native function called."; |
if (!webframe) return NULL; |
WebView* webview = webframe->view(); |
@@ -216,7 +284,7 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetValue( |
return v8::String::New( |
reinterpret_cast<const uint16_t*>( |
SearchBox::Get(render_view)->value().c_str()), |
- SearchBox::Get(render_view)->value().length()); |
+ SearchBox::Get(render_view)->value().length()); |
} |
// static |
@@ -275,112 +343,333 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetHeight( |
return v8::Int32::New(SearchBox::Get(render_view)->GetRect().height()); |
} |
-// Accepts a single argument in form: |
-// { |
-// suggestions: [ |
-// { |
-// value: "..." |
-// } |
-// ] |
-// } |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetNativeSuggestions( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (!render_view) return v8::Undefined(); |
+ const std::vector<InstantNativeSuggestionsParts>& suggestions = |
+ SearchBox::Get(render_view)->native_suggestions(); |
+ const int rid_base = SearchBox::Get(render_view)->rid_base(); |
+ v8::Handle<v8::Array> suggestions_array(v8::Array::New(suggestions.size())); |
+ for (size_t i = 0; i < suggestions.size(); ++i) { |
+ v8::Handle<v8::Object> suggestion(v8::Object::New()); |
+ suggestion->Set(v8::String::New("provider"), |
+ v8::String::New(suggestions[i].provider.c_str())); |
+ suggestion->Set(v8::String::New("contents"), |
+ v8::String::New(suggestions[i].contents.c_str())); |
+ suggestion->Set(v8::String::New("destination_url"), |
+ v8::String::New(suggestions[i].destination_url.spec().c_str())); |
+ suggestion->Set(v8::String::New("rid"), v8::Uint32::New(rid_base + i)); |
+ |
+ v8::Handle<v8::Object> ranking_data(v8::Object::New()); |
+ ranking_data->Set(v8::String::New("relevance"), |
+ v8::Int32::New(suggestions[i].relevance)); |
+ suggestion->Set(v8::String::New("rankingData"), ranking_data); |
+ |
+ suggestions_array->Set(i, suggestion); |
+ } |
+ |
+ return suggestions_array; |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetKeyCode( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (!render_view) return v8::Undefined(); |
+ return v8::Int32::New(SearchBox::Get(render_view)->key_code()); |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetSessionContext( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (!render_view) return v8::Undefined(); |
+ v8::Handle<v8::Object> session_context(v8::Object::New()); |
+ session_context->Set(v8::String::New("lastSearchQuery"), |
+ v8::String::New(SearchBox::Get(render_view)->last_query().c_str())); |
+ // NOTE: SECURITY RISK -- Providing the current url in this way is insecure. |
+ session_context->Set(v8::String::New("currentUrl"), |
+ v8::String::New(SearchBox::Get(render_view)->current_url().c_str())); |
+ return session_context; |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetIsFocused( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (!render_view) return v8::Undefined(); |
+ return v8::Boolean::New(SearchBox::Get(render_view)->is_focused()); |
+} |
+ |
// static |
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
|
const v8::Arguments& args) { |
- std::vector<std::string> suggestions; |
- InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; |
- |
- if (args.Length() && args[0]->IsArray()) { |
- // For backwards compatibility, also accept an array of strings. |
- // TODO(tonyg): Remove this when it is confirmed to be unused. |
- v8::Local<v8::Array> suggestions_array = |
- v8::Local<v8::Array>::Cast(args[0]); |
- uint32_t length = suggestions_array->Length(); |
- for (uint32_t i = 0; i < length; i++) { |
- std::string suggestion = *v8::String::Utf8Value( |
- suggestions_array->Get(v8::Integer::New(i))->ToString()); |
- if (!suggestion.length()) continue; |
- suggestions.push_back(suggestion); |
+ std::vector<InstantSuggestion> suggestions; |
+ |
+ if (args.Length() && args[0]->IsObject()) { |
+ v8::Local<v8::Object> suggestion_json(args[0]->ToObject()); |
+ |
+ InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; |
+ InstantSuggestionType type = INSTANT_SUGGESTION_SEARCH; |
+ v8::Local<v8::Value> complete_value( |
+ suggestion_json->Get(v8::String::New("complete_behavior"))); |
+ if (complete_value->IsString()) { |
+ if (complete_value->Equals(v8::String::New("now"))) { |
+ behavior = INSTANT_COMPLETE_NOW; |
+ } else if (complete_value->Equals(v8::String::New("never"))) { |
+ behavior = INSTANT_COMPLETE_NEVER; |
+ } else if (complete_value->Equals(v8::String::New("delayed"))) { |
+ behavior = INSTANT_COMPLETE_DELAYED; |
+ } else if (complete_value->Equals(v8::String::New("replace"))) { |
+ behavior = INSTANT_COMPLETE_REPLACE; |
+ } else { |
+ VLOG(1) << "Unsupported complete behavior '" |
+ << *v8::String::Utf8Value(complete_value) << "'"; |
+ } |
} |
- } else if (args.Length() && args[0]->IsObject()) { |
- // Standard version, object argument. |
- v8::Local<v8::Object> suggestion_json = |
- v8::Local<v8::Object>::Cast(args[0]); |
- v8::Local<v8::Value> suggestions_field = |
- suggestion_json->Get(v8::String::New("suggestions")); |
+ v8::Local<v8::Value> suggestions_field( |
+ suggestion_json->Get(v8::String::New("suggestions"))); |
if (suggestions_field->IsArray()) { |
- v8::Local<v8::Array> suggestions_array = |
- suggestions_field.As<v8::Array>(); |
- |
- uint32_t length = suggestions_array->Length(); |
- for (uint32_t i = 0; i < length; i++) { |
- v8::Local<v8::Value> suggestion_value = |
- suggestions_array->Get(v8::Integer::New(i)); |
+ v8::Local<v8::Array> suggestions_array( |
+ suggestions_field.As<v8::Array>()); |
+ size_t length = suggestions_array->Length(); |
+ for (size_t i = 0; i < length; i++) { |
+ v8::Local<v8::Value> suggestion_value(suggestions_array->Get(i)); |
if (!suggestion_value->IsObject()) continue; |
- v8::Local<v8::Object> suggestion_object = |
- suggestion_value.As<v8::Object>(); |
- v8::Local<v8::Value> suggestion_object_value = |
- suggestion_object->Get(v8::String::New("value")); |
+ v8::Local<v8::Object> suggestion_object(suggestion_value->ToObject()); |
+ v8::Local<v8::Value> suggestion_object_value( |
+ suggestion_object->Get(v8::String::New("value"))); |
if (!suggestion_object_value->IsString()) continue; |
- std::string suggestion = *v8::String::Utf8Value( |
- suggestion_object_value->ToString()); |
- if (!suggestion.length()) continue; |
- suggestions.push_back(suggestion); |
+ std::string text = *v8::String::Utf8Value(suggestion_object_value); |
+ |
+ suggestions.push_back(InstantSuggestion(text, behavior, type)); |
} |
} |
- if (suggestion_json->Has(v8::String::New("complete_behavior"))) { |
- v8::Local<v8::Value> complete_value = |
- suggestion_json->Get(v8::String::New("complete_behavior")); |
- if (complete_value->IsString()) { |
- if (complete_value->Equals(v8::String::New("never"))) |
- behavior = INSTANT_COMPLETE_NEVER; |
- else if (complete_value->Equals(v8::String::New("delayed"))) |
- behavior = INSTANT_COMPLETE_DELAYED; |
+ } |
+ |
+ if (content::RenderView* render_view = GetRenderView()) |
+ SearchBox::Get(render_view)->SetSuggestions(suggestions); |
+ return v8::Undefined(); |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetAutocompleteText( |
+ const v8::Arguments& args) { |
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) { |
+ std::string text = *v8::String::Utf8Value(args[0]); |
+ InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; |
+ InstantSuggestionType type = INSTANT_SUGGESTION_URL; |
+ |
+ if (args.Length() >= 2 && args[1]->Uint32Value() == 2) { |
+ behavior = INSTANT_COMPLETE_NEVER; |
+ // TODO(sreeram): The page should really set the type explicitly. |
+ type = INSTANT_SUGGESTION_SEARCH; |
+ } |
+ |
+ if (content::RenderView* render_view = GetRenderView()) { |
+ std::vector<InstantSuggestion> suggestions; |
+ suggestions.push_back(InstantSuggestion(text, behavior, type)); |
+ SearchBox::Get(render_view)->SetSuggestions(suggestions); |
+ } |
+ } |
+ return v8::Undefined(); |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetRestrictedAutocompleteText( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsNumber() && |
+ render_view) { |
+ const int rid = args[0]->Uint32Value(); |
+ const int rid_base = SearchBox::Get(render_view)->rid_base(); |
+ // Note that stale rids, less than the current rid_base, will wrap. |
+ const size_t index = rid - rid_base; |
+ const std::vector<InstantNativeSuggestionsParts>& suggestions = |
+ SearchBox::Get(render_view)->native_suggestions(); |
+ if (index < suggestions.size()) { |
+ std::string text = suggestions[index].destination_url.spec(); |
+ InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW; |
+ InstantSuggestionType type = INSTANT_SUGGESTION_URL; |
+ |
+ if (args.Length() >= 2 && args[1]->Uint32Value() == 2) |
+ behavior = INSTANT_COMPLETE_NEVER; |
+ |
+ if (suggestions[index].is_search) { |
+ text = suggestions[index].contents; |
+ type = INSTANT_SUGGESTION_SEARCH; |
} |
+ |
+ std::vector<InstantSuggestion> suggestions; |
+ suggestions.push_back(InstantSuggestion(text, behavior, type)); |
+ SearchBox::Get(render_view)->SetSuggestions(suggestions); |
+ } else { |
+ VLOG(1) << "Invalid rid " << rid << "; " |
+ << "rid_base is " << rid_base << "."; |
} |
} |
+ return v8::Undefined(); |
+} |
- if (content::RenderView* render_view = GetRenderView()) |
- SearchBox::Get(render_view)->SetSuggestions(suggestions, behavior); |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetValue( |
+ const v8::Arguments& args) { |
+ // TODO(sreeram): Make the second argument (type) mandatory. |
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) { |
+ std::string text = *v8::String::Utf8Value(args[0]); |
+ InstantCompleteBehavior behavior = INSTANT_COMPLETE_REPLACE; |
+ InstantSuggestionType type = INSTANT_SUGGESTION_SEARCH; |
+ |
+ if (args.Length() >= 2 && args[1]->Uint32Value() == 1) |
+ type = INSTANT_SUGGESTION_URL; |
+ |
+ if (content::RenderView* render_view = GetRenderView()) { |
+ std::vector<InstantSuggestion> suggestions; |
+ suggestions.push_back(InstantSuggestion(text, behavior, type)); |
+ SearchBox::Get(render_view)->SetSuggestions(suggestions); |
+ } |
+ } |
return v8::Undefined(); |
} |
// static |
-void Dispatch(WebFrame* frame, |
- WebString event_dispatch_script, |
- WebString no_event_handler_script) { |
- DCHECK(frame) << "Dispatch requires frame"; |
- if (!frame) |
- return; |
- |
- v8::Handle<v8::Value> result = frame->executeScriptAndReturnValue( |
- WebScriptSource(event_dispatch_script)); |
- if (result.IsEmpty() || result->IsUndefined() || result->IsNull() || |
- result->IsFalse()) { |
- frame->executeScript(WebScriptSource(no_event_handler_script)); |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetRestrictedValue( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsNumber() && |
+ render_view) { |
+ const int rid = args[0]->Uint32Value(); |
+ const int rid_base = SearchBox::Get(render_view)->rid_base(); |
+ // Note that stale rids, less than the current rid_base, will wrap. |
+ const size_t index = rid - rid_base; |
+ const std::vector<InstantNativeSuggestionsParts>& suggestions = |
+ SearchBox::Get(render_view)->native_suggestions(); |
+ if (index < suggestions.size()) { |
+ std::string text = suggestions[index].destination_url.spec(); |
+ InstantCompleteBehavior behavior = INSTANT_COMPLETE_REPLACE; |
+ InstantSuggestionType type = INSTANT_SUGGESTION_URL; |
+ |
+ if ((args.Length() >= 2 && args[1]->Uint32Value() == 0) || |
+ (args.Length() < 2 && suggestions[index].is_search)) { |
+ text = suggestions[index].contents; |
+ type = INSTANT_SUGGESTION_SEARCH; |
+ } |
+ |
+ std::vector<InstantSuggestion> suggestions; |
+ suggestions.push_back(InstantSuggestion(text, behavior, type)); |
+ SearchBox::Get(render_view)->SetSuggestions(suggestions); |
+ } else { |
+ VLOG(1) << "Invalid rid " << rid << "; " |
+ << "rid_base is " << rid_base << "."; |
+ } |
} |
+ return v8::Undefined(); |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetNonNativeDropdownHeight( |
+ const v8::Arguments& args) { |
+ if (args.Length() == 1) { |
+ int height = 0; |
+ InstantSizeUnits units = INSTANT_SIZE_PIXELS; |
+ if (args[0]->IsInt32()) { |
+ height = args[0]->Int32Value(); |
+ } else if (args[0]->IsString()) { |
+ std::string height_str = *v8::String::Utf8Value(args[0]); |
+ std::string units_str; |
+ SplitLeadingNumberToken(&height_str, &units_str); |
+ if (!base::StringToInt(height_str, &height)) |
+ return v8::Undefined(); |
+ if (units_str == "%") { |
+ units = INSTANT_SIZE_PERCENT; |
+ } else if (!units_str.empty() && units_str != "px") { |
+ return v8::Undefined(); |
+ } |
+ } else { |
+ return v8::Undefined(); |
+ } |
+ content::RenderView* render_view = GetRenderView(); |
+ if (render_view && height >= 0) |
+ SearchBox::Get(render_view)->SetInstantPreviewHeight(height, units); |
+ } |
+ return v8::Undefined(); |
+} |
+ |
+// static |
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::NavigateContentWindow( |
+ const v8::Arguments& args) { |
+ content::RenderView* render_view = GetRenderView(); |
+ if (args.Length() == 1 && args[0]->IsNumber() && render_view) { |
+ const int rid = args[0]->Uint32Value(); |
+ const int rid_base = SearchBox::Get(render_view)->rid_base(); |
+ // Note that stale rids, less than the current rid_base, will wrap. |
+ const size_t index = rid - rid_base; |
+ const std::vector<InstantNativeSuggestionsParts>& suggestions = |
+ SearchBox::Get(render_view)->native_suggestions(); |
+ if (index < suggestions.size()) { |
+ // Navigate directly to the selected URL. |
+ // TODO(sreeram): SECURITY RISK! Disconnect the InstantLoader and call |
+ // SearchBox::Reset to not leak sensitive data to the new page. |
+ WebKit::WebURLRequest request(suggestions[index].destination_url); |
+ render_view->GetWebView()->mainFrame()->loadRequest(request); |
+ } else { |
+ VLOG(1) << "Invalid rid " << rid << "; " |
+ << "rid_base is " << rid_base << "."; |
+ } |
+ } |
+ return v8::Undefined(); |
+} |
+ |
+// static |
+void Dispatch(WebFrame* frame, WebString event_dispatch_script) { |
+ DCHECK(frame) << "Dispatch requires frame"; |
+ if (!frame) return; |
+ frame->executeScript(WebScriptSource(event_dispatch_script)); |
} |
// static |
void SearchBoxExtension::DispatchChange(WebFrame* frame) { |
- Dispatch(frame, kDispatchChangeEventScript, kUserInputScript); |
+ Dispatch(frame, kDispatchChangeEventScript); |
} |
// static |
void SearchBoxExtension::DispatchSubmit(WebFrame* frame) { |
- Dispatch(frame, kDispatchSubmitEventScript, kUserDoneScript); |
+ Dispatch(frame, kDispatchSubmitEventScript); |
} |
// static |
void SearchBoxExtension::DispatchCancel(WebFrame* frame) { |
- Dispatch(frame, kDispatchCancelEventScript, kUserDoneScript); |
+ Dispatch(frame, kDispatchCancelEventScript); |
} |
// static |
void SearchBoxExtension::DispatchResize(WebFrame* frame) { |
- Dispatch(frame, kDispatchResizeEventScript, kSetOmniboxBoundsScript); |
+ Dispatch(frame, kDispatchResizeEventScript); |
+} |
+ |
+// static |
+void SearchBoxExtension::DispatchNativeSuggestions(WebFrame* frame) { |
+ Dispatch(frame, kDispatchNativeSuggestionsEventScript); |
+} |
+ |
+// static |
+void SearchBoxExtension::DispatchKeyPress(WebFrame* frame) { |
+ Dispatch(frame, kDispatchKeyPressEventScript); |
+} |
+ |
+// static |
+void SearchBoxExtension::DispatchFocus(WebFrame* frame) { |
+ Dispatch(frame, kDispatchFocusEventScript); |
+} |
+ |
+// static |
+void SearchBoxExtension::DispatchBlur(WebFrame* frame) { |
+ Dispatch(frame, kDispatchBlurEventScript); |
} |
// static |
@@ -390,20 +679,14 @@ bool SearchBoxExtension::PageSupportsInstant(WebFrame* frame) { |
v8::Handle<v8::Value> v = frame->executeScriptAndReturnValue( |
WebScriptSource(kSupportsInstantScript)); |
- bool supports_deprecated_api = !v.IsEmpty() && v->BooleanValue(); |
- // TODO(tonyg): Add way of detecting instant support to SearchBox API. |
- bool supports_searchbox_api = supports_deprecated_api; |
- |
- // The deprecated API needs to notify the page of events it may have missed. |
- // This isn't necessary in the SearchBox API, since the page can query the |
- // API at any time. |
- CR_DEFINE_STATIC_LOCAL(std::string, init_script, |
- (StringPrintf(kInitScript, kSetOmniboxBoundsScript, kUserInputScript))); |
- if (supports_deprecated_api) { |
- frame->executeScript(WebScriptSource(WebString::fromUTF8(init_script))); |
+ if (!v.IsEmpty() && v->BooleanValue()) { |
+ // Send a resize message to tell the page that Chrome is actively using |
+ // the searchbox API with it. The page uses the message to transition from |
+ // "homepage" mode to "search" mode. |
+ DispatchResize(frame); |
+ return true; |
} |
- |
- return supports_searchbox_api || supports_deprecated_api; |
+ return false; |
} |
// static |