tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

UrlbarProviderOmnibox.sys.mjs (5422B)


      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/. */
      4 
      5 /**
      6 * This module exports a provider class that is used for providers created by
      7 * extensions using the `omnibox` API.
      8 */
      9 
     10 import {
     11  SkippableTimer,
     12  UrlbarProvider,
     13  UrlbarUtils,
     14 } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
     15 
     16 const lazy = {};
     17 
     18 ChromeUtils.defineESModuleGetters(lazy, {
     19  ExtensionSearchHandler:
     20    "resource://gre/modules/ExtensionSearchHandler.sys.mjs",
     21 
     22  UrlbarPrefs: "moz-src:///browser/components/urlbar/UrlbarPrefs.sys.mjs",
     23  UrlbarResult: "moz-src:///browser/components/urlbar/UrlbarResult.sys.mjs",
     24 });
     25 
     26 /**
     27 * This provider handles results returned by extensions using the WebExtensions
     28 * Omnibox API. If the user types a registered keyword, we send subsequent
     29 * keystrokes to the extension.
     30 */
     31 export class UrlbarProviderOmnibox extends UrlbarProvider {
     32  constructor() {
     33    super();
     34  }
     35 
     36  /**
     37   * @returns {Values<typeof UrlbarUtils.PROVIDER_TYPE>}
     38   */
     39  get type() {
     40    return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
     41  }
     42 
     43  /**
     44   * Whether the provider should be invoked for the given context.  If this
     45   * method returns false, the providers manager won't start a query with this
     46   * provider, to save on resources.
     47   *
     48   * @param {UrlbarQueryContext} queryContext
     49   *   The query context object.
     50   */
     51  async isActive(queryContext) {
     52    if (
     53      queryContext.tokens[0] &&
     54      queryContext.tokens[0].value.length &&
     55      lazy.ExtensionSearchHandler.isKeywordRegistered(
     56        queryContext.tokens[0].value
     57      ) &&
     58      UrlbarUtils.substringAfter(
     59        queryContext.searchString,
     60        queryContext.tokens[0].value
     61      ) &&
     62      !queryContext.searchMode
     63    ) {
     64      return true;
     65    }
     66 
     67    // We need to handle cancellation here since isActive is called once per
     68    // query but cancelQuery can be called multiple times per query.
     69    // The frequent cancels can cause the extension's state to drift from the
     70    // provider's state.
     71    if (lazy.ExtensionSearchHandler.hasActiveInputSession()) {
     72      lazy.ExtensionSearchHandler.handleInputCancelled();
     73    }
     74 
     75    return false;
     76  }
     77 
     78  /**
     79   * Gets the provider's priority.
     80   *
     81   * @returns {number}
     82   *   The provider's priority for the given query.
     83   */
     84  getPriority() {
     85    return 0;
     86  }
     87 
     88  /**
     89   * Starts querying.
     90   *
     91   * @param {UrlbarQueryContext} queryContext
     92   * @param {(provider: UrlbarProvider, result: UrlbarResult) => void} addCallback
     93   *   Callback invoked by the provider to add a new result.
     94   */
     95  async startQuery(queryContext, addCallback) {
     96    let instance = this.queryInstance;
     97 
     98    // Fetch heuristic result.
     99    let keyword = queryContext.tokens[0].value;
    100    let description = lazy.ExtensionSearchHandler.getDescription(keyword);
    101    let heuristicResult = new lazy.UrlbarResult({
    102      type: UrlbarUtils.RESULT_TYPE.OMNIBOX,
    103      source: UrlbarUtils.RESULT_SOURCE.ADDON,
    104      heuristic: true,
    105      payload: {
    106        title: description,
    107        content: queryContext.searchString,
    108        keyword: queryContext.tokens[0].value,
    109        icon: UrlbarUtils.ICON.EXTENSION,
    110      },
    111      highlights: {
    112        title: UrlbarUtils.HIGHLIGHT.TYPED,
    113        content: UrlbarUtils.HIGHLIGHT.TYPED,
    114        keyword: UrlbarUtils.HIGHLIGHT.TYPED,
    115      },
    116    });
    117    addCallback(this, heuristicResult);
    118 
    119    // Fetch non-heuristic results.
    120    let data = {
    121      keyword,
    122      text: queryContext.searchString,
    123      inPrivateWindow: queryContext.isPrivate,
    124    };
    125    let resultsPromise = lazy.ExtensionSearchHandler.handleSearch(
    126      data,
    127      suggestions => {
    128        if (instance != this.queryInstance) {
    129          return;
    130        }
    131        for (let suggestion of suggestions) {
    132          let content = `${queryContext.tokens[0].value} ${suggestion.content}`;
    133          if (content == heuristicResult.payload.content) {
    134            continue;
    135          }
    136          let result = new lazy.UrlbarResult({
    137            type: UrlbarUtils.RESULT_TYPE.OMNIBOX,
    138            source: UrlbarUtils.RESULT_SOURCE.ADDON,
    139            payload: {
    140              title: suggestion.description,
    141              content,
    142              keyword: queryContext.tokens[0].value,
    143              isBlockable: suggestion.deletable,
    144              icon: UrlbarUtils.ICON.EXTENSION,
    145            },
    146            highlights: {
    147              title: UrlbarUtils.HIGHLIGHT.TYPED,
    148              content: UrlbarUtils.HIGHLIGHT.TYPED,
    149              keyword: UrlbarUtils.HIGHLIGHT.TYPED,
    150            },
    151          });
    152          addCallback(this, result);
    153        }
    154      }
    155    );
    156 
    157    // Since the extension has no way to signal when it's done pushing results,
    158    // we add a timer racing with the addition.
    159    let timeoutPromise = new SkippableTimer({
    160      name: "ProviderOmnibox",
    161      time: lazy.UrlbarPrefs.get("extension.omnibox.timeout"),
    162      logger: this.logger,
    163    }).promise;
    164    await Promise.race([timeoutPromise, resultsPromise]).catch(ex =>
    165      this.logger.error(ex)
    166    );
    167  }
    168 
    169  onEngagement(queryContext, controller, details) {
    170    let { result } = details;
    171    if (details.selType == "dismiss" && result.payload.isBlockable) {
    172      lazy.ExtensionSearchHandler.handleInputDeleted(result.payload.title);
    173      controller.removeResult(result);
    174    }
    175  }
    176 }