Bug 1357021 - Part 1: Handle tours completed state, r=mossop

This commit
- turns on the `onboarding-complete` css style for completed tours
- sets individual tour as completed when action button of that tour is clicked
- sets all tours as completed if hide-the-tour checkbox is checked after toggling the overlay

MozReview-Commit-ID: mps3BrdhOz

--HG--
extra : rebase_source : 3023997897dc80f18b59b69e79a82c211338f88c
This commit is contained in:
Fischer.json 2017-06-18 14:46:09 +08:00
parent a6052d02e5
commit 219d62f6f1
4 changed files with 75 additions and 32 deletions

View File

@ -15,6 +15,15 @@ const PREF_WHITELIST = [
"browser.onboarding.notification.lastPrompted" "browser.onboarding.notification.lastPrompted"
]; ];
[
"onboarding-tour-private-browsing",
"onboarding-tour-addons",
"onboarding-tour-customize",
"onboarding-tour-search",
"onboarding-tour-default-browser",
"onboarding-tour-sync",
].forEach(tourId => PREF_WHITELIST.push(`browser.onboarding.tour.${tourId}.completed`));
/** /**
* Set pref. Why no `getPrefs` function is due to the priviledge level. * Set pref. Why no `getPrefs` function is due to the priviledge level.
* We cannot set prefs inside a framescript but can read. * We cannot set prefs inside a framescript but can read.

View File

@ -177,7 +177,7 @@
padding: 7px; padding: 7px;
} }
#onboarding-tour-sync-page form > button { #onboarding-tour-sync-page form > #onboarding-tour-sync-button {
padding: 10px 20px; padding: 10px 20px;
min-width: 40%; min-width: 40%;
font-size: 15px; font-size: 15px;
@ -190,6 +190,7 @@
box-shadow: 0 1px 0 rgba(0,0,0,0.23); box-shadow: 0 1px 0 rgba(0,0,0,0.23);
cursor: pointer; cursor: pointer;
margin: 15px 0; margin: 15px 0;
float: none;
} }
/* Onboarding tour pages */ /* Onboarding tour pages */
@ -242,18 +243,18 @@
grid-column: tour-content-start / tour-page-end; grid-column: tour-content-start / tour-page-end;
} }
.onboarding-tour-button { .onboarding-tour-button-container {
grid-row: tour-button-start / tour-page-end; grid-row: tour-button-start / tour-page-end;
grid-column: tour-content-start / tour-page-end; grid-column: tour-content-start / tour-page-end;
} }
.onboarding-tour-page.onboarding-no-button > .onboarding-tour-button { .onboarding-tour-page.onboarding-no-button > .onboarding-tour-button-container {
display: none; display: none;
grid-row: tour-page-end; grid-row: tour-page-end;
grid-column: tour-page-end; grid-column: tour-page-end;
} }
.onboarding-tour-button > button { .onboarding-tour-action-button {
padding: 10px 20px; padding: 10px 20px;
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
@ -269,7 +270,7 @@
margin-top: -32px; margin-top: -32px;
} }
.onboarding-tour-button > button:active { .onboarding-tour-action-button:active {
background: #0881dd; background: #0881dd;
} }
@ -418,6 +419,7 @@
#onboarding-notification-tour-icon { #onboarding-notification-tour-icon {
width: 64px; width: 64px;
height: 64px; height: 64px;
background-size: 64px;
background-repeat: no-repeat; background-repeat: no-repeat;
} }

View File

