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

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: Fixing Windows Build. 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
« no previous file with comments | « chrome/renderer/searchbox/searchbox_extension.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..2fba2e1766863541b0b36eb679fb387188394ec7 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -4,14 +4,51 @@
#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/string_util.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/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);
+}
+
+// Converts a V8 String to a UTF16 string16.
+// This code also exists in net/proxy/proxy_resolver_v8.cc.
+// TODO(shishir): Find a common place for this function.
+string16 V8StringToUTF16(v8::Handle<v8::String> s) {
+ int len = s->Length();
+ string16 result;
+ // Note that the reinterpret cast is because on Windows string16 is an alias
+ // to wstring, and hence has character type wchar_t not uint16_t.
+ if (len > 0)
+ s->Write(reinterpret_cast<uint16_t*>(WriteInto(&result, len + 1)), 0, len);
sreeram 2012/08/13 22:40:56 How about this instead? string16 V8ValueToUTF16(v8
Shishir 2012/08/13 23:24:36 Done with minor modifications.
+ return result;
+}
+
+} // namespace
+
namespace extensions_v8 {
static const char kSearchBoxExtensionName[] = "v8/SearchBox";
@@ -63,6 +100,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 {
@@ -78,7 +135,7 @@ class SearchBoxExtensionWrapper : public v8::Extension {
static content::RenderView* GetRenderView();
// Gets the value of the user's search query.
- static v8::Handle<v8::Value> GetValue(const v8::Arguments& args);
+ static v8::Handle<v8::Value> GetQuery(const v8::Arguments& args);
// Gets whether the |value| should be considered final -- as opposed to a
// partial match. This may be set if the user clicks a suggestion, presses
@@ -105,9 +162,33 @@ 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> SetQuerySuggestion(const v8::Arguments& args);
+
+ // Like |SetQuerySuggestion| but uses a restricted ID to identify the text.
+ static v8::Handle<v8::Value> SetQuerySuggestionFromAutocompleteResult(
+ const v8::Arguments& args);
+
+ // Sets the search box text, completely replacing what the user typed.
+ static v8::Handle<v8::Value> SetQuery(const v8::Arguments& args);
+
+ // Like |SetQuery| but uses a restricted ID to identify the text.
+ static v8::Handle<v8::Value> SetQueryFromAutocompleteResult(
+ const v8::Arguments& args);
+
+ // Resize the preview to the given height.
+ static v8::Handle<v8::Value> SetPreviewHeight(const v8::Arguments& args);
+
private:
DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper);
};
@@ -119,8 +200,8 @@ SearchBoxExtensionWrapper::SearchBoxExtensionWrapper(
v8::Handle<v8::FunctionTemplate> SearchBoxExtensionWrapper::GetNativeFunction(
v8::Handle<v8::String> name) {
- if (name->Equals(v8::String::New("GetValue"))) {
- return v8::FunctionTemplate::New(GetValue);
+ if (name->Equals(v8::String::New("GetQuery"))) {
+ return v8::FunctionTemplate::New(GetQuery);
} else if (name->Equals(v8::String::New("GetVerbatim"))) {
return v8::FunctionTemplate::New(GetVerbatim);
} else if (name->Equals(v8::String::New("GetSelectionStart"))) {
@@ -135,8 +216,23 @@ 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("SetQuerySuggestion"))) {
+ return v8::FunctionTemplate::New(SetQuerySuggestion);
+ } else if (name->Equals(v8::String::New(
+ "SetQuerySuggestionFromAutocompleteResult"))) {
+ return v8::FunctionTemplate::New(SetQuerySuggestionFromAutocompleteResult);
+ } else if (name->Equals(v8::String::New("SetQuery"))) {
+ return v8::FunctionTemplate::New(SetQuery);
+ } else if (name->Equals(v8::String::New("SetQueryFromAutocompleteResult"))) {
+ return v8::FunctionTemplate::New(SetQueryFromAutocompleteResult);
+ } else if (name->Equals(v8::String::New("SetPreviewHeight"))) {
+ return v8::FunctionTemplate::New(SetPreviewHeight);
}
return v8::Handle<v8::FunctionTemplate>();
}
@@ -155,14 +251,14 @@ content::RenderView* SearchBoxExtensionWrapper::GetRenderView() {
}
// static
-v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetValue(
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetQuery(
const v8::Arguments& args) {
content::RenderView* render_view = GetRenderView();
if (!render_view) return v8::Undefined();
return v8::String::New(
reinterpret_cast<const uint16_t*>(
- SearchBox::Get(render_view)->value().data()),
- SearchBox::Get(render_view)->value().length());
+ SearchBox::Get(render_view)->query().data()),
+ SearchBox::Get(render_view)->query().length());
sreeram 2012/08/13 22:40:56 This can be simplified to: return UTF16ToV8String(
Shishir 2012/08/13 23:24:36 Done.
}
// static
@@ -222,16 +318,61 @@ 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>& results =
+ SearchBox::Get(render_view)->autocomplete_results();
+ const int results_base = SearchBox::Get(render_view)->results_base();
+ v8::Handle<v8::Array> results_array = v8::Array::New(results.size());
+ for (size_t i = 0; i < results.size(); ++i) {
+ v8::Handle<v8::Object> result = v8::Object::New();
+ const string16& provider = results[i].provider;
+ result->Set(
+ v8::String::New("provider"),
+ v8::String::New(reinterpret_cast<const uint16_t*>(provider.data()),
+ provider.length()));
+ const string16& contents = results[i].contents;
+ result->Set(
+ v8::String::New("contents"),
+ v8::String::New(reinterpret_cast<const uint16_t*>(contents.data()),
+ contents.length()));
sreeram 2012/08/13 22:40:56 These can be simplified to: result->Set(v8::Stri
Shishir 2012/08/13 23:24:36 Done.
+ result->Set(v8::String::New("destination_url"),
+ v8::String::New(results[i].destination_url.spec().c_str()));
+ result->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(results[i].relevance));
+ result->Set(v8::String::New("rankingData"), ranking_data);
+
+ results_array->Set(i, result);
+ }
+
+ return results_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();
sreeram 2012/08/13 22:40:56 I'm not sure why we refer to v8::Local explicitly,
Shishir 2012/08/13 23:24:36 Done.
+ InstantCompleteBehavior behavior = INSTANT_COMPLETE_NOW;
+ InstantSuggestionType type = INSTANT_SUGGESTION_SEARCH;
v8::Local<v8::Value> complete_value =
- suggestion_json->Get(v8::String::New("complete_behavior"));
+ 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,19 +380,18 @@ 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"));
-
if (suggestions_field->IsArray()) {
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);
@@ -261,16 +401,161 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::SetSuggestions(
v8::Local<v8::Value> suggestion_object_value =
suggestion_object->Get(v8::String::New("value"));
if (!suggestion_object_value->IsString()) continue;
+ string16 text = V8StringToUTF16(suggestion_object_value->ToString());
sreeram 2012/08/13 22:40:56 This can be simplified to: string16 text = V8Value
Shishir 2012/08/13 23:24:36 Done.
- 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::SetQuerySuggestion(
+ const v8::Arguments& args) {
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) {
+ string16 text = V8StringToUTF16(args[0]->ToString());
+ 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::SetQuerySuggestionFromAutocompleteResult(
+ 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::SetQuery(
+ const v8::Arguments& args) {
+ // TODO(sreeram): Make the second argument (type) mandatory.
+ if (1 <= args.Length() && args.Length() <= 2 && args[0]->IsString()) {
+ string16 text = V8StringToUTF16(args[0]->ToString());
+ 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::SetQueryFromAutocompleteResult(
+ 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::SetPreviewHeight(
+ 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 +587,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;
« no previous file with comments | « chrome/renderer/searchbox/searchbox_extension.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698