summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-21 23:38:45 +0000
committermpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-21 23:38:45 +0000
commit8d677ff0f5085bb583d1b8248f977d009ec4b867 (patch)
treea8d1cb7e23128f910a33effde71fb083e5698838
parent14f769f460022e0d28852adc9ff1ce02f4fe2871 (diff)
downloadchromium_src-8d677ff0f5085bb583d1b8248f977d009ec4b867.zip
chromium_src-8d677ff0f5085bb583d1b8248f977d009ec4b867.tar.gz
chromium_src-8d677ff0f5085bb583d1b8248f977d009ec4b867.tar.bz2
Address some visual problems with the omnibox extension API:
- Remove some of the boilerplate strings. - Allow the description field to be fully customizable and stylable. BUG=46478 BUG=46479 Review URL: http://codereview.chromium.org/2849015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50411 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd8
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc64
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.cc81
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.h20
-rw-r--r--chrome/browser/extensions/extension_omnibox_apitest.cc24
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc2
-rw-r--r--chrome/common/extensions/api/extension_api.json68
-rw-r--r--chrome/common/extensions/docs/examples/extensions/chrome_search/background.html95
-rw-r--r--chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json10
-rw-r--r--chrome/common/extensions/docs/experimental.omnibox.html483
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js13
-rw-r--r--chrome/test/data/extensions/api_test/omnibox/test.html18
12 files changed, 809 insertions, 77 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0c14e22..b6fd109 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1065,12 +1065,6 @@ each locale. -->
<message name="IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION" desc="Description for a keyword match.">
(Keyword: <ph name="KEYWORD">$1</ph>)
</message>
- <message name="IDS_AUTOCOMPLETE_EXTENSION_KEYWORD_DESCRIPTION" desc="Description for an extension keyword match.">
- (Keyword: <ph name="KEYWORD">$1</ph>)
- </message>
- <message name="IDS_AUTOCOMPLETE_EXTENSION_KEYWORD_CONTENT" desc="Extra text describing usage of the suggested extension keyword command.">
- <ph name="EXTENSION_COMMAND">$1<ex>send-mail-to</ex></ph> <ph name="EXTENSION_DESCRIPTION">$2<ex>(username@example.com)</ex></ph>
- </message>
<if expr="not pp_ifdef('use_titlecase')">
<message name="IDS_EDIT_SEARCH_ENGINES"
desc="Title of the popup menu item for editing search engines">
@@ -3820,7 +3814,7 @@ Keep your key file in a safe place. You will need it to create new versions of y
Search <ph name="SITE_NAME">$1<ex>google.com</ex></ph>:
</message>
<message name="IDS_OMNIBOX_EXTENSION_KEYWORD_TEXT" desc="Text shown in the search button at the front of the omnibox when the user has selected an extension keyword">
- <ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph> command:
+ <ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph>:
</message>
<!-- TODO(tc): This doesn't handle singular/plural properly. It needs to be reworded. -->
<message name="IDS_OMNIBOX_RECENT_HISTORY" desc="Text shown in the omnibox that shows how many recent matches there are and allows the user to navigate to destinations->history with the selected text.">
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index a0130b7..0da37e8 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -324,22 +324,23 @@ AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
// into keyword templates.
FillInURLAndContents(remaining_input, element, &result);
- // Create popup entry description based on the keyword name.
- int message_id = element->IsExtensionKeyword() ?
- IDS_AUTOCOMPLETE_EXTENSION_KEYWORD_DESCRIPTION :
- IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION;
- result.description.assign(l10n_util::GetStringF(message_id, keyword));
if (supports_replacement)
result.template_url = element;
- static const std::wstring kKeywordDesc(l10n_util::GetString(message_id));
- AutocompleteMatch::ClassifyLocationInString(kKeywordDesc.find(L"%s"),
- prefix_length,
- result.description.length(),
- ACMatchClassification::DIM,
- &result.description_class);
-
result.transition = PageTransition::KEYWORD;
+ // Create popup entry description based on the keyword name.
+ if (!element->IsExtensionKeyword()) {
+ result.description.assign(l10n_util::GetStringF(
+ IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION, keyword));
+ static const std::wstring kKeywordDesc(
+ l10n_util::GetString(IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION));
+ AutocompleteMatch::ClassifyLocationInString(kKeywordDesc.find(L"%s"),
+ prefix_length,
+ result.description.length(),
+ ACMatchClassification::DIM,
+ &result.description_class);
+ }
+
return result;
}
@@ -350,8 +351,9 @@ void KeywordProvider::Observe(NotificationType type,
// AutocompleteProvider::kMaxMatches.
DCHECK(type == NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY);
- int suggest_id = Details<ExtensionOmniboxSuggestions>(details).ptr()->first;
- if (suggest_id != current_input_id_)
+ const ExtensionOmniboxSuggestions& suggestions =
+ *Details<ExtensionOmniboxSuggestions>(details).ptr();
+ if (suggestions.request_id != current_input_id_)
return; // This is an old result. Just ignore.
const AutocompleteInput& input = extension_suggest_last_input_;
@@ -364,16 +366,8 @@ void KeywordProvider::Observe(NotificationType type,
TemplateURLModel* model =
profile_ ? profile_->GetTemplateURLModel() : model_;
- ListValue* suggestions =
- Details<ExtensionOmniboxSuggestions>(details).ptr()->second;
- for (size_t i = 0; i < suggestions->GetSize(); ++i) {
- DictionaryValue* suggestion;
- string16 content, description;
- if (!suggestions->GetDictionary(i, &suggestion) ||
- !suggestion->GetString("content", &content) ||
- !suggestion->GetString("description", &description))
- break;
-
+ for (size_t i = 0; i < suggestions.suggestions.size(); ++i) {
+ const ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i];
// We want to order these suggestions in descending order, so start with
// the relevance of the first result (added synchronously in Start()),
// and subtract 1 for each subsequent suggestion from the extension.
@@ -382,20 +376,14 @@ void KeywordProvider::Observe(NotificationType type,
int first_relevance =
CalculateRelevance(input.type(), true, input.prefer_keyword());
extension_suggest_matches_.push_back(CreateAutocompleteMatch(
- model, keyword, input, keyword.length(), UTF16ToWide(content),
- first_relevance - (i + 1)));
-
- if (!description.empty()) {
- AutocompleteMatch* match = &extension_suggest_matches_.back();
- std::vector<size_t> offsets;
- match->contents.assign(l10n_util::GetStringF(
- IDS_AUTOCOMPLETE_EXTENSION_KEYWORD_CONTENT,
- match->contents, UTF16ToWide(description), &offsets));
- CHECK_EQ(2U, offsets.size()) <<
- "Expected 2 params for IDS_AUTOCOMPLETE_EXTENSION_KEYWORD_CONTENT";
- match->contents_class.push_back(
- ACMatchClassification(offsets[1], ACMatchClassification::NONE));
- }
+ model, keyword, input, keyword.length(),
+ UTF16ToWide(suggestion.content), first_relevance - (i + 1)));
+
+ AutocompleteMatch* match = &extension_suggest_matches_.back();
+ match->contents.assign(UTF16ToWide(suggestion.description));
+ match->contents_class = suggestion.description_styles;
+ match->description.clear();
+ match->description_class.clear();
}
done_ = true;
diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc
index 7b526d7..5c046a3 100644
--- a/chrome/browser/extensions/extension_omnibox_api.cc
+++ b/chrome/browser/extensions/extension_omnibox_api.cc
@@ -16,6 +16,20 @@ const char kOnInputChanged[] = "experimental.omnibox.onInputChanged/";
const char kOnInputEntered[] = "experimental.omnibox.onInputEntered/";
}; // namespace events
+namespace {
+const char kDescriptionStylesOrderError[] =
+ "Suggestion descriptionStyles must be in increasing non-overlapping order.";
+const char kDescriptionStylesLengthError[] =
+ "Suggestion descriptionStyles contains an offset longer than the"
+ " description text";
+
+const wchar_t kSuggestionContent[] = L"content";
+const wchar_t kSuggestionDescription[] = L"description";
+const wchar_t kSuggestionDescriptionStyles[] = L"descriptionStyles";
+const wchar_t kDescriptionStylesType[] = L"type";
+const wchar_t kDescriptionStylesOffset[] = L"offset";
+}; // namespace
+
// static
bool ExtensionOmniboxEventRouter::OnInputChanged(
Profile* profile, const std::string& extension_id,
@@ -51,17 +65,74 @@ void ExtensionOmniboxEventRouter::OnInputEntered(
}
bool OmniboxSendSuggestionsFunction::RunImpl() {
- int request_id;
+ ExtensionOmniboxSuggestions suggestions;
ListValue* suggestions_value;
- EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id));
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &suggestions.request_id));
EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &suggestions_value));
- ExtensionOmniboxSuggestions details(request_id, suggestions_value);
+ suggestions.suggestions.resize(suggestions_value->GetSize());
+ for (size_t i = 0; i < suggestions_value->GetSize(); ++i) {
+ ExtensionOmniboxSuggestion& suggestion = suggestions.suggestions[i];
+ DictionaryValue* suggestion_value;
+ EXTENSION_FUNCTION_VALIDATE(suggestions_value->GetDictionary(
+ i, &suggestion_value));
+ EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetStringAsUTF16(
+ kSuggestionContent, &suggestion.content));
+ EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetStringAsUTF16(
+ kSuggestionDescription, &suggestion.description));
+
+ if (suggestion_value->HasKey(kSuggestionDescriptionStyles)) {
+ ListValue* styles;
+ EXTENSION_FUNCTION_VALIDATE(
+ suggestion_value->GetList(kSuggestionDescriptionStyles, &styles));
+
+ suggestion.description_styles.clear();
+
+ int last_offset = -1;
+ for (size_t j = 0; j < styles->GetSize(); ++j) {
+ DictionaryValue* style;
+ std::string type;
+ int offset;
+ EXTENSION_FUNCTION_VALIDATE(styles->GetDictionary(j, &style));
+ EXTENSION_FUNCTION_VALIDATE(
+ style->GetString(kDescriptionStylesType, &type));
+ EXTENSION_FUNCTION_VALIDATE(
+ style->GetInteger(kDescriptionStylesOffset, &offset));
+
+ int type_class =
+ (type == "none") ? ACMatchClassification::NONE :
+ (type == "match") ? ACMatchClassification::MATCH :
+ (type == "dim") ? ACMatchClassification::DIM : -1;
+ EXTENSION_FUNCTION_VALIDATE(type_class != -1);
+
+ if (offset <= last_offset) {
+ error_ = kDescriptionStylesOrderError;
+ return false;
+ }
+ if (static_cast<size_t>(offset) >= suggestion.description.length()) {
+ error_ = kDescriptionStylesLengthError;
+ return false;
+ }
+
+ suggestion.description_styles.push_back(
+ ACMatchClassification(offset, type_class));
+ last_offset = offset;
+ }
+ }
+
+ // Ensure the styles cover the whole range of text.
+ if (suggestion.description_styles.empty() ||
+ suggestion.description_styles[0].offset != 0) {
+ suggestion.description_styles.insert(
+ suggestion.description_styles.begin(),
+ ACMatchClassification(0, ACMatchClassification::NONE));
+ }
+ }
+
NotificationService::current()->Notify(
NotificationType::EXTENSION_OMNIBOX_SUGGESTIONS_READY,
Source<Profile>(profile_),
- Details<ExtensionOmniboxSuggestions>(&details));
+ Details<ExtensionOmniboxSuggestions>(&suggestions));
return true;
}
-
diff --git a/chrome/browser/extensions/extension_omnibox_api.h b/chrome/browser/extensions/extension_omnibox_api.h
index f77e904..4af9ee5 100644
--- a/chrome/browser/extensions/extension_omnibox_api.h
+++ b/chrome/browser/extensions/extension_omnibox_api.h
@@ -5,10 +5,10 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_OMNIBOX_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_OMNIBOX_API_H_
+#include "base/string16.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/extensions/extension_function.h"
-class ListValue;
-
// Event router class for events related to the omnibox API.
class ExtensionOmniboxEventRouter {
public:
@@ -34,6 +34,20 @@ class OmniboxSendSuggestionsFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION_NAME("experimental.omnibox.sendSuggestions");
};
-typedef std::pair<int, ListValue*> ExtensionOmniboxSuggestions;
+struct ExtensionOmniboxSuggestion {
+ // The text that gets put in the edit box.
+ string16 content;
+
+ // The text that is displayed in the drop down.
+ string16 description;
+
+ // Contains style ranges for the description.
+ ACMatchClassifications description_styles;
+};
+
+struct ExtensionOmniboxSuggestions {
+ int request_id;
+ std::vector<ExtensionOmniboxSuggestion> suggestions;
+};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_OMNIBOX_API_H_
diff --git a/chrome/browser/extensions/extension_omnibox_apitest.cc b/chrome/browser/extensions/extension_omnibox_apitest.cc
index a012d8e..61021b5 100644
--- a/chrome/browser/extensions/extension_omnibox_apitest.cc
+++ b/chrome/browser/extensions/extension_omnibox_apitest.cc
@@ -122,6 +122,30 @@ IN_PROC_BROWSER_TEST_F(OmniboxApiTest, Basic) {
EXPECT_EQ(L"keyword suggestion2", result.match_at(2).fill_into_edit);
EXPECT_EQ(L"keyword suggestion3", result.match_at(3).fill_into_edit);
+ std::wstring description = L"Description with style: <match> [dim], none";
+ EXPECT_EQ(description, result.match_at(1).contents);
+ ASSERT_EQ(5u, result.match_at(1).contents_class.size());
+ EXPECT_EQ(0u,
+ result.match_at(1).contents_class[0].offset);
+ EXPECT_EQ(ACMatchClassification::NONE,
+ result.match_at(1).contents_class[0].style);
+ EXPECT_EQ(description.find('<'),
+ result.match_at(1).contents_class[1].offset);
+ EXPECT_EQ(ACMatchClassification::MATCH,
+ result.match_at(1).contents_class[1].style);
+ EXPECT_EQ(description.find('>'),
+ result.match_at(1).contents_class[2].offset);
+ EXPECT_EQ(ACMatchClassification::NONE,
+ result.match_at(1).contents_class[2].style);
+ EXPECT_EQ(description.find('['),
+ result.match_at(1).contents_class[3].offset);
+ EXPECT_EQ(ACMatchClassification::DIM,
+ result.match_at(1).contents_class[3].style);
+ EXPECT_EQ(description.find(']'),
+ result.match_at(1).contents_class[4].offset);
+ EXPECT_EQ(ACMatchClassification::NONE,
+ result.match_at(1).contents_class[4].style);
+
AutocompleteMatch match = result.match_at(4);
EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
EXPECT_FALSE(match.deletable);
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc
index e937c7f..8f9334f2e 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc
@@ -431,6 +431,8 @@ int AutocompleteResultView::DrawString(
const ResultViewState state = GetState();
if (style & ACMatchClassification::URL)
current_data->color = GetColor(state, URL);
+ else if (style & ACMatchClassification::DIM)
+ current_data->color = GetColor(state, DIMMED_TEXT);
else
current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT);
current_data->pixel_width =
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index 8481a20..b309a55 100644
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -3025,27 +3025,71 @@
},
{
"namespace": "experimental.omnibox",
- "types": [],
+ "types": [
+ {
+ "id": "SuggestResult",
+ "type": "object",
+ "description": "A suggest result.",
+ "properties": {
+ "content": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The text that is put into the URL bar, and that is sent to the extension when the user chooses this entry."
+ },
+ "description": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The text that is displayed in the URL dropdown. Can optionally be stylized by the descriptionStyles parameter."
+ },
+ "descriptionStyles": {
+ "type": "array",
+ "optional": true,
+ "items": {
+ "type": "object",
+ "description": "A style object, created using styleNone, styleMatch, or styleDim. A style applies to the region of text starting at the style's offset, until either the next style or the end of the description.",
+ "properties": {
+ "type": {"type": "string", "enum": ["none", "match", "dim"]},
+ "offset": {"type": "integer"}
+ }
+ }
+ }
+ }
+ }
+ ],
"functions": [
{
"name": "sendSuggestions",
"nodoc": true,
"type": "function",
- "description": "",
+ "description": "A callback passed to the onInputChanged event used for sending suggestions back to the browser.",
"parameters": [
{"type": "integer", "name": "requestId"},
{
"type": "array",
"description": "Array of suggest results",
"items": {
- "type": "object",
- "properties": {
- "content": {"type": "string"},
- "description": {"type": "string"}
- }
+ "$ref": "SuggestResult"
}
}
]
+ },
+ {
+ "name": "styleNone",
+ "type": "function",
+ "description": "Constructor for the descriptionStyles parameter of the suggest callback.",
+ "parameters": [ {"type": "integer", "name": "offset", "minimum": 0} ]
+ },
+ {
+ "name": "styleMatch",
+ "type": "function",
+ "description": "Constructor for the descriptionStyles parameter of the suggest callback. This style designates a region of text matching what the user typed.",
+ "parameters": [ {"type": "integer", "name": "offset", "minimum": 0} ]
+ },
+ {
+ "name": "styleDim",
+ "type": "function",
+ "description": "Constructor for the descriptionStyles parameter of the suggest callback. This style designates a region of dim helper text.",
+ "parameters": [ {"type": "integer", "name": "offset", "minimum": 0} ]
}
],
"events": [
@@ -3059,18 +3103,16 @@
"name": "text"
},
{
- "type": "function",
"name": "suggest",
+ "type": "function",
+ "description": "A callback passed to the onInputChanged event used for sending suggestions back to the browser.",
"parameters": [
+ {"type": "integer", "name": "requestId"},
{
"type": "array",
"description": "Array of suggest results",
"items": {
- "type": "object",
- "properties": {
- "content": {"type": "string"},
- "description": {"type": "string"}
- }
+ "$ref": "SuggestResult"
}
}
]
diff --git a/chrome/common/extensions/docs/examples/extensions/chrome_search/background.html b/chrome/common/extensions/docs/examples/extensions/chrome_search/background.html
new file mode 100644
index 0000000..258ee77
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/chrome_search/background.html
@@ -0,0 +1,95 @@
+<script>
+var currentRequest = null;
+
+chrome.experimental.omnibox.onInputChanged.addListener(
+ function(text, suggest) {
+ if (text == '') {
+ return;
+ }
+
+ if (currentRequest != null) {
+ currentRequest.onreadystatechange = null;
+ currentRequest.abort();
+ currentRequest = null;
+ }
+
+ currentRequest = search(text, function(xml) {
+ var results = [];
+ var entries = xml.getElementsByTagName("entry");
+
+ for (var i = 0, entry; i < 5 && (entry = entries[i]); i++) {
+ var path = entry.getElementsByTagName("file")[0].getAttribute("name");
+ var line =
+ entry.getElementsByTagName("match")[0].getAttribute("lineNumber");
+ var file = path.split("/").pop();
+
+ // Remove HTML tags from description since omnibox cannot display them.
+ var description = entry.getElementsByTagName("content")[0].textContent;
+ description = description.replace(/<\/?.+?>/g, '');
+ description = file + ': ' + description;
+
+ results.push({
+ content: path + '@' + line,
+ description: description,
+ descriptionStyles: [
+ chrome.experimental.omnibox.styleMatch(0),
+ chrome.experimental.omnibox.styleNone(file.length),
+ ],
+ });
+ }
+
+ suggest(results);
+ });
+ }
+);
+
+function search(query, callback) {
+ var url = "http://www.google.com/codesearch/feeds/search?" +
+ "q=package:git.chromium.org/chromium.git+" + query;
+ var req = new XMLHttpRequest();
+ req.open("GET", url, true);
+ req.setRequestHeader("GData-Version", "2");
+ req.onreadystatechange = function() {
+ if (req.readyState == 4) {
+ callback(req.responseXML);
+ }
+ }
+ req.send(null);
+ return req;
+}
+
+function getUrl(path, line) {
+ var url =
+ "http://src.chromium.org/cgi-bin/gitweb.cgi?p=chromium.git;a=blob;hb=HEAD;f=" +
+ path + "#l" + line;
+ return url;
+}
+
+function getEntryUrl(entry) {
+ return getUrl(
+ entry.getElementsByTagName("file")[0].getAttribute("name"),
+ entry.getElementsByTagName("match")[0].getAttribute("lineNumber"));
+ return url;
+}
+
+function navigate(url) {
+ chrome.tabs.getSelected(null, function(tab) {
+ chrome.tabs.update(tab.id, {url: url});
+ });
+}
+
+chrome.experimental.omnibox.onInputEntered.addListener(
+ function(text) {
+ if (text.indexOf('@') > 0) {
+ var chunks = text.split('@');
+ var path = chunks[0];
+ var line = chunks[1];
+ navigate(getUrl(path, line));
+ } else {
+ search(text, function(xml) {
+ navigate(getEntryUrl(xml.getElementsByTagName("entry")[0]));
+ });
+ }
+ }
+);
+</script>
diff --git a/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json b/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
new file mode 100644
index 0000000..ace8a0b
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
@@ -0,0 +1,10 @@
+{
+ "background_page": "background.html",
+ "description": "Add support to the omnibox to search the Chromium source code.",
+ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRx0y4f/CuomPPeGxcVMo7yfYZ1apxD+9e3ItNtPRBi8WMmzG0xhjnqvm03LTfTljbzA1L93s31HkjS5Bd12qM8SSZxOOizsZveK1tdpX0QelikSUaz1wwIyjatoC/jJy7vuuk0j5kPeLkNAhYGJTqN3H/Pqt0lFF1VFX4+fCEvQIDAQAB",
+ "name": "Chromium Search",
+ "omnibox_keyword": "src",
+ "permissions": [ "experimental", "tabs", "http://www.google.com/" ],
+ "update_url": "http://dl.dropbox.com/u/124107/chromium-search/update.xml",
+ "version": "4"
+}
diff --git a/chrome/common/extensions/docs/experimental.omnibox.html b/chrome/common/extensions/docs/experimental.omnibox.html
index 5a52e54..d89360e 100644
--- a/chrome/common/extensions/docs/experimental.omnibox.html
+++ b/chrome/common/extensions/docs/experimental.omnibox.html
@@ -225,6 +225,12 @@
<ol>
<li style="display: none; ">
<a href="#method-anchor">methodName</a>
+ </li><li>
+ <a href="#method-styleDim">styleDim</a>
+ </li><li>
+ <a href="#method-styleMatch">styleMatch</a>
+ </li><li>
+ <a href="#method-styleNone">styleNone</a>
</li>
</ol>
</li>
@@ -238,11 +244,11 @@
</li>
</ol>
</li>
- <li style="display: none; ">
+ <li>
<a href="#types">Types</a>
<ol>
<li>
- <a href="#id-anchor">id</a>
+ <a href="#type-SuggestResult">SuggestResult</a>
</li>
</ol>
</li>
@@ -350,6 +356,297 @@ see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
</div> <!-- /description -->
+ </div><div class="apiItem">
+ <a name="method-styleDim"></a> <!-- method-anchor -->
+ <h4>styleDim</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.omnibox.styleDim</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span>
+ <var><span>offset</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Constructor for the descriptionStyles parameter of the suggest callback. This style designates a region of dim helper text.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>offset</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div style="display: none; ">
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>Type param1, Type param2</span>) <span class="subdued">{...}</span>);</pre>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ </div> <!-- /description -->
+
+ </div><div class="apiItem">
+ <a name="method-styleMatch"></a> <!-- method-anchor -->
+ <h4>styleMatch</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.omnibox.styleMatch</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span>
+ <var><span>offset</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Constructor for the descriptionStyles parameter of the suggest callback. This style designates a region of text matching what the user typed.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>offset</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div style="display: none; ">
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>Type param1, Type param2</span>) <span class="subdued">{...}</span>);</pre>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ </div> <!-- /description -->
+
+ </div><div class="apiItem">
+ <a name="method-styleNone"></a> <!-- method-anchor -->
+ <h4>styleNone</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.omnibox.styleNone</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span>
+ <var><span>offset</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Constructor for the descriptionStyles parameter of the suggest callback.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>offset</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div style="display: none; ">
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>Type param1, Type param2</span>) <span class="subdued">{...}</span>);</pre>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ </div> <!-- /description -->
+
</div> <!-- /apiItem -->
</div> <!-- /apiGroup -->
@@ -445,12 +742,10 @@ see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
</em>
</dt>
- <dd class="todo">
+ <dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd style="display: none; ">
- Description of this parameter from the json schema.
- </dd>
+ <dd>A callback passed to the onInputChanged event used for sending suggestions back to the browser.</dd>
<!-- OBJECT PROPERTIES -->
<dd style="display: none; ">
@@ -536,17 +831,187 @@ see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
</div> <!-- /apiGroup -->
<!-- TYPES -->
- <div class="apiGroup" style="display: none; ">
+ <div class="apiGroup">
<a name="types.sort(sortByName)"></a>
<h3 id="types">Types</h3>
<!-- iterates over all types -->
<div class="apiItem">
- <a></a>
- <h4>type name</h4>
+ <a name="type-SuggestResult"></a>
+ <h4>SuggestResult</h4>
<div>
+ <dt>
+ <var style="display: none; ">paramName</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>A suggest result.</dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>content</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The text that is put into the URL bar, and that is sent to the extension when the user chooses this entry.</dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
</div>
+ </dl>
+ </dd>
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>description</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The text that is displayed in the URL dropdown. Can optionally be stylized by the descriptionStyles parameter.</dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>descriptionStyles</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span>
+ array of <span><span>
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ </span>
+ </span></span>
+ </span>
+ <span style="display: none; ">paramType</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
</div> <!-- /apiItem -->
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index 779a13a..c408f8e 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -654,6 +654,19 @@ var chrome = chrome || {};
return newArgs;
};
+ apiFunctions["experimental.omnibox.styleNone"].handleRequest =
+ function(offset) {
+ return {type: "none", offset: offset};
+ }
+ apiFunctions["experimental.omnibox.styleMatch"].handleRequest =
+ function(offset) {
+ return {type: "match", offset: offset};
+ }
+ apiFunctions["experimental.omnibox.styleDim"].handleRequest =
+ function(offset) {
+ return {type: "dim", offset: offset};
+ }
+
if (chrome.test) {
chrome.test.getApiDefinitions = GetExtensionAPIDefinition;
}
diff --git a/chrome/test/data/extensions/api_test/omnibox/test.html b/chrome/test/data/extensions/api_test/omnibox/test.html
index 6c2c6e0..95cfcc2 100644
--- a/chrome/test/data/extensions/api_test/omnibox/test.html
+++ b/chrome/test/data/extensions/api_test/omnibox/test.html
@@ -5,10 +5,24 @@ if (!chrome.omnibox) {
chrome.omnibox.onInputChanged.addListener(
function(text, suggest) {
+ chrome.test.log("onInputChanged: " + text);
+ if (text != "suggestio")
+ return;
+
+ var desc = 'Description with style: <match> [dim], none';
suggest([
- {content: text + "n1", description: "description1"},
+ {
+ content: text + "n1",
+ description: desc,
+ descriptionStyles: [
+ chrome.omnibox.styleMatch(desc.indexOf('<')),
+ chrome.omnibox.styleNone(desc.indexOf('>')),
+ chrome.omnibox.styleDim(desc.indexOf('[')),
+ chrome.omnibox.styleNone(desc.indexOf(']')),
+ ]
+ },
{content: text + "n2", description: "description2"},
- {content: text + "n3", description: "description3"}
+ {content: text + "n3", description: "description3"},
]);
});