Backed out 8 changesets (bug 1549803, bug 1550095) for Browser-chrome failures in browser/components/aboutlogins/tests/browser/browser_updateLogin.js
authorDorel Luca <dluca@mozilla.com>
Sat, 11 May 2019 06:28:15 +0300
changeset 532319 1be22e2d35d1e2a40451b2d555ced98a49d533af
parent 532318 a07d7f8f53ca2bf81e5650a499481793c9b89fce
child 532329 2f94885dcf94f823f37c99231c79146b6b907e4c
child 532330 dba3c6692a02d1e874bbdbfae9a8424bb68375d3
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1549803, 1550095
milestone68.0a1
backs outaf805180a1e6329754d626a62d17bdca87ffc2b0
aa8595d46694869462197ef452f787c70b518d52
fe75205edc195b77e0a90d8703ddb07d1c7ed4c0
fe60f9cc2007212395954c6d5b343034a0480d86
b665ca03d2f6b9853383bec29db258ca3393f3e7
c5d450a431c8e1bea3ab2720cc4492c6926d12c6
93a0674140fc007a0f2d378a90cc4b53b77734e0
4a3dacc5d3b2edfa76b28800c9a4f53b144975a4
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
Backed out 8 changesets (bug 1549803, bug 1550095) for Browser-chrome failures in browser/components/aboutlogins/tests/browser/browser_updateLogin.js Backed out changeset af805180a1e6 (bug 1549803) Backed out changeset aa8595d46694 (bug 1549803) Backed out changeset fe75205edc19 (bug 1549803) Backed out changeset fe60f9cc2007 (bug 1549803) Backed out changeset b665ca03d2f6 (bug 1549803) Backed out changeset c5d450a431c8 (bug 1550095) Backed out changeset 93a0674140fc (bug 1550095) Backed out changeset 4a3dacc5d3b2 (bug 1550095)
browser/components/BrowserGlue.jsm
browser/components/aboutlogins/AboutLoginsChild.jsm
browser/components/aboutlogins/AboutLoginsParent.jsm
browser/components/aboutlogins/content/aboutLogins.ftl
browser/components/aboutlogins/content/aboutLogins.html
browser/components/aboutlogins/content/aboutLogins.js
browser/components/aboutlogins/content/components/login-item.css
browser/components/aboutlogins/content/components/login-item.js
browser/components/aboutlogins/content/components/login-list-item.css
browser/components/aboutlogins/content/components/login-list-item.js
browser/components/aboutlogins/content/components/login-list.css
browser/components/aboutlogins/content/components/login-list.js
browser/components/aboutlogins/jar.mn
browser/components/aboutlogins/tests/browser/browser.ini
browser/components/aboutlogins/tests/browser/browser_loginChanges.js
browser/components/aboutlogins/tests/browser/browser_loginListChanges.js
browser/components/aboutlogins/tests/browser/browser_updateLogin.js
browser/components/aboutlogins/tests/mochitest/aboutlogins_common.js
browser/components/aboutlogins/tests/mochitest/test_login_item.html
browser/components/aboutlogins/tests/mochitest/test_login_list.html
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -31,17 +31,16 @@ let ACTORS = {
 
 let LEGACY_ACTORS = {
   AboutLogins: {
     child: {
       matches: ["about:logins"],
       module: "resource:///actors/AboutLoginsChild.jsm",
       events: {
         "AboutLoginsDeleteLogin": {wantUntrusted: true},
-        "AboutLoginsUpdateLogin": {wantUntrusted: true},
         "AboutLoginsInit": {wantUntrusted: true},
       },
       messages: [
         "AboutLogins:AllLogins",
         "AboutLogins:LoginAdded",
         "AboutLogins:LoginModified",
         "AboutLogins:LoginRemoved",
       ],
@@ -541,17 +540,16 @@ const listeners = {
     // PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN AsyncPrefs.init
 
     "webrtc:UpdateGlobalIndicators": ["webrtcUI"],
     "webrtc:UpdatingIndicators": ["webrtcUI"],
   },
 
   mm: {
     "AboutLogins:DeleteLogin": ["AboutLoginsParent"],
-    "AboutLogins:UpdateLogin": ["AboutLoginsParent"],
     "AboutLogins:Subscribe": ["AboutLoginsParent"],
     "Content:Click": ["ContentClick"],
     "ContentSearch": ["ContentSearch"],
     "FormValidation:ShowPopup": ["FormValidationHandler"],
     "FormValidation:HidePopup": ["FormValidationHandler"],
     "PictureInPicture:Request": ["PictureInPicture"],
     "PictureInPicture:Close": ["PictureInPicture"],
     "PictureInPicture:Playing": ["PictureInPicture"],
--- a/browser/components/aboutlogins/AboutLoginsChild.jsm
+++ b/browser/components/aboutlogins/AboutLoginsChild.jsm
@@ -25,20 +25,16 @@ class AboutLoginsChild extends ActorChil
           cloneFunctions: true,
         });
         break;
       }
       case "AboutLoginsDeleteLogin": {
         this.mm.sendAsyncMessage("AboutLogins:DeleteLogin", {login: event.detail});
         break;
       }
-      case "AboutLoginsUpdateLogin": {
-        this.mm.sendAsyncMessage("AboutLogins:UpdateLogin", {login: event.detail});
-        break;
-      }
     }
   }
 
   receiveMessage(message) {
     switch (message.name) {
       case "AboutLogins:AllLogins":
         this.sendToContent("AllLogins", message.data);
         break;
--- a/browser/components/aboutlogins/AboutLoginsParent.jsm
+++ b/browser/components/aboutlogins/AboutLoginsParent.jsm
@@ -1,28 +1,21 @@
 /* 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/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["AboutLoginsParent"];
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "E10SUtils",
-                               "resource://gre/modules/E10SUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "LoginHelper",
                                "resource://gre/modules/LoginHelper.jsm");
 ChromeUtils.defineModuleGetter(this, "Services",
                                "resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "log", () => {
-  return LoginHelper.createLogger("AboutLoginsParent");
-});
-
 const ABOUT_LOGINS_ORIGIN = "about:logins";
 
 const isValidLogin = login => {
   return !(login.hostname || "").startsWith("chrome://");
 };
 
 const convertSubjectToLogin = subject => {
     subject.QueryInterface(Ci.nsILoginMetaInfo).QueryInterface(Ci.nsILoginInfo);
@@ -34,18 +27,17 @@ const convertSubjectToLogin = subject =>
 };
 
 var AboutLoginsParent = {
   _subscribers: new WeakSet(),
 
   // Listeners are added in BrowserGlue.jsm
   receiveMessage(message) {
     // Only respond to messages sent from about:logins.
-    if (message.target.remoteType != E10SUtils.PRIVILEGED_REMOTE_TYPE ||
-        message.target.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN) {
+    if (message.target.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN) {
       return;
     }
 
     switch (message.name) {
       case "AboutLogins:DeleteLogin": {
         let login = LoginHelper.vanillaObjectToLogin(message.data.login);
         Services.logins.removeLogin(login);
         break;
@@ -55,35 +47,16 @@ var AboutLoginsParent = {
           Services.obs.addObserver(this, "passwordmgr-storage-changed");
         }
         this._subscribers.add(message.target);
 
         let messageManager = message.target.messageManager;
         messageManager.sendAsyncMessage("AboutLogins:AllLogins", this.getAllLogins());
         break;
       }
-      case "AboutLogins:UpdateLogin": {
-        let loginUpdates = message.data.login;
-        let logins = LoginHelper.searchLoginsWithObject({guid: loginUpdates.guid});
-        if (!logins || logins.length != 1) {
-          log.warn(`AboutLogins:UpdateLogin: expected to find a login for guid: ${loginUpdates.guid} but found ${(logins || []).length}`);
-          return;
-        }
-
-        let modifiedLogin = logins[0].clone();
-        if (loginUpdates.hasOwnProperty("username")) {
-          modifiedLogin.username = loginUpdates.username;
-        }
-        if (loginUpdates.hasOwnProperty("password")) {
-          modifiedLogin.password = loginUpdates.password;
-        }
-
-        Services.logins.modifyLogin(logins[0], modifiedLogin);
-        break;
-      }
     }
   },
 
   observe(subject, topic, type) {
     if (!ChromeUtils.nondeterministicGetWeakSetKeys(this._subscribers).length) {
       Services.obs.removeObserver(this, "passwordmgr-storage-changed");
       return;
     }
@@ -117,19 +90,17 @@ var AboutLoginsParent = {
         break;
       }
     }
   },
 
   messageSubscribers(name, details) {
     let subscribers = ChromeUtils.nondeterministicGetWeakSetKeys(this._subscribers);
     for (let subscriber of subscribers) {
-      if (subscriber.remoteType != E10SUtils.PRIVILEGED_REMOTE_TYPE ||
-          !subscriber.contentPrincipal ||
-          subscriber.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN) {
+      if (subscriber.contentPrincipal.originNoSuffix != ABOUT_LOGINS_ORIGIN) {
         this._subscribers.delete(subscriber);
         continue;
       }
       try {
         subscriber.messageManager.sendAsyncMessage(name, details);
       } catch (ex) {}
     }
   },
--- a/browser/components/aboutlogins/content/aboutLogins.ftl
+++ b/browser/components/aboutlogins/content/aboutLogins.ftl
@@ -11,17 +11,13 @@
 ### descendant after translation.
 
 about-logins-page-title = Login Manager
 
 login-list =
   .login-list-header = Logins
 
 login-item =
-  .cancel-button = Cancel
-  .delete-button = Delete
-  .hostname-label = Website Address
-  .password-label = Password
-  .save-changes-button = Save Changes
-  .time-created = Created: { DATETIME($timeCreated, day: "numeric", month: "long", year: "numeric") }
-  .time-changed = Last changed: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
-  .time-used = Last used: { DATETIME($timeUsed, day: "numeric", month: "long", year: "numeric") }
-  .username-label = Username
+  .login-item-hostname = Hostname
+  .login-item-password = Password
+  .login-item-username = Username
+  .login-item-time-created = Time Created
+  .login-item-delete = Delete
--- a/browser/components/aboutlogins/content/aboutLogins.html
+++ b/browser/components/aboutlogins/content/aboutLogins.html
@@ -8,62 +8,53 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';"/>
     <title data-l10n-id="about-logins-page-title"></title>
     <link rel="localization" href="browser/aboutLogins.ftl">
     <script defer="defer" src="chrome://browser/content/aboutlogins/components/login-item.js"></script>
     <script defer="defer" src="chrome://browser/content/aboutlogins/components/login-list.js"></script>
     <script defer="defer" src="chrome://browser/content/aboutlogins/components/login-list-item.js"></script>
     <script defer="defer" src="chrome://browser/content/aboutlogins/aboutLogins.js"></script>
-    <link rel="stylesheet" type="text/css" href="chrome://global/skin/in-content/common.css">
   </head>
   <body>
     <login-list data-l10n-id="login-list"
                 data-l10n-attrs="login-list-header"></login-list>
     <login-item data-l10n-id="login-item"
-                data-l10n-args='{"timeCreated": 0, "timeChanged": 0, "timeUsed": 0}'
-                data-l10n-attrs="cancel-button,
-                                 delete-button,
-                                 hostname-label,
-                                 password-label,
-                                 save-changes-button,
-                                 time-created,
-                                 time-changed,
-                                 time-used,
-                                 username-label"></login-item>
+                data-l10n-attrs="login-item-hostname, login-item-password, login-item-username, login-item-time-created, login-item-delete"></login-item>
 
     <template id="login-list-template">
-      <link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/login-list.css">
       <h2></h2>
-      <ol>
-      </ol>
+      <pre>
+      </pre>
     </template>
 
     <template id="login-list-item-template">
-      <link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/login-list-item.css">
-      <span class="hostname"></span>
-      <span class="username"></span>
+      <style>
+        :host(.selected) {
+          font-weight: bold;
+        }
+      </style>
+      <span class="login-list-item-hostname"></span>
+      <span class="login-list-item-username"></span>
     </template>
 
     <template id="login-item-template">
-      <link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/login-item.css">
-      <h2 class="header"></h2>
-      <button class="delete-button"></button>
+      <h2 data-l10n-id="login-item-header"></h2>
       <label>
-        <span class="hostname-label field-label"></span>
-        <span class="hostname"/>
+        <span class="hostname-label"></span>
+        <input name="hostname"/>
       </label>
       <label>
-        <span class="username-label field-label"></span>
+        <span class="username-label"></span>
         <input name="username"/>
       </label>
       <label>
-        <span class="password-label field-label"></span>
+        <span class="password-label"></span>
         <input type="password" name="password"/>
       </label>
-      <p class="time-created meta-info"></p>
-      <p class="time-changed meta-info"></p>
-      <p class="time-used meta-info"></p>
-      <button class="save-changes-button"></button>
-      <button class="cancel-button"></button>
+      <p>
+        <span class="time-created-label"></span>
+        <span class="time-created"></span>
+      </p>
+      <button class="delete-button"></button>
     </template>
   </body>
 </html>
--- a/browser/components/aboutlogins/content/aboutLogins.js
+++ b/browser/components/aboutlogins/content/aboutLogins.js
@@ -14,16 +14,17 @@ document.addEventListener("DOMContentLoa
 window.addEventListener("AboutLoginsChromeToContent", event => {
   switch (event.detail.messageType) {
     case "AllLogins": {
       gElements.loginList.setLogins(event.detail.value);
       break;
     }
     case "LoginAdded": {
       gElements.loginList.loginAdded(event.detail.value);
+      gElements.loginItem.loginAdded(event.detail.value);
       break;
     }
     case "LoginModified": {
       gElements.loginList.loginModified(event.detail.value);
       gElements.loginItem.loginModified(event.detail.value);
       break;
     }
     case "LoginRemoved": {
deleted file mode 100644
--- a/browser/components/aboutlogins/content/components/login-item.css
+++ /dev/null
@@ -1,27 +0,0 @@
-/* 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/. */
-
-h2 {
-  border-bottom: 1px solid var(--grey-30);
-}
-
-.field-label {
-  display: block;
-}
-
-.meta-info {
-  font-size: smaller;
-}
-
-.meta-info:not(:first-of-type) {
-  margin-top: 0;
-}
-
-.meta-info:not(:last-of-type) {
-  margin-bottom: 0;
-}
-
-.meta-info:first-of-type {
-  border-top: 1px solid var(--grey-30);
-}
--- a/browser/components/aboutlogins/content/components/login-item.js
+++ b/browser/components/aboutlogins/content/components/login-item.js
@@ -13,116 +13,111 @@ class LoginItem extends HTMLElement {
       this.render();
       return;
     }
 
     let loginItemTemplate = document.querySelector("#login-item-template");
     this.attachShadow({mode: "open"})
         .appendChild(loginItemTemplate.content.cloneNode(true));
 
-    for (let selector of [
-      ".delete-button",
-      ".save-changes-button",
-      ".cancel-button",
-    ]) {
-      let button = this.shadowRoot.querySelector(selector);
-      button.addEventListener("click", this);
-    }
+    let deleteButton = this.shadowRoot.querySelector(".delete-button");
+    deleteButton.addEventListener("click", this);
 
     window.addEventListener("AboutLoginsLoginSelected", this);
 
     this.render();
   }
 
   static get observedAttributes() {
     return [
-      "cancel-button",
-      "delete-button",
-      "hostname-label",
-      "password-label",
-      "save-changes-button",
-      "time-created",
-      "time-changed",
-      "time-used",
-      "username-label",
+      "login-item-delete",
+      "login-item-hostname",
+      "login-item-password",
+      "login-item-time-created",
+      "login-item-username",
     ];
   }
 
   /* Fluent doesn't handle localizing into Shadow DOM yet so strings
      need to get reflected in to their targeted element. */
   attributeChangedCallback(attr, oldValue, newValue) {
     if (!this.shadowRoot) {
       return;
     }
 
-    // Strings that are reflected to their shadowed element are assigned
-    // to an attribute name that matches a className on the element.
-    let shadowedElement = this.shadowRoot.querySelector("." + attr);
-    shadowedElement.textContent = newValue;
+    switch (attr) {
+      case "login-item-delete":
+        this.shadowRoot.querySelector(".delete-button").textContent = newValue;
+        break;
+      case "login-item-hostname":
+        this.shadowRoot.querySelector(".hostname-label").textContent = newValue;
+        break;
+      case "login-item-password":
+        this.shadowRoot.querySelector(".password-label").textContent = newValue;
+        break;
+      case "login-item-time-created":
+        this.shadowRoot.querySelector(".time-created-label").textContent = newValue;
+        break;
+      case "login-item-username":
+        this.shadowRoot.querySelector(".username-label").textContent = newValue;
+        break;
+    }
   }
 
   render() {
-    let l10nArgs = {
-      timeCreated: this._login.timeCreated || "",
-      timeChanged: this._login.timePasswordChanged || "",
-      timeUsed: this._login.timeLastUsed || "",
-    };
-    document.l10n.setAttributes(this, "login-item", l10nArgs);
-    let hostnameNoScheme = this._login.hostname && new URL(this._login.hostname).hostname;
-    this.shadowRoot.querySelector(".header").textContent = hostnameNoScheme || "";
-    this.shadowRoot.querySelector(".hostname").textContent = this._login.hostname || "";
+    this.shadowRoot.querySelector("input[name='hostname']").value = this._login.hostname || "";
     this.shadowRoot.querySelector("input[name='username']").value = this._login.username || "";
     this.shadowRoot.querySelector("input[name='password']").value = this._login.password || "";
+    this.shadowRoot.querySelector(".time-created").textContent = this._login.timeCreated || "";
   }
 
   handleEvent(event) {
     switch (event.type) {
       case "AboutLoginsLoginSelected": {
         this.setLogin(event.detail);
         break;
       }
       case "click": {
         if (event.target.classList.contains("delete-button")) {
           document.dispatchEvent(new CustomEvent("AboutLoginsDeleteLogin", {
             bubbles: true,
             detail: this._login,
           }));
-          return;
-        }
-        if (event.target.classList.contains("save-changes-button")) {
-          let loginUpdates = {
-            guid: this._login.guid,
-          };
-          let formUsername = this.shadowRoot.querySelector("input[name='username']").value.trim();
-          if (formUsername != this._login.username) {
-            loginUpdates.username = formUsername;
-          }
-          let formPassword = this.shadowRoot.querySelector("input[name='password']").value.trim();
-          if (formPassword != this._login.password) {
-            loginUpdates.password = formPassword;
-          }
-          document.dispatchEvent(new CustomEvent("AboutLoginsUpdateLogin", {
-            bubbles: true,
-            detail: loginUpdates,
-          }));
-          return;
-        }
-        if (event.target.classList.contains("cancel-button")) {
-          this.render();
         }
         break;
       }
     }
   }
 
   setLogin(login) {
     this._login = login;
     this.render();
   }
 
+  loginAdded(login) {
+    if (!this._login.guid) {
+      let tempLogin = {
+        username: this.shadowRoot.querySelector("input[name='username']").value,
+        formSubmitURL: "", // Use the wildcard since the user doesn't supply it.
+        hostname: this.shadowRoot.querySelector("input[name='hostname']").value,
+        password: this.shadowRoot.querySelector("input[name='password']").value,
+      };
+      // Need to use LoginHelper.doLoginsMatch() to see if the login
+      // that was added is the login that was being edited, so we
+      // can update time-created, etc.
+      if (window.AboutLoginsUtils.doLoginsMatch(tempLogin, login)) {
+        this._login = login;
+        this.render();
+      }
+    } else if (login.guid == this._login.guid) {
+      this._login = login;
+      this.render();
+    }
+  }
+
   loginModified(login) {
     if (login.guid != this._login.guid) {
       return;
     }
 
     this._login = login;
     this.render();
   }
deleted file mode 100644
--- a/browser/components/aboutlogins/content/components/login-list-item.css
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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/. */
-
-:host {
-  border-inline-start: 4px solid transparent;
-  border-bottom: 1px solid var(--grey-30);
-  display: block;
-  padding: 10px;
-}
-
-:host(:hover) {
-  background-color: var(--grey-90-a10);
-}
-
-:host(:hover:active) {
-  background-color: var(--grey-90-a20);
-}
-
-:host(.selected) {
-  border-inline-start-color: var(--blue-40);
-  background-color: var(--grey-20);
-}
-
-:host(.selected:hover) {
-}
-
-:host(.selected:hover:active) {
-  background-color: var(--grey-30);
-}
-
-.hostname {
-  font-weight: bold;
-}
-
-.hostname,
-.username {
-  display: block;
-}
--- a/browser/components/aboutlogins/content/components/login-list-item.js
+++ b/browser/components/aboutlogins/content/components/login-list-item.js
@@ -1,40 +1,50 @@
 /* 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/. */
 
 class LoginListItem extends HTMLElement {
   constructor(login) {
     super();
     this._login = login;
+    this._selected = false;
   }
 
   connectedCallback() {
     if (this.children.length) {
       this.render();
       return;
     }
 
     let loginListItemTemplate = document.querySelector("#login-list-item-template");
     this.attachShadow({mode: "open"})
         .appendChild(loginListItemTemplate.content.cloneNode(true));
     this.render();
 
     this.addEventListener("click", this);
+    window.addEventListener("AboutLoginsLoginSelected", this);
   }
 
   render() {
+    this.classList.toggle("selected", this._selected);
     this.setAttribute("guid", this._login.guid);
-    this.shadowRoot.querySelector(".hostname").textContent = this._login.hostname;
-    this.shadowRoot.querySelector(".username").textContent = this._login.username;
+    this.shadowRoot.querySelector(".login-list-item-hostname").textContent = this._login.hostname;
+    this.shadowRoot.querySelector(".login-list-item-username").textContent = this._login.username;
   }
 
   handleEvent(event) {
     switch (event.type) {
+      case "AboutLoginsLoginSelected": {
+        if (this._selected != (event.detail.guid == this._login.guid)) {
+          this._selected = event.detail.guid == this._login.guid;
+          this.render();
+        }
+        break;
+      }
       case "click": {
         this.dispatchEvent(new CustomEvent("AboutLoginsLoginSelected", {
           bubbles: true,
           composed: true,
           detail: this._login,
         }));
       }
     }
deleted file mode 100644
--- a/browser/components/aboutlogins/content/components/login-list.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/* 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/. */
-
-ol {
-  padding-inline-start: 0;
-}
--- a/browser/components/aboutlogins/content/components/login-list.js
+++ b/browser/components/aboutlogins/content/components/login-list.js
@@ -3,51 +3,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* globals LoginListItem */
 
 class LoginList extends HTMLElement {
   constructor() {
     super();
     this._logins = [];
-    this._selectedItem = null;
   }
 
   connectedCallback() {
     if (this.children.length) {
       return;
     }
     let loginListTemplate = document.querySelector("#login-list-template");
     this.attachShadow({mode: "open"})
         .appendChild(loginListTemplate.content.cloneNode(true));
     this.render();
-
-    window.addEventListener("AboutLoginsLoginSelected", this);
   }
 
   render() {
-    let list = this.shadowRoot.querySelector("ol");
+    let pre = this.shadowRoot.querySelector("pre");
     for (let login of this._logins) {
-      list.append(new LoginListItem(login));
-    }
-  }
-
-  handleEvent(event) {
-    switch (event.type) {
-      case "AboutLoginsLoginSelected": {
-        if (this._selectedItem) {
-          if (this._selectedItem.getAttribute("guid") == event.detail.guid) {
-            return;
-          }
-          this._selectedItem.classList.toggle("selected", false);
-        }
-        this._selectedItem = this.shadowRoot.querySelector(`login-list-item[guid="${event.detail.guid}"]`);
-        this._selectedItem.classList.toggle("selected", true);
-        break;
-      }
+      pre.append(new LoginListItem(login));
     }
   }
 
   static get observedAttributes() {
     return ["login-list-header"];
   }
 
   /* Fluent doesn't handle localizing into Shadow DOM yet so strings
@@ -60,48 +41,48 @@ class LoginList extends HTMLElement {
     switch (attr) {
       case "login-list-header":
         this.shadowRoot.querySelector("h2").textContent = newValue;
         break;
     }
   }
 
   setLogins(logins) {
-    let list = this.shadowRoot.querySelector("ol");
-    list.textContent = "";
+    let pre = this.shadowRoot.querySelector("pre");
+    pre.textContent = "";
     this._logins = logins;
     this.render();
   }
 
   loginAdded(login) {
     this._logins.push(login);
-    let list = this.shadowRoot.querySelector("ol");
-    list.append(new LoginListItem(login));
+    let pre = this.shadowRoot.querySelector("pre");
+    pre.append(new LoginListItem(login));
   }
 
   loginModified(login) {
     for (let i = 0; i < this._logins.length; i++) {
       if (this._logins[i].guid == login.guid) {
         this._logins[i] = login;
         break;
       }
     }
-    let list = this.shadowRoot.querySelector("ol");
-    for (let loginListItem of list.children) {
+    let pre = this.shadowRoot.querySelector("pre");
+    for (let loginListItem of pre.children) {
       if (loginListItem.getAttribute("guid") == login.guid) {
         loginListItem.update(login);
         break;
       }
     }
   }
 
   loginRemoved(login) {
     this._logins = this._logins.filter(l => l.guid != login.guid);
-    let list = this.shadowRoot.querySelector("ol");
-    for (let loginListItem of list.children) {
+    let pre = this.shadowRoot.querySelector("pre");
+    for (let loginListItem of pre.children) {
       if (loginListItem.getAttribute("guid") == login.guid) {
         loginListItem.remove();
         break;
       }
     }
   }
 }
 customElements.define("login-list", LoginList);
--- a/browser/components/aboutlogins/jar.mn
+++ b/browser/components/aboutlogins/jar.mn
@@ -1,13 +1,10 @@
 # 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/.
 
 browser.jar:
-  content/browser/aboutlogins/components/login-item.css        (content/components/login-item.css)
   content/browser/aboutlogins/components/login-item.js         (content/components/login-item.js)
-  content/browser/aboutlogins/components/login-list.css        (content/components/login-list.css)
   content/browser/aboutlogins/components/login-list.js         (content/components/login-list.js)
-  content/browser/aboutlogins/components/login-list-item.css   (content/components/login-list-item.css)
   content/browser/aboutlogins/components/login-list-item.js    (content/components/login-list-item.js)
   content/browser/aboutlogins/aboutLogins.js    (content/aboutLogins.js)
   content/browser/aboutlogins/aboutLogins.html  (content/aboutLogins.html)
--- a/browser/components/aboutlogins/tests/browser/browser.ini
+++ b/browser/components/aboutlogins/tests/browser/browser.ini
@@ -1,7 +1,6 @@
 [DEFAULT]
 prefs =
   signon.management.page.enabled=true
 
 [browser_deleteLogin.js]
-[browser_loginListChanges.js]
-[browser_updateLogin.js]
+[browser_loginChanges.js]
rename from browser/components/aboutlogins/tests/browser/browser_loginListChanges.js
rename to browser/components/aboutlogins/tests/browser/browser_loginChanges.js
deleted file mode 100644
--- a/browser/components/aboutlogins/tests/browser/browser_updateLogin.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
-                                             Ci.nsILoginInfo, "init");
-const LOGIN_URL = "https://www.example.com";
-let TEST_LOGIN1 = new nsLoginInfo(LOGIN_URL, LOGIN_URL, null, "user1", "pass1", "username", "password");
-
-add_task(async function setup() {
-  TEST_LOGIN1 = Services.logins.addLogin(TEST_LOGIN1);
-  await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
-  registerCleanupFunction(() => {
-    BrowserTestUtils.removeTab(gBrowser.selectedTab);
-    Services.logins.removeAllLogins();
-  });
-});
-
-add_task(async function test_show_logins() {
-  let browser = gBrowser.selectedBrowser;
-  await ContentTask.spawn(browser, TEST_LOGIN1.guid, async (loginGuid) => {
-    let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
-    let loginFound = await ContentTaskUtils.waitForCondition(() => {
-      return loginList._logins.length == 1 &&
-             loginList._logins[0].guid == loginGuid;
-    }, "Waiting for login to be displayed");
-    ok(loginFound, "Stored logins should be displayed upon loading the page");
-  });
-});
-
-add_task(async function test_login_item() {
-  let browser = gBrowser.selectedBrowser;
-  await ContentTask.spawn(browser, LoginHelper.loginToVanillaObject(TEST_LOGIN1), async (login) => {
-    let loginList = content.document.querySelector("login-list");
-    let loginListItem = Cu.waiveXrays(loginList.shadowRoot.querySelector("login-list-item"));
-    loginListItem.click();
-
-    let loginItem = Cu.waiveXrays(content.document.querySelector("login-item"));
-    let loginItemPopulated = await ContentTaskUtils.waitForCondition(() => {
-      return loginItem._login.guid == loginListItem.getAttribute("guid") &&
-             loginItem._login.guid == login.guid;
-    }, "Waiting for login item to get populated");
-    ok(loginItemPopulated, "The login item should get populated");
-
-    let usernameInput = loginItem.shadowRoot.querySelector("input[name='username']");
-    let passwordInput = loginItem.shadowRoot.querySelector("input[name='password']");
-
-    usernameInput.value += "-undome";
-    passwordInput.value += "-undome";
-
-    let cancelButton = loginItem.shadowRoot.querySelector(".cancel-button");
-    cancelButton.click();
-    await Promise.resolve();
-    is(usernameInput.value, login.username, "Username change should be reverted");
-    is(passwordInput.value, login.password, "Password change should be reverted");
-
-    usernameInput.value += "-saveme";
-    passwordInput.value += "-saveme";
-
-    let saveChangesButton = loginItem.shadowRoot.querySelector(".save-changes-button");
-    saveChangesButton.click();
-
-    await ContentTaskUtils.waitForCondition(() => {
-      return loginListItem._login.username == usernameInput.value &&
-             loginListItem._login.password == passwordInput.value;
-    }, "Waiting for corresponding login in login list to update");
-  });
-});
--- a/browser/components/aboutlogins/tests/mochitest/aboutlogins_common.js
+++ b/browser/components/aboutlogins/tests/mochitest/aboutlogins_common.js
@@ -1,11 +1,11 @@
 "use strict";
 
-/* exported asyncElementRendered, importDependencies, stubFluentL10n */
+/* exported asyncElementRendered, importDependencies */
 
 /**
  * A helper to await on while waiting for an asynchronous rendering of a Custom
  * Element.
  * @returns {Promise}
  */
 function asyncElementRendered() {
   return Promise.resolve();
@@ -19,20 +19,8 @@ function asyncElementRendered() {
 function importDependencies(templateFrame, destinationEl) {
   let templates = templateFrame.contentDocument.querySelectorAll("template");
   isnot(templates, null, "Check some templates found");
   for (let template of templates) {
     let imported = document.importNode(template, true);
     destinationEl.appendChild(imported);
   }
 }
-
-function stubFluentL10n(argsMap) {
-  document.l10n = {
-    setAttributes(element, id, args) {
-      element.setAttribute("data-l10n-id", id);
-      for (let attrName of Object.keys(argsMap)) {
-        let varName = argsMap[attrName];
-        element.setAttribute(attrName, args[varName]);
-      }
-    },
-  };
-}
--- a/browser/components/aboutlogins/tests/mochitest/test_login_item.html
+++ b/browser/components/aboutlogins/tests/mochitest/test_login_item.html
@@ -26,104 +26,84 @@ Test the login-item component
 
 let gLoginItem;
 const TEST_LOGIN_1 = {
   guid: "123456789",
   hostname: "https://example.com",
   username: "user1",
   password: "pass1",
   timeCreated: "1000",
-  timePasswordChanged: "2000",
-  timeLastUsed: "4000",
 };
 
 add_task(async function setup() {
-  stubFluentL10n({
-    "time-created": "timeCreated",
-    "time-changed": "timeChanged",
-    "time-used": "timeUsed",
-  });
-
   let templateFrame = document.getElementById("templateFrame");
   let displayEl = document.getElementById("display");
   importDependencies(templateFrame, displayEl);
 
   gLoginItem = document.createElement("login-item");
   displayEl.appendChild(gLoginItem);
 });
 
 add_task(async function test_empty_item() {
   ok(gLoginItem, "loginItem exists");
-  is(gLoginItem.shadowRoot.querySelector(".hostname").textContent, "", "hostname should be blank");
+  is(gLoginItem.shadowRoot.querySelector("input[name='hostname']").value, "", "hostname should be blank");
   is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, "", "username should be blank");
   is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, "", "password should be blank");
   is(gLoginItem.shadowRoot.querySelector(".time-created").textContent, "", "time-created should be blank");
-  is(gLoginItem.shadowRoot.querySelector(".time-changed").textContent, "", "time-changed should be blank");
-  is(gLoginItem.shadowRoot.querySelector(".time-used").textContent, "", "time-used should be blank");
 });
 
 add_task(async function test_set_login() {
   gLoginItem.setLogin(TEST_LOGIN_1);
   await asyncElementRendered();
 
-  is(gLoginItem.shadowRoot.querySelector(".hostname").textContent, TEST_LOGIN_1.hostname, "hostname should be populated");
+  is(gLoginItem.shadowRoot.querySelector("input[name='hostname']").value, TEST_LOGIN_1.hostname, "hostname should be populated");
   is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, TEST_LOGIN_1.username, "username should be populated");
   is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, TEST_LOGIN_1.password, "password should be populated");
   is(gLoginItem.shadowRoot.querySelector(".time-created").textContent, TEST_LOGIN_1.timeCreated, "time-created should be populated");
-  is(gLoginItem.shadowRoot.querySelector(".time-changed").textContent, TEST_LOGIN_1.timePasswordChanged, "time-changed should be populated");
-  is(gLoginItem.shadowRoot.querySelector(".time-used").textContent, TEST_LOGIN_1.timeLastUsed, "time-used should be populated");
 });
 
 add_task(async function test_different_login_modified() {
   let otherLogin = Object.assign({}, TEST_LOGIN_1, {username: "fakeuser", guid: "fakeguid"});
   gLoginItem.loginModified(otherLogin);
   await asyncElementRendered();
 
-  is(gLoginItem.shadowRoot.querySelector(".hostname").textContent, TEST_LOGIN_1.hostname, "hostname should be unchanged");
+  is(gLoginItem.shadowRoot.querySelector("input[name='hostname']").value, TEST_LOGIN_1.hostname, "hostname should be unchanged");
   is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, TEST_LOGIN_1.username, "username should be unchanged");
   is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, TEST_LOGIN_1.password, "password should be unchanged");
   is(gLoginItem.shadowRoot.querySelector(".time-created").textContent, TEST_LOGIN_1.timeCreated, "time-created should be unchanged");
-  is(gLoginItem.shadowRoot.querySelector(".time-changed").textContent, TEST_LOGIN_1.timePasswordChanged, "time-changed should be unchanged");
-  is(gLoginItem.shadowRoot.querySelector(".time-used").textContent, TEST_LOGIN_1.timeLastUsed, "time-used should be unchanged");
 });
 
 add_task(async function test_different_login_removed() {
   let otherLogin = Object.assign({}, TEST_LOGIN_1, {username: "fakeuser", guid: "fakeguid"});
   gLoginItem.loginRemoved(otherLogin);
   await asyncElementRendered();
 
-  is(gLoginItem.shadowRoot.querySelector(".hostname").textContent, TEST_LOGIN_1.hostname, "hostname should be unchanged");
+  is(gLoginItem.shadowRoot.querySelector("input[name='hostname']").value, TEST_LOGIN_1.hostname, "hostname should be unchanged");
   is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, TEST_LOGIN_1.username, "username should be unchanged");
   is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, TEST_LOGIN_1.password, "password should be unchanged");
   is(gLoginItem.shadowRoot.querySelector(".time-created").textContent, TEST_LOGIN_1.timeCreated, "time-created should be unchanged");
