Bug 1592467 - Add 'Learn More' links and change breach alert inline link to point to the login origin. r=sfoster,fluent-reviewers,flod
☠☠ backed out by 62b434d3602a ☠ ☠
authorJared Wein <jwein@mozilla.com>
Fri, 27 Mar 2020 02:28:50 +0000
changeset 520689 c64620a2abf9294639555543dd83b94408a51cb2
parent 520688 25f9704e31e1412186685e832df8752d427ad6e6
child 520690 b353abb5f07fd48e7957653dbc4c05ddfdd1544f
push id111253
push userjwein@mozilla.com
push dateFri, 27 Mar 2020 02:31:31 +0000
treeherderautoland@7f78c8fb5c6e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster, fluent-reviewers, flod
bugs1592467
milestone76.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
Bug 1592467 - Add 'Learn More' links and change breach alert inline link to point to the login origin. r=sfoster,fluent-reviewers,flod Differential Revision: https://phabricator.services.mozilla.com/D68108
browser/components/aboutlogins/AboutLoginsChild.jsm
browser/components/aboutlogins/content/aboutLogins.html
browser/components/aboutlogins/content/components/login-intro.js
browser/components/aboutlogins/content/components/login-item.css
browser/components/aboutlogins/content/components/login-item.js
browser/components/aboutlogins/tests/chrome/test_login_item.html
browser/locales/en-US/browser/aboutLogins.ftl
--- a/browser/components/aboutlogins/AboutLoginsChild.jsm
+++ b/browser/components/aboutlogins/AboutLoginsChild.jsm
@@ -41,17 +41,18 @@ class AboutLoginsChild extends JSWindowA
         this.sendAsyncMessage("AboutLogins:Subscribe");
 
         let documentElement = this.document.documentElement;
         documentElement.classList.toggle(
           "official-branding",
           AppConstants.MOZILLA_OFFICIAL
         );
 
-        let waivedContent = Cu.waiveXrays(this.browsingContext.window);
+        let win = this.browsingContext.window;
+        let waivedContent = Cu.waiveXrays(win);
         let that = this;
         let AboutLoginsUtils = {
           doLoginsMatch(loginA, loginB) {
             return LoginHelper.doLoginsMatch(loginA, loginB, {});
           },
           getLoginOrigin(uriString) {
             return LoginHelper.getLoginOrigin(uriString);
           },
@@ -80,24 +81,20 @@ class AboutLoginsChild extends JSWindowA
         };
         waivedContent.AboutLoginsUtils = Cu.cloneInto(
           AboutLoginsUtils,
           waivedContent,
           {
             cloneFunctions: true,
           }
         );
