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

Unified Diff: chrome/renderer/searchbox/searchbox_extension.cc

Issue 10809063: Adding Javascript support for the Extended Searchbox API. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Syncing to pickup moved searchbox code. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/searchbox/searchbox_extension.cc
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index ab3ad2b3db99004b7f3af1376ac2510f6ec50124..a92957a8961dcf9043aca41fe718a26240227011 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -4,14 +4,38 @@
#include "chrome/renderer/searchbox/searchbox_extension.h"
+#include <ctype.h>
+#include <vector>
+
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
#include "chrome/renderer/searchbox/searchbox.h"
#include "content/public/renderer/render_view.h"
#include "grit/renderer_resources.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
sreeram 2012/08/13 16:37:08 We don't need this header.
Shishir 2012/08/13 18:11:12 Done.
#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 "ui/base/resource/resource_bundle.h"
#include "v8/include/v8.h"
+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";
@@ -63,6 +87,26 @@ static const char kSupportsInstantScript[] =
" false;"
"}";
+// Extended API.
+static const char kDispatchAutocompleteResultsEventScript[] =
+ "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;"
+ "}";
+
// ----------------------------------------------------------------------------
class SearchBoxExtensionWrapper : public v8::Extension {
@@ -105,9 +149,34 @@ 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 autocomplete results from search box.
+ static v8::Handle<v8::Value> GetAutocompleteResults(
+ const v8::Arguments& args);
+
+ // Gets the last key code entered in search box.
+ static v8::Handle<v8::Value> GetKeyCode(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> SetSuggestionInline(const v8::Arguments& args);
+
+ // Like |SetSuggestionInline| but uses a restricted ID to identify the text.
+ static v8::Handle<v8::Value> SetAutocompleteResultInline(
+ const v8::Arguments& args);
+
+ // Sets the search box text, completely replacing what the user typed.
+ static v8::Handle<v8::Value> SetSuggestionReplace(const v8::Arguments& args);
+
+ // Like |SetSuggestionReplace| but uses a restricted ID to identify the text.
+ static v8::Handle<v8::Value> SetAutocompleteResultReplace(
+ const v8::Arguments& args);
+
+ // Resize the preview to the given height.
+ static v8::Handle<v8::Value> SetNonNativeDropdownHeight(
+ const v8::Arguments& args);
+
private:
DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper);
};
@@ -135,8 +204,22 @@ 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("GetAutocompleteResults"))) {
+ return v8::FunctionTemplate::New(GetAutocompleteResults);
+ } else if (name->Equals(v8::String::New("GetKeyCode"))) {
+ return v8::FunctionTemplate::New(GetKeyCode);
} else if (name->Equals(v8::String::New("SetSuggestions"))) {
return v8::FunctionTemplate::New(SetSuggestions);
+ } else if (name->Equals(v8::String::New("SetSuggestionInline"))) {
+ return v8::FunctionTemplate::New(SetSuggestionInline);
+ } else if (name->Equals(v8::String::New("SetAutocompleteResultInline"))) {
+ return v8::FunctionTemplate::New(SetAutocompleteResultInline);
+ } else if (name->Equals(v8::String::New("SetSuggestionReplace"))) {
+ return v8::FunctionTemplate::New(SetSuggestionReplace);
+ } else if (name->Equals(v8::String::New("SetAutocompleteResultReplace"))) {
+ return v8::FunctionTemplate::New(SetAutocompleteResultReplace);
+ } else if (name->Equals(v8::String::New("SetNonNativeDropdownHeight"))) {
+ return v8::FunctionTemplate::New(SetNonNativeDropdownHeight);
}
return v8::Handle<v8::FunctionTemplate>();
}
@@ -222,16 +305,55 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetHeight(
}
// static
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetAutocompleteResults(
+ const v8::Arguments& args) {
+ content::RenderView* render_view = GetRenderView();
+ if (!render_view) return v8::Undefined();
+ const std::vector<InstantAutocompleteResult>& suggestions =
+ SearchBox::Get(render_view)->autocomplete_results();
sreeram 2012/08/13 16:37:08 suggestions -> results, throughout this method.
Shishir 2012/08/13 18:11:12 Done.
+ const int results_base = SearchBox::Get(render_view)->results_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()));
sreeram 2012/08/13 16:37:08 suggestions[i].provider/contents are string16s. .c
Shishir 2012/08/13 18:11:12 Done.
+ 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(results_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::SetSuggestions(
const v8::Arguments& args) {
- std::vector<string16> suggestions;
- InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW;
+ std::vector<InstantSuggestion> suggestions;
if (args.Length() && args[0]->IsObject()) {
- v8::Local<v8::Object> suggestion_json = args[0]->ToObject();
+ v8::Local<v8::Object> suggestion_json(args[0]->ToObject());
- v8::Local<v8::Value> complete_value =
- suggestion_json->Get(v8::String::New("complete_behavior"));
+ 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;
@@ -239,38 +361,180 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestions(
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) << "'";
}
}
-
- 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>();
-
+ 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);
+ v8::Local<v8::Value> suggestion_value(suggestions_array->Get(i));
if (!suggestion_value->IsObject()) continue;
- v8::Local<v8::Object> suggestion_object = suggestion_value->ToObject();
- 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")));
sreeram 2012/08/13 16:37:08 Why replace all the "type foo = bar;" statements w
Shishir 2012/08/13 18:11:12 Done.
if (!suggestion_object_value->IsString()) continue;
+ string16 text = *v8::String::Value(suggestion_object_value);
- string16 suggestion(reinterpret_cast<char16*>(*v8::String::Value(
- suggestion_object_value->ToString())));
- suggestions.push_back(suggestion);
+ suggestions.push_back(InstantSuggestion(text, behavior, type));
}
}
}
if (content::RenderView* render_view = GetRenderView())
- SearchBox::Get(render_view)->SetSuggestions(suggestions, behavior);
+ SearchBox::Get(render_view)->SetSuggestions(suggestions);
+ return v8::Undefined();
+}
+
+// static
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestionInline(
+ const v8::Arguments& args) {
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) {
+ string16 text = *v8::String::Value(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::SetAutocompleteResultInline(
+ const v8::Arguments& args) {
+ content::RenderView* render_view = GetRenderView();
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsNumber() &&
+ render_view) {
+ const int results_id = args[0]->Uint32Value();
+ const int results_base = SearchBox::Get(render_view)->results_base();
+ // Note that stale results_ids, less than the current results_base, will
+ // wrap.
+ const size_t index = results_id - results_base;
+ const std::vector<InstantAutocompleteResult>& suggestions =
+ SearchBox::Get(render_view)->autocomplete_results();
+ if (index < suggestions.size()) {
+ string16 text = UTF8ToUTF16(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 results_id " << results_id << "; "
+ << "results_base is " << results_base << ".";
+ }
+ }
+ return v8::Undefined();
+}
+
+// static
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestionReplace(
+ const v8::Arguments& args) {
+ // TODO(sreeram): Make the second argument (type) mandatory.
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) {
+ string16 text = *v8::String::Value(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();
+}
+
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetAutocompleteResultReplace(
+ const v8::Arguments& args) {
+ content::RenderView* render_view = GetRenderView();
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsNumber() &&
+ render_view) {
+ const int results_id = args[0]->Uint32Value();
+ const int results_base = SearchBox::Get(render_view)->results_base();
+ // Note that stale results_ids, less than the current results_base, will
+ // wrap.
+ const size_t index = results_id - results_base;
+ const std::vector<InstantAutocompleteResult>& suggestions =
+ SearchBox::Get(render_view)->autocomplete_results();
+ if (index < suggestions.size()) {
+ string16 text = UTF8ToUTF16(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 results_id " << results_id << "; "
+ << "results_base is " << results_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();
}
@@ -302,6 +566,16 @@ void SearchBoxExtension::DispatchResize(WebKit::WebFrame* frame) {
}
// static
+void SearchBoxExtension::DispatchAutocompleteResults(WebKit::WebFrame* frame) {
+ Dispatch(frame, kDispatchAutocompleteResultsEventScript);
+}
+
+// static
+void SearchBoxExtension::DispatchKeyPress(WebKit::WebFrame* frame) {
+ Dispatch(frame, kDispatchKeyPressEventScript);
+}
+
+// static
bool SearchBoxExtension::PageSupportsInstant(WebKit::WebFrame* frame) {
DCHECK(frame) << "PageSupportsInstant requires frame";
if (!frame) return false;
« chrome/renderer/searchbox/searchbox.h ('K') | « chrome/renderer/searchbox/searchbox_extension.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698