-  is(gLoginItem.shadowRoot.querySelector(".time-changed").textContent, TEST_LOGIN_1.timePasswordChanged, "time-changed should be unchanged");
-  is(gLoginItem.shadowRoot.querySelector(".time-used").textContent, TEST_LOGIN_1.timeLastUsed, "time-used should be unchanged");
 });
 
 add_task(async function test_login_modified() {
   let modifiedLogin = Object.assign({}, TEST_LOGIN_1, {username: "updateduser"});
   gLoginItem.loginModified(modifiedLogin);
   await asyncElementRendered();
 
-  is(gLoginItem.shadowRoot.querySelector(".hostname").textContent, modifiedLogin.hostname, "hostname should be updated");
+  is(gLoginItem.shadowRoot.querySelector("input[name='hostname']").value, modifiedLogin.hostname, "hostname should be updated");
   is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, modifiedLogin.username, "username should be updated");
   is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, modifiedLogin.password, "password should be updated");
   is(gLoginItem.shadowRoot.querySelector(".time-created").textContent, modifiedLogin.timeCreated, "time-created should be updated");
-  is(gLoginItem.shadowRoot.querySelector(".time-changed").textContent, modifiedLogin.timePasswordChanged, "time-changed should be updated");
-  is(gLoginItem.shadowRoot.querySelector(".time-used").textContent, modifiedLogin.timeLastUsed, "time-used should be updated");
 });
 
 add_task(async function test_login_removed() {
   gLoginItem.loginRemoved(TEST_LOGIN_1);
   await asyncElementRendered();
 
-  is(gLoginItem.shadowRoot.querySelector(".hostname").textContent, "", "hostname should be cleared");
+  is(gLoginItem.shadowRoot.querySelector("input[name='hostname']").value, "", "hostname should be cleared");
   is(gLoginItem.shadowRoot.querySelector("input[name='username']").value, "", "username should be cleared");
   is(gLoginItem.shadowRoot.querySelector("input[name='password']").value, "", "password should be cleared");
   is(gLoginItem.shadowRoot.querySelector(".time-created").textContent, "", "time-created should be cleared");
-  is(gLoginItem.shadowRoot.querySelector(".time-changed").textContent, "", "time-changed should be cleared");
-  is(gLoginItem.shadowRoot.querySelector(".time-used").textContent, "", "time-used should be cleared");
 });
 
 </script>
 
 </body>
 </html>
