Bug 1467572 - Part 18: Show an onboarding tooltip for the setting menu button in RDM. r=jdescottes
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 15 Aug 2018 17:27:57 -0400
changeset 486963 5d6965e5700a8fb2e00b652a49153bbad09ee175
parent 486962 599eb93053e0c513acdc25bc921b5b2103732151
child 486964 7080672c7b8e659ffecf3ea8a7cb1d28888f8fc7
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1467572, 12408235
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1467572 - Part 18: Show an onboarding tooltip for the setting menu button in RDM. r=jdescottes Design https://mozilla.invisionapp.com/d/main#/console/12408235/300479943/preview
devtools/client/inspector/shared/three-pane-onboarding-tooltip.js
devtools/client/locales/en-US/responsive.properties
devtools/client/preferences/devtools-client.js
devtools/client/responsive.html/manager.js
devtools/client/responsive.html/moz.build
devtools/client/responsive.html/setting-onboarding-tooltip.js
devtools/client/responsive.html/test/browser/head.js
devtools/client/themes/tooltips.css
--- a/devtools/client/inspector/shared/three-pane-onboarding-tooltip.js
+++ b/devtools/client/inspector/shared/three-pane-onboarding-tooltip.js
@@ -29,45 +29,45 @@ class ThreePaneOnboardingTooltip {
       type: "arrow",
       useXulWrapper: true,
     });
 
     this.onCloseButtonClick = this.onCloseButtonClick.bind(this);
     this.onLearnMoreLinkClick = this.onLearnMoreLinkClick.bind(this);
 
     const container = doc.createElementNS(XHTML_NS, "div");
-    container.className = "three-pane-onboarding-container";
+    container.className = "onboarding-container";
 
     const icon = doc.createElementNS(XHTML_NS, "span");
-    icon.className = "three-pane-onboarding-icon";
+    icon.className = "onboarding-icon";
     container.appendChild(icon);
 
     const content = doc.createElementNS(XHTML_NS, "div");
-    content.className = "three-pane-onboarding-content";
+    content.className = "onboarding-content";
     container.appendChild(content);
 
     const message = doc.createElementNS(XHTML_NS, "div");
     const learnMoreString = L10N.getStr("inspector.threePaneOnboarding.learnMoreLink");
     const messageString = L10N.getFormatStr("inspector.threePaneOnboarding.content",
       learnMoreString);
     const learnMoreStartIndex = messageString.indexOf(learnMoreString);
 
     message.append(messageString.substring(0, learnMoreStartIndex));
 
     this.learnMoreLink = doc.createElementNS(XHTML_NS, "a");
-    this.learnMoreLink.className = "three-pane-onboarding-link";
+    this.learnMoreLink.className = "onboarding-link";
     this.learnMoreLink.href = "#";
     this.learnMoreLink.textContent = learnMoreString;
 
     message.append(this.learnMoreLink);
     message.append(messageString.substring(learnMoreStartIndex + learnMoreString.length));
     content.append(message);
 
     this.closeButton = doc.createElementNS(XHTML_NS, "button");
