Bug 1420193 - Add Connect Another Device button to Sync onboarding panel. r?markh, mossop draft
authorEdouard Oger <eoger@fastmail.com>
Thu, 23 Nov 2017 12:17:37 -0500
changeset 713136 cea2584e00428f69e95f2e037293292daf38e51f
parent 713074 f1329009bf0da7b40229ea75ffe18f201b71359e
child 744256 75c934253d7555b271dc7ce590bf48598d93518f
push id93557
push userbmo:eoger@fastmail.com
push dateTue, 19 Dec 2017 18:25:01 +0000
reviewersmarkh, mossop
bugs1420193
milestone59.0a1
Bug 1420193 - Add Connect Another Device button to Sync onboarding panel. r?markh, mossop MozReview-Commit-ID: 7M6JMJALz2j
browser/components/uitour/UITour-lib.js
browser/components/uitour/UITour.jsm
browser/extensions/onboarding/content/onboarding-tour-agent.js
browser/extensions/onboarding/content/onboarding.css
browser/extensions/onboarding/content/onboarding.js
browser/extensions/onboarding/locales/en-US/onboarding.properties
--- a/browser/components/uitour/UITour-lib.js
+++ b/browser/components/uitour/UITour-lib.js
@@ -590,16 +590,43 @@ if (typeof Mozilla == "undefined") {
   Mozilla.UITour.showFirefoxAccounts = function(extraURLCampaignParams, email) {
     _sendEvent("showFirefoxAccounts", {
       extraURLCampaignParams: JSON.stringify(extraURLCampaignParams),
       email
     });
   };
 
   /**
+   * Request the browser open the "Connect Another Device" Firefox Accounts page.
+   *
+   * @param {Object} extraURLCampaignParams - 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, begins with "utm_" and contains only only alphanumeric
+   * characters, dashes or underscores. The values may be any string and will
+   * automatically be encoded.
+   * @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(extraURLCampaignParams) {
+    _sendEvent("showConnectAnotherDevice", {
+      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() {
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -564,16 +564,30 @@ this.UITour = {
           }
 
           // We want to replace the current tab.
           browser.loadURI(url.href);
         });
         break;
       }
 
+      case "showConnectAnotherDevice": {
+        const url = new URL(Services.prefs.getCharPref("identity.fxaccounts.remote.connectdevice.uri"));
+        url.searchParams.append("entrypoint", "uitour");
+        // Call our helper to validate extraURLCampaignParams and populate URLSearchParams
+        if (!this._populateCampaignParams(url, data.extraURLCampaignParams)) {
+          log.warn("showConnectAnotherDevice: invalid campaign args specified");
+          return false;
+        }
+
+        // We want to replace the current tab.
+        browser.loadURI(url.href);
+        break;
+      }
+
       case "resetFirefox": {
         // Open a reset profile dialog window.
         if (ResetProfile.resetSupported()) {
           ResetProfile.openConfirmationDialog(window);
         }
         break;
       }
 
--- a/browser/extensions/onboarding/content/onboarding-tour-agent.js
+++ b/browser/extensions/onboarding/content/onboarding-tour-agent.js
@@ -52,16 +52,19 @@ let onClick = evt => {
       Mozilla.UITour.showMenu("urlbar");
       break;
     case "onboarding-tour-sync-button":
       let emailInput = document.getElementById("onboarding-tour-sync-email-input");
       if (emailInput.checkValidity()) {
         Mozilla.UITour.showFirefoxAccounts(null, emailInput.value);
       }
       break;
+    case "onboarding-tour-sync-connect-device-button":
+      Mozilla.UITour.showConnectAnotherDevice();
+      break;
   }
   let classList = evt.target.classList;
   // On keyboard navigation the target would be .onboarding-tour-item.
   // On mouse clicking the target would be .onboarding-tour-item-container.
   if (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container")) {
     Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to change to other tours.
   }
 };
--- a/browser/extensions/onboarding/content/onboarding.css
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -351,34 +351,23 @@
 }
 
 .onboarding-tour-content > iframe {
   width: 100%;
   height: 100%;
   border: none;
 }
 
-.onboarding-tour-page.onboarding-no-button > .onboarding-tour-content {
-  grid-row: tour-page-start / tour-page-end;
-  grid-column: tour-content-start / tour-page-end;
-}
-
 .onboarding-tour-button-container {
   /* Get higher z-index in order to ensure buttons within container are selectable */
   z-index: 2;
   grid-row: tour-button-start / tour-page-end;
   grid-column: tour-content-start / tour-page-end;
 }
 
