架构概述

地址栏作为模型-视图-控制器 (MVC) 系统实现。该架构的范围之一是允许轻松替换其组件,以便于进行实验。

每个搜索都由一个唯一的对象UrlbarQueryContext表示。此对象由视图创建,描述搜索并传递给所有组件,在此过程中,它会添加其他信息。UrlbarQueryContext传递给控制器,最后传递给模型。模型将结果分块添加到UrlbarQueryContext的属性中,通过Muxer进行排序,然后通知控制器

有关每个组件的任务和职责的更多详细信息,请参阅下面的具体组件。

UrlbarQueryContext

UrlbarQueryContext对象描述搜索的单个实例。在整个系统中,它会添加各种信息。

UrlbarQueryContext {
  allowAutofill; // {boolean} If true, providers are allowed to return
                 // autofill results.  Even if true, it's up to providers
                 // whether to include autofill results, but when false, no
                 // provider should include them.
  isPrivate; // {boolean} Whether the search started in a private context.
  maxResults; // {integer} The maximum number of results requested. It is
              // possible to request more results than the shown ones, and
              // do additional filtering at the View level.
  searchString; // {string} The user typed string.
  userContextId; // {integer} The user context ID (containers feature).

  // Optional properties.
  muxer; // {string} Name of a registered muxer. Muxers can be registered
         // through the UrlbarProvidersManager.
  providers; // {array} List of registered provider names. Providers can be
             // registered through the UrlbarProvidersManager.
  sources: {array} list of accepted UrlbarUtils.RESULT_SOURCE for the context.
          // This allows to switch between different search modes. If not
          // provided, a default will be generated by the Model, depending on
          // the search string.
  engineName: // {string} if sources is restricting to just SEARCH, this
              // property can be used to pick a specific search engine, by
              // setting it to the name under which the engine is registered
              // with the search service.
  currentPage: // {string} url of the page that was loaded when the search
               // began.
  prohibitRemoteResults:
    // {boolean} This provides a short-circuit override for
    // context.allowRemoteResults(). If it's false, then allowRemoteResults()
    // will do its usual checks to determine whether remote results are
    // allowed. If it's true, then allowRemoteResults() will immediately
    // return false. Defaults to false.

  // Properties added by the Model.
  results; // {array} list of UrlbarResult objects.
  tokens; // {array} tokens extracted from the searchString, each token is an
          // object in the form {type, value, lowerCaseValue}.
}

模型

模型是负责根据用户的输入检索搜索结果并根据其重要性对其进行排序的组件。核心是UrlbarProvidersManager,它跟踪所有可用的搜索提供程序,并管理跨提供程序的搜索。

UrlbarProvidersManager是一个单例,它在启动时注册内部提供程序,并且可以动态注册/注销提供程序。它可以管理多个并发查询,并在内部将其跟踪为单独的Query对象。

控制器通过UrlbarProvidersManager启动和停止查询。可以通过等待startQuery返回的 Promise 来知道何时不再返回结果,但这并非强制性要求。查询可以取消。

注意

取消查询将在数据库连接上发出 interrupt(),终止任何正在运行和将来的 SQL 查询,除非查询在runInCriticalSection任务中运行。

searchStringUrlbarTokenizer组件标记化为标记,其中一些标记具有特殊含义,用户可以使用它们将搜索限制为特定的结果类型(请参阅UrlbarTokenizer::TYPE枚举)。

警告

标记器使用启发式方法来确定每个标记的类型,因此使用者可能需要在应用过滤器之前检查该值。

UrlbarProvidersManager {
  registerProvider(providerObj);
  unregisterProvider(providerObj);
  registerMuxer(muxerObj);
  unregisterMuxer(muxerObjOrName);
  async startQuery(queryContext);
  cancelQuery(queryContext);
  // Can be used by providers to run uninterruptible queries.
  runInCriticalSection(taskFn);
}

UrlbarProvider

提供程序专门用于从不同的信息源搜索和返回结果。内部提供程序通常在单独的sys.mjs模块中实现,并以UrlbarProvider作为名称前缀。外部提供程序可以通过UrlbarProvidersManager作为对象注册。每个提供程序都是独立的,必须满足基本 API,而内部实现细节在不同提供程序之间可能存在很大差异。

重要

提供程序是单例,必须在内部跟踪并发搜索,例如通过 UrlbarQueryContext 对其进行映射。

注意

内部提供程序可以通过PlacesUtils.promiseLargeCacheDBConnection实用程序访问 Places 数据库。

class UrlbarProvider {
  /**
   * Unique name for the provider, used by the context to filter on providers.
   * Not using a unique name will cause the newest registration to win.
   * @abstract
   */
  get name() {
    return "UrlbarProviderBase";
  }
  /**
   * The type of the provider, must be one of UrlbarUtils.PROVIDER_TYPE.
   * @abstract
   */
  get type() {
    throw new Error("Trying to access the base class, must be overridden");
  }
  /**
   * 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.
   * @abstract
   */
  isActive(queryContext) {
    throw new Error("Trying to access the base class, must be overridden");
  }
  /**
   * Gets the provider's priority.  Priorities are numeric values starting at
   * zero and increasing in value.  Smaller values are lower priorities, and
   * larger values are higher priorities.  For a given query, `startQuery` is
   * called on only the active and highest-priority providers.
   * @param {UrlbarQueryContext} queryContext The query context object
   * @returns {number} The provider's priority for the given query.
   * @abstract
   */
  getPriority(queryContext) {
    // By default, all providers share the lowest priority.
    return 0;
  }
  /**
   * Starts querying.
   * @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.
   * @note Extended classes should return a Promise resolved when the provider
   *       is done searching AND returning results.
   * @abstract
   */
  startQuery(queryContext, addCallback) {
    throw new Error("Trying to access the base class, must be overridden");
  }
  /**
   * Cancels a running query,
   * @param {UrlbarQueryContext} queryContext The query context object to cancel
   *        query for.
   * @abstract
   */
  cancelQuery(queryContext) {
    throw new Error("Trying to access the base class, must be overridden");
  }
}