-
-        const SUPPORT_URL =
-          Services.urlFormatter.formatURLPref("app.support.baseURL") +
-          "firefox-lockwise";
-        let loginIntro = Cu.waiveXrays(
-          this.document.querySelector("login-intro")
+        let aboutLoginsUtilsReadyEvent = new win.CustomEvent(
+          "AboutLoginsUtilsReady"
         );
-        loginIntro.supportURL = SUPPORT_URL;
+        win.dispatchEvent(aboutLoginsUtilsReadyEvent);
         break;
       }
       case "AboutLoginsCopyLoginDetail": {
         ClipboardHelper.copyString(event.detail);
         break;
       }
       case "AboutLoginsCreateLogin": {
         this.sendAsyncMessage("AboutLogins:CreateLogin", {
@@ -207,16 +204,19 @@ class AboutLoginsChild extends JSWindowA
       case "AboutLogins:Setup":
         let waivedContent = Cu.waiveXrays(this.browsingContext.window);
         waivedContent.AboutLoginsUtils.masterPasswordEnabled =
           message.data.masterPasswordEnabled;
         waivedContent.AboutLoginsUtils.passwordRevealVisible =
           message.data.passwordRevealVisible;
         waivedContent.AboutLoginsUtils.importVisible =
           message.data.importVisible;
+        waivedContent.AboutLoginsUtils.supportBaseURL = Services.urlFormatter.formatURLPref(
+          "app.support.baseURL"
+        );
         this.sendToContent("Setup", message.data);
         break;
       default:
         this.passMessageDataToContent(message);
     }
   }
 
   passMessageDataToContent(message) {
--- a/browser/components/aboutlogins/content/aboutLogins.html
+++ b/browser/components/aboutlogins/content/aboutLogins.html
@@ -159,23 +159,25 @@
               <a data-l10n-name="duplicate-link" href=""></a>
             </span>
           </div>
           <div class="breach-alert">
             <h3 class="alert-title" data-l10n-id="about-logins-breach-alert-title"></h3>
             <img class="alert-icon" src="chrome://global/skin/icons/warning.svg"/>
             <span class="alert-date" data-l10n-id="about-logins-breach-alert-date" data-l10n-args='{"date": 0}'></span>
             <span class="alert-text" data-l10n-id="breach-alert-text"></span>
-            <a class="alert-link" data-l10n-id="breach-alert-link" href="#" rel="noreferrer" target="_blank"></a>
+            <a class="alert-link" data-l10n-id="about-logins-breach-alert-link" data-l10n-args='{"hostname": ""}' href="#" rel="noreferrer" target="_blank"></a>
+            <a class="alert-learn-more-link" data-l10n-id="about-logins-breach-alert-learn-more-link" href="#" rel="noreferrer" target="_blank"></a>
           </div>
           <div class="vulnerable-alert">
             <h3 class="alert-title" data-l10n-id="about-logins-vulnerable-alert-title"></h3>
             <img class="alert-icon" src="chrome://browser/content/aboutlogins/icons/vulnerable-password.svg"/>
             <span class="alert-text" data-l10n-id="about-logins-vulnerable-alert-text"></span>
             <a class="alert-link" data-l10n-id="about-logins-vulnerable-alert-link" data-l10n-args='{"hostname": ""}' href="#" rel="noreferrer" target="_blank"></a>
+            <a class="alert-learn-more-link" data-l10n-id="about-logins-vulnerable-alert-learn-more-link" href="#" rel="noreferrer" target="_blank"></a>
           </div>
           <div class="header">
             <div class="login-item-favicon-wrapper">
               <img class="login-item-favicon" src=""/>
             </div>
             <h2 class="title">
               <span class="login-item-title"></span>
               <span class="new-login-title" data-l10n-id="login-item-new-login-title"></span>
--- a/browser/components/aboutlogins/content/components/login-intro.js
+++ b/browser/components/aboutlogins/content/components/login-intro.js
@@ -10,41 +10,44 @@ export default class LoginIntro extends 
 
     let loginIntroTemplate = document.querySelector("#login-intro-template");
     let shadowRoot = this.attachShadow({ mode: "open" });
     document.l10n.connectRoot(shadowRoot);
     shadowRoot.appendChild(loginIntroTemplate.content.cloneNode(true));
 
     this._importText = shadowRoot.querySelector(".intro-import-text");
     this._importText.addEventListener("click", this);
+    this.addEventListener("AboutLoginsUtilsReady", this);
   }
 
   focus() {
     let helpLink = this.shadowRoot.querySelector(".intro-help-link");
     helpLink.focus();
   }
 
   handleEvent(event) {
-    if (
+    if (event.type == "AboutLoginsUtilsReady") {
+      let supportURL =
+        window.AboutLoginsUtils.supportBaseURL + "firefox-lockwise";
+      this.shadowRoot
+        .querySelector(".intro-help-link")
+        .setAttribute("href", supportURL);
+    } else if (
       event.currentTarget.classList.contains("intro-import-text") &&
       event.target.localName == "a"
     ) {
       document.dispatchEvent(
         new CustomEvent("AboutLoginsImport", {
           bubbles: true,
         })
       );
     }
     event.preventDefault();
   }
 
-  set supportURL(val) {
-    this.shadowRoot.querySelector(".intro-help-link").setAttribute("href", val);
-  }
-
   updateState(syncState) {
     let l10nId = syncState.loggedIn
       ? "about-logins-login-intro-heading-logged-in"
       : "login-intro-heading";
     document.l10n.setAttributes(
       this.shadowRoot.querySelector(".heading"),
       l10nId
     );
--- a/browser/components/aboutlogins/content/components/login-item.css
+++ b/browser/components/aboutlogins/content/components/login-item.css
@@ -348,16 +348,30 @@ input[name="password"] {
   position: absolute;
   inset-block-start: 16px;
   inset-inline-start: 32px;
   -moz-context-properties: fill;
   fill: currentColor;
   width: 24px;
 }
 
+.alert-learn-more-link:hover,
+.alert-learn-more-link:visited,
+.alert-learn-more-link {
+  position: absolute;
+  inset-block-start: 16px;
+  inset-inline-end: 32px;
+  color: inherit;
+  font-size: 13px;
+}
+
+.vulnerable-alert > .alert-learn-more-link {
+  color: var(--in-content-deemphasized-text);
+}
+
 .error-message {
   color: #fff;
   background-color: var(--red-60);
   border: 1px solid transparent;
   padding-block: 6px;
   display: inline-block;
   padding-inline-start: 32px;
   padding-inline-end: 16px;
--- a/browser/components/aboutlogins/content/components/login-item.js
+++ b/browser/components/aboutlogins/content/components/login-item.js
@@ -78,20 +78,26 @@ export default class LoginItem extends H
     );
     this._title = this.shadowRoot.querySelector(".login-item-title");
     this._timeCreated = this.shadowRoot.querySelector(".time-created");
     this._timeChanged = this.shadowRoot.querySelector(".time-changed");
     this._timeUsed = this.shadowRoot.querySelector(".time-used");
     this._breachAlert = this.shadowRoot.querySelector(".breach-alert");
     this._breachAlertLink = this._breachAlert.querySelector(".alert-link");
     this._breachAlertDate = this._breachAlert.querySelector(".alert-date");
+    this._breachAlertLearnMoreLink = this._breachAlert.querySelector(
+      ".alert-learn-more-link"
+    );
     this._vulnerableAlert = this.shadowRoot.querySelector(".vulnerable-alert");
     this._vulnerableAlertLink = this._vulnerableAlert.querySelector(
       ".alert-link"
     );
+    this._vulnerableAlertLearnMoreLink = this._vulnerableAlert.querySelector(
+      ".alert-learn-more-link"
+    );
 
     this.render();
 
     this._breachAlertLink.addEventListener("click", this);
     this._cancelButton.addEventListener("click", this);
     this._copyPasswordButton.addEventListener("click", this);
     this._copyUsernameButton.addEventListener("click", this);
     this._deleteButton.addEventListener("click", this);
@@ -143,17 +149,23 @@ export default class LoginItem extends H
       }
     }
     this._errorMessage.hidden = !this._error;
 
     this._breachAlert.hidden =
       !this._breachesMap || !this._breachesMap.has(this._login.guid);
     if (!this._breachAlert.hidden) {
       const breachDetails = this._breachesMap.get(this._login.guid);
-      this._breachAlertLink.href = breachDetails.breachAlertURL;
+      this._breachAlertLearnMoreLink.href = breachDetails.breachAlertURL;
+      this._breachAlertLink.href = this._login.origin;
+      document.l10n.setAttributes(
+        this._breachAlertLink,
+        "about-logins-breach-alert-link",
+        { hostname: this._login.displayOrigin }
+      );
       if (breachDetails.BreachDate) {
         let breachDate = new Date(breachDetails.BreachDate);
         this._breachAlertDate.hidden = isNaN(breachDate);
         if (!isNaN(breachDate)) {
           document.l10n.setAttributes(
             this._breachAlertDate,
             "about-logins-breach-alert-date",
             {
@@ -171,16 +183,20 @@ export default class LoginItem extends H
       this._vulnerableAlertLink.href = this._login.origin;
       document.l10n.setAttributes(
         this._vulnerableAlertLink,
         "about-logins-vulnerable-alert-link",
         {
           hostname: this._login.displayOrigin,
         }
       );
+      this._vulnerableAlertLearnMoreLink.setAttribute(
+        "href",
+        window.AboutLoginsUtils.supportBaseURL + "lockwise-alerts"
+      );
     }
     document.l10n.setAttributes(this._timeCreated, "login-item-time-created", {
       timeCreated: this._login.timeCreated || "",
     });
     document.l10n.setAttributes(this._timeChanged, "login-item-time-changed", {
       timeChanged: this._login.timePasswordChanged || "",
     });
     document.l10n.setAttributes(this._timeUsed, "login-item-time-used", {
--- a/browser/components/aboutlogins/tests/chrome/test_login_item.html
+++ b/browser/components/aboutlogins/tests/chrome/test_login_item.html
@@ -130,17 +130,17 @@ add_task(async function test_set_login()
 add_task(async function test_update_breaches() {
   gLoginItem.setLogin(TEST_LOGIN_1);
   gLoginItem.setBreaches(TEST_BREACHES_MAP);
   await asyncElementRendered();
 
   let correspondingBreach = TEST_BREACHES_MAP.get(gLoginItem._login.guid);
   let breachAlert = gLoginItem.shadowRoot.querySelector(".breach-alert");
   ok(!isHidden(breachAlert), "Breach alert should be visible");
-  is(breachAlert.querySelector(".alert-link").getAttribute("href"), correspondingBreach.breachAlertURL, "Breach alert link should be equal to the correspondingBreach.breachAlertURL.");
+  is(breachAlert.querySelector(".alert-learn-more-link").getAttribute("href"), correspondingBreach.breachAlertURL, "Breach alert link should be equal to the correspondingBreach.breachAlertURL.");
 });
 
 add_task(async function test_breach_alert_is_correctly_hidden() {
   gLoginItem.setLogin(TEST_LOGIN_2);
   gLoginItem.setBreaches(TEST_BREACHES_MAP);
   await asyncElementRendered();
 
   let breachAlert = gLoginItem.shadowRoot.querySelector(".breach-alert");
--- a/browser/locales/en-US/browser/aboutLogins.ftl
+++ b/browser/locales/en-US/browser/aboutLogins.ftl
@@ -164,26 +164,30 @@ about-logins-confirm-remove-dialog-confi
 confirm-discard-changes-dialog-title = Discard unsaved changes?
 confirm-discard-changes-dialog-message = All unsaved changes will be lost.
 confirm-discard-changes-dialog-confirm-button = Discard
 
 ## Breach Alert notification
 
 about-logins-breach-alert-title = Website Breach
 breach-alert-text = Passwords were leaked or stolen from this website since you last updated your login details. Change your password to protect your account.
-breach-alert-link = Learn more about this breach.
 about-logins-breach-alert-date = This breach occurred on { DATETIME($date, day: "numeric", month: "long", year: "numeric") }
+# Variables:
+#   $hostname (String) - The hostname of the website associated with the login, e.g. "example.com"
+about-logins-breach-alert-link = Go to { $hostname }
+about-logins-breach-alert-learn-more-link = Learn more
 
 ## Vulnerable Password notification
 
 about-logins-vulnerable-alert-title = Vulnerable Password
 about-logins-vulnerable-alert-text = This password was leaked or stolen in another company’s data breach. Reusing credentials puts all of your accounts at risk. To improve your online security, change this password.
 # Variables:
 #   $hostname (String) - The hostname of the website associated with the login, e.g. "example.com"
 about-logins-vulnerable-alert-link = Go to { $hostname }
+about-logins-vulnerable-alert-learn-more-link = Learn more
 
 ## Error Messages
 
 # This is an error message that appears when a user attempts to save
 # a new login that is identical to an existing saved login.
 # Variables:
 #   $loginTitle (String) - The title of the website associated with the login.
 about-logins-error-message-duplicate-login-with-link = An entry for { $loginTitle } with that username already exists. <a data-l10n-name="duplicate-link">Go to existing entry?</a>