/* 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 * {@link https://dxr.mozilla.org/mozilla-central/source/browser/app/permissions| * browser/app/permissions}.
* * @since 29 * @namespace */ Mozilla.UITour = {}; } var themeIntervalId = null; function _stopCyclingThemes() { if (themeIntervalId) { clearInterval(themeIntervalId); themeIntervalId = null; } } 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 *`Mozilla.UITour.getConfiguration('availableTargets', callback)` 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:`[...UITour.targets.keys()].join("\n* <li>")`
   */
  /**
   * 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,
      learnMoreURL,
    };
    if (options) {
      for (var option in options) {
	if (!options.hasOwnProperty(option)) {
	  continue;
	}
	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:[...UITour.highlightEffects].join("\n* <li>")
   * @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");
  };
  /**
   * 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",
   *   "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() {
      var theme = themes.shift();
      themes.push(theme);
      _sendEvent("previewTheme", {
	theme: JSON.stringify(theme),
	state: true
      });
      callback(theme);
    }
    themeIntervalId = setInterval(nextTheme, delay);
    nextTheme();
  };
  /**
   * @typedef {String} Mozilla.UITour.MenuName
   * Valid values:Valid configuration names: