author | Fischer.json <fischer.json@gmail.com> |
Sun, 18 Jun 2017 14:46:09 +0800 | |
changeset 366486 | 2a78b750352f |
parent 366485 | 22017d54ba07 |
child 366487 | 3a2a088b9465 |
push id | 45613 |
push user | rchien@mozilla.com |
push date | Wed, 28 Jun 2017 22:36:31 +0000 |
treeherder | autoland@3a2a088b9465 [default view] [failures only] |
reviewers | mossop |
bugs | 1357021 |
milestone | 56.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
|
--- a/browser/extensions/onboarding/bootstrap.js +++ b/browser/extensions/onboarding/bootstrap.js @@ -10,16 +10,25 @@ Cu.import("resource://gre/modules/Prefer const PREF_WHITELIST = [ "browser.onboarding.enabled", "browser.onboarding.hidden", "browser.onboarding.notification.finished", "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. * 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. * The array element carrys info to set pref, should contain * - {String} name the pref name, such as `browser.onboarding.hidden`
--- a/browser/extensions/onboarding/content/onboarding.css +++ b/browser/extensions/onboarding/content/onboarding.css @@ -172,29 +172,30 @@ #onboarding-tour-sync-page form > input { margin-top: 10px; height: 40px; width: 80%; padding: 7px; } -#onboarding-tour-sync-page form > button { +#onboarding-tour-sync-page form > #onboarding-tour-sync-button { padding: 10px 20px; min-width: 40%; font-size: 15px; font-weight: normal; line-height: 20px; background: #0d96ff; border: none; border-radius: 3px; color: #fff; box-shadow: 0 1px 0 rgba(0,0,0,0.23); cursor: pointer; margin: 15px 0; + float: none; } /* Onboarding tour pages */ .onboarding-tour-page { grid-row: page-start / footer-end; grid-column: page-start; display: grid; grid-template-rows: [tour-page-start] 393px [tour-button-start] 1fr [tour-page-end]; @@ -237,44 +238,44 @@ 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 { +.onboarding-tour-button-container { 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 { +.onboarding-tour-page.onboarding-no-button > .onboarding-tour-button-container { display: none; grid-row: tour-page-end; grid-column: tour-page-end; } -.onboarding-tour-button > button { +.onboarding-tour-action-button { padding: 10px 20px; font-size: 15px; font-weight: 600; line-height: 21px; background: #0d96ff; border: none; border-radius: 3px; color: #fff; box-shadow: 0 1px 0 rgba(0,0,0,0.23); cursor: pointer; float: inline-end; margin-inline-end: 26px; margin-top: -32px; } -.onboarding-tour-button > button:active { +.onboarding-tour-action-button:active { background: #0881dd; } /* Tour Icons */ #onboarding-tour-search { background-image: url("img/icons_search.svg"); } @@ -413,16 +414,17 @@ #onboarding-notification-tour-title { margin: 0; } #onboarding-notification-tour-icon { width: 64px; height: 64px; + background-size: 64px; background-repeat: no-repeat; } #onboarding-notification-action-btn { background: #0d96ff; border: none; border-radius: 3px; padding: 10px 20px;
--- a/browser/extensions/onboarding/content/onboarding.js +++ b/browser/extensions/onboarding/content/onboarding.js @@ -29,19 +29,19 @@ const BRAND_SHORT_NAME = Services.string * 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 onboarding-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 + * // .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 onboardingTours = [ { id: "onboarding-tour-private-browsing", tourNameId: "onboarding.tour-private-browsing", getNotificationStrings(bundle) { @@ -56,18 +56,18 @@ var onboardingTours = [ 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"> <img src="resource://onboarding/img/figure_private.svg" /> </section> - <aside class="onboarding-tour-button"> - <button id="onboarding-tour-private-browsing-button" data-l10n-id="onboarding.tour-private-browsing.button"></button> + <aside class="onboarding-tour-button-container"> + <button id="onboarding-tour-private-browsing-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-private-browsing.button"></button> </aside> `; return div; }, }, { id: "onboarding-tour-addons", tourNameId: "onboarding.tour-addons", @@ -83,18 +83,18 @@ var onboardingTours = [ 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"> <img src="resource://onboarding/img/figure_addons.svg" /> </section> - <aside class="onboarding-tour-button"> - <button id="onboarding-tour-addons-button" data-l10n-id="onboarding.tour-addons.button"></button> + <aside class="onboarding-tour-button-container"> + <button id="onboarding-tour-addons-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-addons.button"></button> </aside> `; return div; }, }, { id: "onboarding-tour-customize", tourNameId: "onboarding.tour-customize", @@ -110,18 +110,18 @@ var onboardingTours = [ 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"> <img src="resource://onboarding/img/figure_customize.svg" /> </section> - <aside class="onboarding-tour-button"> - <button id="onboarding-tour-customize-button" data-l10n-id="onboarding.tour-customize.button"></button> + <aside class="onboarding-tour-button-container"> + <button id="onboarding-tour-customize-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-customize.button"></button> </aside> `; return div; }, }, { id: "onboarding-tour-search", tourNameId: "onboarding.tour-search", @@ -137,18 +137,18 @@ var onboardingTours = [ 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"> <img src="resource://onboarding/img/figure_search.svg" /> </section> - <aside class="onboarding-tour-button"> - <button id="onboarding-tour-search-button" data-l10n-id="onboarding.tour-search.button"></button> + <aside class="onboarding-tour-button-container"> + <button id="onboarding-tour-search-button" class="onboarding-tour-action-button" data-l10n-id="onboarding.tour-search.button"></button> </aside> `; return div; }, }, { id: "onboarding-tour-default-browser", tourNameId: "onboarding.tour-default-browser", @@ -166,18 +166,18 @@ var onboardingTours = [ 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> </section> <section class="onboarding-tour-content"> <img src="resource://onboarding/img/figure_default.svg" /> </section> - <aside class="onboarding-tour-button"> - <button id="onboarding-tour-default-browser-button" data-l10n-id="${defaultBrowserButtonId}"></button> + <aside class="onboarding-tour-button-container"> + <button id="onboarding-tour-default-browser-button" class="onboarding-tour-action-button" data-l10n-id="${defaultBrowserButtonId}"></button> </aside> `; return div; }, }, { id: "onboarding-tour-sync", tourNameId: "onboarding.tour-sync", @@ -196,17 +196,17 @@ var onboardingTours = [ <h1 data-l10n-id="onboarding.tour-sync.title"></h1> <p data-l10n-id="onboarding.tour-sync.description"></p> </section> <section class="onboarding-tour-content"> <form> <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="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> <img src="resource://onboarding/img/figure_sync.svg" /> </section> `; div.querySelector("#onboarding-tour-sync-email-input").placeholder = bundle.GetStringFromName("onboarding.tour-sync.email-input.placeholder"); return div; }, @@ -273,16 +273,22 @@ class Onboarding { } this._prefsObserved = new Map(); this._prefsObserved.set("browser.onboarding.hidden", prefValue => { if (prefValue) { 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) { Preferences.observe(name, callback); } } _clearPrefObserver() { if (this._prefsObserved) { for (let [name, callback] of this._prefsObserved) { @@ -318,18 +324,22 @@ class Onboarding { 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")) { + let classList = evt.target.classList; + if (classList.contains("onboarding-tour-item")) { 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 ]); } } destroy() { this._clearPrefObserver(); this._overlayIcon.remove(); this._overlay.remove(); if (this._notificationBar) { @@ -365,16 +375,39 @@ class Onboarding { } } } isTourCompleted(tourId) { 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() { if (Preferences.get("browser.onboarding.notification.finished", false)) { return; } // Pick out the next target tour to show let targetTour = null; @@ -464,16 +497,17 @@ class Onboarding { <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.setToursCompleted(onboardingTours.map(tour => tour.id)); this.sendMessageToChrome("set-prefs", [ { name: "browser.onboarding.hidden", value: true }, { name: "browser.onboarding.notification.finished", value: true @@ -495,17 +529,17 @@ class Onboarding { </nav> <footer id="onboarding-footer"> <input type="checkbox" id="onboarding-tour-hidden-checkbox" /><label for="onboarding-tour-hidden-checkbox"></label> </footer> </div> `; 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 = this._bundle.formatStringFromName("onboarding.overlay-title", [BRAND_SHORT_NAME], 1); return div; } _renderOverlayIcon() { let img = this._window.document.createElement("div"); img.id = "onboarding-overlay-icon"; @@ -539,16 +573,17 @@ class Onboarding { div.id = `${tour.id}-page`; div.classList.add("onboarding-tour-page"); div.style.display = "none"; pagesFrag.appendChild(div); // Cache elements in arrays for later use to avoid cost of querying elements this._tourItems.push(li); this._tourPages.push(div); } + tours.forEach(tour => this.markTourCompletionState(tour.id)); let dialog = this._window.document.getElementById("onboarding-overlay-dialog"); let ul = this._window.document.getElementById("onboarding-tour-list"); ul.appendChild(itemsFrag); let footer = this._window.document.getElementById("onboarding-footer"); dialog.insertBefore(pagesFrag, footer); this.gotoPage(tours[0].id); }
--- a/browser/extensions/onboarding/locales/en-US/onboarding.properties +++ b/browser/extensions/onboarding/locales/en-US/onboarding.properties @@ -1,13 +1,18 @@ # 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.overlay-title): This string will be used in the overlay title. %S is brandShortName 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.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. @@ -21,23 +26,23 @@ onboarding.tour-private-browsing.title=A # 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.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. +# 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.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. @@ -50,24 +55,16 @@ onboarding.tour-default-browser.descript 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? - onboarding.tour-sync=Firefox Sync 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 don’t. # LOCALIZATION NOTE(onboarding.tour-sync.form.title): This string is displayed # as a title and followed by onboarding.tour-sync.form.description. # Your translation should be consistent with the form displayed in # about:accounts when signing up to Firefox Account.