@ -34,9 +34,9 @@ const BRAND_SHORT_NAME = Services.strings
* - button: // The string of tour notification action button title * - button: // The string of tour notification action button title
* // Return a div appended with elements for this tours. * // Return a div appended with elements for this tours.
* // Each tour should contain the following 3 sections in the div: * // Each tour should contain the following 3 sections in the div:
* // .onboarding-tour-description, .onboarding-tour-content, .onboarding-tour-button. * // .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. * // Add onboarding-no-button css class in the div if this tour does not need a button container.
* // The overlay layout will responsively position and distribute space for these 3 sections based on viewport size * // If there was a .onboarding-tour-action-button present and was clicked, tour would be marked as completed.
* getPage() {}, * getPage() {},
* }, * },
**/ **/
@ -61,8 +61,8 @@ var onboardingTours = [
<section class="onboarding-tour-content"> <section class="onboarding-tour-content">
<img src="resource://onboarding/img/figure_private.svg" /> <img src="resource://onboarding/img/figure_private.svg" />
</section> </section>
<aside class="onboarding-tour-button"> <aside class="onboarding-tour-button-container">
<button id="onboarding-tour-private-browsing-button" data-l10n-id="onboarding.tour-private-browsing.button"></button> <button id="onboarding-tour-private-browsing-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-private-browsing.button"></button>
</aside> </aside>
`; `;
return div; return div;
@ -88,8 +88,8 @@ var onboardingTours = [
<section class="onboarding-tour-content"> <section class="onboarding-tour-content">
<img src="resource://onboarding/img/figure_addons.svg" /> <img src="resource://onboarding/img/figure_addons.svg" />
</section> </section>
<aside class="onboarding-tour-button"> <aside class="onboarding-tour-button-container">
<button id="onboarding-tour-addons-button" data-l10n-id="onboarding.tour-addons.button"></button> <button id="onboarding-tour-addons-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-addons.button"></button>
</aside> </aside>
`; `;
return div; return div;
@ -115,8 +115,8 @@ var onboardingTours = [
<section class="onboarding-tour-content"> <section class="onboarding-tour-content">
<img src="resource://onboarding/img/figure_customize.svg" /> <img src="resource://onboarding/img/figure_customize.svg" />
</section> </section>
<aside class="onboarding-tour-button"> <aside class="onboarding-tour-button-container">
<button id="onboarding-tour-customize-button" data-l10n-id="onboarding.tour-customize.button"></button> <button id="onboarding-tour-customize-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-customize.button"></button>
</aside> </aside>
`; `;
return div; return div;
@ -142,8 +142,8 @@ var onboardingTours = [
<section class="onboarding-tour-content"> <section class="onboarding-tour-content">
<img src="resource://onboarding/img/figure_search.svg" /> <img src="resource://onboarding/img/figure_search.svg" />
</section> </section>
<aside class="onboarding-tour-button"> <aside class="onboarding-tour-button-container">
<button id="onboarding-tour-search-button" data-l10n-id="onboarding.tour-search.button"></button> <button id="onboarding-tour-search-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-search.button"></button>
</aside> </aside>
`; `;
return div; return div;
@ -171,8 +171,8 @@ var onboardingTours = [
<section class="onboarding-tour-content"> <section class="onboarding-tour-content">
<img src="resource://onboarding/img/figure_default.svg" /> <img src="resource://onboarding/img/figure_default.svg" />
</section> </section>
<aside class="onboarding-tour-button"> <aside class="onboarding-tour-button-container">
<button id="onboarding-tour-default-browser-button" data-l10n-id="${defaultBrowserButtonId}"></button> <button id="onboarding-tour-default-browser-button" class="onboarding-tour-action-button" data-l10n-id="${defaultBrowserButtonId}"></button>
</aside> </aside>
`; `;
return div; return div;
@ -201,7 +201,7 @@ var onboardingTours = [
<h3 data-l10n-id="onboarding.tour-sync.form.title"></h3> <h3 data-l10n-id="onboarding.tour-sync.form.title"></h3>
<p data-l10n-id="onboarding.tour-sync.form.description"></p> <p data-l10n-id="onboarding.tour-sync.form.description"></p>
<input id="onboarding-tour-sync-email-input" type="text"></input><br /> <input id="onboarding-tour-sync-email-input" type="text"></input><br />
<button id="onboarding-tour-sync-button" data-l10n-id="onboarding.tour-sync.button"></button> <button id="onboarding-tour-sync-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-sync.button"></button>
</form> </form>
<img src="resource://onboarding/img/figure_sync.svg" /> <img src="resource://onboarding/img/figure_sync.svg" />
</section> </section>
@ -278,6 +278,12 @@ class Onboarding {
this.destroy(); this.destroy();
} }
}); });
onboardingTours.forEach(tour => {
let tourId = tour.id;
this._prefsObserved.set(`browser.onboarding.tour.${tourId}.completed`, () => {
this.markTourCompletionState(tourId);
});
});
for (let [name, callback] of this._prefsObserved) { for (let [name, callback] of this._prefsObserved) {
Preferences.observe(name, callback); Preferences.observe(name, callback);
} }
@ -323,8 +329,12 @@ class Onboarding {
this.gotoPage(tourId); this.gotoPage(tourId);
break; break;
} }
if (evt.target.classList.contains("onboarding-tour-item")) { let classList = evt.target.classList;
if (classList.contains("onboarding-tour-item")) {
this.gotoPage(evt.target.id); this.gotoPage(evt.target.id);
} else if (classList.contains("onboarding-tour-action-button")) {
let activeItem = this._tourItems.find(item => item.classList.contains("onboarding-active"));
this.setToursCompleted([ activeItem.id ]);
} }
} }
@ -370,6 +380,29 @@ class Onboarding {
return Preferences.get(`browser.onboarding.tour.${tourId}.completed`, false); return Preferences.get(`browser.onboarding.tour.${tourId}.completed`, false);
} }
setToursCompleted(tourIds) {
let params = [];
tourIds.forEach(id => {
if (!this.isTourCompleted(id)) {
params.push({
name: `browser.onboarding.tour.${id}.completed`,
value: true
});
}
});
if (params.length > 0) {
this.sendMessageToChrome("set-prefs", params);
}
}
markTourCompletionState(tourId) {
// We are doing lazy load so there might be no items.
if (this._tourItems.length > 0 && this.isTourCompleted(tourId)) {
let targetItem = this._tourItems.find(item => item.id == tourId);
targetItem.classList.add("onboarding-complete");
}
}
showNotification() { showNotification() {
if (Preferences.get("browser.onboarding.notification.finished", false)) { if (Preferences.get("browser.onboarding.notification.finished", false)) {
return; return;
@ -469,6 +502,7 @@ class Onboarding {
} }
hide() { hide() {
this.setToursCompleted(onboardingTours.map(tour => tour.id));
this.sendMessageToChrome("set-prefs", [ this.sendMessageToChrome("set-prefs", [
{ {
name: "browser.onboarding.hidden", name: "browser.onboarding.hidden",
@ -500,7 +534,7 @@ class Onboarding {
`; `;
div.querySelector("label[for='onboarding-tour-hidden-checkbox']").textContent = div.querySelector("label[for='onboarding-tour-hidden-checkbox']").textContent =
this._bundle.GetStringFromName("onboarding.hidden-checkbox-label"); this._bundle.GetStringFromName("onboarding.hidden-checkbox-label-text");
div.querySelector("#onboarding-header").textContent = div.querySelector("#onboarding-header").textContent =
this._bundle.formatStringFromName("onboarding.overlay-title", [BRAND_SHORT_NAME], 1); this._bundle.formatStringFromName("onboarding.overlay-title", [BRAND_SHORT_NAME], 1);
return div; return div;
@ -544,6 +578,7 @@ class Onboarding {
this._tourItems.push(li); this._tourItems.push(li);
this._tourPages.push(div); this._tourPages.push(div);
} }
tours.forEach(tour => this.markTourCompletionState(tour.id));
let dialog = this._window.document.getElementById("onboarding-overlay-dialog"); let dialog = this._window.document.getElementById("onboarding-overlay-dialog");
let ul = this._window.document.getElementById("onboarding-tour-list"); let ul = this._window.document.getElementById("onboarding-tour-list");

View File

@ -3,6 +3,11 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
# LOCALIZATION NOTE(onboarding.overlay-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.overlay-title=Getting started with %S
onboarding.hidden-checkbox-label-text=Mark all as complete, and 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?
onboarding.tour-search=One-Click Search onboarding.tour-search=One-Click Search
onboarding.tour-search.title=Find the needle or the haystack. onboarding.tour-search.title=Find the needle or the haystack.
@ -26,13 +31,13 @@ onboarding.notification.onboarding-tour-private-browsing.message=Theres no re
onboarding.tour-addons=Add-ons onboarding.tour-addons=Add-ons
onboarding.tour-addons.title=Add more functionality. onboarding.tour-addons.title=Add more functionality.
# 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$Ss 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.notification.onboarding-tour-addons.title=Get more done. onboarding.notification.onboarding-tour-addons.title=Get more done.
# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-addons.message): %S is brandShortName. # 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. 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$Ss 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=Customize
onboarding.tour-customize.title=Do things your way. 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 # LOCALIZATION NOTE(onboarding.tour-customize.description): This string will be used in the customize tour description. %S is brandShortName
@ -55,14 +60,6 @@ onboarding.notification.onboarding-tour-default-browser.title=Make %S your go-to
# LOCALIZATION NOTE(onboarding.notification.onboarding-tour-default-browser.message): %1$S is brandShortName # LOCALIZATION NOTE(onboarding.notification.onboarding-tour-default-browser.message): %1$S is brandShortName
onboarding.notification.onboarding-tour-default-browser.message=It doesnt 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.notification.onboarding-tour-default-browser.message=It doesnt 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?
onboarding.tour-sync=Firefox Sync onboarding.tour-sync=Firefox Sync
onboarding.tour-sync.title=Sync brings it all together. onboarding.tour-sync.title=Sync brings it all together.
onboarding.tour-sync.description=Access your bookmarks and passwords on any device. You can even send a tab from your laptop to your phone! Better yet, you can choose what you sync and what you dont. onboarding.tour-sync.description=Access your bookmarks and passwords on any device. You can even send a tab from your laptop to your phone! Better yet, you can choose what you sync and what you dont.