Bug 1176107 - Search suggestions in awesomebar: update input and perform search with selected suggestion. r=mak

This commit is contained in:
Drew Willcoxon 2015-06-27 22:14:45 -07:00
Родитель bd3d49eb70
Коммит fd34e282bf
4 изменённых файлов: 136 добавлений и 65 удалений

Просмотреть файл

@ -330,7 +330,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
url = action.params.url;
} else if (action.type == "searchengine") {
let engine = Services.search.getEngineByName(action.params.engineName);
let submission = engine.getSubmission(action.params.searchQuery);
let query = action.params.searchSuggestion ||
action.params.searchQuery;
let submission = engine.getSubmission(query);
url = submission.uri.spec;
postData = submission.postData;
@ -790,12 +792,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
try {
action.params = JSON.parse(params);
if (action.params.input) {
action.params.input = decodeURIComponent(action.params.input);
}
if (action.params.searchQuery) {
action.params.searchQuery = decodeURIComponent(action.params.searchQuery);
}
} catch (e) {
// If this failed, we assume that params is not a JSON object, and
// is instead just a flat string. This will happen when
@ -804,6 +800,17 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
action.params = {
url: params,
}
return action;
}
for (let key of [
"input",
"searchQuery",
"searchSuggestion",
]) {
if (action.params[key]) {
action.params[key] = decodeURIComponent(action.params[key]);
}
}
return action;
@ -1577,7 +1584,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
}
case "searchengine": {
let engine = Services.search.getEngineByName(action.params.engineName);
let submission = engine.getSubmission(action.params.searchQuery);
let query = action.params.searchSuggestion ||
action.params.searchQuery;
let submission = engine.getSubmission(query);
url = submission.uri.spec;
options.postData = submission.postData;
break;

Просмотреть файл

@ -1038,7 +1038,7 @@ Search.prototype = {
_addSearchEngineMatch(match, query, suggestion) {
let actionURLParams = {
engineName: match.engineName,
input: this._originalSearchString,
input: suggestion || this._originalSearchString,
searchQuery: query,
};
if (suggestion)
@ -1190,8 +1190,9 @@ Search.prototype = {
if (this._searchSuggestionController) {
let [match, suggestion] = this._searchSuggestionController.consume();
if (suggestion) {
this._addSearchEngineMatch(match, this._originalSearchString,
suggestion);
// Don't include the restrict token, if present.
let searchString = this._searchTokens.join(" ");
this._addSearchEngineMatch(match, searchString, suggestion);
return true;
}
}

Просмотреть файл

@ -5,12 +5,21 @@ const SERVER_PORT = 9000;
const SUGGEST_PREF = "browser.urlbar.suggest.searches";
const SUGGEST_RESTRICT_TOKEN = "$";
// Set this to some other function to change how the server converts search
// strings into suggestions.
let suggestionsFromSearchString = searchStr => {
let suffixes = ["foo", "bar"];
return suffixes.map(s => searchStr + " " + s);
};
let suggestionsFn;
let previousSuggestionsFn;
function setSuggestionsFn(fn) {
previousSuggestionsFn = suggestionsFn;
suggestionsFn = fn;
}
function* cleanUpSuggestions() {
yield cleanup();
if (previousSuggestionsFn) {
suggestionsFn = previousSuggestionsFn;
previousSuggestionsFn = null;
}
}
add_task(function* setUp() {
// Set up a server that provides some suggestions by appending strings onto
@ -20,19 +29,21 @@ add_task(function* setUp() {
// URL query params are x-www-form-urlencoded, which converts spaces into
// plus signs, so un-convert any plus signs back to spaces.
let searchStr = decodeURIComponent(req.queryString.replace(/\+/g, " "));
let suggestions = suggestionsFromSearchString(searchStr);
let suggestions = suggestionsFn(searchStr);
let data = [searchStr, suggestions];
resp.setHeader("Content-Type", "application/json", false);
resp.write(JSON.stringify(data));
});
setSuggestionsFn(searchStr => {
let suffixes = ["foo", "bar"];
return suffixes.map(s => searchStr + " " + s);
});
// Install the test engine.
let oldCurrentEngine = Services.search.currentEngine;
do_register_cleanup(() => Services.search.currentEngine = oldCurrentEngine);
let engine = yield addTestEngine(ENGINE_NAME, server);
Services.search.currentEngine = engine;
yield cleanup();
});
add_task(function* disabled() {
@ -41,20 +52,19 @@ add_task(function* disabled() {
search: "hello",
matches: [],
});
yield cleanup();
yield cleanUpSuggestions();
});
add_task(function* singleWordQuery() {
Services.prefs.setBoolPref(SUGGEST_PREF, true);
let searchStr = "hello";
yield check_autocomplete({
search: searchStr,
search: "hello",
matches: [{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello foo",
searchQuery: "hello",
searchSuggestion: "hello foo",
}),
title: ENGINE_NAME,
@ -63,8 +73,8 @@ add_task(function* singleWordQuery() {
}, {
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello bar",
searchQuery: "hello",
searchSuggestion: "hello bar",
}),
title: ENGINE_NAME,
@ -73,20 +83,19 @@ add_task(function* singleWordQuery() {
}],
});
yield cleanup();
yield cleanUpSuggestions();
});
add_task(function* multiWordQuery() {
Services.prefs.setBoolPref(SUGGEST_PREF, true);
let searchStr = "hello world";
yield check_autocomplete({
search: searchStr,
search: "hello world",
matches: [{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello world foo",
searchQuery: "hello world",
searchSuggestion: "hello world foo",
}),
title: ENGINE_NAME,
@ -95,8 +104,8 @@ add_task(function* multiWordQuery() {
}, {
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello world bar",
searchQuery: "hello world",
searchSuggestion: "hello world bar",
}),
title: ENGINE_NAME,
@ -105,26 +114,24 @@ add_task(function* multiWordQuery() {
}],
});
yield cleanup();
yield cleanUpSuggestions();
});
add_task(function* suffixMatch() {
Services.prefs.setBoolPref(SUGGEST_PREF, true);
let oldFn = suggestionsFromSearchString;
suggestionsFromSearchString = searchStr => {
setSuggestionsFn(searchStr => {
let prefixes = ["baz", "quux"];
return prefixes.map(p => p + " " + searchStr);
};
});
let searchStr = "hello";
yield check_autocomplete({
search: searchStr,
search: "hello",
matches: [{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "baz hello",
searchQuery: "hello",
searchSuggestion: "baz hello",
}),
title: ENGINE_NAME,
@ -133,8 +140,8 @@ add_task(function* suffixMatch() {
}, {
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "quux hello",
searchQuery: "hello",
searchSuggestion: "quux hello",
}),
title: ENGINE_NAME,
@ -143,8 +150,42 @@ add_task(function* suffixMatch() {
}],
});
suggestionsFromSearchString = oldFn;
yield cleanup();
yield cleanUpSuggestions();
});
add_task(function* queryIsNotASubstring() {
Services.prefs.setBoolPref(SUGGEST_PREF, true);
setSuggestionsFn(searchStr => {
return ["aaa", "bbb"];
});
yield check_autocomplete({
search: "hello",
matches: [{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: "aaa",
searchQuery: "hello",
searchSuggestion: "aaa",
}),
title: ENGINE_NAME,
style: ["action", "searchengine"],
icon: "",
}, {
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: "bbb",
searchQuery: "hello",
searchSuggestion: "bbb",
}),
title: ENGINE_NAME,
style: ["action", "searchengine"],
icon: "",
}],
});
yield cleanUpSuggestions();
});
add_task(function* restrictToken() {
@ -171,9 +212,8 @@ add_task(function* restrictToken() {
// Do an unrestricted search to make sure everything appears in it, including
// the visit and bookmark.
let searchStr = "hello";
yield check_autocomplete({
search: searchStr,
search: "hello",
matches: [
{
uri: NetUtil.newURI("http://example.com/hello-visit"),
@ -187,8 +227,8 @@ add_task(function* restrictToken() {
{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello foo",
searchQuery: "hello",
searchSuggestion: "hello foo",
}),
title: ENGINE_NAME,
@ -198,8 +238,8 @@ add_task(function* restrictToken() {
{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello bar",
searchQuery: "hello",
searchSuggestion: "hello bar",
}),
title: ENGINE_NAME,
@ -210,15 +250,14 @@ add_task(function* restrictToken() {
});
// Now do a restricted search to make sure only suggestions appear.
searchStr = SUGGEST_RESTRICT_TOKEN + " hello";
yield check_autocomplete({
search: searchStr,
search: SUGGEST_RESTRICT_TOKEN + " hello",
matches: [
{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello foo",
searchQuery: "hello",
searchSuggestion: "hello foo",
}),
title: ENGINE_NAME,
@ -228,8 +267,8 @@ add_task(function* restrictToken() {
{
uri: makeActionURI(("searchengine"), {
engineName: ENGINE_NAME,
input: searchStr,
searchQuery: searchStr,
input: "hello bar",
searchQuery: "hello",
searchSuggestion: "hello bar",
}),
title: ENGINE_NAME,
@ -239,5 +278,5 @@ add_task(function* restrictToken() {
],
});
yield cleanup();
yield cleanUpSuggestions();
});

Просмотреть файл

@ -1651,14 +1651,36 @@ extends="chrome://global/content/bindings/popup.xml#popup">
let engineStr = "- " +
this._stringBundle.formatStringFromName("searchWithEngine",
[engineName], 1);
let suggestedPart = "";
// Make the title by generating an array of pairs and its
// corresponding interpolation string (e.g., "%1$S") to pass to
// _generateEmphasisPairs.
let pairs;
if (searchSuggestion) {
suggestedPart = searchSuggestion.substr(searchQuery.length);
// Check if the search query appears in the suggestion. It may
// not. If it does, then emphasize the query in the suggestion
// and otherwise just include the suggestion without emphasis.
let idx = searchSuggestion.indexOf(searchQuery);
if (idx >= 0) {
pairs = [
[searchSuggestion.substring(0, idx), ""],
[searchQuery, "match"],
[searchSuggestion.substring(idx + searchQuery.length), ""],
];
} else {
pairs = [
[searchSuggestion, ""],
];
}
} else {
pairs = [
[searchQuery, ""],
];
}
title = this._generateEmphasisPairs(`%1$S${suggestedPart} %2$S`, [
[searchQuery, "match"],
[engineStr, "selected"],
]);
pairs.push([engineStr, "selected"]);
let interpStr = pairs.map((pair, i) => `%${i + 1}$S`).join("");
title = this._generateEmphasisPairs(interpStr, pairs);
// If this is a default search match, we remove the image so we
// can style it ourselves with a generic search icon.
// We don't do this when matching an aliased search engine,