overview.rst (15634B)
1 Architecture Overview 2 ===================== 3 4 The address bar is implemented as a *model-view-controller* (MVC) system. One of 5 the scopes of this architecture is to allow easy replacement of its components, 6 for easier experimentation. 7 8 Each search is represented by a unique object, the *UrlbarQueryContext*. This 9 object, created by the *View*, describes the search and is passed through all of 10 the components, along the way it gets augmented with additional information. 11 The *UrlbarQueryContext* is passed to the *Controller*, and finally to the 12 *Model*. The model appends results to a property of *UrlbarQueryContext* in 13 chunks, it sorts them through a *Muxer* and then notifies the *Controller*. 14 15 See the specific components below, for additional details about each one's tasks 16 and responsibilities. 17 18 19 The UrlbarQueryContext 20 ---------------------- 21 22 The *UrlbarQueryContext* object describes a single instance of a search. 23 It is augmented as it progresses through the system, with various information: 24 25 .. code:: JavaScript 26 27 UrlbarQueryContext { 28 allowAutofill; // {boolean} If true, providers are allowed to return 29 // autofill results. Even if true, it's up to providers 30 // whether to include autofill results, but when false, no 31 // provider should include them. 32 isPrivate; // {boolean} Whether the search started in a private context. 33 maxResults; // {integer} The maximum number of results requested. It is 34 // possible to request more results than the shown ones, and 35 // do additional filtering at the View level. 36 searchString; // {string} The user typed string. 37 userContextId; // {integer} The user context ID (containers feature). 38 39 // Optional properties. 40 muxer; // {string} Name of a registered muxer. Muxers can be registered 41 // through the UrlbarProvidersManager. 42 providers; // {array} List of registered provider names. Providers can be 43 // registered through the UrlbarProvidersManager. 44 sources: {array} list of accepted UrlbarUtils.RESULT_SOURCE for the context. 45 // This allows to switch between different search modes. If not 46 // provided, a default will be generated by the Model, depending on 47 // the search string. 48 engineName: // {string} if sources is restricting to just SEARCH, this 49 // property can be used to pick a specific search engine, by 50 // setting it to the name under which the engine is registered 51 // with the search service. 52 currentPage: // {string} url of the page that was loaded when the search 53 // began. 54 prohibitRemoteResults: 55 // {boolean} This provides a short-circuit override for 56 // context.allowRemoteResults(). If it's false, then allowRemoteResults() 57 // will do its usual checks to determine whether remote results are 58 // allowed. If it's true, then allowRemoteResults() will immediately 59 // return false. Defaults to false. 60 61 // Properties added by the Model. 62 results; // {array} list of UrlbarResult objects. 63 tokens; // {array} tokens extracted from the searchString, each token is an 64 // object in the form {type, value, lowerCaseValue}. 65 } 66 67 68 The Model 69 --------- 70 71 The *Model* is the component responsible for retrieving search results based on 72 the user's input, and sorting them accordingly to their importance. 73 At the core is the `UrlbarProvidersManager <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarProvidersManager.sys.mjs>`_, 74 a component tracking all the available search providers, and managing searches 75 across them. 76 77 The *UrlbarProvidersManager* is a singleton, it registers internal providers on 78 startup and can register/unregister providers on the fly. 79 It can manage multiple concurrent queries, and tracks them internally as 80 separate *Query* objects. 81 82 The *Controller* starts and stops queries through the *UrlbarProvidersManager*. 83 It's possible to wait for the promise returned by *startQuery* to know when no 84 more results will be returned, it is not mandatory though. 85 Queries can be canceled. 86 87 .. note:: 88 89 Canceling a query will issue an interrupt() on the database connection, 90 terminating any running and future SQL query, unless a query is running inside 91 a *runInCriticalSection* task. 92 93 The *searchString* gets tokenized by the `UrlbarTokenizer <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarTokenizer.sys.mjs>`_ 94 component into tokens, some of these tokens have a special meaning and can be 95 used by the user to restrict the search to specific result type (See the 96 *UrlbarTokenizer::TYPE* enum). 97 98 .. caution:: 99 100 The tokenizer uses heuristics to determine each token's type, as such the 101 consumer may want to check the value before applying filters. 102 103 .. code:: JavaScript 104 105 UrlbarProvidersManager { 106 registerProvider(providerObj); 107 unregisterProvider(providerObj); 108 registerMuxer(muxerObj); 109 unregisterMuxer(muxerObjOrName); 110 async startQuery(queryContext); 111 cancelQuery(queryContext); 112 // Can be used by providers to run uninterruptible queries. 113 runInCriticalSection(taskFn); 114 } 115 116 UrlbarProvider 117 ~~~~~~~~~~~~~~ 118 119 A provider is specialized into searching and returning results from different 120 information sources. Internal providers are usually implemented in separate 121 *sys.mjs* modules with a *UrlbarProvider* name prefix. External providers can be 122 registered as *Objects* through the *UrlbarProvidersManager*. 123 Each provider is independent and must satisfy a base API, while internal 124 implementation details may vary deeply among different providers. 125 126 .. important:: 127 128 Providers are singleton, and must track concurrent searches internally, for 129 example mapping them by UrlbarQueryContext. 130 131 .. note:: 132 133 Internal providers can access the Places database through the 134 *PlacesUtils.promiseLargeCacheDBConnection* utility. 135 136 .. code:: JavaScript 137 138 class UrlbarProvider { 139 /** 140 * Unique name for the provider, used by the context to filter on providers. 141 * Not using a unique name will cause the newest registration to win. 142 * @abstract 143 */ 144 get name() { 145 return "UrlbarProviderBase"; 146 } 147 /** 148 * The type of the provider, must be one of UrlbarUtils.PROVIDER_TYPE. 149 * 150 * @returns {Values<typeof UrlbarUtils.PROVIDER_TYPE>} 151 * @abstract 152 */ 153 get type() { 154 throw new Error("Trying to access the base class, must be overridden"); 155 } 156 /** 157 * Whether this provider should be invoked for the given context. 158 * If this method returns false, the providers manager won't start a query 159 * with this provider, to save on resources. 160 * 161 * @param {UrlbarQueryContext} queryContext 162 * The query context object 163 * @param {UrlbarController} controller 164 * The current controller. 165 * @returns {Promise<boolean>} 166 * Whether this provider should be invoked for the search. 167 * @abstract 168 */ 169 isActive(queryContext) { 170 throw new Error("Trying to access the base class, must be overridden"); 171 } 172 /** 173 * Gets the provider's priority. Priorities are numeric values starting at 174 * zero and increasing in value. Smaller values are lower priorities, and 175 * larger values are higher priorities. For a given query, `startQuery` is 176 * called on only the active and highest-priority providers. 177 * @param {UrlbarQueryContext} queryContext The query context object 178 * @returns {number} The provider's priority for the given query. 179 * @abstract 180 */ 181 getPriority(queryContext) { 182 // By default, all providers share the lowest priority. 183 return 0; 184 } 185 /** 186 * Starts querying. 187 * @param {UrlbarQueryContext} queryContext The query context object 188 * @param {function} addCallback Callback invoked by the provider to add a new 189 * result. A UrlbarResult should be passed to it. 190 * @note Extended classes should return a Promise resolved when the provider 191 * is done searching AND returning results. 192 * @abstract 193 */ 194 startQuery(queryContext, addCallback) { 195 throw new Error("Trying to access the base class, must be overridden"); 196 } 197 /** 198 * Cancels a running query, 199 * @param {UrlbarQueryContext} queryContext The query context object to cancel 200 * query for. 201 * @abstract 202 */ 203 cancelQuery(queryContext) { 204 throw new Error("Trying to access the base class, must be overridden"); 205 } 206 } 207 208 UrlbarMuxer 209 ~~~~~~~~~~~ 210 211 The *Muxer* is responsible for sorting results based on their importance and 212 additional rules that depend on the UrlbarQueryContext. The muxer to use is 213 indicated by the UrlbarQueryContext.muxer property. 214 215 .. caution:: 216 217 The Muxer is a replaceable component, as such what is described here is a 218 reference for the default View, but may not be valid for other implementations. 219 220 .. code:: JavaScript 221 222 class UrlbarMuxer { 223 /** 224 * Unique name for the muxer, used by the context to sort results. 225 * Not using a unique name will cause the newest registration to win. 226 * @abstract 227 */ 228 get name() { 229 return "UrlbarMuxerBase"; 230 } 231 /** 232 * Sorts UrlbarQueryContext results in-place. 233 * @param {UrlbarQueryContext} queryContext the context to sort results for. 234 * @param {Array} unsortedResults 235 * The array of UrlbarResult that is not sorted yet. 236 * @abstract 237 */ 238 sort(queryContext, unsortedResults) { 239 throw new Error("Trying to access the base class, must be overridden"); 240 } 241 } 242 243 244 The Controller 245 -------------- 246 247 `UrlbarController <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarController.sys.mjs>`_ 248 is the component responsible for reacting to user's input, by communicating 249 proper course of action to the Model (e.g. starting/stopping a query) and the 250 View (e.g. showing/hiding a panel). It is also responsible for reporting Telemetry. 251 252 .. note:: 253 254 Each *View* has a different *Controller* instance. 255 256 .. code:: JavaScript 257 258 UrlbarController { 259 async startQuery(queryContext); 260 cancelQuery(queryContext); 261 // Invoked by the ProvidersManager when results are available. 262 receiveResults(queryContext); 263 // Used by the View to listen for results. 264 addListener(listener); 265 removeListener(listener); 266 } 267 268 269 The View 270 -------- 271 272 The View is the component responsible for presenting search results to the 273 user and handling their input. 274 275 .. caution 276 277 The View is a replaceable component, as such what is described here is a 278 reference for the default View, but may not be valid for other implementations. 279 280 `UrlbarInput.sys.mjs <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarInput.sys.mjs>`_ 281 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 282 283 Implements an input box *View*, owns an *UrlbarView*. 284 285 .. code:: JavaScript 286 287 UrlbarInput { 288 constructor(options = { textbox, panel }); 289 // Uses UrlbarValueFormatter to highlight the base host, search aliases 290 // and to keep the host visible on overflow. 291 formatValue(val); 292 openResults(); 293 // Converts an internal URI (e.g. a URI with a username or password) into 294 // one which we can expose to the user. 295 makeURIReadable(uri); 296 // Handles an event which would cause a url or text to be opened. 297 handleCommand(); 298 // Called by the view when a result is selected. 299 resultsSelected(); 300 // The underlying textbox 301 textbox; 302 // The results panel. 303 panel; 304 // The containing window. 305 window; 306 // The containing document. 307 document; 308 // An UrlbarController instance. 309 controller; 310 // An UrlbarView instance. 311 view; 312 // Whether the current value was typed by the user. 313 valueIsTyped; 314 // Whether the context is in Private Browsing mode. 315 isPrivate; 316 // Whether the input box is focused. 317 focused; 318 // The go button element. 319 goButton; 320 // The current value, can also be set. 321 value; 322 } 323 324 `UrlbarView.sys.mjs <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarView.sys.mjs>`_ 325 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 326 327 Represents the base *View* implementation, communicates with the *Controller*. 328 329 .. code:: JavaScript 330 331 UrlbarView { 332 // Manage View visibility. 333 open(); 334 close(); 335 // Invoked when the query starts. 336 onQueryStarted(queryContext); 337 // Invoked when new results are available. 338 onQueryResults(queryContext); 339 // Invoked when the query has been canceled. 340 onQueryCancelled(queryContext); 341 // Invoked when the query is done. This is invoked in any case, even if the 342 // query was canceled earlier. 343 onQueryFinished(queryContext); 344 // Invoked when the view opens. 345 onViewOpen(); 346 // Invoked when the view closes. 347 onViewClose(); 348 } 349 350 351 UrlbarResult 352 ------------ 353 354 An `UrlbarResult <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarResult.sys.mjs>`_ 355 instance represents a single search result with a result type, that 356 identifies specific kind of results. 357 Each kind has its own properties, that the *View* may support, and a few common 358 properties, supported by all of the results. 359 360 .. note:: 361 362 Result types are also enumerated by *UrlbarUtils.RESULT_TYPE*. 363 364 .. code-block:: JavaScript 365 366 UrlbarResult { 367 constructor(resultType, payload); 368 369 type: {integer} One of UrlbarUtils.RESULT_TYPE. 370 source: {integer} One of UrlbarUtils.RESULT_SOURCE. 371 title: {string} A title that may be used as a label for this result. 372 icon: {string} Url of an icon for this result. 373 payload: {object} Object containing properties for the specific RESULT_TYPE. 374 autofill: {object} An object describing the text that should be 375 autofilled in the input when the result is selected, if any. 376 autofill.value: {string} The autofill value. 377 autofill.selectionStart: {integer} The first index in the autofill 378 selection. 379 autofill.selectionEnd: {integer} The last index in the autofill selection. 380 suggestedIndex: {integer} Suggest a preferred position for this result 381 within the result set. Undefined if none. 382 isSuggestedIndexRelativeToGroup: {boolean} Whether the suggestedIndex 383 property is relative to the result's group 384 instead of the entire result set. 385 } 386 387 The following RESULT_TYPEs are supported: 388 389 .. code:: JavaScript 390 391 // An open tab. 392 // Payload: { icon, url, userContextId } 393 TAB_SWITCH: 1, 394 // A search suggestion or engine. 395 // Payload: { icon, suggestion, keyword, query, providesSearchMode, inPrivateWindow, isPrivateEngine } 396 SEARCH: 2, 397 // A common url/title tuple, may be a bookmark with tags. 398 // Payload: { icon, url, title, tags } 399 URL: 3, 400 // A bookmark keyword. 401 // Payload: { icon, url, keyword, postData } 402 KEYWORD: 4, 403 // A WebExtension Omnibox result. 404 // Payload: { icon, keyword, title, content } 405 OMNIBOX: 5, 406 // A tab from another synced device. 407 // Payload: { icon, url, device, title } 408 REMOTE_TAB: 6, 409 // An actionable message to help the user with their query. 410 // Payload: { buttons, helpL10n, helpUrl, icon, titleL10n, type } 411 TIP: 7, 412 // A type of result which layout is defined at runtime. 413 // Payload: { dynamicType } 414 DYNAMIC: 8,