diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /browser/components/urlbar/UrlbarProviderOmnibox.sys.mjs | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | browser/components/urlbar/UrlbarProviderOmnibox.sys.mjs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/browser/components/urlbar/UrlbarProviderOmnibox.sys.mjs b/browser/components/urlbar/UrlbarProviderOmnibox.sys.mjs new file mode 100644 index 0000000000..00727c132d --- /dev/null +++ b/browser/components/urlbar/UrlbarProviderOmnibox.sys.mjs @@ -0,0 +1,196 @@ +/* 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 class that is used for providers created by + * extensions using the `omnibox` API. + */ + +import { + SkippableTimer, + UrlbarProvider, + UrlbarUtils, +} from "resource:///modules/UrlbarUtils.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + ExtensionSearchHandler: + "resource://gre/modules/ExtensionSearchHandler.sys.mjs", + + UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", + UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs", +}); + +/** + * This provider handles results returned by extensions using the WebExtensions + * Omnibox API. If the user types a registered keyword, we send subsequent + * keystrokes to the extension. + */ +class ProviderOmnibox extends UrlbarProvider { + constructor() { + super(); + } + + /** + * Returns the name of this provider. + * + * @returns {string} the name of this provider. + */ + get name() { + return "Omnibox"; + } + + /** + * Returns the type of this provider. + * + * @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.* + */ + get type() { + return UrlbarUtils.PROVIDER_TYPE.HEURISTIC; + } + + /** + * Whether the 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) { + if ( + queryContext.tokens[0] && + queryContext.tokens[0].value.length && + lazy.ExtensionSearchHandler.isKeywordRegistered( + queryContext.tokens[0].value + ) && + UrlbarUtils.substringAfter( + queryContext.searchString, + queryContext.tokens[0].value + ) + ) { + return true; + } + + // We need to handle cancellation here since isActive is called once per + // query but cancelQuery can be called multiple times per query. + // The frequent cancels can cause the extension's state to drift from the + // provider's state. + if (lazy.ExtensionSearchHandler.hasActiveInputSession()) { + lazy.ExtensionSearchHandler.handleInputCancelled(); + } + + return false; + } + + /** + * Gets the provider's priority. + * + * @param {UrlbarQueryContext} queryContext + * The query context object. + * @returns {number} + * The provider's priority for the given query. + */ + getPriority(queryContext) { + return 0; + } + + /** + * This method is called by the providers manager when a query starts to fetch + * each extension provider's results. It fires the resultsRequested event. + * + * @param {UrlbarQueryContext} queryContext + * The query context object. + * @param {Function} addCallback + * The callback invoked by this method to add each result. + */ + async startQuery(queryContext, addCallback) { + let instance = this.queryInstance; + + // Fetch heuristic result. + let keyword = queryContext.tokens[0].value; + let description = lazy.ExtensionSearchHandler.getDescription(keyword); + let heuristicResult = new lazy.UrlbarResult( + UrlbarUtils.RESULT_TYPE.OMNIBOX, + UrlbarUtils.RESULT_SOURCE.ADDON, + ...lazy.UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, { + title: [description, UrlbarUtils.HIGHLIGHT.TYPED], + content: [queryContext.searchString, UrlbarUtils.HIGHLIGHT.TYPED], + keyword: [queryContext.tokens[0].value, UrlbarUtils.HIGHLIGHT.TYPED], + icon: UrlbarUtils.ICON.EXTENSION, + }) + ); + heuristicResult.heuristic = true; + addCallback(this, heuristicResult); + + // Fetch non-heuristic results. + let data = { + keyword, + text: queryContext.searchString, + inPrivateWindow: queryContext.isPrivate, + }; + this._resultsPromise = lazy.ExtensionSearchHandler.handleSearch( + data, + suggestions => { + if (instance != this.queryInstance) { + return; + } + for (let suggestion of suggestions) { + let content = `${queryContext.tokens[0].value} ${suggestion.content}`; + if (content == heuristicResult.payload.content) { + continue; + } + let result = new lazy.UrlbarResult( + UrlbarUtils.RESULT_TYPE.OMNIBOX, + UrlbarUtils.RESULT_SOURCE.ADDON, + ...lazy.UrlbarResult.payloadAndSimpleHighlights( + queryContext.tokens, + { + title: [suggestion.description, UrlbarUtils.HIGHLIGHT.TYPED], + content: [content, UrlbarUtils.HIGHLIGHT.TYPED], + keyword: [ + queryContext.tokens[0].value, + UrlbarUtils.HIGHLIGHT.TYPED, + ], + blockL10n: { id: "urlbar-result-menu-dismiss-firefox-suggest" }, + isBlockable: suggestion.deletable, + icon: UrlbarUtils.ICON.EXTENSION, + } + ) + ); + + addCallback(this, result); + } + } + ); + + // Since the extension has no way to signal when it's done pushing results, + // we add a timer racing with the addition. + let timeoutPromise = new SkippableTimer({ + name: "ProviderOmnibox", + time: lazy.UrlbarPrefs.get("extension.omnibox.timeout"), + logger: this.logger, + }).promise; + await Promise.race([timeoutPromise, this._resultsPromise]).catch(ex => + this.logger.error(ex) + ); + } + + onEngagement(isPrivate, state, queryContext, details) { + let { result } = details; + if (result?.providerName != this.name) { + return; + } + + if (details.selType == "dismiss" && result.payload.isBlockable) { + lazy.ExtensionSearchHandler.handleInputDeleted(result.payload.title); + queryContext.view.controller.removeResult(result); + } + } +} + +export var UrlbarProviderOmnibox = new ProviderOmnibox(); |