summaryrefslogtreecommitdiffstats
path: root/browser/components/uitour/UITour-lib.js
blob: a83ec9520057b23646e4f3fc3fad8d495876e22f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
/* 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/. */

/* eslint valid-jsdoc: ["error", { "requireReturn": false }] */

// create namespace
if (typeof Mozilla == "undefined") {
  var Mozilla = {};
}

(function () {
  "use strict";

  // create namespace
  if (typeof Mozilla.UITour == "undefined") {
    /**
     * Library that exposes an event-based Web API for communicating with the
     * desktop browser chrome. It can be used for tasks such as opening menu
     * panels and highlighting the position of buttons in the toolbar.
     *
     * For security/privacy reasons `Mozilla.UITour` will only work on a list of allowed
     * secure origins. The list of allowed origins can be found in
     * https://searchfox.org/mozilla-central/source/browser/app/permissions.
     *
     * @since 29
     * @namespace
     */
    Mozilla.UITour = {};
  }

  function _sendEvent(action, data) {
    var event = new CustomEvent("mozUITour", {
      bubbles: true,
      detail: {
        action,
        data: data || {},
      },
    });

    document.dispatchEvent(event);
  }

  function _generateCallbackID() {
    return Math.random()
      .toString(36)
      .replace(/[^a-z]+/g, "");
  }

  function _waitForCallback(callback) {
    var id = _generateCallbackID();

    function listener(event) {
      if (typeof event.detail != "object") {
        return;
      }
      if (event.detail.callbackID != id) {
        return;
      }

      document.removeEventListener("mozUITourResponse", listener);
      callback(event.detail.data);
    }
    document.addEventListener("mozUITourResponse", listener);

    return id;
  }

  var notificationListener = null;
  function _notificationListener(event) {
    if (typeof event.detail != "object") {
      return;
    }
    if (typeof notificationListener != "function") {
      return;
    }

    notificationListener(event.detail.event, event.detail.params);
  }

  Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY = 10 * 1000;

  Mozilla.UITour.CONFIGNAME_SYNC = "sync";
  Mozilla.UITour.CONFIGNAME_AVAILABLETARGETS = "availableTargets";

  /**
   * @typedef {string} Mozilla.UITour.Target
   *
   * @summary Not all targets are available at all times because they may not be visible
   * or UITour doesn't not how to automatically make them visible. Use the
   * following to determine which ones are available at a given time::
   *
   * .. code-block:: javascript
   *
   *    Mozilla.UITour.getConfiguration('availableTargets', callback)
   *
   * @see Mozilla.UITour.getConfiguration
   * @see Mozilla.UITour.showHighlight
   * @see Mozilla.UITour.showInfo
   *
   * @description Valid values:
   *
   * - accountStatus
   * - addons
   * - appMenu
   * - backForward
   * - bookmarks
   * - forget
   * - help
   * - home
   * - logins
   * - pageAction-bookmark
   * - pocket
   * - privateWindow
   * - quit
   * - readerMode-urlBar
   * - search
   * - searchIcon
   * - selectedTabIcon
   * - urlbar
   *
   * Generate using the following in the Browser Console:
   *
   * .. code-block:: javascript
   *
   *    [...UITour.targets.keys()].join("\n* - ")
   *
   */

  /**
   * Ensure the browser is ready to handle this document as a tour.
   *
   * @param {Function} [callback] Callback to call if UITour is working for the document.
   * @since 35
   */
  Mozilla.UITour.ping = function (callback) {
    var data = {};
    if (callback) {
      data.callbackID = _waitForCallback(callback);
    }
    _sendEvent("ping", data);
  };

  /**
   * @summary Register a listener to observe all UITour notifications.
   *
   * @description There can only be one observer per tour tab so calling this a second time will
   * replace any previous `listener`.
   * To remove an observer, call the method with `null` as the first argument.
   *
   * @param {?Function} listener - Called when any UITour notification occurs.
   * @param {Function} [callback] - Called when the browser acknowledges the observer.
   */
  Mozilla.UITour.observe = function (listener, callback) {
    notificationListener = listener;

    if (listener) {
      document.addEventListener("mozUITourNotification", _notificationListener);
      Mozilla.UITour.ping(callback);
    } else {
      document.removeEventListener(
        "mozUITourNotification",
        _notificationListener
      );
    }
  };

  /**
   * Register an identifier to use in
   * `Telemetry <https://wiki.mozilla.org/Telemetry>`_. `pageID` must be a
   * string unique to the page/tour.
   *
   * @example
   * Mozilla.UITour.registerPageID('firstrun-page-firefox-29');
   *
   * @param {string} pageID Unique identifier for the page/tour.
   * @memberof Mozilla.UITour
   */
  Mozilla.UITour.registerPageID = function (pageID) {
    _sendEvent("registerPageID", {
      pageID,
    });
  };

  /**
   * @typedef {string} Mozilla.UITour.HighlightEffect
   *
   * Specifies the effect/animation to use when highlighting UI elements.
   * @description Valid values:
   *
   * - random
   * - wobble
   * - zoom
   * - color
   *
   * Generate using the following in the Browser Console:
   *
   * .. code-block:: javascript
   *
   *    [...UITour.highlightEffects].join("\n* - ")
   *
   * @see Mozilla.UITour.showHighlight
   */

  /**
   * Visually highlight a UI widget.
   *
   * @see Mozilla.UITour.hideHighlight
   * @example Mozilla.UITour.showHighlight('appMenu', 'wobble');
   *
   * @param {Mozilla.UITour.Target} target - Identifier of the UI widget to show a highlight on.
   * @param {Mozilla.UITour.HighlightEffect} [effect="none"] - Name of the effect to use when highlighting.
   */
  Mozilla.UITour.showHighlight = function (target, effect) {
    _sendEvent("showHighlight", {
      target,
      effect,
    });
  };

  /**
   * Hide any visible UI highlight.
   *
   * @see Mozilla.UITour.showHighlight
   */
  Mozilla.UITour.hideHighlight = function () {
    _sendEvent("hideHighlight");
  };

  /**
   * Show an arrow panel with optional images and buttons anchored at a specific UI target.
   *
   * @see Mozilla.UITour.hideInfo
   *
   * @param {Mozilla.UITour.Target} target - Identifier of the UI widget to anchor the panel at.
   * @param {string} title - Title text to be shown as the heading of the panel.
   * @param {string} text - Body text of the panel.
   * @param {string} [icon=null] - URL of a 48x48px (96px @ 2dppx) image (which will be resolved
   *                               relative to the tab's URI) to display in the panel.
   * @param {object[]} [buttons=[]] - Array of objects describing buttons.
   * @param {string} buttons[].label - Button label
   * @param {string} buttons[].icon - Button icon URL
   * @param {string} buttons[].style - Button style ("primary" or "link")
   * @param {Function} buttons[].callback - Called when the button is clicked
   * @param {object} [options={}] - Advanced options
   * @param {Function} options.closeButtonCallback - Called when the panel's close button is clicked.
   *
   * @example
   * var buttons = [
   *   {
   *     label: 'Cancel',
   *     style: 'link',
   *     callback: cancelBtnCallback
   *   },
   *   {
   *     label: 'Confirm',
   *     style: 'primary',
   *     callback: confirmBtnCallback
   *   }
   * ];
   *
   * var icon = '//mozorg.cdn.mozilla.net/media/img/firefox/australis/logo.png';
   *
   * var options = {
   *   closeButtonCallback: closeBtnCallback
   * };
   *
   * Mozilla.UITour.showInfo('appMenu', 'my title', 'my text', icon, buttons, options);
   */
  Mozilla.UITour.showInfo = function (
    target,
    title,
    text,
    icon,
    buttons,
    options
  ) {
    var buttonData = [];
    if (Array.isArray(buttons)) {
      for (var i = 0; i < buttons.length; i++) {
        buttonData.push({
          label: buttons[i].label,
          icon: buttons[i].icon,
          style: buttons[i].style,
          callbackID: _waitForCallback(buttons[i].callback),
        });
      }
    }

    var closeButtonCallbackID, targetCallbackID;
    if (options && options.closeButtonCallback) {
      closeButtonCallbackID = _waitForCallback(options.closeButtonCallback);
    }
    if (options && options.targetCallback) {
      targetCallbackID = _waitForCallback(options.targetCallback);
    }

    _sendEvent("showInfo", {
      target,
      title,
      text,
      icon,
      buttons: buttonData,
      closeButtonCallbackID,
      targetCallbackID,
    });
  };

  /**
   * Hide any visible info panels.
   *
   * @see Mozilla.UITour.showInfo
   */
  Mozilla.UITour.hideInfo = function () {
    _sendEvent("hideInfo");
  };

  /**
   * @typedef {string} Mozilla.UITour.MenuName
   * Valid values:
   *
   * - appMenu
   * - bookmarks
   * - pocket
   *
   * @see Mozilla.UITour.showMenu
   * @see Mozilla.UITour.hideMenu
   * @see Mozilla.UITour.openSearchPanel
   */

  /**
   * Open the named application menu.
   *
   * @see Mozilla.UITour.hideMenu
   *
   * @param {Mozilla.UITour.MenuName} name - Menu name
   * @param {Function} [callback] - Callback to be called with no arguments when
   *                                the menu opens.
   *
   * @example
   * Mozilla.UITour.showMenu('appMenu', function() {
   *   console.log('menu was opened');
   * });
   */
  Mozilla.UITour.showMenu = function (name, callback) {
    var showCallbackID;
    if (callback) {
      showCallbackID = _waitForCallback(callback);
    }

    _sendEvent("showMenu", {
      name,
      showCallbackID,
    });
  };

  /**
   * Close the named application menu.
   *
   * @see Mozilla.UITour.showMenu
   *
   * @param {Mozilla.UITour.MenuName} name - Menu name
   */
  Mozilla.UITour.hideMenu = function (name) {
    _sendEvent("hideMenu", {
      name,
    });
  };

  /**
   * Loads about:newtab in the tour tab.
   *
   * @since 51
   */
  Mozilla.UITour.showNewTab = function () {
    _sendEvent("showNewTab");
  };

  /**
   * Loads about:protections in the tour tab.
   *
   * @since 70
   */
  Mozilla.UITour.showProtectionReport = function () {
    _sendEvent("showProtectionReport");
  };

  /**
   * @typedef Mozilla.UITour.ConfigurationName
   * @description Valid values:
   *
   * - :js:func:`appinfo <Mozilla.UITour.Configuration.AppInfo>`
   * - :js:func:`canReset <Mozilla.UITour.Configuration.CanReset>`
   * - :js:func:`availableTargets <Mozilla.UITour.Configuration.AvailableTargets>`
   * - :js:func:`search <Mozilla.UITour.Configuration.Search>`
   * - :js:func:`selectedSearchEngine <Mozilla.UITour.Configuration.Search>`
   *   DEPRECATED, use 'search'
   * - :js:func:`sync <Mozilla.UITour.Configuration.Sync>`
   *   DEPRECATED, use 'fxa'
   * - :js:func:`fxa <Mozilla.UITour.Configuration.FxA>`
   * - :js:func:`fxaConnections <Mozilla.UITour.Configuration.FxAConnections>`
   *
   */

  /**
   * @namespace Mozilla.UITour.Configuration
   * @see Mozilla.UITour.getConfiguration
   * @see Mozilla.UITour.ConfigurationName
   */

  /**
   * @typedef {boolean} Mozilla.UITour.Configuration.CanReset
   *
   * @description Indicate whether a user can refresh their Firefox profile via :js:func:`Mozilla.UITour.resetFirefox`.
   *
   * @see Mozilla.UITour.resetFirefox
   * @since 48
   */

  /**
   * @typedef {object} Mozilla.UITour.Configuration.AppInfo
   * @property {boolean} canSetDefaultBrowserInBackground - Whether the application can be set as
   *                                                        the default browser in the background
   *                                                        without user interaction.
   * @property {boolean} defaultBrowser - Whether the application is the default browser. Since Fx40.
   * @property {string} defaultUpdateChannel - Update channel e.g. 'release', 'beta', 'aurora',
   *                                           'nightly', 'default'
   *                                           (self-built or automated testing builds)
   * @property {string} distribution - Contains the distributionId property. This value will be
   *                                   "default" in most cases but can differ for repack or
   *                                   funnelcake builds. Since Fx48
   * @property {number} profileCreatedWeeksAgo - The number of weeks since the profile was created,
   *                                             starting from 0 for profiles dating less than
   *                                             seven days old. Since Fx56.
   * @property {number} profileResetWeeksAgo - The number of weeks since the profile was last reset,
   *                                           starting from 0 for profiles reset less than seven
   *                                           days ago. If the profile has never been reset it
   *                                           returns null. Since Fx56.
   * @property {string} version - Version string e.g. "48.0a2"
   * @since 35
   */

  /**
   * @summary Search service configuration.
   *
   * @description From version 34 through 42 inclusive, a string was returned for the 'selectedSearchEngine'
   * configuration instead of the object like 'search'.
   *
   * @typedef {string | object} Mozilla.UITour.Configuration.Search
   * @property {string} searchEngineIdentifier - The default engine's identifier
   * @property {string[]} engines - Identifiers of visible engines
   * @since 43
   */

  /**
   * Sync status and device counts.
   *
   * @typedef {object} Mozilla.UITour.Configuration.Sync
   * @property {boolean} setup - Whether sync is setup
   * @property {number} desktopDevices - Number of desktop devices
   * @property {number} mobileDevices - Number of mobile devices
   * @property {number} totalDevices - Total number of connected devices
   * @since 50
   */

  /**
   * FxA local status, including whether FxA is connected and the general
   * account state.
   *
   * @typedef {object} Mozilla.UITour.Configuration.FxA
   * @property {boolean} setup - Whether FxA is setup on this device. If false,
   *    no other properties will exist.
   * @property {boolean} accountStateOK - Whether the FxA account state is OK.
   *    If false, it probably means the account is unverified or the user has
   *    changed their password on another device and needs to update it here.
   *    In that case many other properties will not exist.
   * @property {Mozilla.UITour.Configuration.BrowserServices} [browserServices] -
   *    Information about account services attached to this browser, and with
   *    special support implemented by this browser. You should not expect
   *    every accountService connected in this browser to get a special entry
   *    here. Indeed, what services, and in what circumstances they may appear
   *    here in the future is largely TBD.
   * @since 71
   */

  /**
   * FxA connections status - information about the account which typically
   * isn't stored locally, so needs to be obtained from the FxA servers. As such,
   * requesting this information is likely to be high-latency and may return
   * incomplete data if there is a network or server error.
   *
   * @typedef {object} Mozilla.UITour.Configuration.FxAConnections
   * @property {boolean} setup - Whether FxA is setup on this device. If false,
   *    no other properties will exist.
   * @property {number} [numOtherDevices] - Number of devices connected to this
   *    account, not counting this device.
   * @property {Object<string, number>} [numDevicesByType] - A count of devices
   *    connected to the account by device 'type'. Valid values for type are
   *    defined by the FxA server but roughly correspond to form-factor with
   *    values like 'desktop', 'mobile', 'vr', etc.
   * @property {Mozilla.UITour.Configuration.AccountServices} [accountServices] -
   *    Information about services attached to this account. These services
   *    may be enabled on devices or applications external to this
   *    browser and should not be confused with devices. For example, if the user
   *    has enabled Monitor or Lockwise on one or more devices - including on
   *    this device - that service will have a single entry here.
   * @since 73
   */

  /**
   * Information about clients attached to the account.
   * An object. The key is a string ID of the attached service. A list of attached
   * service IDs can be found
   * `on our telemetry documentation site <https://docs.telemetry.mozilla.org/datasets/fxa_metrics/attribution.html#service-attribution>`_.
   * The value is a :js:func:`Mozilla.UITour.Configuration.AccountService`
   *
   * @typedef {Object<string, Mozilla.UITour.Configuration.AccountService>} Mozilla.UITour.Configuration.AccountServices
   * @since 71
   */

  /**
   * Information about an account service
   *
   * @typedef {object} Mozilla.UITour.Configuration.AccountService
   * @property {string} id - The service ID. A list of attached
   * service IDs can be found
   * `on our telemetry documentation site <https://docs.telemetry.mozilla.org/datasets/fxa_metrics/attribution.html#service-attribution>`_.
   * @property {number} lastAccessedWeeksAgo - How many weeks ago the service
   *    was accessed by this account.
   * @since 71
   */

  /**
   * Information about a services attached to the browser. All properties are
   * optional and only exist if the service is enabled.
   *
   * @typedef {object} Mozilla.UITour.Configuration.BrowserServices
   * @property {Mozilla.UITour.Configuration.Sync} sync - If sync is configured
   * @since 71
   */

  /**
   * Array of UI :js:func:`Targets <Mozilla.UITour.Target>` currently available to be annotated.
   *
   * @typedef {Mozilla.UITour.Target[]} Mozilla.UITour.Configuration.AvailableTargets
   */

  /**
   * Retrieve some information about the application/profile.
   *
   * @param {Mozilla.UITour.ConfigurationName} configName - Name of configuration to retrieve
   * @param {Function} callback - Called with one argument containing the value of the configuration.
   */
  Mozilla.UITour.getConfiguration = function (configName, callback) {
    _sendEvent("getConfiguration", {
      callbackID: _waitForCallback(callback),
      configuration: configName,
    });
  };

  /**
   * Set some value or take some action.
   *
   * Valid configuration names:
   *
   * defaultBrowser
   *   Try to set the application as the default web browser. Since Fx40
   *
   * @param {string} configName - Configuration name to set (e.g. "defaultBrowser")
   * @param {string | number | boolean} [configValue] - Not currently used
   *
   * @since 40
   * @example
   * Mozilla.UITour.setConfiguration('defaultBrowser');
   */
  Mozilla.UITour.setConfiguration = function (configName, configValue) {
    _sendEvent("setConfiguration", {
      configuration: configName,
      value: configValue,
    });
  };

  /**
   * Request the browser open the Firefox Accounts page.
   *
   * @param {object} extraURLParams - An object containing additional
   * parameters for the URL opened by the browser for reasons of promotional
   * campaign tracking. Each attribute of the object must have a name that
   * is a string, is "flow_id", "flow_begin_time", "device_id" or begins
   * with `utm_` and contains only only alphanumeric characters, dashes or
   * underscores. The values may be any string and will automatically be encoded.
   * For Flow metrics, see details at https://mozilla.github.io/ecosystem-platform/docs/fxa-engineering/fxa-metrics#content-server
   * @param {string} entrypoint - A string containing the entrypoint name.
   * @param {string} email - A string containing the default email account
   * for the URL opened by the browser.
   * @since 31, 47 for `extraURLParams`
   * @since 79 for "flow_id", "flow_begin_time", "device_id", "entrypoint_experiment",
   * "entrypoint", "entrypoint_variation" fields.
   * @example
   * // Will open https://accounts.firefox.com/signup?entrypoint=uitour
   * Mozilla.UITour.showFirefoxAccounts();
   * @example
   * // Will open:
   * // https://accounts.firefox.com/signup?entrypoint=uitour&utm_foo=bar&utm_bar=baz
   * Mozilla.UITour.showFirefoxAccounts({
   *   'utm_foo': 'bar',
   *   'utm_bar': 'baz'
   * });
   * @example
   * // Will open:
   * // https://accounts.firefox.com/?action=email&email=foo%40bar.com&entrypoint=uitour
   * Mozilla.UITour.showFirefoxAccounts(null, null, "foo@bar.com");
   * @example
   * // Will open:
   * // https://accounts.firefox.com/signup?entrypoint=sample
   * Mozilla.UITour.showFirefoxAccounts(null, "sample");
   * @example
   * // Will open:
   * // https://accounts.firefox.com/?action=email&email=foo%40bar.com&entrypoint=uitour&flow_id=c5b5ad7c4a94462afe4b9a7fbcca263dbd6c8409fb4539449c50c4a52544b2ed&flow_begin_time=1590680755812
   * Mozilla.UITour.showFirefoxAccounts({
   *   flow_id: 'c5b5ad7c4a94462afe4b9a7fbcca263dbd6c8409fb4539449c50c4a52544b2ed',
   *   flow_begin_time: 1590680755812,
   *   device_id: '7e450f3337d3479b8582ea1c9bb5ba6c'
   * }, "foo@bar.com");
   */
  Mozilla.UITour.showFirefoxAccounts = function (
    extraURLParams,
    entrypoint,
    email
  ) {
    _sendEvent("showFirefoxAccounts", {
      extraURLParams: JSON.stringify(extraURLParams),
      entrypoint,
      email,
    });
  };

  /**
   * Request the browser open the "Connect Another Device" Firefox Accounts page.
   *
   * @param {object} extraURLParams - An object containing additional
   * parameters for the URL opened by the browser for reasons of promotional
   * campaign tracking. Each attribute of the object must have a name that
   * is a string, is "flow_id", "flow_begin_time", "device_id" or begins
   * with `utm_` and contains only only alphanumeric characters, dashes or
   * underscores. The values may be any string and will automatically be encoded.
   * For Flow metrics, see details at https://mozilla.github.io/ecosystem-platform/docs/fxa-engineering/fxa-metrics#content-server
   * @since 59
   * @example
   * // Will open https://accounts.firefox.com/connect_another_device?entrypoint=uitour
   * Mozilla.UITour.showConnectAnotherDevice();
   * @example
   * // Will open:
   * // https://accounts.firefox.com/connect_another_device?entrypoint=uitour&utm_foo=bar&utm_bar=baz
   * Mozilla.UITour.showConnectAnotherDevice({
   *   'utm_foo': 'bar',
   *   'utm_bar': 'baz'
   * });
   */
  Mozilla.UITour.showConnectAnotherDevice = function (extraURLParams) {
    _sendEvent("showConnectAnotherDevice", {
      extraURLParams: JSON.stringify(extraURLParams),
    });
  };

  /**
   * Show a profile refresh/reset dialog, allowing users to choose to reomve
   * add-ons and customizations as well as restore browser defaults, if possible.
   * `getConfiguration('canReset')` should first be used to determine whether
   * Refresh/Reset is possible for the user's build/profile.
   *
   * @since 48
   * @see Mozilla.UITour.Configuration.CanReset
   */
  Mozilla.UITour.resetFirefox = function () {
    _sendEvent("resetFirefox");
  };

  /**
   * Add the specified customizable widget to the navigation toolbar.
   *
   * @param {Mozilla.UITour.Target} name - Identifier of the customizable widget.
   * @param {Function} callback - Called with no arguments once the icon was successfully added to
   *                              the toolbar. Not called if it doesn't succeed.
   * @since 33.1
   * @example
   * Mozilla.UITour.addNavBarWidget('forget', function () {
   *   console.log('forget button added to toolbar');
   * });
   */
  Mozilla.UITour.addNavBarWidget = function (name, callback) {
    _sendEvent("addNavBarWidget", {
      name,
      callbackID: _waitForCallback(callback),
    });
  };

  /**
   * Set the specified search engine as the user-set default.
   *
   * See https://searchfox.org/mozilla-release/source/browser/locales/search/list.json
   *
   * @param {string} identifier - Identifier of the engine (e.g. 'yahoo').
   * @see Mozilla.UITour.Configuration.Search
   * @since 34
   */
  Mozilla.UITour.setDefaultSearchEngine = function (identifier) {
    _sendEvent("setDefaultSearchEngine", {
      identifier,
    });
  };

  /**
   * Sets a key+value pair as a treatment tag for recording in FHR.
   *
   * @param {string} name - tag name for the treatment
   * @param {string} value - tag value for the treatment
   * @since 34
   * @see Mozilla.UITour.getTreatmentTag
   * @example
   * Mozilla.UITour.setTreatmentTag('srch-chg-action', 'Switch');
   */
  Mozilla.UITour.setTreatmentTag = function (name, value) {
    _sendEvent("setTreatmentTag", {
      name,
      value,
    });
  };

  /**
   * Retrieved the value for a set FHR treatment tag.
   *
   * @param {string} name - Tag name to be retrieved
   * @param {Function} callback - Called once the data has been retrieved
   * @since 34
   * @see Mozilla.UITour.setTreatmentTag
   * @example
   * Mozilla.UITour.getTreatmentTag('srch-chg-action', function(value) {
   *   console.log(value);
   * });
   */
  Mozilla.UITour.getTreatmentTag = function (name, callback) {
    _sendEvent("getTreatmentTag", {
      name,
      callbackID: _waitForCallback(callback),
    });
  };

  /**
   * Set the search term in the search box.
   *
   * This should have been implemented via `setConfiguration("searchTerm", …)`.
   *
   * @param {string} term - Search string e.g. 'Firefox'
   * @since 34
   */
  Mozilla.UITour.setSearchTerm = function (term) {
    _sendEvent("setSearchTerm", {
      term,
    });
  };

  /**
   * @summary Opens the search box's panel.
   *
   * @description This should have been implemented via `showMenu("search", …)`.
   *
   * @param {Function} callback - Called once the panel has opened.
   * @since 34
   */
  Mozilla.UITour.openSearchPanel = function (callback) {
    _sendEvent("openSearchPanel", {
      callbackID: _waitForCallback(callback),
    });
  };

  /**
   * @summary Force the reader mode icon to appear in the address bar regardless of whether
   * heuristics determine it's appropriate.
   *
   * @description This is useful if you want to target an annotation (panel/highlight) on it
   * but the tour page doesn't have much textual content.
   */
  Mozilla.UITour.forceShowReaderIcon = function () {
    _sendEvent("forceShowReaderIcon");
  };

  /**
   * Toggle into reader mode for the current tab. Once the user enters reader
   * mode, the UITour document will not be active and therefore cannot call other
   * UITour APIs.
   */
  Mozilla.UITour.toggleReaderMode = function () {
    _sendEvent("toggleReaderMode");
  };

  /**
   * @param {string} pane - Pane to open/switch the preferences to.
   * Valid values match fragments on about:preferences and are subject to change e.g.:
   *
   * For the Preferences:
   *
   * - general
   * - applications
   * - sync
   * - privacy
   * - advanced
   *
   * To open to the options of sending telemetry, health report, crash reports,
   * that is, the privacy pane > reports on the preferences.
   * Please call `Mozilla.UITour.openPreferences("privacy-reports")`.
   * UITour would do route mapping automatically.
   *
   * @since 42
   */
  Mozilla.UITour.openPreferences = function (pane) {
    _sendEvent("openPreferences", {
      pane,
    });
  };

  /**
   * @summary Closes the tab where this code is running. As usual, if the tab is in the
   * foreground, the tab that was displayed before is selected.
   *
   * @description The last tab in the current window will never be closed, in which case
   * this call will have no effect. The calling code is expected to take an
   * action after a small timeout in order to handle this case, for example by
   * displaying a goodbye message or a button to restart the tour.
   * @since 46
   */
  Mozilla.UITour.closeTab = function () {
    _sendEvent("closeTab");
  };
})();

// Make this library Require-able.
/* eslint-env commonjs */
if (typeof module !== "undefined" && module.exports) {
  module.exports = Mozilla.UITour;
}