1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 } from "resource:///modules/ActionsProvider.sys.mjs";
11 ChromeUtils.defineESModuleGetters(lazy, {
12 QuickActionsLoaderDefault:
13 "resource:///modules/QuickActionsLoaderDefault.sys.mjs",
14 UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
17 // These prefs are relative to the `browser.urlbar` branch.
18 const ENABLED_PREF = "suggest.quickactions";
19 const MATCH_IN_PHRASE_PREF = "quickactions.matchInPhrase";
20 const MIN_SEARCH_PREF = "quickactions.minimumSearchString";
23 * A provider that matches the urlbar input to built in actions.
25 class ProviderQuickActions extends ActionsProvider {
27 return "ActionsProviderQuickActions";
30 isActive(queryContext) {
32 lazy.UrlbarPrefs.get(ENABLED_PREF) &&
33 !queryContext.searchMode &&
34 queryContext.trimmedSearchString.length < 50 &&
35 queryContext.trimmedSearchString.length >=
36 lazy.UrlbarPrefs.get(MIN_SEARCH_PREF)
40 async queryActions(queryContext) {
41 let input = queryContext.trimmedLowerCaseSearchString;
42 let results = await this.getActions(input);
44 if (lazy.UrlbarPrefs.get(MATCH_IN_PHRASE_PREF)) {
45 for (let [keyword, key] of this.#keywords) {
46 if (input.includes(keyword)) {
52 // Remove invisible actions.
53 results = results.filter(key => {
54 const action = this.#actions.get(key);
55 return action.isVisible?.() ?? true;
58 if (!results.length) {
62 return results.map(key => {
63 let action = this.#actions.get(key);
64 return new ActionsResult({
70 inputLength: queryContext.trimmedSearchString.length,
72 onPick: action.onPick,
77 async getActions(prefix) {
78 await lazy.QuickActionsLoaderDefault.ensureLoaded();
79 return [...(this.#prefixes.get(prefix) ?? [])];
83 return this.#actions.get(key);
86 pickAction(_queryContext, _controller, element) {
87 let action = element.dataset.action;
88 let inputLength = Math.min(element.dataset.inputLength, 10);
89 Glean.urlbarQuickaction.picked[`${action}-${inputLength}`].add(1);
90 let options = this.#actions.get(action).onPick();
91 if (options?.focusContent) {
92 element.ownerGlobal.gBrowser.selectedBrowser.focus();
97 * Adds a new QuickAction.
99 * @param {string} key A key to identify this action.
100 * @param {string} definition An object that describes the action.
102 addAction(key, definition) {
103 this.#actions.set(key, definition);
104 definition.commands.forEach(cmd => this.#keywords.set(cmd, key));
105 this.#loopOverPrefixes(definition.commands, prefix => {
106 let result = this.#prefixes.get(prefix);
108 if (!result.includes(key)) {
114 this.#prefixes.set(prefix, result);
121 * @param {string} key A key to identify this action.
124 let definition = this.#actions.get(key);
125 this.#actions.delete(key);
126 definition.commands.forEach(cmd => this.#keywords.delete(cmd));
127 this.#loopOverPrefixes(definition.commands, prefix => {
128 let result = this.#prefixes.get(prefix);
130 result = result.filter(val => val != key);
132 this.#prefixes.set(prefix, result);
136 // A map from keywords to an action.
137 #keywords = new Map();
139 // A map of all prefixes to an array of actions.
140 #prefixes = new Map();
142 // The actions that have been added.
143 #actions = new Map();
145 #loopOverPrefixes(commands, fun) {
146 for (const command of commands) {
147 // Loop over all the prefixes of the word, ie
148 // "", "w", "wo", "wor", stopping just before the full
149 // word itself which will be matched by the whole
151 for (let i = 1; i <= command.length; i++) {
152 let prefix = command.substring(0, command.length - i);
159 export var ActionsProviderQuickActions = new ProviderQuickActions();