-.onboarding-tour-page.onboarding-no-button > .onboarding-tour-button-container {
-  display: none;
-  grid-row: tour-page-end;
-  grid-column: tour-page-end;
-}
-
 .onboarding-tour-action-button {
   background: #0060df;
   /* With 1px transparent border, could see a border in the high-constrast mode */
   border: 1px solid transparent;
   border-radius: 2px;
   padding: 10px 20px;
   font-size: 14px;
   font-weight: 600;
--- a/browser/extensions/onboarding/content/onboarding.js
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -38,17 +38,16 @@ const ICON_STATE_DEFAULT = "default";
  *   // The method returing strings used on tour notification
  *   getNotificationStrings(bundle):
  *     - title: // The string of tour notification title
  *     - message: // The string of tour notification message
  *     - button: // The string of tour notification action button title
  *   // Return a div appended with elements for this tours.
  *   // Each tour should contain the following 3 sections in the div:
  *   // .onboarding-tour-description, .onboarding-tour-content, .onboarding-tour-button-container.
- *   // Add onboarding-no-button css class in the div if this tour does not need a button container.
  *   // If there was a .onboarding-tour-action-button present and was clicked, tour would be marked as completed.
  *   getPage() {},
  * },
  **/
 var onboardingTourset = {
   "private": {
     id: "onboarding-tour-private-browsing",
     tourNameId: "onboarding.tour-private-browsing",
@@ -179,17 +178,16 @@ var onboardingTourset = {
         message: bundle.GetStringFromName("onboarding.notification.onboarding-tour-sync.message"),
         button: bundle.GetStringFromName("onboarding.button.learnMore"),
       };
     },
     getPage(win, bundle) {
       const STATE_LOGOUT = "logged-out";
       const STATE_LOGIN = "logged-in";
       let div = win.document.createElement("div");
-      div.classList.add("onboarding-no-button");
       div.dataset.loginState = STATE_LOGOUT;
       // The email validation pattern used in the form comes from IETF rfc5321,
       // which is identical to server-side checker of Firefox Account. See
       // discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1378770#c6
       // for detail.
       let emailRegex = "^[\\w.!#$%&’*+\\/=?^`{|}~-]{1,64}@[a-z\\d](?:[a-z\\d-]{0,253}[a-z\\d])?(?:\\.[a-z\\d](?:[a-z\\d-]{0,253}[a-z\\d])?)+$";
       div.innerHTML = `
         <section class="onboarding-tour-description">
@@ -202,16 +200,19 @@ var onboardingTourset = {
           <form class="show-on-logged-out">
             <h3 data-l10n-id="onboarding.tour-sync.form.title"></h3>
             <p data-l10n-id="onboarding.tour-sync.form.description"></p>
             <input id="onboarding-tour-sync-email-input" type="email" required="true"></input><br />
             <button id="onboarding-tour-sync-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-sync.button"></button>
           </form>
           <img src="resource://onboarding/img/figure_sync.svg" role="presentation"/>
         </section>
+        <aside class="onboarding-tour-button-container show-on-logged-in">
+          <button id="onboarding-tour-sync-connect-device-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-sync.connect-device.button"></button>
+        </aside>
       `;
       let emailInput = div.querySelector("#onboarding-tour-sync-email-input");
       emailInput.placeholder =
         bundle.GetStringFromName("onboarding.tour-sync.email-input.placeholder");
       emailInput.pattern = emailRegex;
 
       div.addEventListener("beforeshow", () => {
         function loginStatusListener(msg) {
--- a/browser/extensions/onboarding/locales/en-US/onboarding.properties
+++ b/browser/extensions/onboarding/locales/en-US/onboarding.properties
@@ -79,16 +79,17 @@ onboarding.tour-sync.logged-in.description=Sync works when you’re signed in to %1$S on more than one device. Have a mobile device? Install the %1$S app and sign in to get your bookmarks, history, and passwords on the go.
 # as a title and followed by onboarding.tour-sync.form.description.
 onboarding.tour-sync.form.title=Create a Firefox Account
 # LOCALIZATION NOTE(onboarding.tour-sync.form.description): The description
 # continues after onboarding.tour-sync.form.title to create a complete sentence.
 # If it's not possible for your locale, you can translate this string as
 # "Continue to Firefox Sync" instead.
 onboarding.tour-sync.form.description=to continue to Firefox Sync
 onboarding.tour-sync.button=Next
+onboarding.tour-sync.connect-device.button=Connect Another Device
 onboarding.tour-sync.email-input.placeholder=Email
 onboarding.notification.onboarding-tour-sync.title=Pick up where you left off.
 onboarding.notification.onboarding-tour-sync.message=Still sending yourself links to save or read on your phone? Do it the easy way: get Sync and have the things you save here show up on all of your devices.
 
 onboarding.tour-library=Library
 onboarding.tour-library.title=Keep it together.
 # LOCALIZATION NOTE (onboarding.tour-library.description2): This string will be used in the library tour description. %1$S is brandShortName
 onboarding.tour-library.description2=Check out the new %1$S library in the redesigned toolbar. The library puts the things you’ve seen and saved to %1$S — your browsing history, bookmarks, Pocket list, and synced tabs — in one convenient place.