summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/UrlbarProviderQuickActions.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/UrlbarProviderQuickActions.sys.mjs')
-rw-r--r--browser/components/urlbar/UrlbarProviderQuickActions.sys.mjs357
1 files changed, 0 insertions, 357 deletions
diff --git a/browser/components/urlbar/UrlbarProviderQuickActions.sys.mjs b/browser/components/urlbar/UrlbarProviderQuickActions.sys.mjs
deleted file mode 100644
index 29370cbaaf..0000000000
--- a/browser/components/urlbar/UrlbarProviderQuickActions.sys.mjs
+++ /dev/null
@@ -1,357 +0,0 @@
-/* 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/. */
-
-import {
- UrlbarProvider,
- UrlbarUtils,
-} from "resource:///modules/UrlbarUtils.sys.mjs";
-
-const lazy = {};
-ChromeUtils.defineESModuleGetters(lazy, {
- QuickActionsLoaderDefault:
- "resource:///modules/QuickActionsLoaderDefault.sys.mjs",
- UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
- UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
-});
-
-// These prefs are relative to the `browser.urlbar` branch.
-const ENABLED_PREF = "quickactions.enabled";
-const SUGGEST_PREF = "suggest.quickactions";
-const MATCH_IN_PHRASE_PREF = "quickactions.matchInPhrase";
-const MIN_SEARCH_PREF = "quickactions.minimumSearchString";
-const DYNAMIC_TYPE_NAME = "quickactions";
-
-// When the urlbar is first focused and no search term has been
-// entered we show a limited number of results.
-const ACTIONS_SHOWN_FOCUS = 4;
-
-// Default icon shown for actions if no custom one is provided.
-const DEFAULT_ICON = "chrome://global/skin/icons/settings.svg";
-
-// The suggestion index of the actions row within the urlbar results.
-const SUGGESTED_INDEX = 1;
-
-/**
- * A provider that returns a suggested url to the user based on what
- * they have currently typed so they can navigate directly.
- */
-class ProviderQuickActions extends UrlbarProvider {
- constructor() {
- super();
- lazy.UrlbarResult.addDynamicResultType(DYNAMIC_TYPE_NAME);
- }
-
- /**
- * Returns the name of this provider.
- *
- * @returns {string} the name of this provider.
- */
- get name() {
- return DYNAMIC_TYPE_NAME;
- }
-
- /**
- * The type of the provider.
- *
- * @returns {UrlbarUtils.PROVIDER_TYPE}
- */
- get type() {
- return UrlbarUtils.PROVIDER_TYPE.PROFILE;
- }
-
- getPriority(context) {
- if (!context.searchString) {
- return 1;
- }
- return 0;
- }
-
- /**
- * Whether this provider should be invoked for the given context.
- * If this method returns false, the providers manager won't start a query
- * with this provider, to save on resources.
- *
- * @param {UrlbarQueryContext} queryContext The query context object
- * @returns {boolean} Whether this provider should be invoked for the search.
- */
- isActive(queryContext) {
- return (
- queryContext.trimmedSearchString.length < 50 &&
- lazy.UrlbarPrefs.get(ENABLED_PREF) &&
- ((lazy.UrlbarPrefs.get(SUGGEST_PREF) && !queryContext.searchMode) ||
- queryContext.searchMode?.source == UrlbarUtils.RESULT_SOURCE.ACTIONS)
- );
- }
-
- /**
- * Starts querying. Extended classes should return a Promise resolved when the
- * provider is done searching AND returning results.
- *
- * @param {UrlbarQueryContext} queryContext The query context object
- * @param {Function} addCallback Callback invoked by the provider to add a new
- * result. A UrlbarResult should be passed to it.
- * @returns {Promise}
- */
- async startQuery(queryContext, addCallback) {
- await lazy.QuickActionsLoaderDefault.ensureLoaded();
- let input = queryContext.trimmedLowerCaseSearchString;
-
- if (
- !queryContext.searchMode &&
- input.length < lazy.UrlbarPrefs.get(MIN_SEARCH_PREF)
- ) {
- return;
- }
-
- let results = [...(this.#prefixes.get(input) ?? [])];
-
- if (lazy.UrlbarPrefs.get(MATCH_IN_PHRASE_PREF)) {
- for (let [keyword, key] of this.#keywords) {
- if (input.includes(keyword)) {
- results.push(key);
- }
- }
- }
- // Ensure results are unique.
- results = [...new Set(results)];
-
- // Remove invisible actions.
- results = results.filter(key => {
- const action = this.#actions.get(key);
- return !action.isVisible || action.isVisible();
- });
-
- if (!results?.length) {
- return;
- }
-
- // If all actions are inactive, don't show anything.
- if (
- results.every(key => {
- const action = this.#actions.get(key);
- return action.isActive && !action.isActive();
- })
- ) {
- return;
- }
-
- // If we are in the Actions searchMode then we want to show all the actions
- // but not when we are in the normal url mode on first focus.
- if (
- results.length > ACTIONS_SHOWN_FOCUS &&
- !input &&
- !queryContext.searchMode
- ) {
- results.length = ACTIONS_SHOWN_FOCUS;
- }
-
- const result = new lazy.UrlbarResult(
- UrlbarUtils.RESULT_TYPE.DYNAMIC,
- UrlbarUtils.RESULT_SOURCE.ACTIONS,
- {
- results: results.map(key => ({ key })),
- dynamicType: DYNAMIC_TYPE_NAME,
- inputLength: input.length,
- inQuickActionsSearchMode:
- queryContext.searchMode?.source == UrlbarUtils.RESULT_SOURCE.ACTIONS,
- }
- );
- result.suggestedIndex = SUGGESTED_INDEX;
- addCallback(this, result);
- this.#resultFromLastQuery = result;
- }
-
- getViewTemplate(result) {
- return {
- children: [
- {
- name: "buttons",
- tag: "div",
- attributes: {
- "data-is-quickactions-searchmode":
- result.payload.inQuickActionsSearchMode,
- },
- children: result.payload.results.map(({ key }, i) => {
- let action = this.#actions.get(key);
- let inActive = "isActive" in action && !action.isActive();
- return {
- name: `button-${i}`,
- tag: "span",
- attributes: {
- "data-key": key,
- "data-input-length": result.payload.inputLength,
- class: "urlbarView-quickaction-button",
- role: inActive ? "" : "button",
- disabled: inActive,
- },
- children: [
- {
- name: `icon-${i}`,
- tag: "div",
- attributes: { class: "urlbarView-favicon" },
- children: [
- {
- name: `image-${i}`,
- tag: "img",
- attributes: {
- class: "urlbarView-favicon-img",
- src: action.icon || DEFAULT_ICON,
- },
- },
- ],
- },
- {
- name: `label-${i}`,
- tag: "span",
- attributes: { class: "urlbarView-label" },
- },
- ],
- };
- }),
- },
- ],
- };
- }
-
- getViewUpdate(result) {
- let viewUpdate = {};
- result.payload.results.forEach(({ key }, i) => {
- let action = this.#actions.get(key);
- viewUpdate[`label-${i}`] = {
- l10n: { id: action.label, cacheable: true },
- };
- });
- return viewUpdate;
- }
-
- #pickResult(result, itemPicked) {
- let { key, inputLength } = itemPicked.dataset;
- // We clamp the input length to limit the number of keys to
- // the number of actions * 10.
- inputLength = Math.min(inputLength, 10);
- Services.telemetry.keyedScalarAdd(
- `quickaction.picked`,
- `${key}-${inputLength}`,
- 1
- );
- let options = this.#actions.get(itemPicked.dataset.key).onPick() ?? {};
- if (options.focusContent) {
- itemPicked.ownerGlobal.gBrowser.selectedBrowser.focus();
- }
- }
-
- onLegacyEngagement(state, queryContext, details, controller) {
- // Ignore engagements on other results that didn't end the session.
- if (details.result?.providerName != this.name && details.isSessionOngoing) {
- return;
- }
-
- if (state == "engagement" && queryContext) {
- // Get the result that's visible in the view. `details.result` is the
- // engaged result, if any; if it's from this provider, then that's the
- // visible result. Otherwise fall back to #getVisibleResultFromLastQuery.
- let { result } = details;
- if (result?.providerName != this.name) {
- result = this.#getVisibleResultFromLastQuery(controller.view);
- }
-
- result?.payload.results.forEach(({ key }) => {
- Services.telemetry.keyedScalarAdd(
- `quickaction.impression`,
- `${key}-${queryContext.trimmedSearchString.length}`,
- 1
- );
- });
- }
-
- // Handle picks.
- if (details.result?.providerName == this.name) {
- this.#pickResult(details.result, details.element);
- }
-
- this.#resultFromLastQuery = null;
- }
-
- /**
- * Adds a new QuickAction.
- *
- * @param {string} key A key to identify this action.
- * @param {string} definition An object that describes the action.
- */
- addAction(key, definition) {
- this.#actions.set(key, definition);
- definition.commands.forEach(cmd => this.#keywords.set(cmd, key));
- this.#loopOverPrefixes(definition.commands, prefix => {
- let result = this.#prefixes.get(prefix);
- if (result) {
- if (!result.includes(key)) {
- result.push(key);
- }
- } else {
- result = [key];
- }
- this.#prefixes.set(prefix, result);
- });
- }
-
- /**
- * Removes an action.
- *
- * @param {string} key A key to identify this action.
- */
- removeAction(key) {
- let definition = this.#actions.get(key);
- this.#actions.delete(key);
- definition.commands.forEach(cmd => this.#keywords.delete(cmd));
- this.#loopOverPrefixes(definition.commands, prefix => {
- let result = this.#prefixes.get(prefix);
- if (result) {
- result = result.filter(val => val != key);
- }
- this.#prefixes.set(prefix, result);
- });
- }
-
- // A map from keywords to an action.
- #keywords = new Map();
-
- // A map of all prefixes to an array of actions.
- #prefixes = new Map();
-
- // The actions that have been added.
- #actions = new Map();
-
- // The result we added during the most recent query.
- #resultFromLastQuery = null;
-
- #loopOverPrefixes(commands, fun) {
- for (const command of commands) {
- // Loop over all the prefixes of the word, ie
- // "", "w", "wo", "wor", stopping just before the full
- // word itself which will be matched by the whole
- // phrase matching.
- for (let i = 1; i <= command.length; i++) {
- let prefix = command.substring(0, command.length - i);
- fun(prefix);
- }
- }
- }
-
- #getVisibleResultFromLastQuery(view) {
- let result = this.#resultFromLastQuery;
-
- if (
- result?.rowIndex >= 0 &&
- view?.visibleResults?.[result.rowIndex] == result
- ) {
- // The result was visible.
- return result;
- }
-
- // Find a visible result.
- return view?.visibleResults?.find(r => r.providerName == this.name);
- }
-}
-
-export var UrlbarProviderQuickActions = new ProviderQuickActions();