-    this.closeButton.className = "three-pane-onboarding-close-button devtools-button";
+    this.closeButton.className = "onboarding-close-button devtools-button";
     container.appendChild(this.closeButton);
 
     this.closeButton.addEventListener("click", this.onCloseButtonClick);
     this.learnMoreLink.addEventListener("click", this.onLearnMoreLinkClick);
 
     this.tooltip.setContent(container, { width: CONTAINER_WIDTH });
     this.tooltip.show(this.doc.querySelector("#inspector-sidebar .sidebar-toggle"), {
       position: "top",
--- a/devtools/client/locales/en-US/responsive.properties
+++ b/devtools/client/locales/en-US/responsive.properties
@@ -127,8 +127,13 @@ responsive.reloadConditions.userAgent=Re
 # LOCALIZATION NOTE (responsive.reloadNotification.description): Text in notification bar
 # shown on first open to clarify that some features need a reload to apply.  %1$S is the
 # label on the reload conditions menu (responsive.reloadConditions.label).
 responsive.reloadNotification.description=Device simulation changes require a reload to fully apply.  Automatic reloads are disabled by default to avoid losing any changes in DevTools.  You can enable reloading via the ā€œ%1$Sā€ menu.
 
 # LOCALIZATION NOTE (responsive.leftAlignViewport): Label on checkbox used in the settings
 # menu.
 responsive.leftAlignViewport = Left-align Viewport
+
+# LOCALIZATION NOTE (responsive.settingOnboarding.content): This is the content shown in
+# the setting onboarding tooltip that is displayed below the settings menu button in
+# Responsive Design Mode.
+responsive.settingOnboarding.content=New: Change to left-alignment or edit reload behavior here.
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -313,16 +313,22 @@ pref("devtools.editor.autocomplete", tru
 // Whether or not the viewports are left aligned.
 pref("devtools.responsive.leftAlignViewport.enabled", false);
 // Whether to reload when touch simulation is toggled
 pref("devtools.responsive.reloadConditions.touchSimulation", false);
 // Whether to reload when user agent is changed
 pref("devtools.responsive.reloadConditions.userAgent", false);
 // Whether to show the notification about reloading to apply emulation
 pref("devtools.responsive.reloadNotification.enabled", true);
+// Whether to show the settings onboarding tooltip only in release or beta builds.
+#if defined(RELEASE_OR_BETA)
+pref("devtools.responsive.show-setting-tooltip", true);
+#else
+pref("devtools.responsive.show-setting-tooltip", false);
+#endif
 
 // Enable new about:debugging.
 pref("devtools.aboutdebugging.new-enabled", false);
 pref("devtools.aboutdebugging.network-locations", "[]");
 
 // about:debugging: only show system add-ons in local builds by default.
 #ifdef MOZILLA_OFFICIAL
   pref("devtools.aboutdebugging.showSystemAddons", false);
--- a/devtools/client/responsive.html/manager.js
+++ b/devtools/client/responsive.html/manager.js
@@ -9,29 +9,31 @@ const promise = require("promise");
 const Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 
 const TOOL_URL = "chrome://devtools/content/responsive.html/index.xhtml";
 
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/components/throttling/profiles");
+loader.lazyRequireGetter(this, "SettingOnboardingTooltip", "devtools/client/responsive.html/setting-onboarding-tooltip");
 loader.lazyRequireGetter(this, "swapToInnerBrowser", "devtools/client/responsive.html/browser/swap", true);
 loader.lazyRequireGetter(this, "startup", "devtools/client/responsive.html/utils/window", true);
 loader.lazyRequireGetter(this, "message", "devtools/client/responsive.html/utils/message");
 loader.lazyRequireGetter(this, "showNotification", "devtools/client/responsive.html/utils/notification", true);
 loader.lazyRequireGetter(this, "l10n", "devtools/client/responsive.html/utils/l10n");
 loader.lazyRequireGetter(this, "EmulationFront", "devtools/shared/fronts/emulation", true);
 loader.lazyRequireGetter(this, "PriorityLevels", "devtools/client/shared/components/NotificationBox", true);
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 
 const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
 const RELOAD_NOTIFICATION_PREF = "devtools.responsive.reloadNotification.enabled";
+const SHOW_SETTING_TOOLTIP_PREF = "devtools.responsive.show-setting-tooltip";
 
 function debug(msg) {
   // console.log(`RDM manager: ${msg}`);
 }
 
 /**
  * ResponsiveUIManager is the external API for the browser UI, etc. to use when
  * opening and closing the responsive UI.
@@ -372,16 +374,22 @@ ResponsiveUI.prototype = {
     // Notify the inner browser to start the frame script
     debug("Wait until start frame script");
     await message.request(this.toolWindow, "start-frame-script");
 
     // Get the protocol ready to speak with emulation actor
     debug("Wait until RDP server connect");
     await this.connectToServer();
 
+    // Show the settings onboarding tooltip
+    if (Services.prefs.getBoolPref(SHOW_SETTING_TOOLTIP_PREF)) {
+      this.settingOnboardingTooltip =
+        new SettingOnboardingTooltip(ui.toolWindow.document);
+    }
+
     // Non-blocking message to tool UI to start any delayed init activities
     message.post(this.toolWindow, "post-init");
 
     debug("Init done");
   },
 
   /**
    * Close RDM and restore page content back into a regular tab.
@@ -431,16 +439,21 @@ ResponsiveUI.prototype = {
                       this.reloadOnChange("userAgent");
       reloadNeeded |= await this.updateTouchSimulation() &&
                       this.reloadOnChange("touchSimulation");
       if (reloadNeeded) {
         this.getViewportBrowser().reload();
       }
     }
 
+    if (this.settingOnboardingTooltip) {
+      this.settingOnboardingTooltip.destroy();
+      this.settingOnboardingTooltip = null;
+    }
+
     // Destroy local state
     const swap = this.swap;
     this.browserWindow = null;
     this.tab = null;
     this.inited = null;
     this.toolWindow = null;
     this.swap = null;
 
--- a/devtools/client/responsive.html/moz.build
+++ b/devtools/client/responsive.html/moz.build
@@ -16,16 +16,17 @@ DIRS += [
 DevToolsModules(
     'commands.js',
     'constants.js',
     'index.css',
     'index.js',
     'manager.js',
     'reducers.js',
     'responsive-ua.css',
+    'setting-onboarding-tooltip.js',
     'store.js',
     'types.js',
 )
 
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 with Files('**'):
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/setting-onboarding-tooltip.js
@@ -0,0 +1,71 @@
+/* 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/. */
+
+"use strict";
+
+const Services = require("Services");
+const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
+
+const { getStr } = require("./utils/l10n");
+
+const SHOW_SETTING_TOOLTIP_PREF = "devtools.responsive.show-setting-tooltip";
+
+const CONTAINER_WIDTH = 270;
+
+/**
+ * Setting onboarding tooltip that is shown on the setting menu button in the RDM toolbar
+ * when the pref is on.
+ */
+class SettingOnboardingTooltip {
+  constructor(doc) {
+    this.doc = doc;
+    this.tooltip = new HTMLTooltip(this.doc, { type: "arrow" });
+
+    this.onCloseButtonClick = this.onCloseButtonClick.bind(this);
+
+    const container = doc.createElement("div");
+    container.className = "onboarding-container";
+
+    const icon = doc.createElement("span");
+    icon.className = "onboarding-icon";
+    container.appendChild(icon);
+
+    const content = doc.createElement("div");
+    content.className = "onboarding-content";
+    content.textContent = getStr("responsive.settingOnboarding.content");
+    container.appendChild(content);
+
+    this.closeButton = doc.createElement("button");
+    this.closeButton.className = "onboarding-close-button devtools-button";
+    container.appendChild(this.closeButton);
+
+    this.closeButton.addEventListener("click", this.onCloseButtonClick);
+
+    this.tooltip.setContent(container, { width: CONTAINER_WIDTH });
+    this.tooltip.show(this.doc.getElementById("settings-button"), {
+      position: "bottom",
+    });
+  }
+
+  destroy() {
+    this.closeButton.removeEventListener("click", this.onCloseButtonClick);
+
+    this.tooltip.destroy();
+
+    this.closeButton = null;
+    this.doc = null;
+    this.tooltip = null;
+  }
+
+  /**
+   * Handler for the "click" event on the close button. Hides the onboarding tooltip
+   * and sets the show three pane onboarding tooltip pref to false.
+   */
+  onCloseButtonClick() {
+    Services.prefs.setBoolPref(SHOW_SETTING_TOOLTIP_PREF, false);
+    this.tooltip.hide();
+  }
+}
+
+module.exports = SettingOnboardingTooltip;
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -50,23 +50,26 @@ SimpleTest.waitForExplicitFinish();
 // on debug builds. Usually we are just barely over the limit, so a blanket factor of 2
 // should be enough.
 requestLongerTimeout(2);
 
 Services.prefs.setCharPref("devtools.devices.url", TEST_URI_ROOT + "devices.json");
 // The appearance of this notification causes intermittent behavior in some tests that
 // send mouse events, since it causes the content to shift when it appears.
 Services.prefs.setBoolPref("devtools.responsive.reloadNotification.enabled", false);
+// Don't show the setting onboarding tooltip in the test suites.
+Services.prefs.setBoolPref("devtools.responsive.show-setting-tooltip", false);
 
 registerCleanupFunction(async () => {
   Services.prefs.clearUserPref("devtools.devices.url");
   Services.prefs.clearUserPref("devtools.responsive.reloadNotification.enabled");
   Services.prefs.clearUserPref("devtools.responsive.html.displayedDeviceList");
   Services.prefs.clearUserPref("devtools.responsive.reloadConditions.touchSimulation");
   Services.prefs.clearUserPref("devtools.responsive.reloadConditions.userAgent");
+  Services.prefs.clearUserPref("devtools.responsive.show-setting-tooltip");
   await asyncStorage.removeItem("devtools.devices.url_cache");
   await removeLocalDevices();
 });
 
 /**
  * Open responsive design mode for the given tab.
  */
 var openRDM = async function(tab) {
--- a/devtools/client/themes/tooltips.css
+++ b/devtools/client/themes/tooltips.css
@@ -558,57 +558,57 @@
 /* Tooltip: Image tooltip */
 
 .devtools-tooltip-image-broken {
   box-sizing: border-box;
   height: 100%;
   padding: 7px;
 }
 
-/* Tooltip: 3 Pane Inspecot Onboarding Tooltip */
+/* Tooltip: Onboarding Tooltip */
 
-.three-pane-onboarding-container {
+.onboarding-container {
   align-items: center;
   background-color: var(--theme-toolbar-background);
   box-sizing: border-box;
   color: var(--theme-body-color);
   display: flex;
   font-size: 12px;
   padding: 7px;
   width: 100%;
   -moz-user-select: none;
 }
 
-.three-pane-onboarding-icon {
+.onboarding-icon {
   display: inline-block;
   background-size: 21px;
   width: 21px;
   height: 21px;
   margin: 8px;
   background-image: url("chrome://devtools/skin/images/fox-smiling.svg");
 }
 
-.three-pane-onboarding-content {
+.onboarding-content {
   flex: 1;
   padding-inline-start: 5px;
 }
 
-.three-pane-onboarding-link {
+.onboarding-link {
   color: var(--onboarding-link-color);
   cursor: pointer;
 }
 
-.three-pane-onboarding-link:hover {
+.onboarding-link:hover {
   text-decoration: underline;
 }
 
-.three-pane-onboarding-link:active {
+.onboarding-link:active {
   color: var(--onboarding-link-active-color);
 }
 
-.three-pane-onboarding-close-button {
+.onboarding-close-button {
   align-self: flex-start;
 }
 
-.three-pane-onboarding-close-button::before {
+.onboarding-close-button::before {
   background-image: url("chrome://devtools/skin/images/close.svg");
   margin: -6px 0 0 -6px;
 }