зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 5 changesets (bug 1859590, bug 1854056) for causing gv-junit failures on loginSelectAccept. CLOSED TREE
Backed out changeset c83019663baf (bug 1854056) Backed out changeset 41dbe84c99b5 (bug 1854056) Backed out changeset 7b85cd7e7676 (bug 1859590) Backed out changeset eae1e90e7c10 (bug 1854056) Backed out changeset fa2c482c3fbd (bug 1854056)
This commit is contained in:
Родитель
cfb3227981
Коммит
4a5f6cbf98
|
@ -83,6 +83,7 @@
|
|||
return `
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" class="autofill-item-box">
|
||||
<div class="profile-label-col profile-item-col">
|
||||
<span class="profile-label-affix"></span>
|
||||
<span class="profile-label"></span>
|
||||
</div>
|
||||
<div class="profile-comment-col profile-item-col">
|
||||
|
@ -102,6 +103,7 @@
|
|||
this.appendChild(this.constructor.fragment);
|
||||
|
||||
this._itemBox = this.querySelector(".autofill-item-box");
|
||||
this._labelAffix = this.querySelector(".profile-label-affix");
|
||||
this._label = this.querySelector(".profile-label");
|
||||
this._comment = this.querySelector(".profile-comment");
|
||||
|
||||
|
@ -137,12 +139,13 @@
|
|||
`url(${this.getAttribute("ac-image")})`
|
||||
);
|
||||
|
||||
let { primary, secondary, ariaLabel } = JSON.parse(
|
||||
let { primaryAffix, primary, secondary, ariaLabel } = JSON.parse(
|
||||
this.getAttribute("ac-value")
|
||||
);
|
||||
|
||||
this._label.textContent = primary.toString().replaceAll("*", "•");
|
||||
this._comment.textContent = secondary.toString().replaceAll("*", "•");
|
||||
this._labelAffix.textContent = primaryAffix;
|
||||
this._label.textContent = primary;
|
||||
this._comment.textContent = secondary;
|
||||
if (ariaLabel) {
|
||||
this.setAttribute("aria-label", ariaLabel);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ xul|richlistitem[originaltype="autofill-insecureWarning"] {
|
|||
--warning-background-color: rgba(248, 232, 28, .2);
|
||||
|
||||
--default-font-size: 12;
|
||||
--label-affix-font-size: 10;
|
||||
--label-font-size: 12;
|
||||
--comment-font-size: 10;
|
||||
--warning-font-size: 10;
|
||||
|
@ -105,6 +106,11 @@ xul|richlistitem[originaltype="autofill-insecureWarning"] {
|
|||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.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;
|
||||
|
|
|
@ -16,40 +16,25 @@ Form autofill test: simple form credit card autofill
|
|||
"use strict";
|
||||
|
||||
const MOCK_STORAGE = [{
|
||||
cc: {
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
"cc-exp-month": 4,
|
||||
"cc-exp-year": 2017,
|
||||
},
|
||||
expected: {
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg"
|
||||
},
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
"cc-exp-month": 4,
|
||||
"cc-exp-year": 2017,
|
||||
}, {
|
||||
cc: {
|
||||
"cc-name": "Timothy Berners-Lee",
|
||||
"cc-number": "5103059495477870",
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2022,
|
||||
},
|
||||
expected: {
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-mastercard.svg"
|
||||
},
|
||||
"cc-name": "Timothy Berners-Lee",
|
||||
"cc-number": "5103059495477870",
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2022,
|
||||
}];
|
||||
|
||||
const reducedMockRecord = {
|
||||
cc: {
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
},
|
||||
expected: {
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg"
|
||||
},
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
};
|
||||
|
||||
async function setupCreditCardStorage() {
|
||||
await addCreditCard(MOCK_STORAGE[0].cc);
|
||||
await addCreditCard(MOCK_STORAGE[1].cc);
|
||||
await addCreditCard(MOCK_STORAGE[0]);
|
||||
await addCreditCard(MOCK_STORAGE[1]);
|
||||
}
|
||||
|
||||
async function setupFormHistory() {
|
||||
|
@ -79,16 +64,15 @@ add_task(async function history_only_menu_checking() {
|
|||
|
||||
// Display credit card result even if the number of fillable fields is less than the threshold.
|
||||
add_task(async function all_saved_fields_less_than_threshold() {
|
||||
await addCreditCard(reducedMockRecord.cc);
|
||||
await addCreditCard(reducedMockRecord);
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries([reducedMockRecord].map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries([reducedMockRecord].map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `Visa ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `Visa ${cc["cc-name"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
|
||||
await cleanUpCreditCards();
|
||||
|
@ -101,41 +85,38 @@ add_task(async function check_menu_when_both_existed() {
|
|||
await setInput("#cc-number", "");
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc.ccNumberFmt,
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primaryAffix: cc.ccNumberFmt.affix,
|
||||
primary: cc.ccNumberFmt.label,
|
||||
secondary: cc["cc-name"],
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc.ccNumberFmt.replaceAll("*", "")} ${cc["cc-name"]}`,
|
||||
image: expected.image,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc.ccNumberFmt.affix} ${cc.ccNumberFmt.label} ${cc["cc-name"]}`,
|
||||
})));
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
|
||||
await setInput("#cc-exp-year", "");
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-exp-year"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-year"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-year"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
|
||||
await setInput("#cc-exp-month", "");
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-exp-month"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-month"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-month"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
|
||||
await cleanUpCreditCards();
|
||||
|
@ -143,7 +124,7 @@ add_task(async function check_menu_when_both_existed() {
|
|||
|
||||
// Display history search result if no matched data in credit card.
|
||||
add_task(async function check_fallback_for_mismatched_field() {
|
||||
await addCreditCard(reducedMockRecord.cc);
|
||||
await addCreditCard(reducedMockRecord);
|
||||
|
||||
await setInput("#cc-exp-year", "");
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
|
@ -184,17 +165,16 @@ add_task(async function check_fields_after_form_autofill() {
|
|||
synthesizeKey("KEY_ArrowDown");
|
||||
// The popup doesn't auto-show on focus because the field isn't empty
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.slice(1).map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.slice(1).map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-exp-year"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-year"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-year"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
let osKeyStoreLoginShown = waitForOSKeyStoreLogin(true);
|
||||
await new Promise(resolve => SimpleTest.executeSoon(resolve));
|
||||
await triggerAutofillAndCheckProfile(MOCK_STORAGE[1].cc);
|
||||
await triggerAutofillAndCheckProfile(MOCK_STORAGE[1]);
|
||||
await osKeyStoreLoginShown;
|
||||
});
|
||||
|
||||
|
@ -218,11 +198,10 @@ add_task(async function check_cc_popup_on_field_blank() {
|
|||
|
||||
await setInput("#cc-name", "", true);
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
});
|
||||
|
||||
|
@ -238,11 +217,10 @@ add_task(async function check_form_autofill_resume() {
|
|||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
});
|
||||
|
||||
|
|
|
@ -16,30 +16,20 @@ Form autofill test: simple form credit card autofill
|
|||
"use strict";
|
||||
|
||||
const MOCK_STORAGE = [{
|
||||
cc: {
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
"cc-exp-month": 4,
|
||||
"cc-exp-year": 2017,
|
||||
},
|
||||
expected: {
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg"
|
||||
},
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
"cc-exp-month": 4,
|
||||
"cc-exp-year": 2017,
|
||||
}, {
|
||||
cc: {
|
||||
"cc-name": "Timothy Berners-Lee",
|
||||
"cc-number": "5103059495477870",
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2022,
|
||||
},
|
||||
expected: {
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-mastercard.svg"
|
||||
},
|
||||
"cc-name": "Timothy Berners-Lee",
|
||||
"cc-number": "5103059495477870",
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2022,
|
||||
}];
|
||||
|
||||
async function setupCreditCardStorage() {
|
||||
await addCreditCard(MOCK_STORAGE[0].cc);
|
||||
await addCreditCard(MOCK_STORAGE[1].cc);
|
||||
await addCreditCard(MOCK_STORAGE[0]);
|
||||
await addCreditCard(MOCK_STORAGE[1]);
|
||||
}
|
||||
|
||||
async function setupFormHistory() {
|
||||
|
@ -72,21 +62,20 @@ add_task(async function check_menu_when_both_with_autocomplete_off() {
|
|||
await setInput("#cc-number", "");
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc.ccNumberFmt,
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primaryAffix: cc.ccNumberFmt.affix,
|
||||
primary: cc.ccNumberFmt.label,
|
||||
secondary: cc["cc-name"],
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc.ccNumberFmt.replaceAll("*", "")} ${cc["cc-name"]}`,
|
||||
image: expected.image,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc.ccNumberFmt.affix} ${cc.ccNumberFmt.label} ${cc["cc-name"]}`,
|
||||
})));
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt.affix}${cc.ccNumberFmt.label}`,
|
||||
})));
|
||||
});
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ async function checkMultipleCCNumberFormStyle(profile, isPreviewing = true) {
|
|||
for (const element of elements) {
|
||||
let fillableValue;
|
||||
if (element.id.includes("cc-number") && isPreviewing) {
|
||||
fillableValue = profile["cc-number"].slice(-8).replaceAll("*", "•");
|
||||
fillableValue = profile["cc-number"].slice(-8);
|
||||
} else if (element.id.includes("cc-number")) {
|
||||
fillableValue = profile["cc-number"];
|
||||
} else {
|
||||
|
|
|
@ -139,8 +139,7 @@ async function checkFormFieldsStyle(profile, isPreviewing = true) {
|
|||
previewValue = "";
|
||||
} else {
|
||||
fillableValue = profile && profile[elem.id];
|
||||
previewValue =
|
||||
(isPreviewing && fillableValue?.toString().replaceAll("*", "•")) || "";
|
||||
previewValue = (isPreviewing && fillableValue) || "";
|
||||
}
|
||||
await checkFieldHighlighted(elem, !!fillableValue);
|
||||
await checkFieldPreview(elem, previewValue);
|
||||
|
@ -372,12 +371,13 @@ async function waitForOSKeyStoreLogin(login = false) {
|
|||
}
|
||||
|
||||
function patchRecordCCNumber(record) {
|
||||
const ccNumberFmt = "****" + record.cc["cc-number"].substr(-4);
|
||||
|
||||
return {
|
||||
cc: Object.assign({}, record.cc, { ccNumberFmt }),
|
||||
expected: record.expected,
|
||||
const number = record["cc-number"];
|
||||
const ccNumberFmt = {
|
||||
affix: "****",
|
||||
label: number.substr(-4),
|
||||
};
|
||||
|
||||
return Object.assign({}, record, { ccNumberFmt });
|
||||
}
|
||||
|
||||
// Utils for registerPopupShownListener(in satchel_common.js) that handles dropdown popup
|
||||
|
|
|
@ -293,7 +293,6 @@ let creditCardTestCases = [
|
|||
primary: "Timothy Berners-Lee",
|
||||
secondary: "****6785",
|
||||
ariaLabel: "Visa Timothy Berners-Lee ****6785",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg",
|
||||
}),
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg",
|
||||
},
|
||||
|
@ -305,7 +304,6 @@ let creditCardTestCases = [
|
|||
primary: "John Doe",
|
||||
secondary: "****1234",
|
||||
ariaLabel: "American Express John Doe ****1234",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-amex.png",
|
||||
}),
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-amex.png",
|
||||
},
|
||||
|
@ -328,10 +326,10 @@ let creditCardTestCases = [
|
|||
style: "autofill-profile",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "****6785",
|
||||
primaryAffix: "****",
|
||||
primary: "6785",
|
||||
secondary: "Timothy Berners-Lee",
|
||||
ariaLabel: "Visa 6785 Timothy Berners-Lee",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg",
|
||||
ariaLabel: "Visa **** 6785 Timothy Berners-Lee",
|
||||
}),
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg",
|
||||
},
|
||||
|
@ -340,10 +338,10 @@ let creditCardTestCases = [
|
|||
style: "autofill-profile",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "****1234",
|
||||
primaryAffix: "****",
|
||||
primary: "1234",
|
||||
secondary: "John Doe",
|
||||
ariaLabel: "American Express 1234 John Doe",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-amex.png",
|
||||
ariaLabel: "American Express **** 1234 John Doe",
|
||||
}),
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-amex.png",
|
||||
},
|
||||
|
@ -352,10 +350,10 @@ let creditCardTestCases = [
|
|||
style: "autofill-profile",
|
||||
comment: JSON.stringify(matchingProfiles[2]),
|
||||
label: JSON.stringify({
|
||||
primary: "****5678",
|
||||
primaryAffix: "****",
|
||||
primary: "5678",
|
||||
secondary: "",
|
||||
ariaLabel: "5678",
|
||||
image: "chrome://formautofill/content/icon-credit-card-generic.svg",
|
||||
ariaLabel: "**** 5678",
|
||||
}),
|
||||
image: "chrome://formautofill/content/icon-credit-card-generic.svg",
|
||||
},
|
||||
|
|
|
@ -29,7 +29,6 @@ head = head_addressComponent.js
|
|||
[test_addressComponent_tel.js]
|
||||
head = head_addressComponent.js
|
||||
[test_addressDataLoader.js]
|
||||
skip-if = true # bug 1859588
|
||||
[test_addressRecords.js]
|
||||
skip-if =
|
||||
apple_silicon # bug 1729554
|
||||
|
|
|
@ -24,6 +24,23 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
#PopupAutoComplete > richlistbox > richlistitem > .ac-login-item > .ac-settings-button {
|
||||
visibility: hidden;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border: 0;
|
||||
color: inherit;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
margin-inline: 8px;
|
||||
cursor: pointer;
|
||||
background: url("chrome://global/skin/icons/settings.svg") center no-repeat;
|
||||
}
|
||||
|
||||
#PopupAutoComplete > richlistbox > richlistitem:is(:hover, [selected]) > .ac-login-item > .ac-settings-button {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#PopupAutoComplete > richlistbox > richlistitem > .ac-title {
|
||||
font: icon;
|
||||
margin-inline-start: 4px;
|
||||
|
@ -60,22 +77,6 @@
|
|||
min-width: 0;
|
||||
}
|
||||
|
||||
#PopupAutoComplete > richlistbox > richlistitem > .two-line-wrapper > .ac-secondary-action {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border: 0;
|
||||
color: inherit;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
margin-inline: 8px;
|
||||
cursor: pointer;
|
||||
background: url("chrome://global/skin/icons/settings.svg") center no-repeat;
|
||||
}
|
||||
|
||||
#PopupAutoComplete > richlistbox > richlistitem:not(:hover, [selected]) > .two-line-wrapper > .ac-secondary-action {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#PopupAutoComplete > richlistbox > richlistitem[originaltype="login"] > .ac-site-icon,
|
||||
#PopupAutoComplete > richlistbox > richlistitem[originaltype="possible-username"] > .ac-site-icon,
|
||||
#PopupAutoComplete > richlistbox > richlistitem > .two-line-wrapper > .ac-site-icon {
|
||||
|
|
|
@ -226,7 +226,7 @@ AutofillProfileAutoCompleteSearch.prototype = {
|
|||
...externalEntries.map(
|
||||
entry =>
|
||||
new GenericAutocompleteItem(
|
||||
entry.image,
|
||||
entry.icon,
|
||||
entry.title,
|
||||
entry.subtitle,
|
||||
entry.fillMessageName,
|
||||
|
|
|
@ -174,7 +174,8 @@ class ProfileAutoCompleteResult {
|
|||
* @returns {string} The image url at the specified index
|
||||
*/
|
||||
getImageAt(index) {
|
||||
return this.getAt(index).image ?? "";
|
||||
this.getAt(index);
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,6 +209,10 @@ class ProfileAutoCompleteResult {
|
|||
}
|
||||
|
||||
export class AddressResult extends ProfileAutoCompleteResult {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
}
|
||||
|
||||
_getSecondaryLabel(focusedFieldName, allFieldNames, profile) {
|
||||
// We group similar fields into the same field name so we won't pick another
|
||||
// field in the same group as the secondary label.
|
||||
|
@ -326,6 +331,15 @@ export class AddressResult extends ProfileAutoCompleteResult {
|
|||
}
|
||||
|
||||
export class CreditCardResult extends ProfileAutoCompleteResult {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this._cardTypes = this._generateCardTypes(
|
||||
this._focusedFieldName,
|
||||
this._allFieldNames,
|
||||
this._matchingProfiles
|
||||
);
|
||||
}
|
||||
|
||||
_getSecondaryLabel(focusedFieldName, allFieldNames, profile) {
|
||||
const GROUP_FIELDS = {
|
||||
"cc-name": [
|
||||
|
@ -363,7 +377,10 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
|
|||
|
||||
if (matching) {
|
||||
if (currentFieldName == "cc-number") {
|
||||
return lazy.CreditCard.formatMaskedNumber(profile[currentFieldName]);
|
||||
let { affix, label } = lazy.CreditCard.formatMaskedNumber(
|
||||
profile[currentFieldName]
|
||||
);
|
||||
return affix + label;
|
||||
}
|
||||
return profile[currentFieldName];
|
||||
}
|
||||
|
@ -398,10 +415,13 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
|
|||
return !!profile[focusedFieldName];
|
||||
})
|
||||
.map(profile => {
|
||||
let primaryAffix;
|
||||
let primary = profile[focusedFieldName];
|
||||
|
||||
if (focusedFieldName == "cc-number") {
|
||||
primary = lazy.CreditCard.formatMaskedNumber(primary);
|
||||
let { affix, label } = lazy.CreditCard.formatMaskedNumber(primary);
|
||||
primaryAffix = affix;
|
||||
primary = label;
|
||||
}
|
||||
const secondary = this._getSecondaryLabel(
|
||||
focusedFieldName,
|
||||
|
@ -412,23 +432,18 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
|
|||
// to expose it as text. We do this using aria-label. However,
|
||||
// aria-label overrides the text content, so we must include that also.
|
||||
const ccType = profile["cc-type"];
|
||||
const image = lazy.CreditCard.getCreditCardLogo(ccType);
|
||||
const ccTypeL10nId = lazy.CreditCard.getNetworkL10nId(ccType);
|
||||
const ccTypeName = ccTypeL10nId
|
||||
? lazy.l10n.formatValueSync(ccTypeL10nId)
|
||||
: ccType ?? ""; // Unknown card type
|
||||
const ariaLabel = [
|
||||
ccTypeName,
|
||||
primary.toString().replaceAll("*", ""),
|
||||
secondary,
|
||||
]
|
||||
const ariaLabel = [ccTypeName, primaryAffix, primary, secondary]
|
||||
.filter(chunk => !!chunk) // Exclude empty chunks.
|
||||
.join(" ");
|
||||
return {
|
||||
primaryAffix,
|
||||
primary,
|
||||
secondary,
|
||||
ariaLabel,
|
||||
image,
|
||||
};
|
||||
});
|
||||
// Add an empty result entry for footer.
|
||||
|
@ -437,6 +452,29 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
|
|||
return labels;
|
||||
}
|
||||
|
||||
// This method needs to return an array that parallels the
|
||||
// array returned by _generateLabels, above. As a consequence,
|
||||
// its logic follows very closely.
|
||||
_generateCardTypes(focusedFieldName, allFieldNames, profiles) {
|
||||
if (this._isInputAutofilled) {
|
||||
return [
|
||||
"", // Clear button
|
||||
"", // Footer
|
||||
];
|
||||
}
|
||||
|
||||
// Skip results without a primary label.
|
||||
let cardTypes = profiles
|
||||
.filter(profile => {
|
||||
return !!profile[focusedFieldName];
|
||||
})
|
||||
.map(profile => profile["cc-type"]);
|
||||
|
||||
// Add an empty result entry for footer.
|
||||
cardTypes.push("");
|
||||
return cardTypes;
|
||||
}
|
||||
|
||||
getStyleAt(index) {
|
||||
const itemStyle = this.getAt(index).style;
|
||||
if (itemStyle) {
|
||||
|
@ -449,4 +487,15 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
|
|||
|
||||
return super.getStyleAt(index);
|
||||
}
|
||||
|
||||
getImageAt(index) {
|
||||
this.getAt(index);
|
||||
|
||||
if (index < this._cardTypes.length) {
|
||||
let network = this._cardTypes[index];
|
||||
return lazy.CreditCard.getCreditCardLogo(network);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -433,7 +433,7 @@ export class FormAutofillSection {
|
|||
// Skip the field if the user has already entered text and that text is not the site prefilled value.
|
||||
continue;
|
||||
}
|
||||
element.previewValue = value?.toString().replaceAll("*", "•");
|
||||
element.previewValue = value;
|
||||
this.handler.changeFieldState(
|
||||
fieldDetail,
|
||||
value ? FIELD_STATES.PREVIEW : FIELD_STATES.NORMAL
|
||||
|
|
|
@ -148,6 +148,7 @@ class LoginAutocompleteItem extends AutocompleteItem {
|
|||
this.value = hasBeenTypePassword ? login.password : login.username;
|
||||
this.comment = JSON.stringify({
|
||||
guid: login.guid,
|
||||
login,
|
||||
isDuplicateUsername,
|
||||
isOriginMatched,
|
||||
comment:
|
||||
|
@ -155,7 +156,6 @@ class LoginAutocompleteItem extends AutocompleteItem {
|
|||
? getLocalizedString("displaySameOrigin")
|
||||
: login.displayOrigin,
|
||||
});
|
||||
this.image = `page-icon:${login.origin}`;
|
||||
}
|
||||
|
||||
removeFromStorage() {
|
||||
|
@ -175,12 +175,13 @@ class GeneratedPasswordAutocompleteItem extends AutocompleteItem {
|
|||
super("generatedPassword");
|
||||
|
||||
this.label = getLocalizedString("useASecurelyGeneratedPassword");
|
||||
|
||||
this.value = generatedPassword;
|
||||
|
||||
this.comment = JSON.stringify({
|
||||
generatedPassword,
|
||||
willAutoSaveGeneratedPassword,
|
||||
});
|
||||
this.image = "chrome://browser/skin/login.svg";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +337,7 @@ export class LoginAutoCompleteResult {
|
|||
...autocompleteItems.map(
|
||||
item =>
|
||||
new GenericAutocompleteItem(
|
||||
item.image,
|
||||
item.icon,
|
||||
item.title,
|
||||
item.subtitle,
|
||||
item.fillMessageName,
|
||||
|
@ -443,7 +444,7 @@ export class LoginAutoCompleteResult {
|
|||
|
||||
getImageAt(index) {
|
||||
this.#throwOnBadIndex(index);
|
||||
return this.#rows[index].image ?? "";
|
||||
return "";
|
||||
}
|
||||
|
||||
getFinalCompleteValueAt(index) {
|
||||
|
|
|
@ -19,14 +19,14 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||
});
|
||||
|
||||
export class ParentAutocompleteOption {
|
||||
image;
|
||||
icon;
|
||||
title;
|
||||
subtitle;
|
||||
fillMessageName;
|
||||
fillMessageData;
|
||||
|
||||
constructor(image, title, subtitle, fillMessageName, fillMessageData) {
|
||||
this.image = image;
|
||||
constructor(icon, title, subtitle, fillMessageName, fillMessageData) {
|
||||
this.icon = icon;
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
this.fillMessageName = fillMessageName;
|
||||
|
|
|
@ -216,7 +216,7 @@ skip-if = [
|
|||
["browser_openPasswordManager.js"]
|
||||
|
||||
["browser_preselect_login.js"]
|
||||
fail-if = ["a11y_checks"] # Bug 1854452 clicked ac-secondary-action may not be labeled
|
||||
fail-if = ["a11y_checks"] # Bug 1854452 clicked ac-settings-button may not be labeled
|
||||
skip-if = [
|
||||
"os == 'linux' && (asan || tsan || debug)", # Bug 1840479
|
||||
"os == 'win' && (asan || debug)", # Bug 1840479
|
||||
|
|
|
@ -99,15 +99,15 @@ add_task(
|
|||
await openACPopup(popup, browser, "#form-basic-username");
|
||||
|
||||
const secondLoginItem = popup.firstChild.getItemAtIndex(1);
|
||||
const secondLoginItemSecondaryAction = secondLoginItem.querySelector(
|
||||
".ac-secondary-action"
|
||||
const secondLoginItemSettingsIcon = secondLoginItem.querySelector(
|
||||
".ac-settings-button"
|
||||
);
|
||||
|
||||
Assert.ok(
|
||||
!secondLoginItemSecondaryAction.checkVisibility({
|
||||
!secondLoginItemSettingsIcon.checkVisibility({
|
||||
checkVisibilityCSS: true,
|
||||
}),
|
||||
"Secondary action should not be visible initially"
|
||||
"Gear icon should not be visible initially"
|
||||
);
|
||||
|
||||
await EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
|
@ -119,10 +119,10 @@ add_task(
|
|||
);
|
||||
|
||||
Assert.ok(
|
||||
secondLoginItemSecondaryAction.checkVisibility({
|
||||
secondLoginItemSettingsIcon.checkVisibility({
|
||||
checkVisibilityCSS: true,
|
||||
}),
|
||||
"Secondary action should be visible when item is active"
|
||||
"Gear icon should be visible when login item is active"
|
||||
);
|
||||
|
||||
const aboutLoginsTabPromise = BrowserTestUtils.waitForNewTab(
|
||||
|
@ -131,7 +131,7 @@ add_task(
|
|||
true
|
||||
);
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(secondLoginItemSecondaryAction, {});
|
||||
EventUtils.synthesizeMouseAtCenter(secondLoginItemSettingsIcon, {});
|
||||
const aboutLoginsTab = await aboutLoginsTabPromise;
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
|
|
|
@ -138,10 +138,11 @@ async function openRelayAC(browser) {
|
|||
await openACPopup(popup, browser, "#form-basic-username");
|
||||
const popupItem = document
|
||||
.querySelector("richlistitem")
|
||||
.getAttribute("ac-value");
|
||||
.getAttribute("ac-label");
|
||||
const popupItemTitle = JSON.parse(popupItem).title;
|
||||
|
||||
Assert.ok(
|
||||
gRelayACOptionsTitles.some(title => title.value === popupItem),
|
||||
gRelayACOptionsTitles.some(title => title.value === popupItemTitle),
|
||||
"AC Popup has an item Relay option shown in popup"
|
||||
);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
// This item shows image, title & subtitle.
|
||||
// This item shows icon, title & subtitle.
|
||||
// Once selected it will send fillMessageName with fillMessageData
|
||||
// to the parent actor and response will be used to fill into the field.
|
||||
export class GenericAutocompleteItem {
|
||||
|
@ -10,9 +10,9 @@ export class GenericAutocompleteItem {
|
|||
style = "generic";
|
||||
value = "";
|
||||
|
||||
constructor(image, title, subtitle, fillMessageName, fillMessageData) {
|
||||
this.image = image;
|
||||
constructor(icon, title, subtitle, fillMessageName, fillMessageData) {
|
||||
this.comment = JSON.stringify({
|
||||
icon,
|
||||
title,
|
||||
subtitle,
|
||||
fillMessageName,
|
||||
|
|
|
@ -569,7 +569,7 @@ export class FormAutoComplete {
|
|||
...externalEntries.map(
|
||||
entry =>
|
||||
new GenericAutocompleteItem(
|
||||
entry.image,
|
||||
entry.icon,
|
||||
entry.title,
|
||||
entry.subtitle,
|
||||
entry.fillMessageName,
|
||||
|
|
|
@ -386,15 +386,6 @@
|
|||
.replace(/^\s+/, "")
|
||||
.replace(/\s+$/, "");
|
||||
|
||||
// Generic items can pack their details as JSON inside label
|
||||
try {
|
||||
const details = JSON.parse(label);
|
||||
if (details.title) {
|
||||
value = details.title;
|
||||
label = details.subtitle ?? "";
|
||||
}
|
||||
} catch {}
|
||||
|
||||
let reusable = false;
|
||||
if (itemExists) {
|
||||
item = this.richlistbox.children[this._currentIndex];
|
||||
|
@ -447,7 +438,7 @@
|
|||
options = { is: "autocomplete-creditcard-insecure-field" };
|
||||
break;
|
||||
case "generic":
|
||||
options = { is: "autocomplete-two-line-richlistitem" };
|
||||
options = { is: "autocomplete-generic-richlistitem" };
|
||||
break;
|
||||
case "importableLearnMore":
|
||||
options = {
|
||||
|
|
|
@ -634,30 +634,15 @@
|
|||
this.textContent = "";
|
||||
this.appendChild(this.constructor.fragment);
|
||||
this.initializeAttributeInheritance();
|
||||
this.initializeSecondaryAction();
|
||||
this._adjustAcItem();
|
||||
}
|
||||
|
||||
initializeSecondaryAction() {
|
||||
const button = this.querySelector(".ac-secondary-action");
|
||||
|
||||
if (this.onSecondaryAction) {
|
||||
button.addEventListener("mousedown", event => {
|
||||
event.stopPropagation();
|
||||
this.onSecondaryAction();
|
||||
});
|
||||
} else {
|
||||
button?.remove();
|
||||
}
|
||||
}
|
||||
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
// getLabelAt:
|
||||
".line1-label": "text=ac-value",
|
||||
// getCommentAt:
|
||||
".line2-label": "text=ac-label",
|
||||
".ac-site-icon": "src=ac-image",
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -671,7 +656,6 @@
|
|||
<div class="label-row line1-label"></div>
|
||||
<div class="label-row line2-label"></div>
|
||||
</div>
|
||||
<button class="ac-secondary-action"></button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
@ -685,17 +669,39 @@
|
|||
handleOverUnderflow() {}
|
||||
}
|
||||
|
||||
class MozAutocompleteGenericRichlistitem extends MozAutocompleteTwoLineRichlistitem {
|
||||
static get inheritedAttributes() {
|
||||
return {};
|
||||
}
|
||||
|
||||
_adjustAcItem() {
|
||||
super._adjustAcItem();
|
||||
|
||||
try {
|
||||
const details = JSON.parse(this.getAttribute("ac-label"));
|
||||
this.querySelector(".ac-site-icon").src = details.icon;
|
||||
this.querySelector(".line1-label").textContent = details.title;
|
||||
this.querySelector(".line2-label").textContent = details.subtitle;
|
||||
} catch {
|
||||
// Update item content only when expected JSON is provided
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MozAutocompleteLoginRichlistitem extends MozAutocompleteTwoLineRichlistitem {
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.firstChild.classList.add("ac-login-item");
|
||||
}
|
||||
|
||||
onSecondaryAction() {
|
||||
const details = JSON.parse(this.getAttribute("ac-label"));
|
||||
LoginHelper.openPasswordManager(window, {
|
||||
loginGuid: details?.guid,
|
||||
});
|
||||
this.querySelector(".ac-settings-button").addEventListener(
|
||||
"mousedown",
|
||||
event => {
|
||||
event.stopPropagation();
|
||||
const details = JSON.parse(this.getAttribute("ac-label"));
|
||||
LoginHelper.openPasswordManager(window, {
|
||||
loginGuid: details?.guid,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
static get inheritedAttributes() {
|
||||
|
@ -703,15 +709,32 @@
|
|||
// getLabelAt:
|
||||
".line1-label": "text=ac-value",
|
||||
// Don't inherit ac-label with getCommentAt since the label is JSON.
|
||||
".ac-site-icon": "src=ac-image",
|
||||
};
|
||||
}
|
||||
|
||||
static get markup() {
|
||||
return `
|
||||
<div xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
class="two-line-wrapper ac-login-item">
|
||||
<xul:image class="ac-site-icon"></xul:image>
|
||||
<div class="labels-wrapper">
|
||||
<div class="label-row line1-label"></div>
|
||||
<div class="label-row line2-label"></div>
|
||||
</div>
|
||||
<button class="ac-settings-button"></button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
_adjustAcItem() {
|
||||
super._adjustAcItem();
|
||||
|
||||
let details = JSON.parse(this.getAttribute("ac-label"));
|
||||
this.querySelector(".line2-label").textContent = details.comment;
|
||||
this.querySelector(
|
||||
".ac-site-icon"
|
||||
).src = `page-icon:${details.login?.origin}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -815,6 +838,14 @@
|
|||
}
|
||||
);
|
||||
|
||||
customElements.define(
|
||||
"autocomplete-generic-richlistitem",
|
||||
MozAutocompleteGenericRichlistitem,
|
||||
{
|
||||
extends: "richlistitem",
|
||||
}
|
||||
);
|
||||
|
||||
customElements.define(
|
||||
"autocomplete-richlistitem-insecure-warning",
|
||||
MozAutocompleteRichlistitemInsecureWarning,
|
||||
|
|
|
@ -454,15 +454,10 @@ export class CreditCard {
|
|||
}
|
||||
|
||||
static formatMaskedNumber(maskedNumber) {
|
||||
return "*".repeat(4) + maskedNumber.substr(-4);
|
||||
}
|
||||
|
||||
static getMaskedNumber(number) {
|
||||
return "*".repeat(4) + " " + number.substr(-4);
|
||||
}
|
||||
|
||||
static getLongMaskedNumber(number) {
|
||||
return "*".repeat(number.length - 4) + number.substr(-4);
|
||||
return {
|
||||
affix: "****",
|
||||
label: maskedNumber.replace(/^\**/, ""),
|
||||
};
|
||||
}
|
||||
|
||||
static getCreditCardLogo(network) {
|
||||
|
@ -492,6 +487,14 @@ export class CreditCard {
|
|||
}
|
||||
}
|
||||
|
||||
static getMaskedNumber(number) {
|
||||
return "*".repeat(4) + " " + number.substr(-4);
|
||||
}
|
||||
|
||||
static getLongMaskedNumber(number) {
|
||||
return "*".repeat(number.length - 4) + number.substr(-4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validates the number according to the Luhn algorithm. This
|
||||
* method does not throw an exception if the number is invalid.
|
||||
|
|
|
@ -122,15 +122,20 @@ add_task(function isValidNumber() {
|
|||
});
|
||||
|
||||
add_task(function test_formatMaskedNumber() {
|
||||
function assertMaskedNumber(input, expected) {
|
||||
const actual = CreditCard.formatMaskedNumber(input);
|
||||
Assert.equal(actual, expected);
|
||||
function testFormat(number) {
|
||||
let format = CreditCard.formatMaskedNumber(number);
|
||||
Assert.equal(format.affix, "****", "Affix should always be four asterisks");
|
||||
Assert.equal(
|
||||
format.label,
|
||||
number.substr(-4),
|
||||
"The label should always be the last four digits of the card number"
|
||||
);
|
||||
}
|
||||
assertMaskedNumber("************0000", "****0000");
|
||||
assertMaskedNumber("************1045", "****1045");
|
||||
assertMaskedNumber("***********6806", "****6806");
|
||||
assertMaskedNumber("**********0495", "****0495");
|
||||
assertMaskedNumber("**********8250", "****8250");
|
||||
testFormat("************0000");
|
||||
testFormat("************1045");
|
||||
testFormat("***********6806");
|
||||
testFormat("**********0495");
|
||||
testFormat("**********8250");
|
||||
});
|
||||
|
||||
add_task(function test_maskNumber() {
|
||||
|
|
|
@ -53,6 +53,7 @@ panel[type="autocomplete-richlistbox"] {
|
|||
max-height: 16px;
|
||||
margin-inline-start: 6px;
|
||||
margin-inline-end: 8px;
|
||||
list-style-image: url("chrome://global/skin/icons/defaultFavicon.svg");
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ panel[type="autocomplete-richlistbox"] {
|
|||
max-height: 16px;
|
||||
margin-inline-start: 6px;
|
||||
margin-inline-end: 8px;
|
||||
list-style-image: url("chrome://global/skin/icons/defaultFavicon.svg");
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ panel[type="autocomplete-richlistbox"] {
|
|||
max-height: 16px;
|
||||
margin-inline-start: 6px;
|
||||
margin-inline-end: 8px;
|
||||
list-style-image: url("chrome://global/skin/icons/defaultFavicon.svg");
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче