Bug 1548381 - Password generation autocomplete UI. r=sfoster
☠☠ backed out by 2690e619a493 ☠ ☠
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Mon, 20 May 2019 19:56:07 +0000
changeset 474624 38e35b6d8d80300cb306a782d1167ec5343acd36
parent 474623 cddbcd92ec10d62b501a42472f99152af909d26e
child 474625 738ce5e88e05ae37464b0e94889a5156c5497435
push id36042
push userdvarga@mozilla.com
push dateTue, 21 May 2019 04:19:40 +0000
treeherdermozilla-central@ca560ff55451 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs1548381
milestone69.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 1548381 - Password generation autocomplete UI. r=sfoster Differential Revision: https://phabricator.services.mozilla.com/D31211
browser/themes/shared/autocomplete.inc.css
toolkit/components/passwordmgr/LoginAutoCompleteResult.jsm
toolkit/components/passwordmgr/test/unit/test_login_autocomplete_result.js
toolkit/content/widgets/autocomplete-popup.js
toolkit/content/widgets/autocomplete.xml
--- a/browser/themes/shared/autocomplete.inc.css
+++ b/browser/themes/shared/autocomplete.inc.css
@@ -66,35 +66,45 @@
   white-space: nowrap;
 }
 
 #PopupAutoComplete > richlistbox > richlistitem > .two-line-wrapper > .labels-wrapper > .line2-label {
   padding-top: 2px !important;
   opacity: .6;
 }
 
-/* Login form autocompletion with and without origin showing */
+/* Login form autocompletion (with and without origin showing) and generated passwords */
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="generatedPassword"] > .two-line-wrapper > .ac-site-icon,
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="loginWithOrigin"] > .two-line-wrapper > .ac-site-icon,
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="login"] > .ac-site-icon {
   display: initial;
   list-style-image: url(chrome://browser/skin/login.svg);
   -moz-context-properties: fill;
   fill: GrayText;
 }
 
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="generatedPassword"][selected] > .two-line-wrapper > .ac-site-icon,
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="loginWithOrigin"][selected] > .two-line-wrapper > .ac-site-icon,
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="login"] > .ac-site-icon[selected] {
   fill: HighlightText;
 }
 
-/* Login form autocompletion with origin showing */
+/* Login form autocompletion with origin showing and generated passwords */
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="generatedPassword"],
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="loginWithOrigin"] {
   padding: 4px;
 }
 
+
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="login"] + richlistitem[originaltype="generatedPassword"],
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="loginWithOrigin"] + richlistitem[originaltype="generatedPassword"] {
+  /* Separator between logins and generated passwords */
+  border-top: 1px solid var(--panel-separator-color);
+}
+
 /* Insecure field warning */
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] {
   background-color: var(--arrowpanel-dimmed);
   border-bottom: 1px solid var(--panel-separator-color);
   padding-bottom: 4px;
   padding-top: 4px;
 }
 
--- a/toolkit/components/passwordmgr/LoginAutoCompleteResult.jsm
+++ b/toolkit/components/passwordmgr/LoginAutoCompleteResult.jsm
@@ -142,16 +142,17 @@ class LoginAutocompleteItem extends Auto
       Services.logins.removeLogin(this._login);
     }
   }
 }
 
 class GeneratedPasswordAutocompleteItem extends AutocompleteItem {
   constructor(generatedPassword) {
     super("generatedPassword");
+    this.comment = generatedPassword;
     this.value = generatedPassword;
 
     XPCOMUtils.defineLazyGetter(this, "label", () => {
       return getLocalizedString("useGeneratedPassword");
     });
   }
 }
 