UrlbarMuxer

Muxer负责根据其重要性和取决于 UrlbarQueryContext 的其他规则对结果进行排序。要使用的 muxer 由 UrlbarQueryContext.muxer 属性指示。

警告

Muxer 是一个可替换的组件,因此这里描述的是默认视图的参考,但对于其他实现可能无效。

class UrlbarMuxer {
  /**
   * Unique name for the muxer, used by the context to sort results.
   * Not using a unique name will cause the newest registration to win.
   * @abstract
   */
  get name() {
    return "UrlbarMuxerBase";
  }
  /**
   * Sorts UrlbarQueryContext results in-place.
   * @param {UrlbarQueryContext} queryContext the context to sort results for.
   * @abstract
   */
  sort(queryContext) {
    throw new Error("Trying to access the base class, must be overridden");
  }
}

控制器

UrlbarController是负责响应用户输入的组件,通过与模型(例如启动/停止查询)和视图(例如显示/隐藏面板)进行通信来实现正确的操作流程。它还负责报告遥测。

注意

每个视图都有一个不同的控制器实例。

UrlbarController {
  async startQuery(queryContext);
  cancelQuery(queryContext);
  // Invoked by the ProvidersManager when results are available.
  receiveResults(queryContext);
  // Used by the View to listen for results.
  addQueryListener(listener);
  removeQueryListener(listener);
}

视图

视图是负责向用户呈现搜索结果并处理其输入的组件。

UrlbarInput.sys.mjs

实现输入框视图,拥有一个UrlbarView

UrlbarInput {
  constructor(options = { textbox, panel });
  // Uses UrlbarValueFormatter to highlight the base host, search aliases
  // and to keep the host visible on overflow.
  formatValue(val);
  openResults();
  // Converts an internal URI (e.g. a URI with a username or password) into
  // one which we can expose to the user.
  makeURIReadable(uri);
  // Handles an event which would cause a url or text to be opened.
  handleCommand();
  // Called by the view when a result is selected.
  resultsSelected();
  // The underlying textbox
  textbox;
  // The results panel.
  panel;
  // The containing window.
  window;
  // The containing document.
  document;
  // An UrlbarController instance.
  controller;
  // An UrlbarView instance.
  view;
  // Whether the current value was typed by the user.
  valueIsTyped;
  // Whether the context is in Private Browsing mode.
  isPrivate;
  // Whether the input box is focused.
  focused;
  // The go button element.
  goButton;
  // The current value, can also be set.
  value;
}

UrlbarView.sys.mjs

表示基本视图实现,与控制器通信。

UrlbarView {
  // Manage View visibility.
  open();
  close();
  // Invoked when the query starts.
  onQueryStarted(queryContext);
  // Invoked when new results are available.
  onQueryResults(queryContext);
  // Invoked when the query has been canceled.
  onQueryCancelled(queryContext);
  // Invoked when the query is done. This is invoked in any case, even if the
  // query was canceled earlier.
  onQueryFinished(queryContext);
  // Invoked when the view opens.
  onViewOpen();
  // Invoked when the view closes.
  onViewClose();
}

UrlbarResult

一个UrlbarResult实例表示单个搜索结果,具有结果类型,该类型标识特定类型的结果。每种类型都有其自己的属性,视图可能会支持这些属性,以及所有结果都支持的一些通用属性。

注意

结果类型也由UrlbarUtils.RESULT_TYPE枚举。

UrlbarResult {
  constructor(resultType, payload);

  type: {integer} One of UrlbarUtils.RESULT_TYPE.
  source: {integer} One of UrlbarUtils.RESULT_SOURCE.
  title: {string} A title that may be used as a label for this result.
  icon: {string} Url of an icon for this result.
  payload: {object} Object containing properties for the specific RESULT_TYPE.
  autofill: {object} An object describing the text that should be
            autofilled in the input when the result is selected, if any.
  autofill.value: {string} The autofill value.
  autofill.selectionStart: {integer} The first index in the autofill
                           selection.
  autofill.selectionEnd: {integer} The last index in the autofill selection.
  suggestedIndex: {integer} Suggest a preferred position for this result
                  within the result set. Undefined if none.
  isSuggestedIndexRelativeToGroup: {boolean} Whether the suggestedIndex
                                   property is relative to the result's group
                                   instead of the entire result set.
}

支持以下 RESULT_TYPE:

// An open tab.
// Payload: { icon, url, userContextId }
TAB_SWITCH: 1,
// A search suggestion or engine.
// Payload: { icon, suggestion, keyword, query, providesSearchMode, inPrivateWindow, isPrivateEngine }
SEARCH: 2,
// A common url/title tuple, may be a bookmark with tags.
// Payload: { icon, url, title, tags }
URL: 3,
// A bookmark keyword.
// Payload: { icon, url, keyword, postData }
KEYWORD: 4,
// A WebExtension Omnibox result.
// Payload: { icon, keyword, title, content }
OMNIBOX: 5,
// A tab from another synced device.
// Payload: { icon, url, device, title }
REMOTE_TAB: 6,
// An actionable message to help the user with their query.
// Payload: { buttons, helpL10n, helpUrl, icon, titleL10n, type }
TIP: 7,
// A type of result which layout is defined at runtime.
// Payload: { dynamicType }
DYNAMIC: 8,