forked from mirrors/gecko-dev
		
	 73e7350295
			
		
	
	
		73e7350295
		
	
	
	
	
		
			
			We can't use context.isPrivate because sometimes context is undefined. I filed https://bugzilla.mozilla.org/show_bug.cgi?id=1841762 about that. Differential Revision: https://phabricator.services.mozilla.com/D182772
		
			
				
	
	
		
			196 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			6 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 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(state, queryContext, details, controller) {
 | |
|     let { result } = details;
 | |
|     if (result?.providerName != this.name) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (details.selType == "dismiss" && result.payload.isBlockable) {
 | |
|       lazy.ExtensionSearchHandler.handleInputDeleted(result.payload.title);
 | |
|       controller.removeResult(result);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| export var UrlbarProviderOmnibox = new ProviderOmnibox();
 |