Bug 1420193 - Add Connect Another Device button to Sync onboarding panel. r?markh, mossop
MozReview-Commit-ID: 7M6JMJALz2j
--- 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.