| Index: chrome/renderer/searchbox_extension.cc
|
| diff --git a/chrome/renderer/searchbox_extension.cc b/chrome/renderer/searchbox_extension.cc
|
| index 29bddcfecf0669d5b96f5d5210f016fbc3dda72c..fbb812b09d7a976e3d2da758c5b40444663921ca 100644
|
| --- a/chrome/renderer/searchbox_extension.cc
|
| +++ b/chrome/renderer/searchbox_extension.cc
|
| @@ -4,19 +4,24 @@
|
|
|
| #include "chrome/renderer/searchbox_extension.h"
|
|
|
| +#include <ctype.h>
|
| #include <string>
|
| #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 +30,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 +86,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 +176,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 +238,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"))) {
|
| + 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 +268,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 +285,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 +344,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(
|
| 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 +680,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
|
|
|