Files
tubestation/browser/components/urlbar/UrlbarProviderRestrictKeywordsAutofill.sys.mjs
mcheang f8ea71ac19 Bug 1933003 - Add support to use restricted search keywords in both en-US and the localized language. r=mak,fluent-reviewers,settings-reviewers,urlbar-reviewers,mossop
This patch adds English restrict keyword strings to the enUS-searchFeature.ftl
file. The restrictKeywords providers return an array of keywords for their
l10nRestrictKeywords property. The first is the localized keyword, and the
second is the English keyword. If the user is in the English locale, the
providers return an array with one element: the English keyword.

Differential Revision: https://phabricator.services.mozilla.com/D230009
2024-12-24 22:40:09 +00:00

217 lines
5.9 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This module exports a provider that offers restrict keywords autofill for
* search mode.
*/
import {
UrlbarProvider,
UrlbarUtils,
} from "resource:///modules/UrlbarUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
});
const RESTRICT_KEYWORDS_FEATURE_GATE = "searchRestrictKeywords.featureGate";
/**
* Class used to create the provider.
*/
class ProviderRestrictKeywordsAutofill extends UrlbarProvider {
#autofillData;
#lowerCaseTokenToKeywords;
constructor() {
super();
}
get name() {
return "RestrictKeywordsAutofill";
}
get type() {
return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
}
getPriority() {
return 1;
}
async #getLowerCaseTokenToKeywords() {
let tokenToKeywords = await lazy.UrlbarTokenizer.getL10nRestrictKeywords();
this.#lowerCaseTokenToKeywords = new Map(
[...tokenToKeywords].map(([token, keywords]) => [
token,
keywords.map(keyword => keyword.toLowerCase()),
])
);
return this.#lowerCaseTokenToKeywords;
}
async #getKeywordAliases() {
return Array.from(await this.#lowerCaseTokenToKeywords.values())
.flat()
.map(keyword => "@" + keyword);
}
async isActive(queryContext) {
if (!lazy.UrlbarPrefs.getScotchBonnetPref(RESTRICT_KEYWORDS_FEATURE_GATE)) {
return false;
}
this.#autofillData = null;
if (
queryContext.searchMode ||
queryContext.tokens.length != 1 ||
queryContext.searchString.length == 1 ||
queryContext.restrictSource ||
!queryContext.searchString.startsWith("@")
) {
return false;
}
// Returns partial autofill result when the user types
// @h, @hi, @hist, etc.
if (lazy.UrlbarPrefs.get("autoFill") && queryContext.allowAutofill) {
let instance = this.queryInstance;
let result = await this.#getAutofillResult(queryContext);
if (result && instance == this.queryInstance) {
this.#autofillData = { result, instance };
return true;
}
}
// Returns full autofill result when user types keyword with space to
// enter seach mode. Example, "@history ".
let keywordAliases = await this.#getKeywordAliases();
if (
keywordAliases.some(keyword =>
keyword.startsWith(queryContext.trimmedLowerCaseSearchString)
)
) {
return true;
}
return false;
}
async startQuery(queryContext, addCallback) {
if (
this.#autofillData &&
this.#autofillData.instance == this.queryInstance
) {
addCallback(this, this.#autofillData.result);
return;
}
let instance = this.queryInstance;
let typedKeyword = queryContext.lowerCaseSearchString;
let typedKeywordTrimmed =
queryContext.trimmedLowerCaseSearchString.substring(1);
let tokenToKeywords = await this.#getLowerCaseTokenToKeywords();
if (instance != this.queryInstance) {
return;
}
let restrictSymbol;
let aliasKeyword;
for (let [token, keywords] of tokenToKeywords) {
if (keywords.includes(typedKeywordTrimmed)) {
restrictSymbol = token;
aliasKeyword = "@" + typedKeywordTrimmed + " ";
break;
}
}
if (restrictSymbol && typedKeyword == aliasKeyword) {
let result = new lazy.UrlbarResult(
UrlbarUtils.RESULT_TYPE.RESTRICT,
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
...lazy.UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
keyword: restrictSymbol,
providesSearchMode: false,
})
);
result.heuristic = true;
addCallback(this, result);
}
this.#autofillData = null;
}
cancelQuery() {
if (this.#autofillData?.instance == this.queryInstance) {
this.#autofillData = null;
}
}
async #getAutofillResult(queryContext) {
let tokenToKeywords = await this.#getLowerCaseTokenToKeywords();
let { lowerCaseSearchString } = queryContext;
for (let [token, l10nRestrictKeywords] of tokenToKeywords.entries()) {
let keywords = [...l10nRestrictKeywords].map(keyword => `@${keyword}`);
let autofillKeyword = keywords.find(keyword =>
keyword.startsWith(lowerCaseSearchString)
);
// found the keyword
if (autofillKeyword) {
// Add an autofill result. Append a space so the user can hit enter
// or the right arrow key and immediately start typing their query.
let keywordPreservingUserCase =
queryContext.searchString +
autofillKeyword.substr(queryContext.searchString.length);
let value = keywordPreservingUserCase + " ";
let icon = UrlbarUtils.LOCAL_SEARCH_MODES.find(
mode => mode.restrict == token
)?.icon;
let result = new lazy.UrlbarResult(
UrlbarUtils.RESULT_TYPE.RESTRICT,
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
...lazy.UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
icon,
keyword: token,
l10nRestrictKeywords: [
l10nRestrictKeywords,
UrlbarUtils.HIGHLIGHT.TYPED,
],
autofillKeyword: [
keywordPreservingUserCase,
UrlbarUtils.HIGHLIGHT.TYPED,
],
providesSearchMode: true,
})
);
result.autofill = {
value,
selectionStart: queryContext.searchString.length,
selectionEnd: value.length,
};
return result;
}
}
return null;
}
}
export var UrlbarProviderRestrictKeywordsAutofill =
new ProviderRestrictKeywordsAutofill();