mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1883549, remove formautofill autocomplete item components and create one based on MozAutocompleteTwoLineRichlistitem, r=credential-management-reviewers,sgalich,geckoview-reviewers,owlish
Differential Revision: https://phabricator.services.mozilla.com/D203612
This commit is contained in:
parent
65ed3e5559
commit
6052b367ff
@ -13,12 +13,6 @@ let ignoreList = [
|
||||
// CodeMirror is imported as-is, see bug 1004423.
|
||||
{ sourceName: /codemirror\.css$/i, isFromDevTools: true },
|
||||
// UA-only media features.
|
||||
{
|
||||
sourceName: /\b(autocomplete-item)\.css$/,
|
||||
errorMessage: /Expected media feature name but found \u2018-moz.*/i,
|
||||
isFromDevTools: false,
|
||||
platforms: ["windows"],
|
||||
},
|
||||
{
|
||||
sourceName:
|
||||
/\b(contenteditable|EditorOverride|svg|forms|html|mathml|ua)\.css$/i,
|
||||
@ -27,7 +21,7 @@ let ignoreList = [
|
||||
},
|
||||
{
|
||||
sourceName:
|
||||
/\b(scrollbars|xul|html|mathml|ua|forms|svg|manageDialog|autocomplete-item-shared|formautofill)\.css$/i,
|
||||
/\b(scrollbars|xul|html|mathml|ua|forms|svg|manageDialog|formautofill)\.css$/i,
|
||||
errorMessage: /Unknown property.*-moz-/i,
|
||||
isFromDevTools: false,
|
||||
},
|
||||
|
@ -48,14 +48,6 @@ function ensureCssLoaded(domWindow) {
|
||||
}
|
||||
|
||||
insertStyleSheet(domWindow, "chrome://formautofill/content/formautofill.css");
|
||||
insertStyleSheet(
|
||||
domWindow,
|
||||
"chrome://formautofill/content/skin/autocomplete-item-shared.css"
|
||||
);
|
||||
insertStyleSheet(
|
||||
domWindow,
|
||||
"chrome://formautofill/content/skin/autocomplete-item.css"
|
||||
);
|
||||
}
|
||||
|
||||
this.formautofill = class extends ExtensionAPI {
|
||||
|
@ -1,157 +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/. */
|
||||
|
||||
// This file is loaded into the browser window scope.
|
||||
/* eslint-env mozilla/browser-window */
|
||||
/* eslint-disable mozilla/balanced-listeners */ // Not relevant since the document gets unloaded.
|
||||
|
||||
"use strict";
|
||||
|
||||
// Wrap in a block to prevent leaking to window scope.
|
||||
(() => {
|
||||
function sendMessageToBrowser(msgName, data) {
|
||||
let { AutoCompleteParent } = ChromeUtils.importESModule(
|
||||
"resource://gre/actors/AutoCompleteParent.sys.mjs"
|
||||
);
|
||||
|
||||
let actor = AutoCompleteParent.getCurrentActor();
|
||||
if (!actor) {
|
||||
return;
|
||||
}
|
||||
|
||||
actor.manager.getActor("FormAutofill").sendAsyncMessage(msgName, data);
|
||||
}
|
||||
|
||||
class MozAutocompleteProfileListitemBase extends MozElements.MozRichlistitem {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* For form autofill, we want to unify the selection no matter by
|
||||
* keyboard navigation or mouseover in order not to confuse user which
|
||||
* profile preview is being shown. This field is set to true to indicate
|
||||
* that selectedIndex of popup should be changed while mouseover item
|
||||
*/
|
||||
this.selectedByMouseOver = true;
|
||||
}
|
||||
|
||||
get _stringBundle() {
|
||||
if (!this.__stringBundle) {
|
||||
this.__stringBundle = Services.strings.createBundle(
|
||||
"chrome://formautofill/locale/formautofill.properties"
|
||||
);
|
||||
}
|
||||
return this.__stringBundle;
|
||||
}
|
||||
|
||||
_cleanup() {
|
||||
this.removeAttribute("formautofillattached");
|
||||
if (this._itemBox) {
|
||||
this._itemBox.removeAttribute("size");
|
||||
}
|
||||
}
|
||||
|
||||
_onOverflow() {}
|
||||
|
||||
_onUnderflow() {}
|
||||
|
||||
handleOverUnderflow() {}
|
||||
|
||||
_adjustAutofillItemLayout() {
|
||||
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 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MozElements.MozAutocompleteProfileListitem = class MozAutocompleteProfileListitem extends (
|
||||
MozAutocompleteProfileListitemBase
|
||||
) {
|
||||
static get markup() {
|
||||
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"></span>
|
||||
</div>
|
||||
<div class="profile-comment-col profile-item-col">
|
||||
<span class="profile-comment"></span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.delayConnectedCallback()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.textContent = "";
|
||||
|
||||
this.appendChild(this.constructor.fragment);
|
||||
|
||||
this._itemBox = this.querySelector(".autofill-item-box");
|
||||
this._label = this.querySelector(".profile-label");
|
||||
this._comment = this.querySelector(".profile-comment");
|
||||
|
||||
this.initializeAttributeInheritance();
|
||||
this._adjustAcItem();
|
||||
}
|
||||
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
".autofill-item-box": "ac-image",
|
||||
};
|
||||
}
|
||||
|
||||
set selected(val) {
|
||||
if (val) {
|
||||
this.setAttribute("selected", "true");
|
||||
} else {
|
||||
this.removeAttribute("selected");
|
||||
}
|
||||
|
||||
sendMessageToBrowser("FormAutofill:PreviewProfile");
|
||||
}
|
||||
|
||||
get selected() {
|
||||
return this.getAttribute("selected") == "true";
|
||||
}
|
||||
|
||||
_adjustAcItem() {
|
||||
this._adjustAutofillItemLayout();
|
||||
this.setAttribute("formautofillattached", "true");
|
||||
this._itemBox.style.setProperty(
|
||||
"--primary-icon",
|
||||
`url(${this.getAttribute("ac-image")})`
|
||||
);
|
||||
|
||||
let { primary, secondary, ariaLabel } = JSON.parse(
|
||||
this.getAttribute("ac-value")
|
||||
);
|
||||
|
||||
this._label.textContent = primary.toString().replaceAll("*", "•");
|
||||
this._comment.textContent = secondary.toString().replaceAll("*", "•");
|
||||
if (ariaLabel) {
|
||||
this.setAttribute("aria-label", ariaLabel);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
customElements.define(
|
||||
"autocomplete-profile-listitem",
|
||||
MozElements.MozAutocompleteProfileListitem,
|
||||
{ extends: "richlistitem" }
|
||||
);
|
||||
})();
|
@ -3,12 +3,12 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#PopupAutoComplete {
|
||||
&[resultstyles~="autofill-profile"] {
|
||||
&[resultstyles~="autofill"] {
|
||||
min-width: 150px !important;
|
||||
}
|
||||
|
||||
> richlistbox > richlistitem {
|
||||
&[originaltype="autofill-profile"] {
|
||||
&[originaltype="autofill"] {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -18,17 +18,14 @@ FINAL_TARGET_FILES.features["formautofill@mozilla.org"] += [
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
||||
FINAL_TARGET_FILES.features["formautofill@mozilla.org"].chrome.content.skin += [
|
||||
"skin/linux/autocomplete-item.css",
|
||||
"skin/linux/editDialog.css",
|
||||
]
|
||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||
FINAL_TARGET_FILES.features["formautofill@mozilla.org"].chrome.content.skin += [
|
||||
"skin/osx/autocomplete-item.css",
|
||||
"skin/osx/editDialog.css",
|
||||
]
|
||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
|
||||
FINAL_TARGET_FILES.features["formautofill@mozilla.org"].chrome.content.skin += [
|
||||
"skin/windows/autocomplete-item.css",
|
||||
"skin/windows/editDialog.css",
|
||||
]
|
||||
|
||||
|
@ -1,10 +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/. */
|
||||
|
||||
@namespace url("http://www.w3.org/1999/xhtml");
|
||||
|
||||
|
||||
.autofill-item-box {
|
||||
--default-font-size: 14.25;
|
||||
}
|
@ -1,9 +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/. */
|
||||
|
||||
@namespace url("http://www.w3.org/1999/xhtml");
|
||||
|
||||
.autofill-item-box {
|
||||
--default-font-size: 11;
|
||||
}
|
@ -1,105 +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/. */
|
||||
|
||||
@namespace url("http://www.w3.org/1999/xhtml");
|
||||
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
|
||||
xul|richlistitem[originaltype="autofill-profile"][selected="true"] > .autofill-item-box {
|
||||
background-color: SelectedItem;
|
||||
color: SelectedItemText;
|
||||
}
|
||||
|
||||
.autofill-item-box {
|
||||
--item-padding-vertical: 7px;
|
||||
--item-padding-horizontal: 10px;
|
||||
--col-spacer: 7px;
|
||||
--item-width: calc(50% - (var(--col-spacer) / 2));
|
||||
--comment-text-color: GreyText;
|
||||
|
||||
--default-font-size: 12;
|
||||
--label-font-size: 12;
|
||||
--comment-font-size: 10;
|
||||
}
|
||||
|
||||
.autofill-item-box[size="small"] {
|
||||
--item-padding-vertical: 7px;
|
||||
--col-spacer: 0px;
|
||||
--row-spacer: 3px;
|
||||
--item-width: 100%;
|
||||
}
|
||||
|
||||
.autofill-item-box:not([ac-image=""]) {
|
||||
--item-padding-vertical: 6.5px;
|
||||
--comment-font-size: 11;
|
||||
}
|
||||
|
||||
.autofill-item-box {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid rgba(38,38,38,.15);
|
||||
padding: var(--item-padding-vertical) 0;
|
||||
padding-inline: var(--item-padding-horizontal);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
background-color: Field;
|
||||
color: FieldText;
|
||||
}
|
||||
|
||||
.autofill-item-box:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.autofill-item-box > .profile-item-col {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
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-inline-end: 5px;
|
||||
float: inline-start;
|
||||
content: "";
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: var(--primary-icon);
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--comment-text-color)
|
||||
}
|
||||
|
||||
.autofill-item-box > .profile-label-col > .profile-label {
|
||||
font-size: calc(var(--label-font-size) / var(--default-font-size) * 1em);
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.autofill-item-box > .profile-comment-col {
|
||||
margin-inline-start: var(--col-spacer);
|
||||
text-align: end;
|
||||
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);
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.autofill-item-box[size="small"] {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.autofill-item-box[size="small"] > .profile-comment-col {
|
||||
margin-top: var(--row-spacer);
|
||||
text-align: start;
|
||||
}
|
@ -1,20 +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/. */
|
||||
|
||||
@namespace url("http://www.w3.org/1999/xhtml");
|
||||
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
.autofill-item-box {
|
||||
--default-font-size: 12;
|
||||
}
|
||||
|
||||
@media (prefers-contrast) {
|
||||
xul|richlistitem[originaltype="autofill-profile"][selected="true"] > .autofill-item-box {
|
||||
background-color: SelectedItem;
|
||||
}
|
||||
|
||||
.autofill-item-box {
|
||||
--comment-text-color: GrayText;
|
||||
}
|
||||
}
|
@ -7,22 +7,6 @@ add_task(async function setup_storage() {
|
||||
await setStorage(TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3);
|
||||
});
|
||||
|
||||
async function reopenPopupWithResizedInput(browser, selector, newSize) {
|
||||
await closePopup(browser);
|
||||
/* eslint no-shadow: ["error", { "allow": ["selector", "newSize"] }] */
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[{ selector, newSize }],
|
||||
async function ({ selector, newSize }) {
|
||||
const input = content.document.querySelector(selector);
|
||||
|
||||
input.style.boxSizing = "border-box";
|
||||
input.style.width = newSize + "px";
|
||||
}
|
||||
);
|
||||
await openPopupOn(browser, selector);
|
||||
}
|
||||
|
||||
add_task(async function test_address_dropdown() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: URL },
|
||||
@ -33,20 +17,6 @@ add_task(async function test_address_dropdown() {
|
||||
|
||||
is(firstItem.getAttribute("ac-image"), "", "Should not show icon");
|
||||
|
||||
// The breakpoint of two-lines layout is 150px
|
||||
await reopenPopupWithResizedInput(browser, focusInput, 140);
|
||||
is(
|
||||
firstItem._itemBox.getAttribute("size"),
|
||||
"small",
|
||||
"Show two-lines layout"
|
||||
);
|
||||
await reopenPopupWithResizedInput(browser, focusInput, 160);
|
||||
is(
|
||||
firstItem._itemBox.hasAttribute("size"),
|
||||
false,
|
||||
"Show one-line layout"
|
||||
);
|
||||
|
||||
await closePopup(browser);
|
||||
}
|
||||
);
|
||||
|
@ -79,7 +79,7 @@ add_task(async function test_credit_card_dropdown_icon_invalid_types_select() {
|
||||
|
||||
const creditCardItems = getDisplayedPopupItems(
|
||||
browser,
|
||||
"[originaltype='autofill-profile']"
|
||||
"[originaltype='autofill']"
|
||||
);
|
||||
|
||||
for (const [index, creditCardItem] of creditCardItems.entries()) {
|
||||
|
@ -55,21 +55,21 @@ add_task(async function test_insecure_form() {
|
||||
urlPath: TEST_URL_PATH,
|
||||
protocol: "https",
|
||||
focusInput: "#organization",
|
||||
expectedType: "autofill-profile",
|
||||
expectedType: "autofill",
|
||||
expectedResultLength: 3, // add one for the status row
|
||||
},
|
||||
{
|
||||
urlPath: TEST_URL_PATH,
|
||||
protocol: "http",
|
||||
focusInput: "#organization",
|
||||
expectedType: "autofill-profile",
|
||||
expectedType: "autofill",
|
||||
expectedResultLength: 3, // add one for the status row
|
||||
},
|
||||
{
|
||||
urlPath: TEST_URL_PATH_CC,
|
||||
protocol: "https",
|
||||
focusInput: "#cc-name",
|
||||
expectedType: "autofill-profile",
|
||||
expectedType: "autofill",
|
||||
expectedResultLength: 3, // no status row here
|
||||
},
|
||||
{
|
||||
|
@ -59,6 +59,11 @@ async function setupFormHistory() {
|
||||
]);
|
||||
}
|
||||
|
||||
function replaceStars(str)
|
||||
{
|
||||
return str.replaceAll("*", "•")
|
||||
}
|
||||
|
||||
initPopupListener();
|
||||
|
||||
// Form with history only.
|
||||
@ -86,7 +91,7 @@ add_task(async function all_saved_fields_less_than_threshold() {
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries([reducedMockRecord].map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `Visa ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -102,8 +107,8 @@ add_task(async function check_menu_when_both_existed() {
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc.ccNumberFmt,
|
||||
secondary: cc["cc-name"],
|
||||
primary: replaceStars(cc.ccNumberFmt),
|
||||
secondary: cc["cc-name"].toString(),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc.ccNumberFmt.replaceAll("*", "")} ${cc["cc-name"]}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -112,8 +117,8 @@ add_task(async function check_menu_when_both_existed() {
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
primary: cc["cc-name"].toString(),
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -122,8 +127,8 @@ add_task(async function check_menu_when_both_existed() {
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-exp-year"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
primary: cc["cc-exp-year"].toString(),
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-year"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -132,8 +137,8 @@ add_task(async function check_menu_when_both_existed() {
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-exp-month"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
primary: cc["cc-exp-month"].toString(),
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-month"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -185,8 +190,8 @@ add_task(async function check_fields_after_form_autofill() {
|
||||
// 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({
|
||||
primary: cc["cc-exp-year"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
primary: cc["cc-exp-year"].toString(),
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-exp-year"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -220,7 +225,7 @@ add_task(async function check_cc_popup_on_field_blank() {
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
@ -240,7 +245,7 @@ add_task(async function check_form_autofill_resume() {
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
|
@ -49,6 +49,11 @@ async function setupFormHistory() {
|
||||
]);
|
||||
}
|
||||
|
||||
function replaceStars(str)
|
||||
{
|
||||
return str.replaceAll("*", "•")
|
||||
}
|
||||
|
||||
initPopupListener();
|
||||
|
||||
// Show Form History popup for non-autocomplete="off" field only
|
||||
@ -73,7 +78,7 @@ add_task(async function check_menu_when_both_with_autocomplete_off() {
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc.ccNumberFmt,
|
||||
primary: replaceStars(cc.ccNumberFmt),
|
||||
secondary: cc["cc-name"],
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc.ccNumberFmt.replaceAll("*", "")} ${cc["cc-name"]}`,
|
||||
image: expected.image,
|
||||
@ -84,7 +89,7 @@ add_task(async function check_menu_when_both_with_autocomplete_off() {
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(({ cc, expected }) => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
secondary: cc.ccNumberFmt,
|
||||
secondary: replaceStars(cc.ccNumberFmt),
|
||||
ariaLabel: `${getCCTypeName(cc)} ${cc["cc-name"]} ${cc.ccNumberFmt}`,
|
||||
image: expected.image,
|
||||
})));
|
||||
|
@ -65,7 +65,7 @@ let addressTestCases = [
|
||||
items: [
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "Sesame Street",
|
||||
@ -76,7 +76,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "Mozilla",
|
||||
@ -101,7 +101,7 @@ let addressTestCases = [
|
||||
items: [
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "1-345-345-3456.",
|
||||
@ -112,7 +112,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "1-650-903-0800",
|
||||
@ -123,7 +123,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[2]),
|
||||
label: JSON.stringify({
|
||||
primary: "1-000-000-0000",
|
||||
@ -148,7 +148,7 @@ let addressTestCases = [
|
||||
items: [
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "123 Sesame Street.",
|
||||
@ -159,7 +159,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "331 E. Evelyn Avenue",
|
||||
@ -170,7 +170,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[2]),
|
||||
label: JSON.stringify({
|
||||
primary: "321, No Name St. 2nd line 3rd line",
|
||||
@ -195,7 +195,7 @@ let addressTestCases = [
|
||||
items: [
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "123 Sesame Street.",
|
||||
@ -206,7 +206,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "331 E. Evelyn Avenue",
|
||||
@ -217,7 +217,7 @@ let addressTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[2]),
|
||||
label: JSON.stringify({
|
||||
primary: "321, No Name St.",
|
||||
@ -298,11 +298,11 @@ let creditCardTestCases = [
|
||||
items: [
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "Timothy Berners-Lee",
|
||||
secondary: "****6785",
|
||||
secondary: "••••6785",
|
||||
ariaLabel: "Visa Timothy Berners-Lee ****6785",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg",
|
||||
}),
|
||||
@ -310,11 +310,11 @@ let creditCardTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "John Doe",
|
||||
secondary: "****1234",
|
||||
secondary: "••••1234",
|
||||
ariaLabel: "American Express John Doe ****1234",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-amex.png",
|
||||
}),
|
||||
@ -336,10 +336,10 @@ let creditCardTestCases = [
|
||||
items: [
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[0]),
|
||||
label: JSON.stringify({
|
||||
primary: "****6785",
|
||||
primary: "••••6785",
|
||||
secondary: "Timothy Berners-Lee",
|
||||
ariaLabel: "Visa 6785 Timothy Berners-Lee",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-visa.svg",
|
||||
@ -348,10 +348,10 @@ let creditCardTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[1]),
|
||||
label: JSON.stringify({
|
||||
primary: "****1234",
|
||||
primary: "••••1234",
|
||||
secondary: "John Doe",
|
||||
ariaLabel: "American Express 1234 John Doe",
|
||||
image: "chrome://formautofill/content/third-party/cc-logo-amex.png",
|
||||
@ -360,10 +360,10 @@ let creditCardTestCases = [
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
style: "autofill-profile",
|
||||
style: "autofill",
|
||||
comment: JSON.stringify(matchingProfiles[2]),
|
||||
label: JSON.stringify({
|
||||
primary: "****5678",
|
||||
primary: "••••5678",
|
||||
secondary: "",
|
||||
ariaLabel: "5678",
|
||||
image: "chrome://formautofill/content/icon-credit-card-generic.svg",
|
||||
|
@ -178,6 +178,13 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&[originaltype="autofill"] > .two-line-wrapper > .ac-site-icon {
|
||||
width: auto;
|
||||
min-height: 16px;
|
||||
max-width: none; /* reset max-width so that credit card icons don't appear stretched */
|
||||
max-height: 16px;
|
||||
}
|
||||
|
||||
/* Insecure field warning */
|
||||
&[originaltype="insecureWarning"] {
|
||||
background-color: var(--arrowpanel-dimmed);
|
||||
|
@ -609,7 +609,7 @@ export const GeckoViewAutocomplete = {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "autofill-profile": {
|
||||
case "autofill": {
|
||||
const comment = JSON.parse(option.comment);
|
||||
debug`delegateSelection ${comment}`;
|
||||
const creditCard = CreditCard.fromGecko(comment);
|
||||
|
@ -247,7 +247,7 @@ export class AutoCompleteParent extends JSWindowActorParent {
|
||||
// the scrollbar in login or form autofill popups.
|
||||
if (
|
||||
resultStyles.size &&
|
||||
(resultStyles.has("autofill-profile") || resultStyles.has("loginsFooter"))
|
||||
(resultStyles.has("autofill") || resultStyles.has("loginsFooter"))
|
||||
) {
|
||||
this.openedPopup._normalMaxRows = this.openedPopup.maxRows;
|
||||
this.openedPopup.mInput.maxRows = 10;
|
||||
|
@ -422,8 +422,7 @@ export const ProfileAutocomplete = {
|
||||
if (
|
||||
selectedIndex == -1 ||
|
||||
!this.lastProfileAutoCompleteResult ||
|
||||
this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) !=
|
||||
"autofill-profile"
|
||||
this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill"
|
||||
) {
|
||||
await this.sendFillRequestToFormAutofillParent(focusedInput, comment);
|
||||
return;
|
||||
@ -456,8 +455,7 @@ export const ProfileAutocomplete = {
|
||||
|
||||
if (
|
||||
!this.lastProfileAutoCompleteResult ||
|
||||
this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) !=
|
||||
"autofill-profile"
|
||||
this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -478,11 +478,9 @@ export class FormAutofillChild extends JSWindowActorChild {
|
||||
return;
|
||||
}
|
||||
|
||||
const doc = this.document;
|
||||
|
||||
switch (message.name) {
|
||||
case "FormAutofill:PreviewProfile": {
|
||||
this.previewProfile(doc);
|
||||
this.previewProfile(message.data.selectedIndex);
|
||||
break;
|
||||
}
|
||||
case "FormAutofill:ClearForm": {
|
||||
@ -658,9 +656,7 @@ export class FormAutofillChild extends JSWindowActorChild {
|
||||
}
|
||||
}
|
||||
|
||||
previewProfile(doc) {
|
||||
let docWin = doc.ownerGlobal;
|
||||
let selectedIndex = lazy.ProfileAutocomplete._getSelectedIndex(docWin);
|
||||
previewProfile(selectedIndex) {
|
||||
let lastAutoCompleteResult =
|
||||
lazy.ProfileAutocomplete.lastProfileAutoCompleteResult;
|
||||
let focusedInput = this.activeInput;
|
||||
@ -669,7 +665,7 @@ export class FormAutofillChild extends JSWindowActorChild {
|
||||
selectedIndex === -1 ||
|
||||
!focusedInput ||
|
||||
!lastAutoCompleteResult ||
|
||||
lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile"
|
||||
lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill"
|
||||
) {
|
||||
lazy.ProfileAutocomplete._clearProfilePreview();
|
||||
} else {
|
||||
|
@ -84,21 +84,6 @@ export let FormAutofillStatus = {
|
||||
Services.prefs.addObserver(ENABLED_AUTOFILL_CREDITCARDS_PREF, this);
|
||||
}
|
||||
|
||||
// We have to use empty window type to get all opened windows here because the
|
||||
// window type parameter may not be available during startup.
|
||||
for (let win of Services.wm.getEnumerator("")) {
|
||||
let { documentElement } = win.document;
|
||||
if (documentElement?.getAttribute("windowtype") == "navigator:browser") {
|
||||
this.injectElements(win.document);
|
||||
} else {
|
||||
// Manually call onOpenWindow for windows that are already opened but not
|
||||
// yet have the window type set. This ensures we inject the elements we need
|
||||
// when its docuemnt is ready.
|
||||
this.onOpenWindow(win);
|
||||
}
|
||||
}
|
||||
Services.wm.addListener(this);
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled("creditcard", true);
|
||||
Services.telemetry.setEventRecordingEnabled("address", true);
|
||||
},
|
||||
@ -198,31 +183,6 @@ export let FormAutofillStatus = {
|
||||
this.updateStatus();
|
||||
},
|
||||
|
||||
injectElements(doc) {
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://formautofill/content/customElements.js",
|
||||
doc.ownerGlobal
|
||||
);
|
||||
},
|
||||
|
||||
onOpenWindow(xulWindow) {
|
||||
const win = xulWindow.docShell.domWindow;
|
||||
win.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
if (
|
||||
win.document.documentElement.getAttribute("windowtype") ==
|
||||
"navigator:browser"
|
||||
) {
|
||||
this.injectElements(win.document);
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
},
|
||||
|
||||
onCloseWindow() {},
|
||||
|
||||
async observe(subject, topic, data) {
|
||||
lazy.log.debug("observe:", topic, "with data:", data);
|
||||
switch (topic) {
|
||||
|
@ -181,7 +181,7 @@ class ProfileAutoCompleteResult {
|
||||
case "insecure":
|
||||
return "insecureWarning";
|
||||
default:
|
||||
return "autofill-profile";
|
||||
return "autofill";
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,8 +541,8 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
|
||||
.filter(chunk => !!chunk) // Exclude empty chunks.
|
||||
.join(" ");
|
||||
return {
|
||||
primary,
|
||||
secondary,
|
||||
primary: primary.toString().replaceAll("*", "•"),
|
||||
secondary: secondary.toString().replaceAll("*", "•"),
|
||||
ariaLabel,
|
||||
image,
|
||||
};
|
||||
|
@ -411,7 +411,7 @@
|
||||
// The styles on the list which have different <content> structure and overrided
|
||||
// _adjustAcItem() are unreusable.
|
||||
const UNREUSEABLE_STYLES = [
|
||||
"autofill-profile",
|
||||
"autofill",
|
||||
"action",
|
||||
"status",
|
||||
"generatedPassword",
|
||||
@ -436,8 +436,8 @@
|
||||
if (!reusable) {
|
||||
let options = null;
|
||||
switch (style) {
|
||||
case "autofill-profile":
|
||||
options = { is: "autocomplete-profile-listitem" };
|
||||
case "autofill":
|
||||
options = { is: "autocomplete-autofill-richlistitem" };
|
||||
break;
|
||||
case "action":
|
||||
options = { is: "autocomplete-action-richlistitem" };
|
||||
|
@ -725,6 +725,11 @@
|
||||
// and, optionally a secondary label, for example:
|
||||
// { "fillMessageName": "Fill:Clear", secondary: "Second Label" }
|
||||
class MozAutocompleteActionRichlistitem extends MozAutocompleteTwoLineRichlistitem {
|
||||
constructor() {
|
||||
super();
|
||||
this.selectedByMouseOver = true;
|
||||
}
|
||||
|
||||
_adjustAcItem() {
|
||||
super._adjustAcItem();
|
||||
|
||||
@ -782,6 +787,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
class MozAutocompleteAutoFillRichlistitem extends MozAutocompleteTwoLineRichlistitem {
|
||||
constructor() {
|
||||
super();
|
||||
this.selectedByMouseOver = true;
|
||||
}
|
||||
|
||||
_adjustAcItem() {
|
||||
let { primary, secondary, ariaLabel } = JSON.parse(
|
||||
this.getAttribute("ac-value")
|
||||
);
|
||||
|
||||
let line1Label = this.querySelector(".line1-label");
|
||||
line1Label.textContent = primary.toString();
|
||||
|
||||
let line2Label = this.querySelector(".line2-label");
|
||||
line2Label.textContent = secondary.toString();
|
||||
|
||||
if (ariaLabel) {
|
||||
this.setAttribute("aria-label", ariaLabel);
|
||||
}
|
||||
|
||||
this.querySelector(".ac-site-icon").collapsed =
|
||||
this.getAttribute("ac-image") == "";
|
||||
}
|
||||
|
||||
set selected(val) {
|
||||
if (val) {
|
||||
this.setAttribute("selected", "true");
|
||||
} else {
|
||||
this.removeAttribute("selected");
|
||||
}
|
||||
|
||||
let { AutoCompleteParent } = ChromeUtils.importESModule(
|
||||
"resource://gre/actors/AutoCompleteParent.sys.mjs"
|
||||
);
|
||||
|
||||
let actor = AutoCompleteParent.getCurrentActor();
|
||||
if (!actor) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedIndex = val ? this.control.getIndexOfItem(this) : -1;
|
||||
actor.manager
|
||||
.getActor("FormAutofill")
|
||||
.sendAsyncMessage("FormAutofill:PreviewProfile", { selectedIndex });
|
||||
}
|
||||
|
||||
get selected() {
|
||||
return this.getAttribute("selected") == "true";
|
||||
}
|
||||
}
|
||||
|
||||
class MozAutocompleteGeneratedPasswordRichlistitem extends MozAutocompleteTwoLineRichlistitem {
|
||||
constructor() {
|
||||
super();
|
||||
@ -906,6 +963,14 @@
|
||||
}
|
||||
);
|
||||
|
||||
customElements.define(
|
||||
"autocomplete-autofill-richlistitem",
|
||||
MozAutocompleteAutoFillRichlistitem,
|
||||
{
|
||||
extends: "richlistitem",
|
||||
}
|
||||
);
|
||||
|
||||
customElements.define(
|
||||
"autocomplete-login-richlistitem",
|
||||
MozAutocompleteLoginRichlistitem,
|
||||
|
Loading…
Reference in New Issue
Block a user