1Dynamic Result Types 2==================== 3 4This document discusses a special category of address bar results called dynamic 5result types. Dynamic result types allow you to easily add new types of results 6to the address bar and are especially useful for extensions. 7 8The intended audience for this document is developers who need to add new kinds 9of address bar results, either internally in the address bar codebase or through 10extensions. 11 12.. toctree:: 13 :caption: Table of Contents 14 15 dynamic-result-types 16 17Motivation 18---------- 19 20The address bar provides many different types of results in normal Firefox 21usage. For example, when you type a search term, the address bar may show you 22search suggestion results from your current search engine. It may also show you 23results from your browsing history that match your search. If you typed a 24certain phrase like "update Firefox," it will show you a tip result that lets 25you know whether Firefox is up to date. 26 27Each of these types of results is built into the address bar implementation. If 28you wanted to add a new type of result -- say, a card that shows the weather 29forecast when the user types "weather" -- one way to do so would be to add a new 30result type. You would need to update all the code paths in the address bar that 31relate to result types. For instance, you'd need to update the code path that 32handles clicks on results so that your weather card opens an appropriate 33forecast URL when clicked; you'd need to update the address bar view (the panel) 34so that your card is drawn correctly; you may need to update the keyboard 35selection behavior if your card contains elements that can be independently 36selected such as different days of the week; and so on. 37 38If you're implementing your weather card in an extension, as you might in an 39add-on experiment, then you'd need to land your new result type in 40mozilla-central so your extension can use it. Your new result type would ship 41with Firefox even though the vast majority of users would never see it, and your 42fellow address bar hackers would have to work around your code even though it 43would remain inactive most of the time, at least until your experiment 44graduated. 45 46Dynamic Result Types 47-------------------- 48 49**Dynamic result types** are an alternative way of implementing new result 50types. Instead of adding a new built-in type along with all that entails, you 51add a new provider subclass and register a template that describes how the view 52should draw your result type and indicates which elements are selectable. The 53address bar takes care of everything else. (Or if you're implementing an 54extension, you add a few event handlers instead of a provider subclass, although 55we have a shim_ that abstracts away the differences between internal and 56extension address bar code.) 57 58Dynamic result types are essentially an abstraction layer: Support for them as a 59general category of results is built into the address bar, and each 60implementation of a specific dynamic result type fills in the details. 61 62In addition, dynamic result types can be added at runtime. This is important for 63extensions that implement new types of results like the weather forecast example 64above. 65 66.. _shim: https://github.com/0c0w3/dynamic-result-type-extension/blob/master/src/shim.js 67 68Getting Started 69--------------- 70 71To get a feel for how dynamic result types are implemented, you can look at the 72`example dynamic result type extension <exampleExtension_>`__. The extension 73uses the recommended shim_ that makes writing address bar extension code very 74similar to writing internal address bar code, and it's therefore a useful 75example even if you intend to add a new dynamic result type internally in the 76address bar codebase in mozilla-central. 77 78The next section describes the specific steps you need to take to add a new 79dynamic result type. 80 81.. _exampleExtension: https://github.com/0c0w3/dynamic-result-type-extension/blob/master/src/background.js 82 83Implementation Steps 84-------------------- 85 86This section describes how to add a new dynamic result type in either of the 87following cases: 88 89* You want to add a new dynamic result type in an extension using the 90 recommended shim_. 91* You want to add a new dynamic result type internal to the address bar codebase 92 in mozilla-central. 93 94The steps are mostly the same in both cases and are described next. 95 96If you want to add a new dynamic result type in an extension but don't want to 97use the shim, then skip ahead to `Appendix B: Using the WebExtensions API 98Directly`_. 99 1001. Register the dynamic result type 101~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 103First, register the new dynamic result type: 104 105.. code-block:: javascript 106 107 UrlbarResult.addDynamicResultType(name); 108 109``name`` is a string identifier for the new type. It must be unique; that is, it 110must be different from all other dynamic result type names. It will also be used 111in DOM IDs, DOM class names, and CSS selectors, so it should not contain any 112spaces or other characters that are invalid in CSS. 113 1142. Register the view template 115~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 116 117Next, add the view template for the new type: 118 119.. code-block:: javascript 120 121 UrlbarView.addDynamicViewTemplate(name, viewTemplate); 122 123``name`` is the new type's name as described in step 1. 124 125``viewTemplate`` is an object called a view template. It describes in a 126declarative manner the DOM that should be created in the view for all results of 127the new type. For providers created in extensions, it also declares the 128stylesheet that should be applied to results in the view. See `View Templates`_ 129for a description of this object. 130 1313. Add the provider 132~~~~~~~~~~~~~~~~~~~ 133 134As with any type of result, results for dynamic result types must be created by 135one or more providers. Make a ``UrlbarProvider`` subclass for the new provider 136and implement all the usual provider methods as you normally would: 137 138.. code-block:: javascript 139 140 class MyDynamicResultTypeProvider extends UrlbarProvider { 141 // ... 142 } 143 144The ``startQuery`` method should create ``UrlbarResult`` objects with the 145following two requirements: 146 147* Result types must be ``UrlbarUtils.RESULT_TYPE.DYNAMIC``. 148* Result payloads must have a ``dynamicType`` property whose value is the name 149 of the dynamic result type used in step 1. 150 151The results' sources, other payload properties, and other result properties 152aren't relevant to dynamic result types, and you should choose values 153appropriate to your use case. 154 155If any elements created in the view for your results can be picked with the 156keyboard or mouse, then be sure to implement your provider's ``pickResult`` 157method. 158 159For help on implementing providers in general, see the address bar's 160`Architecture Overview`__. 161 162If you are creating the provider in the internal address bar implementation in 163mozilla-central, then don't forget to register it in ``UrlbarProvidersManager``. 164 165If you are creating the provider in an extension, then it's registered 166automatically, and there's nothing else you need to do. 167 168__ https://firefox-source-docs.mozilla.org/browser/urlbar/overview.html#urlbarprovider 169 1704. Implement the provider's getViewUpdate method 171~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 172 173``getViewUpdate`` is a provider method particular to dynamic result type 174providers. Its job is to update the view DOM for a specific result. It's called 175by the view for each result in the view that was created by the provider. It 176returns an object called a view update object. 177 178Recall that the view template was added earlier, in step 2. The view template 179describes how to build the DOM structure for all results of the dynamic result 180type. The view update object, in this step, describes how to fill in that 181structure for a specific result. 182 183Add the ``getViewUpdate`` method to the provider: 184 185.. code-block:: javascript 186 187 /** 188 * Returns a view update object that describes how to update the view DOM 189 * for a given result. 190 * 191 * @param {UrlbarResult} result 192 * The view update object describes how to update the view DOM for this 193 * particular result. 194 * @param {Map} idsByName 195 * A map from names in the view template to the IDs of their corresponding 196 * elements in the DOM. 197 */ 198 getViewUpdate(result, idsByName) { 199 let viewUpdate = { 200 // ... 201 }; 202 return viewUpdate; 203 } 204 205``result`` is the result from the provider for which the view update is being 206requested. 207 208``idsByName`` is a map from names in the view template to the IDs of their 209corresponding elements in the DOM. This is useful if parts of the view update 210depend on element IDs, as some ARIA attributes do. 211 212The return value is a view update object. It describes in a declarative manner 213the updates that should be performed on the view DOM. See `View Update Objects`_ 214for a description of this object. 215 2165. Style the results 217~~~~~~~~~~~~~~~~~~~~ 218 219If you are creating the provider in the internal address bar implementation in 220mozilla-central, then add styling `dynamicResults.inc.css`_. 221 222.. _dynamicResults.inc.css: https://searchfox.org/mozilla-central/source/browser/themes/shared/urlbar/dynamicResults.inc.css 223 224If you are creating the provider in an extension, then bundle a CSS file in your 225extension and declare it in the top-level ``stylesheet`` property of your view 226template, as described in `View Templates`_. Additionally, if any of your rules 227override built-in rules, then you'll need to declare them as ``!important``. 228 229The rest of this section will discuss the CSS rules you need to use to style 230your results. 231 232There are two DOM annotations that are useful for styling. The first is the 233``dynamicType`` attribute that is set on result rows, and the second is a class 234that is set on child elements created from the view template. 235 236dynamicType Row Attribute 237......................... 238 239The topmost element in the view corresponding to a result is called a 240**row**. Rows have a class of ``urlbarView-row``, and rows corresponding to 241results of a dynamic result type have an attributed called ``dynamicType``. The 242value of this attribute is the name of the dynamic result type that was chosen 243in step 1 earlier. 244 245Rows of a specific dynamic result type can therefore be selected with the 246following CSS selector, where ``TYPE_NAME`` is the name of the type: 247 248.. code-block:: css 249 250 .urlbarView-row[dynamicType=TYPE_NAME] 251 252Child Element Class 253................... 254 255As discussed in `View Templates`_, each object in the view template can have a 256``name`` property. The elements in the view corresponding to the objects in the 257view template receive a class named 258``urlbarView-dynamic-TYPE_NAME-ELEMENT_NAME``, where ``TYPE_NAME`` is the name 259of the dynamic result type, and ``ELEMENT_NAME`` is the name of the object in 260the view template. 261 262Elements in dynamic result type rows can therefore be selected with the 263following: 264 265.. code-block:: css 266 267 .urlbarView-dynamic-TYPE_NAME-ELEMENT_NAME 268 269If an object in the view template does not have a ``name`` property, then it 270won't receive the class and it therefore can't be selected using this selector. 271 272View Templates 273-------------- 274 275A **view template** is a plain JS object that declaratively describes how to 276build the DOM for a dynamic result type. When a result of a particular dynamic 277result type is shown in the view, the type's view template is used to construct 278the part of the view that represents the type in general. 279 280The need for view templates arises from the fact that extensions run in a 281separate process from the chrome process and can't directly access the chrome 282DOM, where the address bar view lives. Since extensions are a primary use case 283for dynamic result types, this is an important constraint on their design. 284 285Properties 286~~~~~~~~~~ 287 288A view template object is a tree-like nested structure where each object in the 289nesting represents a DOM element to be created. This tree-like structure is 290achieved using the ``children`` property described below. Each object in the 291structure may include the following properties: 292 293``{string} name`` 294 The name of the object. This is required for all objects in the structure 295 except the root object and serves two important functions: 296 297 1. The element created for the object will automatically have a class named 298 ``urlbarView-dynamic-${dynamicType}-${name}``, where ``dynamicType`` is the 299 name of the dynamic result type. The element will also automatically have 300 an attribute ``name`` whose value is this name. The class and attribute 301 allow the element to be styled in CSS. 302 303 2. The name is used when updating the view, as described in `View Update 304 Objects`_. 305 306 Names must be unique within a view template, but they don't need to be 307 globally unique. In other words, two different view templates can use the same 308 names, and other unrelated DOM elements can use the same names in their IDs 309 and classes. 310 311``{string} tag`` 312 The element tag name of the object. This is required for all objects in the 313 structure except the root object and declares the kind of element that will be 314 created for the object: ``span``, ``div``, ``img``, etc. 315 316``{object} [attributes]`` 317 An optional mapping from attribute names to values. For each name-value pair, 318 an attribute is set on the element created for the object. 319 320 A special ``selectable`` attribute tells the view that the element is 321 selectable with the keyboard. The element will automatically participate in 322 the view's keyboard selection behavior. 323 324 Similarly, the ``role=button`` ARIA attribute will also automatically allow 325 the element to participate in keyboard selection. The ``selectable`` attribute 326 is not necessary when ``role=button`` is specified. 327 328``{array} [children]`` 329 An optional list of children. Each item in the array must be an object as 330 described in this section. For each item, a child element as described by the 331 item is created and added to the element created for the parent object. 332 333``{array} [classList]`` 334 An optional list of classes. Each class will be added to the element created 335 for the object by calling ``element.classList.add()``. 336 337``{string} [stylesheet]`` 338 For dynamic result types created in extensions, this property should be set on 339 the root object in the view template structure, and its value should be a 340 stylesheet URL. The stylesheet will be loaded in all browser windows so that 341 the dynamic result type view may be styled. The specified URL will be resolved 342 against the extension's base URI. We recommend specifying a URL relative to 343 your extension's base directory. 344 345 For dynamic result types created internally in the address bar codebase, this 346 value should not be specified and instead styling should be added to 347 `dynamicResults.inc.css`_. 348 349Example 350~~~~~~~ 351 352Let's return to the weather forecast example from `earlier <Motivation_>`__. For 353each result of our weather forecast dynamic result type, we might want to 354display a label for a city name along with two buttons for today's and 355tomorrow's forecasted high and low temperatures. The view template might look 356like this: 357 358.. code-block:: javascript 359 360 { 361 stylesheet: "style.css", 362 children: [ 363 { 364 name: "cityLabel", 365 tag: "span", 366 }, 367 { 368 name: "today", 369 tag: "div", 370 classList: ["day"], 371 attributes: { 372 selectable: "true", 373 }, 374 children: [ 375 { 376 name: "todayLabel", 377 tag: "span", 378 classList: ["dayLabel"], 379 }, 380 { 381 name: "todayLow", 382 tag: "span", 383 classList: ["temperature", "temperatureLow"], 384 }, 385 { 386 name: "todayHigh", 387 tag: "span", 388 classList: ["temperature", "temperatureHigh"], 389 }, 390 }, 391 }, 392 { 393 name: "tomorrow", 394 tag: "div", 395 classList: ["day"], 396 attributes: { 397 selectable: "true", 398 }, 399 children: [ 400 { 401 name: "tomorrowLabel", 402 tag: "span", 403 classList: ["dayLabel"], 404 }, 405 { 406 name: "tomorrowLow", 407 tag: "span", 408 classList: ["temperature", "temperatureLow"], 409 }, 410 { 411 name: "tomorrowHigh", 412 tag: "span", 413 classList: ["temperature", "temperatureHigh"], 414 }, 415 }, 416 }, 417 ], 418 } 419 420Observe that we set the special ``selectable`` attribute on the ``today`` and 421``tomorrow`` elements so they can be selected with the keyboard. 422 423View Update Objects 424------------------- 425 426A **view update object** is a plain JS object that declaratively describes how 427to update the DOM for a specific result of a dynamic result type. When a result 428of a dynamic result type is shown in the view, a view update object is requested 429from the result's provider and is used to update the DOM for that result. 430 431Note the difference between view update objects, described in this section, and 432view templates, described in the previous section. View templates are used to 433build a general DOM structure appropriate for all results of a particular 434dynamic result type. View update objects are used to fill in that structure for 435a specific result. 436 437When a result is shown in the view, first the view looks up the view template of 438the result's dynamic result type. It uses the view template to build a DOM 439subtree. Next, the view requests a view update object for the result from its 440provider. The view update object tells the view which result-specific attributes 441to set on which elements, result-specific text content to set on elements, and 442so on. View update objects cannot create new elements or otherwise modify the 443structure of the result's DOM subtree. 444 445Typically the view update object is based on the result's payload. 446 447Properties 448~~~~~~~~~~ 449 450The view update object is a nested structure with two levels. It looks like 451this: 452 453.. code-block:: javascript 454 455 { 456 name1: { 457 // individual update object for name1 458 }, 459 name2: { 460 // individual update object for name2 461 }, 462 name3: { 463 // individual update object for name3 464 }, 465 // ... 466 } 467 468The top level maps object names from the view template to individual update 469objects. The individual update objects tell the view how to update the elements 470with the specified names. If a particular element doesn't need to be updated, 471then it doesn't need an entry in the view update object. 472 473Each individual update object can have the following properties: 474 475``{object} [attributes]`` 476 A mapping from attribute names to values. Each name-value pair results in an 477 attribute being set on the element. 478 479``{object} [style]`` 480 A plain object that can be used to add inline styles to the element, like 481 ``display: none``. ``element.style`` is updated for each name-value pair in 482 this object. 483 484``{object} [l10n]`` 485 An ``{ id, args }`` object that will be passed to 486 ``document.l10n.setAttributes()``. 487 488``{string} [textContent]`` 489 A string that will be set as ``element.textContent``. 490 491Example 492~~~~~~~ 493 494Continuing our weather forecast example, the view update object needs to update 495several things that we declared in our view template: 496 497* The city label 498* The "today" label 499* Today's low and high temperatures 500* The "tomorrow" label 501* Tomorrow's low and high temperatures 502 503Typically, each of these, with the possible exceptions of the "today" and 504"tomorrow" labels, would come from our results' payloads. There's an important 505connection between what's in the view and what's in the payloads: The data in 506the payloads serves the information shown in the view. 507 508Our view update object would then look something like this: 509 510.. code-block:: javascript 511 512 { 513 cityLabel: { 514 textContent: result.payload.city, 515 }, 516 todayLabel: { 517 textContent: "Today", 518 }, 519 todayLow: { 520 textContent: result.payload.todayLow, 521 }, 522 todayHigh: { 523 textContent: result.payload.todayHigh, 524 }, 525 tomorrowLabel: { 526 textContent: "Tomorrow", 527 }, 528 tomorrowLow: { 529 textContent: result.payload.tomorrowLow, 530 }, 531 tomorrowHigh: { 532 textContent: result.payload.tomorrowHigh, 533 }, 534 } 535 536Accessibility 537------------- 538 539Just like built-in types, dynamic result types support a11y in the view, and you 540should make sure your view implementation is fully accessible. 541 542Since the views for dynamic result types are implemented using view templates 543and view update objects, in practice supporting a11y for dynamic result types 544means including appropriate `ARIA attributes <aria_>`_ in the view template and 545view update objects, using the ``attributes`` property. 546 547Many ARIA attributes depend on element IDs, and that's why the ``idsByName`` 548parameter to the ``getViewUpdate`` provider method is useful. 549 550Usually, accessible address bar results require the ARIA attribute 551``role=group`` on their top-level DOM element to indicate that all the child 552elements in the result's DOM subtree form a logical group. This attribute can be 553set on the root object in the view template. 554 555.. _aria: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA 556 557Example 558~~~~~~~ 559 560Continuing the weather forecast example, we'd like for screen readers to know 561that our result is labeled by the city label so that they announce the city when 562the result is selected. 563 564The relevant ARIA attribute is ``aria-labelledby``, and its value is the ID of 565the element with the label. In our ``getViewUpdate`` implementation, we can use 566the ``idsByName`` map to get the element ID that the view created for our city 567label, like this: 568 569.. code-block:: javascript 570 571 getViewUpdate(result, idsByName) { 572 return { 573 root: { 574 attributes: { 575 "aria-labelledby": idsByName.get("cityLabel"), 576 }, 577 }, 578 // *snipping the view update object example from earlier* 579 }; 580 } 581 582Here we're using the name "root" to refer to the root object in the view 583template, so we also need to update our view template by adding the ``name`` 584property to the top-level object, like this: 585 586.. code-block:: javascript 587 588 { 589 stylesheet: "style.css", 590 name: "root", 591 attributes: { 592 role: "group", 593 }, 594 children: [ 595 { 596 name: "cityLabel", 597 tag: "span", 598 }, 599 // *snipping the view template example from earlier* 600 ], 601 } 602 603Note that we've also included the ``role=group`` ARIA attribute on the root, as 604discussed above. We could have included it in the view update object instead of 605the view template, but since it doesn't depend on a specific result or element 606ID in the ``idsByName`` map, the view template makes more sense. 607 608Mimicking Built-in Address Bar Results 609-------------------------------------- 610 611Sometimes it's desirable to create a new result type that looks and behaves like 612the usual built-in address bar results. Two conveniences are available that are 613useful in this case. 614 615URL Navigation 616~~~~~~~~~~~~~~ 617 618If a result's payload includes a string ``url`` property and a boolean 619``shouldNavigate: true`` property, then picking the result will navigate to the 620URL. The ``pickResult`` method of the result's provider will still be called 621before navigation. 622 623Text Highlighting 624~~~~~~~~~~~~~~~~~ 625 626Most built-in address bar results emphasize occurrences of the user's search 627string in their text by boldfacing matching substrings. Search suggestion 628results do the opposite by emphasizing the portion of the suggestion that the 629user has not yet typed. This emphasis feature is called **highlighting**, and 630it's also available to the results of dynamic result types. 631 632Highlighting for dynamic result types is a fairly automated process. The text 633that you want to highlight must be present as a property in your result 634payload. Instead of setting the property to a string value as you normally 635would, set it to an array with two elements, where the first element is the text 636and the second element is a ``UrlbarUtils.HIGHLIGHT`` value, like the ``title`` 637payload property in the following example: 638 639.. code-block:: javascript 640 641 let result = new UrlbarResult( 642 UrlbarUtils.RESULT_TYPE.DYNAMIC, 643 UrlbarUtils.RESULT_SOURCE.OTHER_NETWORK, 644 { 645 title: [ 646 "Some result title", 647 UrlbarUtils.HIGHLIGHT.TYPED, 648 ], 649 // *more payload properties* 650 } 651 ); 652 653``UrlbarUtils.HIGHLIGHT`` is defined in the extensions shim_ and is described 654below. 655 656Your view template must create an element corresponding to the payload 657property. That is, it must include an object where the value of the ``name`` 658property is the name of the payload property, like this: 659 660.. code-block:: javascript 661 662 { 663 children: [ 664 { 665 name: "title", 666 tag: "span", 667 }, 668 // ... 669 ], 670 } 671 672In contrast, your view update objects must *not* include an update for the 673element. That is, they must not include a property whose name is the name of the 674payload property. 675 676Instead, when the view is ready to update the DOM of your results, it will 677automatically find the elements corresponding to the payload property, set their 678``textContent`` to the text value in the array, and apply the appropriate 679highlighting, as described next. 680 681There are two possible ``UrlbarUtils.HIGHLIGHT`` values. Each controls how 682highlighting is performed: 683 684``UrlbarUtils.HIGHLIGHT.TYPED`` 685 Substrings in the payload text that match the user's search string will be 686 emphasized. 687 688``UrlbarUtils.HIGHLIGHT.SUGGESTED`` 689 If the user's search string appears in the payload text, then the remainder of 690 the text following the matching substring will be emphasized. 691 692Appendix A: Examples 693-------------------- 694 695This section lists some example and real-world consumers of dynamic result 696types. 697 698`Example Extension`__ 699 This extension demonstrates a simple use of dynamic result types. 700 701`Weather Quick Suggest Extension`__ 702 A real-world Firefox extension experiment that shows weather forecasts and 703 alerts when the user performs relevant searches in the address bar. 704 705`Tab-to-Search Provider`__ 706 This is a built-in provider in mozilla-central that uses dynamic result types. 707 708__ https://github.com/0c0w3/dynamic-result-type-extension 709__ https://github.com/mozilla-extensions/firefox-quick-suggest-weather/blob/master/src/background.js 710__ https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarProviderTabToSearch.jsm 711 712Appendix B: Using the WebExtensions API Directly 713------------------------------------------------ 714 715If you're developing an extension, the recommended way of using dynamic result 716types is to use the shim_, which abstracts away the differences between writing 717internal address bar code and extensions code. The `implementation steps`_ above 718apply to extensions as long as you're using the shim. 719 720For completeness, in this section we'll document the WebExtensions APIs that the 721shim is built on. If you don't use the shim for some reason, then follow these 722steps instead. You'll see that each step above using the shim has an analogous 723step here. 724 725The WebExtensions API schema is declared in `schema.json`_ and implemented in 726`api.js`_. 727 728.. _schema.json: https://github.com/0c0w3/dynamic-result-type-extension/blob/master/src/experiments/urlbar/schema.json 729.. _api.js: https://github.com/0c0w3/dynamic-result-type-extension/blob/master/src/experiments/urlbar/api.js 730 7311. Register the dynamic result type 732~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 733 734First, register the new dynamic result type: 735 736.. code-block:: javascript 737 738 browser.experiments.urlbar.addDynamicResultType(name, type); 739 740``name`` is a string identifier for the new type. See step 1 in `Implementation 741Steps`_ for a description, which applies here, too. 742 743``type`` is an object with metadata for the new type. Currently no metadata is 744supported, so this should be an empty object, which is the default value. 745 7462. Register the view template 747~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 748 749Next, add the view template for the new type: 750 751.. code-block:: javascript 752 753 browser.experiments.urlbar.addDynamicViewTemplate(name, viewTemplate); 754 755See step 2 above for a description of the parameters. 756 7573. Add WebExtension event listeners 758~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 759 760Add all the WebExtension event listeners you normally would in an address bar 761extension, including the two required listeners, ``onBehaviorRequested`` and 762and ``onResultsRequested``. 763 764.. code-block:: javascript 765 766 browser.urlbar.onBehaviorRequested.addListener(query => { 767 return "active"; 768 }, providerName); 769 770 browser.urlbar.onResultsRequested.addListener(query => { 771 let results = [ 772 // ... 773 ]; 774 return results; 775 }, providerName); 776 777See the address bar extensions__ document for help on the urlbar WebExtensions 778API. 779 780__ https://firefox-source-docs.mozilla.org/browser/urlbar/experiments.html 781 7824. Add an onViewUpdateRequested event listener 783~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 784 785``onViewUpdateRequested`` is a WebExtensions event particular to dynamic result 786types. It's analogous to the ``getViewUpdate`` provider method described 787earlier. 788 789.. code-block:: javascript 790 791 browser.experiments.urlbar.onViewUpdateRequested.addListener((payload, idsByName) => { 792 let viewUpdate = { 793 // ... 794 }; 795 return viewUpdate; 796 }); 797 798Note that unlike ``getViewUpdate``, here the listener's first parameter is a 799result payload, not the result itself. 800 801The listener should return a view update object. 802 8035. Style the results 804~~~~~~~~~~~~~~~~~~~~ 805 806This step is the same as step 5 above. Bundle a CSS file in your extension and 807declare it in the top-level ``stylesheet`` property of your view template. 808 809