--- a/browser/components/uitour/UITour-lib.js
+++ b/browser/components/uitour/UITour-lib.js
@@ -1,22 +1,37 @@
/* 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.
+ *
+ * <p>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
+ * {@link https://dxr.mozilla.org/mozilla-central/source/browser/app/permissions|
+ * browser/app/permissions}.</p>
+ *
+ * @since 29
+ * @namespace
+ */
Mozilla.UITour = {};
}
var themeIntervalId = null;
function _stopCyclingThemes() {
if (themeIntervalId) {
clearInterval(themeIntervalId);
themeIntervalId = null;
@@ -66,43 +81,130 @@ if (typeof Mozilla == "undefined") {
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
+ * <code>`Mozilla.UITour.getConfiguration('availableTargets', callback)`</code> to determine
+ * which ones are available at a given time.
+ * @see Mozilla.UITour.getConfiguration
+ * @see Mozilla.UITour.showHighlight
+ * @see Mozilla.UITour.showInfo
+ *
+ * @description Valid values:<ul>
+ * <li>accountStatus
+ * <li>addons
+ * <li>appMenu
+ * <li>backForward
+ * <li>bookmarks
+ * <li>controlCenter-trackingUnblock
+ * <li>controlCenter-trackingBlock
+ * <li>customize
+ * <li>devtools
+ * <li>help
+ * <li>home
+ * <li>forget
+ * <li>pocket
+ * <li>privateWindow
+ * <li>quit
+ * <li>readerMode-urlBar
+ * <li>search
+ * <li>searchIcon
+ * <li>searchPrefsLink
+ * <li>selectedTabIcon
+ * <li>trackingProtection
+ * <li>urlbar
+ * <li>webide
+ * </ul>
+ *
+ * Generate using the following in the Browser Console:
+ * <code>`[...UITour.targets.keys()].join("\n* <li>")`</code>
+ */
+
+ /**
+ * 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
+ * {@link https://wiki.mozilla.org/Telemetry|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
});
};
+ /**
+ * Show a global notification bar with a prompt and optional buttons.
+ *
+ * Only intended for use by Self Support.
+ *
+ * @deprecated Use Heartbeat from
+ * {@link https://wiki.mozilla.org/Firefox/Shield/Heartbeat|Shield} instead.
+ *
+ * @param {String} message - Text to show in the notification bar before an action is taken.
+ * @param {String} thankyouMessage - Text to show in the notification bar after a vote.
+ * @param {String} flowId - An identifier for this rating flow. Please note that this is only used
+ * to identify the notification box.
+ * @param {String} engagementURL - URL to open in a new tab once the user has engaged.
+ * @param {String} learnMoreLabel - The label of the learn more link. No link will be shown if
+ * this is null.
+ * @param {String} learnMoreURL - URL to open when clicking on the learn more link. No link will be
+ * shown if this is an invalid URL.
+ * @param {Object} options - Options to control behavior.
+ */
Mozilla.UITour.showHeartbeat = function(message, thankyouMessage, flowId, engagementURL,
learnMoreLabel, learnMoreURL, options) {
var args = {
message,
thankyouMessage,
flowId,
engagementURL,
learnMoreLabel,
@@ -116,27 +218,96 @@ if (typeof Mozilla == "undefined") {
}
args[option] = options[option];
}
}
_sendEvent("showHeartbeat", args);
};
+ /**
+ * @typedef {String} Mozilla.UITour.HighlightEffect
+ *
+ * Specifies the effect/animation to use when highlighting UI elements.
+ * @description Valid values:<ul>
+ * <li>random
+ * <li>wobble
+ * <li>zoom
+ * <li>color
+ * </ul>
+ *
+ * Generate using the following in the Browser Console:
+ * <code>[...UITour.highlightEffects].join("\n* <li>")</code>
+ * @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,
@@ -157,34 +328,84 @@ if (typeof Mozilla == "undefined") {
text,
icon,
buttons: buttonData,
closeButtonCallbackID,
targetCallbackID
});
};
+ /**
+ * Hide any visible info panels.
+ * @see Mozilla.UITour.showInfo
+ */
Mozilla.UITour.hideInfo = function() {
_sendEvent("hideInfo");
};
+ /**
+ * Preview a lightweight-theme applied to the browser UI.
+ *
+ * @see Mozilla.UITour.cycleThemes
+ * @see Mozilla.UITour.resetTheme
+ *
+ * @param {Object} theme - Theme object format expected by `LightweightThemeManager.previewTheme`
+ * @example
+ * var theme = {
+ * …
+ * "iconURL": "https://addons.mozilla.org/_files/…/preview_small.jpg",
+ * "headerURL": "https://addons.mozilla.org/_files/….jpg",
+ * "name": "My cool theme",
+ * "author": "Mozilla",
+ * "footer": "https://addons.mozilla.org/_files/….jpg",
+ * "previewURL": "https://addons.mozilla.org/_files/…/preview.jpg",
+ * "updateURL": "https://versioncheck.addons.mozilla.org/…",
+ * "accentcolor": "#000000",
+ * "header": "https://addons.mozilla.org/_files/….jpg",
+ * "version": "1.0",
+ * "footerURL": "https://addons.mozilla.org/_files/….jpg",
+ * "detailURL": "https://addons.mozilla.org/firefox/addon/…",
+ * "textcolor": "#ffffff",
+ * "id": "18066",
+ * "description": "My awesome theme.",
+ * …
+ * };
+ *
+ * Mozilla.UITour.previewTheme(theme);
+ */
Mozilla.UITour.previewTheme = function(theme) {
_stopCyclingThemes();
_sendEvent("previewTheme", {
theme: JSON.stringify(theme)
});
};
+ /**
+ * Stop previewing and cycling themes, returning to the user's previous theme.
+ * @see Mozilla.UITour.cycleThemes
+ * @see Mozilla.UITour.previewTheme
+ */
Mozilla.UITour.resetTheme = function() {
_stopCyclingThemes();
_sendEvent("resetTheme");
};
+ /**
+ * Cycle between an array of themes using the given delay.
+ *
+ * @see Mozilla.UITour.previewTheme
+ * @see Mozilla.UITour.resetTheme
+ *
+ * @param {Object[]} themes - Array of themes
+ * @param {Number} [delay=Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY]
+ * - Time in milliseconds between rotating themes
+ * @param {Function} callback - Function called at each rotation
+ */
Mozilla.UITour.cycleThemes = function(themes, delay, callback) {
_stopCyclingThemes();
if (!delay) {
delay = Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY;
}
function nextTheme() {
@@ -198,132 +419,366 @@ if (typeof Mozilla == "undefined") {
callback(theme);
}
themeIntervalId = setInterval(nextTheme, delay);
nextTheme();
};
+ /**
+ * @typedef {String} Mozilla.UITour.MenuName
+ * Valid values:<ul>
+ * <li>appMenu
+ * <li>bookmarks
+ * <li>controlCenter
+ * <li>pocket
+ * </ul>
+ *
+ * @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");
};
+
+ /**
+ * @typedef Mozilla.UITour.ConfigurationName
+ * @description Valid values:<ul>
+ * <li>{@link Mozilla.UITour.Configuration.AppInfo|appinfo}</li>
+ * <li>{@link Mozilla.UITour.Configuration.CanReset|canReset}</li>
+ * <li>{@link Mozilla.UITour.Configuration.AvailableTargets|availableTargets}</li>
+ * <li>{@link Mozilla.UITour.Configuration.Search|search}</li>
+ * <li>{@link Mozilla.UITour.Configuration.Search|selectedSearchEngine}
+ * - DEPRECATED, use 'search'</li>
+ * <li>{@link Mozilla.UITour.Configuration.Sync|sync}</li>
+ * </ul>
+ */
+
+ /**
+ * @namespace Mozilla.UITour.Configuration
+ * @see Mozilla.UITour.getConfiguration
+ * @see Mozilla.UITour.ConfigurationName
+ */
+
+ /**
+ * Indicate whether a user can refresh their Firefox profile via {@link Mozilla.UITour.resetFirefox}.
+ * @typedef {Boolean} Mozilla.UITour.Configuration.CanReset
+ * @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 {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
+ */
+
+ /**
+ * Array of UI {@link Mozilla.UITour.Target|Targets} 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.
+ *
+ * <p><strong>Valid configuration names:</strong><dl>
+ * <dt>defaultBrowser</dt>
+ * <dd>Try to set the application as the default web browser. Since Fx40</dd>
+ * </dl></p>
+ *
+ * @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} extraURLCampaignParams - An object containing additional
- * paramaters for the URL opened by the browser for reasons of promotional
+ * 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, begins with "utm_" and contains only only alphanumeric
* characters, dashes or underscores. The values may be any string and will
* automatically be encoded.
+ * @since 31, 47 for `extraURLCampaignParams`
+ * @example
+ * // Will open about:accounts?action=signup&entrypoint=uitour
+ * Mozilla.UITour.showFirefoxAccounts();
+ * @example
+ * // Will open:
+ * // about:accounts?action=signup&entrypoint=uitour&utm_foo=bar&utm_bar=baz
+ * Mozilla.UITour.showFirefoxAccounts({
+ * 'utm_foo': 'bar',
+ * 'utm_bar': 'baz'
+ * });
*/
Mozilla.UITour.showFirefoxAccounts = function(extraURLCampaignParams) {
_sendEvent("showFirefoxAccounts", {
extraURLCampaignParams: JSON.stringify(extraURLCampaignParams),
});
};
+ /**
+ * 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 {@link https://dxr.mozilla.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.:<ul>
+ * <li>general
+ * <li>search
+ * <li>content
+ * <li>applications
+ * <li>privacy
+ * <li>security
+ * <li>sync
+ * <li>advanced
+ * </ul>
+ * @since 42
+ */
Mozilla.UITour.openPreferences = function(pane) {
_sendEvent("openPreferences", {
pane
});
};
/**
- * Closes the tab where this code is running. As usual, if the tab is in the
+ * @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.
*
- * The last tab in the current window will never be closed, in which case
+ * @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 */