--- a/toolkit/components/passwordmgr/test/unit/test_login_autocomplete_result.js
+++ b/toolkit/components/passwordmgr/test/unit/test_login_autocomplete_result.js
@@ -68,32 +68,34 @@ let expectedResults = [
     insecureFieldWarningEnabled: true,
     isSecure: false,
     isPasswordField: false,
     matchingLogins: [],
     items: [{
       value: "",
       label: "This connection is not secure. Logins entered here could be compromised. Learn More",
       style: "insecureWarning",
+      comment: "",
     }, {
       value: "",
       label: "View Saved Logins",
       style: "loginsFooter",
       comment: "mochi.test",
     }],
   },
   {
     insecureFieldWarningEnabled: true,
     isSecure: false,
     isPasswordField: false,
     matchingLogins,
     items: [{
       value: "",
       label: "This connection is not secure. Logins entered here could be compromised. Learn More",
       style: "insecureWarning",
+      comment: "",
     }, {
       value: "",
       label: LABEL_NO_USERNAME,
       style: "loginWithOrigin",
       comment: "mochi.test:8888",
     }, {
       value: "tempuser1",
       label: "tempuser1",
@@ -162,16 +164,17 @@ let expectedResults = [
     insecureFieldWarningEnabled: true,
     isSecure: false,
     isPasswordField: true,
     matchingLogins,
     items: [{
       value: "",
       label: "This connection is not secure. Logins entered here could be compromised. Learn More",
       style: "insecureWarning",
+      comment: "",
     }, {
       value: "emptypass1",
       label: LABEL_NO_USERNAME,
       style: "loginWithOrigin",
       comment: "mochi.test:8888",
     }, {
       value: "temppass1",
       label: "tempuser1",
@@ -388,16 +391,17 @@ let expectedResults = [
     insecureFieldWarningEnabled: true,
     isSecure: false,
     isPasswordField: false,
     matchingLogins,
     items: [{
       value: "",
       label: "This connection is not secure. Logins entered here could be compromised. Learn More",
       style: "insecureWarning",
+      comment: "",
     }, {
       value: "",
       label: LABEL_NO_USERNAME,
       style: "loginWithOrigin",
       comment: "mochi.test:8888",
     }, {
       value: "tempuser1",
       label: "tempuser1",
@@ -466,16 +470,17 @@ let expectedResults = [
     insecureFieldWarningEnabled: true,
     isSecure: false,
     isPasswordField: true,
     matchingLogins,
     items: [{
       value: "",
       label: "This connection is not secure. Logins entered here could be compromised. Learn More",
       style: "insecureWarning",
+      comment: "",
     }, {
       value: "emptypass1",
       label: LABEL_NO_USERNAME,
       style: "loginWithOrigin",
       comment: "mochi.test:8888",
     }, {
       value: "temppass1",
       label: "tempuser1",
@@ -701,16 +706,17 @@ let expectedResults = [
     insecureFieldWarningEnabled: true,
     isSecure: true,
     isPasswordField: true,
     matchingLogins: [],
     items: [{
       value: "9ljgfd4shyktb45",
       label: "Use Generated Password",
       style: "generatedPassword",
+      comment: "9ljgfd4shyktb45",
     }, {
       value: "",
       label: "View Saved Logins",
       style: "loginsFooter",
       comment: "mochi.test",
     }],
   },
   {
@@ -739,17 +745,17 @@ add_task(async function test_all_pattern
       isSecure: pattern.isSecure,
       isPasswordField: pattern.isPasswordField,
     });
     equal(actual.matchCount, pattern.items.length, "Check matching row count");
     pattern.items.forEach((item, index) => {
       equal(actual.getValueAt(index), item.value, `Value ${index}`);
       equal(actual.getLabelAt(index), item.label, `Label ${index}`);
       equal(actual.getStyleAt(index), item.style, `Style ${index}`);
-      equal(actual.getCommentAt(index), item.comment || "", `Comment ${index}`);
+      equal(actual.getCommentAt(index), item.comment, `Comment ${index}`);
     });
 
     if (pattern.items.length != 0) {
       Assert.throws(() => actual.getValueAt(pattern.items.length),
                     /Index out of range\./);
 
       Assert.throws(() => actual.getLabelAt(pattern.items.length),
                     /Index out of range\./);
--- a/toolkit/content/widgets/autocomplete-popup.js
+++ b/toolkit/content/widgets/autocomplete-popup.js
@@ -372,16 +372,17 @@ MozElements.MozAutocompleteRichlistboxPo
 
         // The styles on the list which have different <content> structure and overrided
         // _adjustAcItem() are unreusable.
         const UNREUSEABLE_STYLES = [
           "autofill-profile",
           "autofill-footer",
           "autofill-clear-button",
           "autofill-insecureWarning",
+          "generatedPassword",
           "insecureWarning",
           "loginsFooter",
           "loginWithOrigin",
         ];
         // Reuse the item when its style is exactly equal to the previous style or
         // neither of their style are in the UNREUSEABLE_STYLES.
         reusable = originalType === style ||
           !(UNREUSEABLE_STYLES.includes(style) || UNREUSEABLE_STYLES.includes(originalType));
@@ -404,16 +405,17 @@ MozElements.MozAutocompleteRichlistboxPo
             options = { is: "autocomplete-creditcard-insecure-field" };
             break;
           case "insecureWarning":
             options = { is: "autocomplete-richlistitem-insecure-warning" };
             break;
           case "loginsFooter":
             options = { is: "autocomplete-richlistitem-logins-footer" };
             break;
+          case "generatedPassword":
           case "loginWithOrigin":
             options = { is: "autocomplete-two-line-richlistitem" };
             break;
           default:
             options = { is: "autocomplete-richlistitem" };
         }
         item = document.createXULElement("richlistitem", options);
         item.className = "autocomplete-richlistitem";
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -1010,16 +1010,17 @@
 
               // The styles on the list which have different <content> structure and overrided
               // _adjustAcItem() are unreusable.
               const UNREUSEABLE_STYLES = [
                 "autofill-profile",
                 "autofill-footer",
                 "autofill-clear-button",
                 "autofill-insecureWarning",
+                "generatedPassword",
                 "insecureWarning",
                 "loginsFooter",
                 "loginWithOrigin",
               ];
               // Reuse the item when its style is exactly equal to the previous style or
               // neither of their style are in the UNREUSEABLE_STYLES.
               reusable = originalType === style ||
                 !(UNREUSEABLE_STYLES.includes(style) || UNREUSEABLE_STYLES.includes(originalType));
@@ -1042,16 +1043,17 @@
                   options = { is: "autocomplete-creditcard-insecure-field" };
                   break;
                 case "insecureWarning":
                   options = { is: "autocomplete-richlistitem-insecure-warning" };
                   break;
                 case "loginsFooter":
                   options = { is: "autocomplete-richlistitem-logins-footer" };
                   break;
+                case "generatedPassword":
                 case "loginWithOrigin":
                   options = { is: "autocomplete-two-line-richlistitem" };
                   break;
                 default:
                   options = { is: "autocomplete-richlistitem" };
               }
               item = document.createXULElement("richlistitem", options);
               item.className = "autocomplete-richlistitem";