Bug 1357641 - Part 1: Add onboarding tour notification, r=mossop,flod
This commit
- adds onboarding tour notification
- shows still not completed onboarding tour notifications in order
- opens target tour from tour notification for the target tour
MozReview-Commit-ID: AwLtwjoeARQ
--- a/browser/extensions/onboarding/bootstrap.js
+++ b/browser/extensions/onboarding/bootstrap.js
@@ -6,17 +6,18 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
const PREF_WHITELIST = [
"browser.onboarding.enabled",
"browser.onboarding.hidden",
- "browser.onboarding.notification.finished"
+ "browser.onboarding.notification.finished",
+ "browser.onboarding.notification.lastPrompted"
];
/**
* Set pref. Why no `getPrefs` function is due to the priviledge level.
* We cannot set prefs inside a framescript but can read.
* For simplicity and effeciency, we still read prefs inside the framescript.
*
* @param {Array} prefs the array of prefs to set.
--- a/browser/extensions/onboarding/content/onboarding.css
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -32,30 +32,32 @@
offset-inline-start: 30px;
background: url("img/overlay-icon.svg") no-repeat;
}
#onboarding-overlay-dialog {
display: none;
}
-#onboarding-overlay-close-btn {
+#onboarding-overlay-close-btn,
+#onboarding-notification-close-btn {
position: absolute;
top: 15px;
offset-inline-end: 15px;
cursor: pointer;
width: 16px;
height: 16px;
background-image: url(chrome://browser/skin/sidebar/close.svg);
background-position: center center;
background-repeat: no-repeat;
padding: 12px;
}
-#onboarding-overlay-close-btn:hover {
+#onboarding-overlay-close-btn:hover,
+#onboarding-notification-close-btn:hover {
background-color: rgba(204, 204, 204, 0.6);
}
#onboarding-overlay.onboarding-opened > #onboarding-overlay-dialog {
width: 960px;
height: 510px;
background: #f5f5f7;
border: 1px solid rgba(9, 6, 13, 0.1); /* #09060D, 0.1 opacity */
@@ -231,47 +233,150 @@
}
/* Tour Icons */
#onboarding-tour-search {
background-image: url("img/icons_search.svg");
}
#onboarding-tour-search.onboarding-active,
-#onboarding-tour-search:hover {
+#onboarding-tour-search:hover,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-search] #onboarding-notification-tour-icon {
background-image: url("img/icons_search-colored.svg");
}
#onboarding-tour-private-browsing {
background-image: url("img/icons_private.svg");
}
#onboarding-tour-private-browsing.onboarding-active,
-#onboarding-tour-private-browsing:hover {
+#onboarding-tour-private-browsing:hover,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-private-browsing] #onboarding-notification-tour-icon {
background-image: url("img/icons_private-colored.svg");
}
#onboarding-tour-addons {
background-image: url("img/icons_addons.svg");
}
#onboarding-tour-addons.onboarding-active,
-#onboarding-tour-addons:hover {
+#onboarding-tour-addons:hover,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-addons] #onboarding-notification-tour-icon {
background-image: url("img/icons_addons-colored.svg");
}
#onboarding-tour-customize {
background-image: url("img/icons_customize.svg");
}
#onboarding-tour-customize.onboarding-active,
-#onboarding-tour-customize:hover {
+#onboarding-tour-customize:hover,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-customize] #onboarding-notification-tour-icon {
background-image: url("img/icons_customize-colored.svg");
}
#onboarding-tour-default-browser {
background-image: url("img/icons_default.svg");
}
#onboarding-tour-default-browser.onboarding-active,
-#onboarding-tour-default-browser:hover {
+#onboarding-tour-default-browser:hover,
+#onboarding-notification-bar[data-target-tour-id=onboarding-tour-default-browser] #onboarding-notification-tour-icon {
background-image: url("img/icons_default-colored.svg");
}
+
+
+/* Tour Notifications */
+#onboarding-notification-bar {
+ position: fixed;
+ z-index: 998; /* We want this always under #onboarding-overlay */
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: 122px;
+ min-width: 1060px;
+ background: rgba(255, 255, 255, 0.97);
+ border-top: 2px solid #e9e9e9;
+ transition: transform 0.8s;
+ transform: translateY(122px);
+}
+
+#onboarding-notification-bar.onboarding-opened {
+ transform: translateY(0px);
+}
+
+#onboarding-notification-icon {
+ height: 36px;
+ background: url("img/overlay-icon.svg") no-repeat;
+ background-size: 36px;
+ background-position: 34px;
+ padding-inline-start: 190px;
+ position: absolute;
+ offset-block-start: 50%;
+ transform: translateY(-50%);
+}
+
+#onboarding-notification-icon::after {
+ --height: 22px;
+ content: attr(data-tooltip);
+ background: #5ce6e6;
+ position: absolute;
+ top: 0;
+ offset-inline-start: 68px;
+ color: #10404a;
+ font-size: 12px;
+ min-height: var(--height);
+ line-height: var(--height);
+ border-radius: calc(var(--height) / 2);
+ border: 1px solid #fff;
+ padding: 0 10px;
+ text-align: center;
+}
+
+#onboarding-notification-close-btn {
+ background-color: rgba(255, 255, 255, 0.97);
+ border: none;
+ position: absolute;
+ offset-block-start: 50%;
+ offset-inline-end: 34px;
+ transform: translateY(-50%);
+}
+
+#onboarding-notification-message-section {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ position: absolute;
+ offset-block-start: 50%;
+ offset-inline-start: 50%;
+ transform: translate(-50%, -50%);
+}
+
+#onboarding-notification-body {
+ width: 420px;
+ margin: 0 15px;
+ color: #0c0c0d;;
+ display: inline-block;
+}
+
+#onboarding-notification-body * {
+ font-size: 13px
+}
+
+#onboarding-notification-tour-title {
+ margin: 0;
+}
+
+#onboarding-notification-tour-icon {
+ width: 64px;
+ height: 64px;
+ background-repeat: no-repeat;
+}
+
+#onboarding-notification-action-btn {
+ background: #0d96ff;
+ border: none;
+ border-radius: 3px;
+ padding: 10px 20px;
+ font-size: 14px;
+ color: #fff;
+ box-shadow: 0 1px 0 rgba(0,0,0,0.23);
+}
--- a/browser/extensions/onboarding/content/onboarding.js
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -22,28 +22,40 @@ const BRAND_SHORT_NAME = Services.string
/**
* Add any number of tours, following the format
* {
* // The unique tour id
* id: "onboarding-tour-addons",
* // The string id of tour name which would be displayed on the navigation bar
* tourNameId: "onboarding.tour-addon",
+ * // 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.
* // Add no-button css class in the div if this tour does not need a button.
* // The overlay layout will responsively position and distribute space for these 3 sections based on viewport size
* getPage() {},
* },
**/
var onboardingTours = [
{
id: "onboarding-tour-private-browsing",
tourNameId: "onboarding.tour-private-browsing",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-private-browsing.title"),
+ message: bundle.GetStringFromName("onboarding.notification.onboarding-tour-private-browsing.message"),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
getPage(win) {
let div = win.document.createElement("div");
div.innerHTML = `
<section class="onboarding-tour-description">
<h1 data-l10n-id="onboarding.tour-private-browsing.title"></h1>
<p data-l10n-id="onboarding.tour-private-browsing.description"></p>
</section>
<section class="onboarding-tour-content">
@@ -54,16 +66,23 @@ var onboardingTours = [
</aside>
`;
return div;
},
},
{
id: "onboarding-tour-addons",
tourNameId: "onboarding.tour-addons",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-addons.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-addons.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
getPage(win) {
let div = win.document.createElement("div");
div.innerHTML = `
<section class="onboarding-tour-description">
<h1 data-l10n-id="onboarding.tour-addons.title"></h1>
<p data-l10n-id="onboarding.tour-addons.description"></p>
</section>
<section class="onboarding-tour-content">
@@ -74,16 +93,23 @@ var onboardingTours = [
</aside>
`;
return div;
},
},
{
id: "onboarding-tour-customize",
tourNameId: "onboarding.tour-customize",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-customize.title"),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-customize.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
getPage(win) {
let div = win.document.createElement("div");
div.innerHTML = `
<section class="onboarding-tour-description">
<h1 data-l10n-id="onboarding.tour-customize.title"></h1>
<p data-l10n-id="onboarding.tour-customize.description"></p>
</section>
<section class="onboarding-tour-content">
@@ -94,16 +120,23 @@ var onboardingTours = [
</aside>
`;
return div;
},
},
{
id: "onboarding-tour-search",
tourNameId: "onboarding.tour-search",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.GetStringFromName("onboarding.notification.onboarding-tour-search.title"),
+ message: bundle.GetStringFromName("onboarding.notification.onboarding-tour-search.message"),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
getPage(win) {
let div = win.document.createElement("div");
div.innerHTML = `
<section class="onboarding-tour-description">
<h1 data-l10n-id="onboarding.tour-search.title"></h1>
<p data-l10n-id="onboarding.tour-search.description"></p>
</section>
<section class="onboarding-tour-content">
@@ -114,16 +147,23 @@ var onboardingTours = [
</aside>
`;
return div;
},
},
{
id: "onboarding-tour-default-browser",
tourNameId: "onboarding.tour-default-browser",
+ getNotificationStrings(bundle) {
+ return {
+ title: bundle.formatStringFromName("onboarding.notification.onboarding-tour-default-browser.title", [BRAND_SHORT_NAME], 1),
+ message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-default-browser.message", [BRAND_SHORT_NAME], 1),
+ button: bundle.GetStringFromName("onboarding.button.learnMore"),
+ };
+ },
getPage(win) {
let div = win.document.createElement("div");
let defaultBrowserButtonId = win.matchMedia("(-moz-os-version: windows-win7)").matches ?
"onboarding.tour-default-browser.win7.button" : "onboarding.tour-default-browser.button";
div.innerHTML = `
<section class="onboarding-tour-description">
<h1 data-l10n-id="onboarding.tour-default-browser.title"></h1>
<p data-l10n-id="onboarding.tour-default-browser.description"></p>
@@ -142,41 +182,61 @@ var onboardingTours = [
/**
* The script won't be initialized if we turned off onboarding by
* setting "browser.onboarding.enabled" to false.
*/
class Onboarding {
constructor(contentWindow) {
this.init(contentWindow);
- this._bundle = Services.strings.createBundle(BUNDLE_URI);
}
async init(contentWindow) {
this._window = contentWindow;
this._tourItems = [];
this._tourPages = [];
// We want to create and append elements after CSS is loaded so
// no flash of style changes and no additional reflow.
await this._loadCSS();
+ this._bundle = Services.strings.createBundle(BUNDLE_URI);
+
this._overlayIcon = this._renderOverlayIcon();
this._overlay = this._renderOverlay();
this._window.document.body.appendChild(this._overlayIcon);
this._window.document.body.appendChild(this._overlay);
this._loadJS(UITOUR_JS_URI);
this._loadJS(TOUR_AGENT_JS_URI);
this._overlayIcon.addEventListener("click", this);
this._overlay.addEventListener("click", this);
// Destroy on unload. This is to ensure we remove all the stuff we left.
// No any leak out there.
this._window.addEventListener("unload", () => this.destroy());
this._initPrefObserver();
+ this._initNotification();
+ }
+
+ _initNotification() {
+ let doc = this._window.document;
+ if (doc.hidden) {
+ // When the preloaded-browser feature is on,
+ // it would preload an hidden about:newtab in the background.
+ // We don't wnat to show notification in that hidden state.
+ let onVisible = () => {
+ if (!doc.hidden) {
+ doc.removeEventListener("visibilitychange", onVisible);
+ this.showNotification();
+ }
+ };
+ doc.addEventListener("visibilitychange", onVisible);
+ } else {
+ this.showNotification();
+ }
}
_initPrefObserver() {
if (this._prefsObserved) {
return;
}
this._prefsObserved = new Map();
@@ -214,58 +274,172 @@ class Onboarding {
case "onboarding-overlay-icon":
case "onboarding-overlay-close-btn":
// If the clicking target is directly on the outer-most overlay,
// that means clicking outside the tour content area.
// Let's toggle the overlay.
case "onboarding-overlay":
this.toggleOverlay();
break;
+
+ case "onboarding-notification-close-btn":
+ this.hideNotification();
+ break;
+
+ case "onboarding-notification-action-btn":
+ let tourId = this._notificationBar.dataset.targetTourId;
+ this.toggleOverlay();
+ this.gotoPage(tourId);
+ break;
}
if (evt.target.classList.contains("onboarding-tour-item")) {
this.gotoPage(evt.target.id);
}
}
destroy() {
this._clearPrefObserver();
this._overlayIcon.remove();
this._overlay.remove();
+ if (this._notificationBar) {
+ this._notificationBar.remove();
+ }
}
toggleOverlay() {
if (this._tourItems.length == 0) {
// Lazy loading until first toggle.
this._loadTours(onboardingTours);
}
- this._overlay.classList.toggle("opened");
+ this.hideNotification();
+ this._overlay.classList.toggle("onboarding-opened");
+
let hiddenCheckbox = this._window.document.getElementById("onboarding-tour-hidden-checkbox");
if (hiddenCheckbox.checked) {
this.hide();
- return;
}
-
- this._overlay.classList.toggle("onboarding-opened");
}
gotoPage(tourId) {
let targetPageId = `${tourId}-page`;
for (let page of this._tourPages) {
page.style.display = page.id != targetPageId ? "none" : "";
}
for (let li of this._tourItems) {
if (li.id == tourId) {
li.classList.add("onboarding-active");
} else {
li.classList.remove("onboarding-active");
}
}
}
+ isTourCompleted(tourId) {
+ return Preferences.get(`browser.onboarding.tour.${tourId}.completed`, false);
+ }
+
+ showNotification() {
+ if (Preferences.get("browser.onboarding.notification.finished", false)) {
+ return;
+ }
+
+ // Pick out the next target tour to show
+ let targetTour = null;
+
+ // Take the last tour as the default last prompted
+ // so below would start from the 1st one if found no the last prompted from the pref.
+ let lastPromptedId = onboardingTours[onboardingTours.length - 1].id;
+ lastPromptedId = Preferences.get("browser.onboarding.notification.lastPrompted", lastPromptedId);
+
+ let lastTourIndex = onboardingTours.findIndex(tour => tour.id == lastPromptedId);
+ if (lastTourIndex < 0) {
+ // Couldn't find the tour.
+ // This could be because the pref was manually modified into unknown value
+ // or the tour version has been updated so have an new tours set.
+ // Take the last tour as the last prompted so would start from the 1st one below.
+ lastTourIndex = onboardingTours.length - 1;
+ }
+
+ // Form tours to notify into the order we want.
+ // For example, There are tour #0 ~ #5 and the #3 is the last prompted.
+ // This would form [#4, #5, #0, #1, #2, #3].
+ // So the 1st met incomplete tour in #4 ~ #2 would be the one to show.
+ // Or #3 would be the one to show if #4 ~ #2 are all completed.
+ let toursToNotify = [ ...onboardingTours.slice(lastTourIndex + 1), ...onboardingTours.slice(0, lastTourIndex + 1) ];
+ targetTour = toursToNotify.find(tour => !this.isTourCompleted(tour.id));
+
+
+ if (!targetTour) {
+ this.sendMessageToChrome("set-prefs", [{
+ name: "browser.onboarding.notification.finished",
+ value: true
+ }]);
+ return;
+ }
+
+ // Show the target tour notification
+ this._notificationBar = this._renderNotificationBar();
+ this._notificationBar.addEventListener("click", this);
+ this._window.document.body.appendChild(this._notificationBar);
+
+ this._notificationBar.dataset.targetTourId = targetTour.id;
+ let notificationStrings = targetTour.getNotificationStrings(this._bundle);
+ let actionBtn = this._notificationBar.querySelector("#onboarding-notification-action-btn");
+ actionBtn.textContent = notificationStrings.button;
+ let tourTitle = this._notificationBar.querySelector("#onboarding-notification-tour-title");
+ tourTitle.textContent = notificationStrings.title;
+ let tourMessage = this._notificationBar.querySelector("#onboarding-notification-tour-message");
+ tourMessage.textContent = notificationStrings.message;
+
+ this._notificationBar.addEventListener("transitionend", () => {
+ this._notificationBar.dataset.cssTransition = "end";
+ }, { once: true });
+ this._window.requestAnimationFrame(() => {
+ // Request the 2nd animation frame.
+ // This is to make sure the appending operation above and the css operation happen
+ // in the different layout tick so as to make sure the transition happens.
+ this._window.requestAnimationFrame(() => this._notificationBar.classList.add("onboarding-opened"));
+ });
+
+ this.sendMessageToChrome("set-prefs", [{
+ name: "browser.onboarding.notification.lastPrompted",
+ value: targetTour.id
+ }]);
+ }
+
+ hideNotification() {
+ if (this._notificationBar) {
+ this._notificationBar.classList.remove("onboarding-opened");
+ delete this._notificationBar.dataset.cssTransition;
+ }
+ }
+
+ _renderNotificationBar() {
+ let div = this._window.document.createElement("div");
+ div.id = "onboarding-notification-bar";
+ // Here we use `innerHTML` is for more friendly reading.
+ // The security should be fine because this is not from an external input.
+ div.innerHTML = `
+ <div id="onboarding-notification-icon"></div>
+ <section id="onboarding-notification-message-section">
+ <div id="onboarding-notification-tour-icon"></div>
+ <div id="onboarding-notification-body">
+ <h6 id="onboarding-notification-tour-title"></h6>
+ <span id="onboarding-notification-tour-message"></span>
+ </div>
+ <button id="onboarding-notification-action-btn"></button>
+ </section>
+ <button id="onboarding-notification-close-btn"></button>
+ `;
+ let toolTip = this._bundle.formatStringFromName("onboarding.notification-icon-tool-tip", [BRAND_SHORT_NAME], 1);
+ div.querySelector("#onboarding-notification-icon").setAttribute("data-tooltip", toolTip);
+ return div;
+ }
+
hide() {
this.sendMessageToChrome("set-prefs", [
{
name: "browser.onboarding.hidden",
value: true
},
{
name: "browser.onboarding.notification.finished",
@@ -274,17 +448,16 @@ class Onboarding {
]);
}
_renderOverlay() {
let div = this._window.document.createElement("div");
div.id = "onboarding-overlay";
// Here we use `innerHTML` is for more friendly reading.
// The security should be fine because this is not from an external input.
- // We're not shipping yet so l10n strings is going to be closed for now.
div.innerHTML = `
<div id="onboarding-overlay-dialog">
<span id="onboarding-overlay-close-btn"></span>
<header id="onboarding-header"></header>
<nav>
<ul id="onboarding-tour-list"></ul>
</nav>
<footer id="onboarding-footer">
--- a/browser/extensions/onboarding/locales/en-US/onboarding.properties
+++ b/browser/extensions/onboarding/locales/en-US/onboarding.properties
@@ -1,45 +1,64 @@
# 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/.
-# LOCALIZATION NOTE(onboarding.tour-title): This string will be used in the overlay title. %S is brandShortName
+# LOCALIZATION NOTE(onboarding.overlay-title): This string will be used in the overlay title. %S is brandShortName
onboarding.overlay-title=Getting started with %S
+
onboarding.tour-search=One-Click Search
onboarding.tour-search.title=Find the needle or the haystack.
-
# LOCALIZATION NOTE (onboarding.tour-search.description): If Amazon is not part
# of the default searchplugins for your locale, you can replace it with another
# ecommerce website (if you're shipping one), but not with a general purpose
# search engine (Google, Bing, Yandex, etc.). Alternatively, only reference
# Wikipedia and drop Amazon from the text.
onboarding.tour-search.description=Having a default search engine doesn’t mean it’s the only one you use. Pick a search engine or a site, like Amazon or Wikipedia, to search on the fly.
onboarding.tour-search.button=Open One-Click Search
+onboarding.notification.onboarding-tour-search.title=Find it faster.
+onboarding.notification.onboarding-tour-search.message=Access all of your favorite search engines with a click. Search the whole Web or just one website right from the search box.
+
onboarding.tour-private-browsing=Private Browsing
onboarding.tour-private-browsing.title=A little privacy goes a long way.
-
# LOCALIZATION NOTE(onboarding.tour-private-browsing.description): %S is brandShortName.
onboarding.tour-private-browsing.description=Browse the internet without saving your searches or the sites you visited. When your session ends, the cookies disappear from %S like they were never there.
onboarding.tour-private-browsing.button=Show Private Browsing in Menu
-onboarding.hidden-checkbox-label=Hide the tour
+onboarding.notification.onboarding-tour-private-browsing.title=Browse by yourself.
+onboarding.notification.onboarding-tour-private-browsing.message=There’s no reason to share your online life with trackers every time you browse. Want to keep something to yourself? Use Private Browsing with Tracking Protection.
+
onboarding.tour-addons=Add-ons
onboarding.tour-addons.title=Add more functionality.
+onboarding.notification.onboarding-tour-addons.title=Get more done.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-addons.message): %S is brandShortName.
+onboarding.notification.onboarding-tour-addons.message=Add-ons are small apps you can add to %S that do lots of things — from managing to-do lists, to downloading videos, to changing the look of your browser.
# LOCALIZATION NOTE(onboarding.tour-addons.description): This string will be used in the add-on tour description. %1$S is brandShortName
onboarding.tour-addons.description=Add-ons expand %1$S’s built-in features, so %1$S works the way you do. Compare prices, check the weather or express your personality with a custom theme.
onboarding.tour-addons.button=Show Add-ons in Menu
onboarding.tour-customize=Customize
onboarding.tour-customize.title=Do things your way.
-
# LOCALIZATION NOTE(onboarding.tour-customize.description): This string will be used in the customize tour description. %S is brandShortName
onboarding.tour-customize.description=Drag, drop, and reorder %S’s toolbar and menu to fit your needs. You can even select a compact theme to give websites more room.
onboarding.tour-customize.button=Show Customize in Menu
+onboarding.notification.onboarding-tour-customize.title=Rearrange your toolbar.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-customize.message): %S is brandShortName.
+onboarding.notification.onboarding-tour-customize.message=Put the tools you use most right at your fingertips. Add more options to your toolbar. Or select a theme to make %S reflect your personality.
+
onboarding.tour-default-browser=Default Browser
onboarding.tour-default-browser.title=We’re there for you.
-
# LOCALIZATION NOTE(onboarding.tour-default-browser.description): This string will be used in the default browser tour description. %1$S is brandShortName
onboarding.tour-default-browser.description=Love %1$S? Set it as your default browser. Then when you open a link from another application, %1$S has you covered.
-
# LOCALIZATION NOTE(onboarding.tour-default-browser.button): Label for a button to open the OS default browser settings where it's not possible to set the default browser directly. (OSX, Linux, Windows 8 and higher)
onboarding.tour-default-browser.button=Open Default Browser Settings
-
# LOCALIZATION NOTE(onboarding.tour-default-browser.win7.button): Label for a button to directly set the default browser (Windows 7). %S is brandShortName
onboarding.tour-default-browser.win7.button=Make %S Your Default Browser
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-default-browser.title): %S is brandShortName.
+onboarding.notification.onboarding-tour-default-browser.title=Make %S your go-to browser.
+# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-default-browser.message): %1$S is brandShortName
+onboarding.notification.onboarding-tour-default-browser.message=It doesn’t take much to get the most from %1$S. Just set %1$S as your default browser and put control, customization, and protection on autopilot.
+
+onboarding.hidden-checkbox-label=Hide the tour
+
+#LOCALIZATION NOTE(onboarding.button.learnMore): this string is used as a button label, displayed near the message, and shared across all the onboarding notifications.
+onboarding.button.learnMore=Learn More
+
+# LOCALIZATION NOTE(onboarding.notification-icon-tool-tip): %S is brandShortName.
+onboarding.notification-icon-tool-tip=New to %S?
--- a/browser/extensions/onboarding/test/browser/head.js
+++ b/browser/extensions/onboarding/test/browser/head.js
@@ -26,17 +26,17 @@ function promiseOnboardingOverlayLoaded(
);
}
function promiseOnboardingOverlayOpened(browser) {
let condition = () => {
return ContentTask.spawn(browser, {}, function() {
return new Promise(resolve => {
let overlay = content.document.querySelector("#onboarding-overlay");
- if (overlay.classList.contains("opened")) {
+ if (overlay.classList.contains("onboarding-opened")) {
resolve(true);
return;
}
resolve(false);
});
})
};
return BrowserTestUtils.waitForCondition(