commit e4a163b58530f37b7f292fe49ad7b882b2f046d0 Author: Kathy Brade brade@pearlcrescent.com Date: Wed Apr 3 16:14:46 2019 -0400
Bug 29768: Introduce new features to users
Add an "update" tour for the Tor Browser 8.5 release that contains two panels: Toolbar and Security (with appropriate description text and images).
Display an attention-grabbing dot on the onboarding text bubble when the update tour is active. The animation lasts for 14 seconds. --- browser/app/profile/000-tor-browser.js | 3 +- browser/extensions/onboarding/bootstrap.js | 2 + .../content/img/figure_tor-security-level.png | Bin 0 -> 12185 bytes .../content/img/figure_tor-toolbar-layout.png | Bin 0 -> 5837 bytes .../extensions/onboarding/content/onboarding.css | 54 +++++++++++++-- .../extensions/onboarding/content/onboarding.js | 75 ++++++++++++++++++++- 6 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js index cca469725d28..c810c18a84a1 100644 --- a/browser/app/profile/000-tor-browser.js +++ b/browser/app/profile/000-tor-browser.js @@ -327,8 +327,9 @@ pref("browser.download.panel.shown", true); pref("dom.securecontext.whitelist_onions", true);
// Onboarding. +pref("browser.onboarding.tourset-version", 3); pref("browser.onboarding.newtour", "welcome,privacy,tor-network,circuit-display,security,expect-differences,onion-services"); -pref("browser.onboarding.updatetour", "welcome,privacy,tor-network,circuit-display,security,expect-differences,onion-services"); +pref("browser.onboarding.updatetour", "toolbar-update-8.5,security-update-8.5"); pref("browser.onboarding.skip-tour-button.hide", true);
// prefs to disable jump-list entries in the taskbar on Windows (see bug #12885) diff --git a/browser/extensions/onboarding/bootstrap.js b/browser/extensions/onboarding/bootstrap.js index a90bef0faaa2..6eec2122ce2a 100644 --- a/browser/extensions/onboarding/bootstrap.js +++ b/browser/extensions/onboarding/bootstrap.js @@ -38,6 +38,8 @@ const PREF_WHITELIST = [ "onboarding-tour-tor-security", "onboarding-tour-tor-expect-differences", "onboarding-tour-tor-onion-services", + "onboarding-tour-tor-toolbar-update-8-5", + "onboarding-tour-tor-security-update-8-5", #if 0 // Firefox tours. To reduce conflicts when rebasing against newer Firefox // code, we use the preprocessor to omit this code block. diff --git a/browser/extensions/onboarding/content/img/figure_tor-security-level.png b/browser/extensions/onboarding/content/img/figure_tor-security-level.png new file mode 100644 index 000000000000..5c7b8c5635fe Binary files /dev/null and b/browser/extensions/onboarding/content/img/figure_tor-security-level.png differ diff --git a/browser/extensions/onboarding/content/img/figure_tor-toolbar-layout.png b/browser/extensions/onboarding/content/img/figure_tor-toolbar-layout.png new file mode 100644 index 000000000000..0a8161087827 Binary files /dev/null and b/browser/extensions/onboarding/content/img/figure_tor-toolbar-layout.png differ diff --git a/browser/extensions/onboarding/content/onboarding.css b/browser/extensions/onboarding/content/onboarding.css index e70cf3fa671a..4804c4fbadc6 100644 --- a/browser/extensions/onboarding/content/onboarding.css +++ b/browser/extensions/onboarding/content/onboarding.css @@ -23,11 +23,44 @@ display: block; }
-#onboarding-overlay-button { - padding: 10px 0 0 0; +#onboarding-overlay-button-container { + padding: 16px 0 0 0; position: fixed; - cursor: pointer; top: 4px; +} + +/* + * Define an animated attention-grabbing dot which is shown on the + * speech bubble when we are displaying the "updated" tour. +*/ +#onboarding-overlay-button-container.onboarding-overlay-attention-dot::after { + display: inline-block; + position: relative; + content: " "; + width: 20px; + height: 20px; + top: -8px; + offset-inline-start: -16px; + background-color: #00E2B1; + border-radius: 50%; + animation: pulsate 2.0s ease-out; + animation-iteration-count: 7; +} + +@keyframes pulsate { + 0% { + opacity: 1.0; + } + 50% { + opacity: 0.5; + } + 100% { + opacity: 1.0; + } +} + +#onboarding-overlay-button { + cursor: pointer; offset-inline-start: 12px; border: none; /* Set to none so no grey contrast background in the high-contrast mode */ @@ -78,7 +111,7 @@ font-weight: 400; content: attr(aria-label); border: 1px solid transparent; - border-radius: 58px; + border-radius: 12px; padding: 10px 16px; width: auto; height: auto; @@ -308,6 +341,19 @@ grid-template-columns: [tour-page-start] 368px [tour-content-start] 1fr [tour-page-end]; }
+.onboarding-tour-description-prefix { + display: inline-block; + margin-bottom: -8px; /* reduce vertical space below */ + padding: 2px 10px; + vertical-align: center; + background-color: #F1F1F3; + border-radius: 4px; + min-height: 25px; + font-size: 10px; + font-weight: 600; + text-transform: uppercase; +} + .onboarding-tour-description { grid-row: tour-page-start / tour-page-end; grid-column: tour-page-start / tour-content-start; diff --git a/browser/extensions/onboarding/content/onboarding.js b/browser/extensions/onboarding/content/onboarding.js index ac5569d4b57b..acfcd93c5cef 100644 --- a/browser/extensions/onboarding/content/onboarding.js +++ b/browser/extensions/onboarding/content/onboarding.js @@ -51,6 +51,17 @@ function createOnboardingTourDescription(div, title, description) { }
/** + * Helper function to insert a prefix above the tour description. + */ +function addOnboardingTourPrefix(section, l10nId) { + let doc = section.ownerDocument; + let div = doc.createElement("div"); + div.className = "onboarding-tour-description-prefix"; + div.setAttribute("data-l10n-id", l10nId); + section.insertBefore(div, section.firstChild); // Insert as first child. +} + +/** * Helper function to create the tour content UI element. */ function createOnboardingTourContent(div, imageSrc) { @@ -108,6 +119,7 @@ function createOnboardingTourButton(div, buttonId, l10nId, buttonElementTagName **/ // Tor Browser tours: var onboardingTourset = { + // Tour items for new users: "welcome": { id: "onboarding-tour-tor-welcome", tourNameId: TORBROWSER_WELCOME_TOUR_NAME_KEY, @@ -228,6 +240,47 @@ var onboardingTourset = { return div; }, }, + // Tour items for users who have updated their Tor Browser: + "toolbar-update-8.5": { + id: "onboarding-tour-tor-toolbar-update-8-5", + tourNameId: "onboarding.tour-tor-toolbar", + instantComplete: true, + getPage(win) { + let div = win.document.createElement("div"); + + let desc = createOnboardingTourDescription(div, + "onboarding.tour-tor-toolbar-update-8.5.title", "onboarding.tour-tor-toolbar-update-8.5.description"); + addOnboardingTourPrefix(desc, "onboarding.tour-tor-update.prefix-updated"); + + createOnboardingTourContent(div, "resource://onboarding/img/figure_tor-toolbar-layout.png"); + createOnboardingTourButton(div, + "onboarding-tour-tor-toolbar-next-button", "onboarding.tour-tor-toolbar-update-8.5.next-button"); + + return div; + }, + }, + "security-update-8.5": { + id: "onboarding-tour-tor-security-update-8-5", + tourNameId: "onboarding.tour-tor-security", + getPage(win) { + let div = win.document.createElement("div"); + + let desc = createOnboardingTourDescription(div, + "onboarding.tour-tor-security-update-8.5.title", "onboarding.tour-tor-security-update-8.5.description"); + addOnboardingTourPrefix(desc, "onboarding.tour-tor-update.prefix-new"); + + createOnboardingTourContent(div, "resource://onboarding/img/figure_tor-security-level.png"); + let btnContainer = createOnboardingTourButton(div, + "onboarding-tour-tor-security-button", "onboarding.tour-tor-security-level.button"); + btnContainer.className = "onboarding-tour-tor-action-button-container"; + // It is confusing to use the two onion-services IDs below, but they + // provide the functionality and translated string ("Done") that we need. + createOnboardingTourButton(div, + "onboarding-tour-tor-onion-services-next-button", "onboarding.tour-tor-onion-services.next-button"); + + return div; + }, + }, }; #if 0 // Firefox tours. To reduce conflicts when rebasing against newer Firefox @@ -669,6 +722,7 @@ class Onboarding { } else { this._overlayIcon.classList.remove("onboarding-speech-bubble"); } + this.updateAttentionDot(); }
_initUI() { @@ -683,7 +737,10 @@ class Onboarding { this._overlayIcon = this._renderOverlayButton(); this._overlayIcon.addEventListener("click", this); this._overlayIcon.addEventListener("keypress", this); - body.insertBefore(this._overlayIcon, body.firstChild); + let buttonContainer = this._window.document.createElement("div"); + buttonContainer.id = "onboarding-overlay-button-container"; + buttonContainer.appendChild(this._overlayIcon); + body.insertBefore(buttonContainer, body.firstChild);
this._overlay = this._renderOverlay(); this._overlay.addEventListener("click", this); @@ -917,6 +974,7 @@ class Onboarding { case "onboarding-tour-tor-security-next-button": case "onboarding-tour-tor-expect-differences-next-button": case "onboarding-tour-tor-onion-services-next-button": + case "onboarding-tour-tor-toolbar-next-button": this.gotoNextTourItem(); handledTourActionClick = true; break; @@ -1131,7 +1189,9 @@ class Onboarding { this._overlayIcon.dispatchEvent(new this._window.CustomEvent("Agent:Destroy"));
this._clearPrefObserver(); + let buttonContainer = this._overlayIcon.parentElement; this._overlayIcon.remove(); + buttonContainer.remove(); if (this._overlay) { // send overlay-session telemetry this.hideOverlay(); @@ -1155,9 +1215,21 @@ class Onboarding { this._overlayIcon.classList.add("onboarding-watermark"); break; } + this.updateAttentionDot(); return true; }
+ // Display an attention-grabbing dot on the speech bubble if the + // bubble is visible and we are showing the "update" tour. + updateAttentionDot() { + let buttonContainer = this._overlayIcon.parentElement; + if ((this._bubbleState === "bubble") && (this._tourType === "update")) { + buttonContainer.classList.add("onboarding-overlay-attention-dot"); + } else { + buttonContainer.classList.remove("onboarding-overlay-attention-dot"); + } + } + showOverlay() { if (this._tourItems.length == 0) { // Lazy loading until first toggle. @@ -1418,6 +1490,7 @@ class Onboarding { // After the notification mute on the 1st session, // we don't want to show the speech bubble by default this._overlayIcon.classList.remove("onboarding-speech-bubble"); + this.updateAttentionDot();
let queue = this._getNotificationQueue(); let totalMaxTime = Services.prefs.getIntPref("browser.onboarding.notification.max-life-time-all-tours-ms");