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/. */
6 * This module exports a provider that returns all the available
7 * global actions for a query.
13 } from "resource:///modules/UrlbarUtils.sys.mjs";
17 // Default icon shown for actions if no custom one is provided.
18 const DEFAULT_ICON = "chrome://global/skin/icons/settings.svg";
19 const DYNAMIC_TYPE_NAME = "actions";
21 // The suggestion index of the actions row within the urlbar results.
22 const SUGGESTED_INDEX = 1;
24 const SCOTCH_BONNET_PREF = "scotchBonnet.enableOverride";
25 const ACTIONS_PREF = "secondaryActions.featureGate";
26 const QUICK_ACTIONS_PREF = "suggest.quickactions";
28 // Prefs relating to the onboarding label shown to new users.
29 const TIMES_TO_SHOW_PREF = "quickactions.timesToShowOnboardingLabel";
30 const TIMES_SHOWN_PREF = "quickactions.timesShownOnboardingLabel";
32 ChromeUtils.defineESModuleGetters(lazy, {
33 UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
34 UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
37 import { ActionsProviderQuickActions } from "resource:///modules/ActionsProviderQuickActions.sys.mjs";
38 import { ActionsProviderContextualSearch } from "resource:///modules/ActionsProviderContextualSearch.sys.mjs";
39 import { ActionsProviderTabGroups } from "resource:///modules/ActionsProviderTabGroups.sys.mjs";
41 let globalActionsProviders = [
42 ActionsProviderContextualSearch,
43 ActionsProviderQuickActions,
44 ActionsProviderTabGroups,
48 * A provider that lets the user view all available global actions for a query.
50 class ProviderGlobalActions extends UrlbarProvider {
51 // A Map of the last queried actions.
55 return "UrlbarProviderGlobalActions";
59 return UrlbarUtils.PROVIDER_TYPE.PROFILE;
64 (lazy.UrlbarPrefs.get(SCOTCH_BONNET_PREF) ||
65 lazy.UrlbarPrefs.get(ACTIONS_PREF)) &&
66 lazy.UrlbarPrefs.get(QUICK_ACTIONS_PREF)
70 async startQuery(queryContext, addCallback) {
71 this.#actions.clear();
73 let searchModeEngine = "";
75 for (let provider of globalActionsProviders) {
76 if (provider.isActive(queryContext)) {
77 for (let action of (await provider.queryActions(queryContext)) || []) {
78 if (action.engine && !searchModeEngine) {
79 searchModeEngine = action.engine;
80 } else if (action.engine) {
81 // We only allow one action that provides an engine search mode.
84 this.#actions.set(action.key, action);
89 if (!this.#actions.size) {
93 let showOnboardingLabel =
94 lazy.UrlbarPrefs.get(TIMES_TO_SHOW_PREF) >
95 lazy.UrlbarPrefs.get(TIMES_SHOWN_PREF);
97 let results = [...this.#actions.keys()];
99 let query = results.includes("matched-contextual-search")
101 : queryContext.searchString;
105 dynamicType: DYNAMIC_TYPE_NAME,
106 inputLength: queryContext.searchString.length,
112 if (searchModeEngine) {
113 payload.providesSearchMode = true;
114 payload.engine = searchModeEngine;
117 let result = new lazy.UrlbarResult(
118 UrlbarUtils.RESULT_TYPE.DYNAMIC,
119 UrlbarUtils.RESULT_SOURCE.ACTIONS,
122 result.suggestedIndex = SUGGESTED_INDEX;
123 addCallback(this, result);
126 onSelection(result, element) {
127 let key = element.dataset.action;
128 this.#actions.get(key).onSelection?.(result, element);
131 onEngagement(queryContext, controller, details) {
132 let key = details.element.dataset.action;
133 let options = this.#actions.get(key).onPick(queryContext, controller);
134 if (options?.focusContent) {
135 details.element.ownerGlobal.gBrowser.selectedBrowser.focus();
137 controller.view.close();
140 onSearchSessionEnd(queryContext, controller, details) {
141 let showOnboardingLabel = queryContext.results?.find(
142 r => r.providerName == this.name
143 )?.payload.showOnboardingLabel;
144 if (showOnboardingLabel) {
145 lazy.UrlbarPrefs.set(
147 lazy.UrlbarPrefs.get(TIMES_SHOWN_PREF) + 1
150 for (let provider of globalActionsProviders) {
151 provider.onSearchSessionEnd?.(queryContext, controller, details);
155 getViewTemplate(result) {
156 let children = result.payload.results.map((key, i) => {
157 let action = this.#actions.get(key);
159 if (action.dataset?.style) {
161 for (let [prop, val] of Object.entries(action.dataset.style)) {
162 style += `${prop}: ${val};`;
168 classList: ["urlbarView-action-btn"],
171 inputLength: result.payload.inputLength,
179 src: action.icon || DEFAULT_ICON,
190 if (result.payload.showOnboardingLabel) {
192 name: "press-tab-label",
194 classList: ["urlbarView-press-tab-label"],
201 getViewUpdate(result) {
203 if (result.payload.showOnboardingLabel) {
204 viewUpdate["press-tab-label"] = {
205 l10n: { id: "press-tab-label", cacheable: true },
208 result.payload.results.forEach((key, i) => {
209 let action = this.#actions.get(key);
210 viewUpdate[`label-${i}`] = {
211 l10n: { id: action.l10nId, args: action.l10nArgs, cacheable: true },
218 export var UrlbarProviderGlobalActions = new ProviderGlobalActions();