Bug 1371139 - Part 1. Implementation of form auto fill credit card layout. r=lchang, seanlee
MozReview-Commit-ID: 59gyOlHvSz8
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -269,16 +269,23 @@ class AddressResult extends ProfileAutoC
}
}
class CreditCardResult extends ProfileAutoCompleteResult {
constructor(...args) {
super(...args);
}
+ _fmtMaskedCreditCardLabel(maskedCCNum = "") {
+ return {
+ affix: "****",
+ label: maskedCCNum.replace(/^\**/, ""),
+ };
+ }
+
_getSecondaryLabel(focusedFieldName, allFieldNames, profile) {
const GROUP_FIELDS = {
"cc-name": [
"cc-name",
"cc-given-name",
"cc-additional-name",
"cc-family-name",
],
@@ -307,16 +314,20 @@ class CreditCardResult extends ProfileAu
continue;
}
let matching = GROUP_FIELDS[currentFieldName] ?
allFieldNames.some(fieldName => GROUP_FIELDS[currentFieldName].includes(fieldName)) :
allFieldNames.includes(currentFieldName);
if (matching) {
+ if (currentFieldName == "cc-number") {
+ let {affix, label} = this._fmtMaskedCreditCardLabel(profile[currentFieldName]);
+ return affix + label;
+ }
return profile[currentFieldName];
}
}
return ""; // Nothing matched.
}
_generateLabels(focusedFieldName, allFieldNames, profiles) {
@@ -328,18 +339,27 @@ class CreditCardResult extends ProfileAu
return [FormAutofillUtils.stringBundle.formatStringFromName("insecureFieldWarningDescription", [brandName], 1)];
}
// Skip results without a primary label.
let labels = profiles.filter(profile => {
return !!profile[focusedFieldName];
}).map(profile => {
+ let primaryAffix;
+ let primary = profile[focusedFieldName];
+
+ if (focusedFieldName == "cc-number") {
+ let {affix, label} = this._fmtMaskedCreditCardLabel(primary);
+ primaryAffix = affix;
+ primary = label;
+ }
return {
- primary: profile[focusedFieldName],
+ primaryAffix,
+ primary,
secondary: this._getSecondaryLabel(focusedFieldName,
allFieldNames,
profile),
};
});
// Add an empty result entry for footer.
labels.push({primary: "", secondary: ""});
@@ -371,9 +391,14 @@ class CreditCardResult extends ProfileAu
}
if (index == this.matchCount - 1) {
return "autofill-footer";
}
return "autofill-profile";
}
+
+ getImageAt(index) {
+ this._checkIndexBounds(index);
+ return "chrome://formautofill/content/icon-credit-card-generic.svg";
+ }
}
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -65,46 +65,53 @@
<method name="_adjustAutofillItemLayout">
<body>
<![CDATA[
let outerBoxRect = this.parentNode.getBoundingClientRect();
// Make item fit in popup as XUL box could not constrain
// item's width
this._itemBox.style.width = outerBoxRect.width + "px";
- // Use two-lines layout when width is smaller than 150px
- if (outerBoxRect.width <= 150) {
+ // Use two-lines layout when width is smaller than 150px or
+ // 185px if an image precedes the label.
+ let oneLineMinRequiredWidth = this.getAttribute("ac-image") ? 185 : 150;
+
+ if (outerBoxRect.width <= oneLineMinRequiredWidth) {
this._itemBox.setAttribute("size", "small");
} else {
this._itemBox.removeAttribute("size");
}
]]>
</body>
</method>
</implementation>
</binding>
<binding id="autocomplete-profile-listitem" extends="chrome://formautofill/content/formautofill.xml#autocomplete-profile-listitem-base">
<xbl:content xmlns="http://www.w3.org/1999/xhtml">
- <div anonid="autofill-item-box" class="autofill-item-box">
+ <div anonid="autofill-item-box" class="autofill-item-box" xbl:inherits="ac-image">
<div class="profile-label-col profile-item-col">
+ <span anonid="profile-label-affix" class="profile-label-affix"></span>
<span anonid="profile-label" class="profile-label"></span>
</div>
<div class="profile-comment-col profile-item-col">
<span anonid="profile-comment" class="profile-comment"></span>
</div>
</div>
</xbl:content>
<implementation implements="nsIDOMXULSelectControlItemElement">
<constructor>
<![CDATA[
this._itemBox = document.getAnonymousElementByAttribute(
this, "anonid", "autofill-item-box"
);
+ this._labelAffix = document.getAnonymousElementByAttribute(
+ this, "anonid", "profile-label-affix"
+ );
this._label = document.getAnonymousElementByAttribute(
this, "anonid", "profile-label"
);
this._comment = document.getAnonymousElementByAttribute(
this, "anonid", "profile-comment"
);
this._adjustAcItem();
@@ -128,19 +135,21 @@
]]></setter>
</property>
<method name="_adjustAcItem">
<body>
<![CDATA[
this._adjustAutofillItemLayout();
this.setAttribute("formautofillattached", "true");
+ this._itemBox.style.setProperty("--primary-icon", `url(${this.getAttribute("ac-image")})`);
- let {primary, secondary} = JSON.parse(this.getAttribute("ac-value"));
+ let {primaryAffix, primary, secondary} = JSON.parse(this.getAttribute("ac-value"));
+ this._labelAffix.textContent = primaryAffix;
this._label.textContent = primary;
this._comment.textContent = secondary;
]]>
</body>
</method>
</implementation>
</binding>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/content/icon-credit-card-generic.svg
@@ -0,0 +1,9 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+ <path fill="context-fill" d="M4.5,9.4H3.2c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5h1.3c0.3,0,0.5-0.2,0.5-0.5S4.8,9.4,4.5,9.4z"/>
+ <path fill="context-fill" d="M9.3,9.4H6.2c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5h3.2c0.3,0,0.5-0.2,0.5-0.5S9.6,9.4,9.3,9.4z"/>
+ <path fill="context-fill" d="M14,2H2C0.9,2,0,2.9,0,4v8c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C16,2.9,15.1,2,14,2z M14,12H2V7.7h12V12z
+ M14,6H2V4h12V6z"/>
+</svg>
--- a/browser/extensions/formautofill/skin/linux/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/linux/autocomplete-item.css
@@ -1,22 +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/. */
@namespace url("http://www.w3.org/1999/xhtml");
-.autofill-item-box > .profile-item-col > .profile-label {
- font-size: .84em;
-}
-
-.autofill-item-box > .profile-item-col > .profile-comment {
- font-size: .7em;
+.autofill-item-box {
+ --default-font-size: 14.25;
}
-
-.autofill-footer > .autofill-warning {
- font-size: .7em;
-}
-
-.autofill-footer > .autofill-option-button {
- font-size: .77em;
-}
--- a/browser/extensions/formautofill/skin/osx/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/osx/autocomplete-item.css
@@ -1,18 +1,9 @@
/* 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/. */
@namespace url("http://www.w3.org/1999/xhtml");
-
-.autofill-item-box > .profile-item-col > .profile-label {
- font-size: 1.09em;
+.autofill-item-box {
+ --default-font-size: 11;
}
-
-.autofill-item-box > .profile-item-col > .profile-comment {
- font-size: .9em;
-}
-
-.autofill-footer > .autofill-warning {
- font-size: .9em;
-}
--- a/browser/extensions/formautofill/skin/shared/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/shared/autocomplete-item.css
@@ -19,26 +19,40 @@ xul|richlistitem[originaltype="autofill-
background-color: var(--arrowpanel-dimmed);
}
.autofill-item-box {
--item-padding-vertical: 6px;
--item-padding-horizontal: 10px;
--col-spacer: 7px;
--item-width: calc(50% - (var(--col-spacer) / 2));
- --item-text-color: -moz-FieldText;
+ --label-text-color: #262626;
+ --comment-text-color: #646464;
+ --warning-text-color: #646464;
+ --option-btn-text-color: -moz-FieldText;
+
+ --default-font-size: 12;
+ --label-affix-font-size: 10;
+ --label-font-size: 12;
+ --comment-font-size: 10;
+ --warning-font-size: 10;
+ --option-btn-font-size: 11;
}
.autofill-item-box[size="small"] {
--item-padding-vertical: 7px;
--col-spacer: 0px;
--row-spacer: 3px;
--item-width: 100%;
}
+.autofill-item-box:not([ac-image=""]) {
+ --comment-font-size: 11;
+}
+
.autofill-footer,
.autofill-footer[size="small"] {
--item-width: 100%;
--item-padding-vertical: 0;
--item-padding-horizontal: 0;
}
.autofill-item-box {
@@ -48,17 +62,17 @@ xul|richlistitem[originaltype="autofill-
padding: var(--item-padding-vertical) 0;
padding-inline-start: var(--item-padding-horizontal);
padding-inline-end: var(--item-padding-horizontal);
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
background-color: #FFFFFF;
- color: var(--item-text-color);
+ color: var(--label-text-color);
}
.autofill-item-box:last-child {
border-bottom: 0;
}
.autofill-item-box > .profile-item-col {
box-sizing: border-box;
@@ -67,20 +81,45 @@ xul|richlistitem[originaltype="autofill-
white-space: nowrap;
width: var(--item-width);
}
.autofill-item-box > .profile-label-col {
text-align: start;
}
+.autofill-item-box:not([ac-image=""]) > .profile-label-col::before {
+ margin-right: 5px;
+ float: left;
+ content: "";
+ width: 16px;
+ height: 16px;
+ background-image: var(--primary-icon);
+ background-size: 16px 16px;
+ -moz-context-properties: fill;
+ fill: #4D4D4D;
+}
+
+.autofill-item-box > .profile-label-col > .profile-label {
+ font-size: calc(var(--label-font-size) / var(--default-font-size) * 1em);
+}
+
+.autofill-item-box > .profile-label-col > .profile-label-affix {
+ font-weight: lighter;
+ font-size: calc(var(--label-affix-font-size) / var(--default-font-size) * 1em);
+}
+
.autofill-item-box > .profile-comment-col {
margin-inline-start: var(--col-spacer);
text-align: end;
- color: GrayText;
+ color: var(--comment-text-color);
+}
+
+.autofill-item-box > .profile-comment-col > .profile-comment {
+ font-size: calc(var(--comment-font-size) / var(--default-font-size) * 1em);
}
.autofill-item-box[size="small"] {
flex-direction: column;
}
.autofill-item-box[size="small"] > .profile-comment-col {
margin-top: var(--row-spacer);
@@ -95,25 +134,28 @@ xul|richlistitem[originaltype="autofill-
display: flex;
justify-content: center;
align-items: center;
width: var(--item-width);
}
.autofill-footer > .autofill-warning {
padding: 2.5px 0;
- color: #737373;
+ color: var(--warning-text-color);
text-align: center;
background-color: rgba(248,232,28,.2);
border-bottom: 1px solid rgba(38,38,38,.15);
+ font-size: calc(var(--warning-font-size) / var(--default-font-size) * 1em);
}
.autofill-footer > .autofill-option-button {
- height: 41px;
+ height: 40px;
background-color: #EDEDED;
+ font-size: calc(var(--option-btn-font-size) / var(--default-font-size) * 1em);
+ color: var(--option-btn-text-color);
}
.autofill-footer[no-warning="true"] > .autofill-warning {
display: none;
}
.autofill-insecure-item {
box-sizing: border-box;
--- a/browser/extensions/formautofill/skin/windows/autocomplete-item.css
+++ b/browser/extensions/formautofill/skin/windows/autocomplete-item.css
@@ -1,25 +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/. */
@namespace url("http://www.w3.org/1999/xhtml");
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-.autofill-item-box > .profile-item-col > .profile-comment {
- font-size: .83em;
-}
-
-.autofill-footer > .autofill-warning {
- font-size: .83em;
-}
-
-.autofill-footer > .autofill-option-button {
- font-size: .91em;
+.autofill-item-box {
+ --default-font-size: 12;
}
@media (-moz-windows-default-theme: 0) {
xul|richlistitem[originaltype="autofill-profile"][selected="true"] > .autofill-item-box {
background-color: Highlight;
}
+
+ .autofill-item-box {
+ --label-text-color: -moz-FieldText;
+ --comment-text-color: GrayText;
+ }
}
--- a/browser/extensions/formautofill/test/unit/test_profileAutocompleteResult.js
+++ b/browser/extensions/formautofill/test/unit/test_profileAutocompleteResult.js
@@ -253,28 +253,28 @@ let creditCardTestCases = [{
searchResult: Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
defaultIndex: 0,
items: [{
value: "",
style: "autofill-profile",
comment: JSON.stringify(matchingProfiles[0]),
label: JSON.stringify({
primary: "Timothy Berners-Lee",
- secondary: "************6785",
+ secondary: "****6785",
}),
- image: "",
+ image: "chrome://formautofill/content/icon-credit-card-generic.svg",
}, {
value: "",
style: "autofill-profile",
comment: JSON.stringify(matchingProfiles[1]),
label: JSON.stringify({
primary: "John Doe",
- secondary: "************1234",
+ secondary: "****1234",
}),
- image: "",
+ image: "chrome://formautofill/content/icon-credit-card-generic.svg",
}],
},
}, {
description: "Focus on a `cc-number` field",
options: {},
matchingProfiles,
allFieldNames,
searchString: "",
@@ -282,38 +282,41 @@ let creditCardTestCases = [{
expected: {
searchResult: Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
defaultIndex: 0,
items: [{
value: "",
style: "autofill-profile",
comment: JSON.stringify(matchingProfiles[0]),
label: JSON.stringify({
- primary: "************6785",
+ primaryAffix: "****",
+ primary: "6785",
secondary: "Timothy Berners-Lee",
}),
- image: "",
+ image: "chrome://formautofill/content/icon-credit-card-generic.svg",
}, {
value: "",
style: "autofill-profile",
comment: JSON.stringify(matchingProfiles[1]),
label: JSON.stringify({
- primary: "************1234",
+ primaryAffix: "****",
+ primary: "1234",
secondary: "John Doe",
}),
- image: "",
+ image: "chrome://formautofill/content/icon-credit-card-generic.svg",
}, {
value: "",
style: "autofill-profile",
comment: JSON.stringify(matchingProfiles[2]),
label: JSON.stringify({
- primary: "************5678",
+ primaryAffix: "****",
+ primary: "5678",
secondary: "",
}),
- image: "",
+ image: "chrome://formautofill/content/icon-credit-card-generic.svg",
}],
},
}, {
description: "No matching profiles",
options: {},
matchingProfiles: [],
allFieldNames,
searchString: "",