--- a/browser/components/aboutlogins/tests/mochitest/test_login_list.html
+++ b/browser/components/aboutlogins/tests/mochitest/test_login_list.html
@@ -54,55 +54,49 @@ add_task(async function test_empty_list(
 });
 
 add_task(async function test_populated_list() {
   gLoginList.setLogins([TEST_LOGIN_1, TEST_LOGIN_2]);
   await asyncElementRendered();
   let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
   is(loginListItems.length, 2, "Both logins should be displayed");
   is(loginListItems[0].getAttribute("guid"), TEST_LOGIN_1.guid, "login-list-item should have correct guid attribute");
-  is(loginListItems[0].shadowRoot.querySelector(".hostname").textContent, TEST_LOGIN_1.hostname,
+  is(loginListItems[0].shadowRoot.querySelector(".login-list-item-hostname").textContent, TEST_LOGIN_1.hostname,
      "login-list-item hostname should match");
-  is(loginListItems[0].shadowRoot.querySelector(".username").textContent, TEST_LOGIN_1.username,
+  is(loginListItems[0].shadowRoot.querySelector(".login-list-item-username").textContent, TEST_LOGIN_1.username,
      "login-list-item username should match");
-
-  ok(!loginListItems[0].classList.contains("selected"), "The first item should not be selected by default");
-  ok(!loginListItems[1].classList.contains("selected"), "The second item should not be selected by default");
-  loginListItems[0].click();
-  ok(loginListItems[0].classList.contains("selected"), "The first item should be selected");
-  ok(!loginListItems[1].classList.contains("selected"), "The second item should still not be selected");
 });
 
 add_task(async function test_login_modified() {
   let modifiedLogin = Object.assign(TEST_LOGIN_1, {username: "user11"});
   gLoginList.loginModified(modifiedLogin);
   await asyncElementRendered();
   let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
   is(loginListItems.length, 2, "Both logins should be displayed");
   is(loginListItems[0].getAttribute("guid"), TEST_LOGIN_1.guid, "login-list-item should have correct guid attribute");
-  is(loginListItems[0].shadowRoot.querySelector(".hostname").textContent, TEST_LOGIN_1.hostname,
+  is(loginListItems[0].shadowRoot.querySelector(".login-list-item-hostname").textContent, TEST_LOGIN_1.hostname,
      "login-list-item hostname should match");
-  is(loginListItems[0].shadowRoot.querySelector(".username").textContent, modifiedLogin.username,
+  is(loginListItems[0].shadowRoot.querySelector(".login-list-item-username").textContent, modifiedLogin.username,
      "login-list-item username should have been updated");
-  is(loginListItems[1].shadowRoot.querySelector(".username").textContent, TEST_LOGIN_2.username,
+  is(loginListItems[1].shadowRoot.querySelector(".login-list-item-username").textContent, TEST_LOGIN_2.username,
      "login-list-item2 username should remain unchanged");
 });
 
 add_task(async function test_login_added() {
   let newLogin = Object.assign({}, TEST_LOGIN_1, {username: "user22", guid: "111222"});
   gLoginList.loginAdded(newLogin);
   await asyncElementRendered();
   let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
   is(loginListItems.length, 3, "New login should be added to the list");
   is(loginListItems[0].getAttribute("guid"), TEST_LOGIN_1.guid, "login-list-item1 should have correct guid attribute");
   is(loginListItems[1].getAttribute("guid"), TEST_LOGIN_2.guid, "login-list-item2 should have correct guid attribute");
   is(loginListItems[2].getAttribute("guid"), newLogin.guid, "login-list-item3 should have correct guid attribute");
-  is(loginListItems[2].shadowRoot.querySelector(".hostname").textContent, newLogin.hostname,
+  is(loginListItems[2].shadowRoot.querySelector(".login-list-item-hostname").textContent, newLogin.hostname,
      "login-list-item hostname should match");
-  is(loginListItems[2].shadowRoot.querySelector(".username").textContent, newLogin.username,
+  is(loginListItems[2].shadowRoot.querySelector(".login-list-item-username").textContent, newLogin.username,
      "login-list-item username should have been updated");
 });
 
 add_task(async function test_login_removed() {
   gLoginList.loginRemoved({guid: "111222"});
   await asyncElementRendered();
   let loginListItems = gLoginList.shadowRoot.querySelectorAll("login-list-item");
   is(loginListItems.length, 2, "New login should be removed from the list");