summaryrefslogtreecommitdiffstats
path: root/toolkit/components/formautofill
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
commitda4c7e7ed675c3bf405668739c3012d140856109 (patch)
treecdd868dba063fecba609a1d819de271f0d51b23e /toolkit/components/formautofill
parentAdding upstream version 125.0.3. (diff)
downloadfirefox-da4c7e7ed675c3bf405668739c3012d140856109.tar.xz
firefox-da4c7e7ed675c3bf405668739c3012d140856109.zip
Adding upstream version 126.0.upstream/126.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/formautofill')
-rw-r--r--toolkit/components/formautofill/AutofillProfileAutoComplete.sys.mjs95
-rw-r--r--toolkit/components/formautofill/FormAutofillChild.sys.mjs94
-rw-r--r--toolkit/components/formautofill/FormAutofillParent.sys.mjs103
-rw-r--r--toolkit/components/formautofill/Helpers.ios.mjs8
-rw-r--r--toolkit/components/formautofill/ProfileAutoCompleteResult.sys.mjs205
-rw-r--r--toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs4
-rw-r--r--toolkit/components/formautofill/default/FormAutofillPrompter.sys.mjs15
-rw-r--r--toolkit/components/formautofill/shared/AddressComponent.sys.mjs3
-rw-r--r--toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs6
-rw-r--r--toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs42
10 files changed, 266 insertions, 309 deletions
diff --git a/toolkit/components/formautofill/AutofillProfileAutoComplete.sys.mjs b/toolkit/components/formautofill/AutofillProfileAutoComplete.sys.mjs
index fc3f0454b0..7594fc8fcf 100644
--- a/toolkit/components/formautofill/AutofillProfileAutoComplete.sys.mjs
+++ b/toolkit/components/formautofill/AutofillProfileAutoComplete.sys.mjs
@@ -6,7 +6,10 @@
* Form Autofill content process module.
*/
-import { GenericAutocompleteItem } from "resource://gre/modules/FillHelpers.sys.mjs";
+import {
+ GenericAutocompleteItem,
+ sendFillRequestToParent,
+} from "resource://gre/modules/FillHelpers.sys.mjs";
/* eslint-disable no-use-before-define */
@@ -31,16 +34,6 @@ const autocompleteController = Cc[
ChromeUtils.defineLazyGetter(
lazy,
- "ADDRESSES_COLLECTION_NAME",
- () => lazy.FormAutofillUtils.ADDRESSES_COLLECTION_NAME
-);
-ChromeUtils.defineLazyGetter(
- lazy,
- "CREDITCARDS_COLLECTION_NAME",
- () => lazy.FormAutofillUtils.CREDITCARDS_COLLECTION_NAME
-);
-ChromeUtils.defineLazyGetter(
- lazy,
"FIELD_STATES",
() => lazy.FormAutofillUtils.FIELD_STATES
);
@@ -191,14 +184,8 @@ AutofillProfileAutoCompleteSearch.prototype = {
isInputAutofilled,
});
} else {
- let infoWithoutElement = { ...activeFieldDetail };
- delete infoWithoutElement.elementWeakRef;
-
- let data = {
- collectionName: isAddressField
- ? lazy.ADDRESSES_COLLECTION_NAME
- : lazy.CREDITCARDS_COLLECTION_NAME,
- info: infoWithoutElement,
+ const data = {
+ fieldName: activeFieldDetail.fieldName,
searchString,
};
@@ -284,12 +271,10 @@ AutofillProfileAutoCompleteSearch.prototype = {
* Input element for autocomplete.
* @param {object} data
* Parameters for querying the corresponding result.
- * @param {string} data.collectionName
- * The name used to specify which collection to retrieve records.
* @param {string} data.searchString
* The typed string for filtering out the matched records.
- * @param {string} data.info
- * The input autocomplete property's information.
+ * @param {string} data.fieldName
+ * The identified field name for the input
* @returns {Promise}
* Promise that resolves when addresses returned from parent process.
*/
@@ -368,44 +353,6 @@ export const ProfileAutocomplete = {
}
},
- fillRequestId: 0,
-
- async sendFillRequestToFormAutofillParent(input, comment) {
- if (!comment) {
- return false;
- }
-
- if (!input || input != autocompleteController?.input.focusedInput) {
- return false;
- }
-
- const { fillMessageName, fillMessageData } = JSON.parse(comment ?? "{}");
- if (!fillMessageName) {
- return false;
- }
-
- this.fillRequestId++;
- const fillRequestId = this.fillRequestId;
- const actor = getActorFromWindow(input.ownerGlobal, "FormAutofill");
- const value = await actor.sendQuery(fillMessageName, fillMessageData ?? {});
-
- // skip fill if another fill operation started during await
- if (fillRequestId != this.fillRequestId) {
- return false;
- }
-
- if (typeof value !== "string") {
- return false;
- }
-
- // If AutoFillParent returned a string to fill, we must do it here because
- // nsAutoCompleteController.cpp already finished it's work before we finished await.
- input.setUserInput(value);
- input.select(value.length, value.length);
-
- return true;
- },
-
_getSelectedIndex(contentWindow) {
let actor = getActorFromWindow(contentWindow, "AutoComplete");
if (!actor) {
@@ -431,18 +378,31 @@ export const ProfileAutocomplete = {
? this.lastProfileAutoCompleteResult.getCommentAt(selectedIndex)
: null;
+ let profile = JSON.parse(comment);
if (
selectedIndex == -1 ||
!this.lastProfileAutoCompleteResult ||
- this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) !=
- "autofill-profile"
+ this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill"
) {
- await this.sendFillRequestToFormAutofillParent(focusedInput, comment);
+ if (
+ focusedInput &&
+ focusedInput == autocompleteController?.input.focusedInput
+ ) {
+ if (profile?.fillMessageName == "FormAutofill:ClearForm") {
+ // The child can do this directly.
+ getActorFromWindow(focusedInput.ownerGlobal)?.clearForm();
+ } else {
+ // Pass focusedInput as both input arguments.
+ await sendFillRequestToParent(
+ "FormAutofill",
+ autocompleteController.input,
+ comment
+ );
+ }
+ }
return;
}
- let profile = JSON.parse(comment);
-
await lazy.FormAutofillContent.activeHandler.autofillFormFields(profile);
},
@@ -468,8 +428,7 @@ export const ProfileAutocomplete = {
if (
!this.lastProfileAutoCompleteResult ||
- this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) !=
- "autofill-profile"
+ this.lastProfileAutoCompleteResult.getStyleAt(selectedIndex) != "autofill"
) {
return;
}
diff --git a/toolkit/components/formautofill/FormAutofillChild.sys.mjs b/toolkit/components/formautofill/FormAutofillChild.sys.mjs
index 8678a7bd45..af84459432 100644
--- a/toolkit/components/formautofill/FormAutofillChild.sys.mjs
+++ b/toolkit/components/formautofill/FormAutofillChild.sys.mjs
@@ -124,33 +124,18 @@ export class FormAutofillChild extends JSWindowActorChild {
lazy.AutoCompleteChild.removePopupStateListener(this);
}
- popupStateChanged(messageName, data, _target) {
- let docShell;
- try {
- docShell = this.docShell;
- } catch (ex) {
- lazy.AutoCompleteChild.removePopupStateListener(this);
- return;
- }
-
+ popupStateChanged(messageName, _data, _target) {
if (!lazy.FormAutofill.isAutofillEnabled) {
return;
}
- const { chromeEventHandler } = docShell;
-
switch (messageName) {
- case "FormAutoComplete:PopupClosed": {
- this.onPopupClosed(data.selectedRowStyle);
- Services.tm.dispatchToMainThread(() => {
- chromeEventHandler.removeEventListener("keydown", this, true);
- });
-
+ case "AutoComplete:PopupClosed": {
+ this.onPopupClosed();
break;
}
- case "FormAutoComplete:PopupOpened": {
+ case "AutoComplete:PopupOpened": {
this.onPopupOpened();
- chromeEventHandler.addEventListener("keydown", this, true);
break;
}
}
@@ -385,10 +370,6 @@ export class FormAutofillChild extends JSWindowActorChild {
}
switch (evt.type) {
- case "keydown": {
- this._onKeyDown(evt);
- break;
- }
case "focusin": {
if (lazy.FormAutofill.isAutofillEnabled) {
this.onFocusIn(evt);
@@ -497,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": {
@@ -677,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;
@@ -688,55 +665,17 @@ export class FormAutofillChild extends JSWindowActorChild {
selectedIndex === -1 ||
!focusedInput ||
!lastAutoCompleteResult ||
- lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill-profile"
+ lastAutoCompleteResult.getStyleAt(selectedIndex) != "autofill"
) {
- this.sendAsyncMessage("FormAutofill:UpdateWarningMessage", {});
-
lazy.ProfileAutocomplete._clearProfilePreview();
} else {
- let focusedInputDetails = this.activeFieldDetail;
- let profile = JSON.parse(
- lastAutoCompleteResult.getCommentAt(selectedIndex)
- );
- let allFieldNames = this.activeSection.allFieldNames;
- let profileFields = allFieldNames.filter(
- fieldName => !!profile[fieldName]
- );
-
- let focusedCategory = lazy.FormAutofillUtils.getCategoryFromFieldName(
- focusedInputDetails.fieldName
- );
- let categories =
- lazy.FormAutofillUtils.getCategoriesFromFieldNames(profileFields);
- this.sendAsyncMessage("FormAutofill:UpdateWarningMessage", {
- focusedCategory,
- categories,
- });
-
lazy.ProfileAutocomplete._previewSelectedProfile(selectedIndex);
}
}
- onPopupClosed(selectedRowStyle) {
+ onPopupClosed() {
this.debug("Popup has closed.");
lazy.ProfileAutocomplete._clearProfilePreview();
-
- let lastAutoCompleteResult =
- lazy.ProfileAutocomplete.lastProfileAutoCompleteResult;
- let focusedInput = this.activeInput;
- if (
- lastAutoCompleteResult &&
- this._keyDownEnterForInput &&
- focusedInput === this._keyDownEnterForInput &&
- focusedInput ===
- lazy.ProfileAutocomplete.lastProfileAutoCompleteFocusedInput
- ) {
- if (selectedRowStyle == "autofill-footer") {
- this.sendAsyncMessage("FormAutofill:OpenPreferences");
- } else if (selectedRowStyle == "autofill-clear-button") {
- this.clearForm();
- }
- }
}
onPopupOpened() {
@@ -764,21 +703,4 @@ export class FormAutofillChild extends JSWindowActorChild {
formFillController.markAsAutofillField(field);
}
-
- _onKeyDown(e) {
- delete this._keyDownEnterForInput;
- let lastAutoCompleteResult =
- lazy.ProfileAutocomplete.lastProfileAutoCompleteResult;
- let focusedInput = this.activeInput;
- if (
- e.keyCode != e.DOM_VK_RETURN ||
- !lastAutoCompleteResult ||
- !focusedInput ||
- focusedInput !=
- lazy.ProfileAutocomplete.lastProfileAutoCompleteFocusedInput
- ) {
- return;
- }
- this._keyDownEnterForInput = focusedInput;
- }
}
diff --git a/toolkit/components/formautofill/FormAutofillParent.sys.mjs b/toolkit/components/formautofill/FormAutofillParent.sys.mjs
index 61c4bd2943..34dac8ce15 100644
--- a/toolkit/components/formautofill/FormAutofillParent.sys.mjs
+++ b/toolkit/components/formautofill/FormAutofillParent.sys.mjs
@@ -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) {
@@ -312,7 +272,7 @@ export class FormAutofillParent extends JSWindowActorParent {
scenarioName: data.scenarioName,
hasInput: !!data.searchString?.length,
});
- const recordsPromise = FormAutofillParent._getRecords(data);
+ const recordsPromise = FormAutofillParent.getRecords(data);
const [records, externalEntries] = await Promise.all([
recordsPromise,
relayPromise,
@@ -448,42 +408,42 @@ export class FormAutofillParent extends JSWindowActorParent {
*
* This is static as a unit test calls this.
*
- * @private
* @param {object} data
- * @param {string} data.collectionName
- * The name used to specify which collection to retrieve records.
* @param {string} data.searchString
* The typed string for filtering out the matched records.
- * @param {string} data.info
- * The input autocomplete property's information.
+ * @param {string} data.collectionName
+ * The name used to specify which collection to retrieve records.
+ * @param {string} data.fieldName
+ * The field name to search. If not specified, return all records in
+ * the collection
*/
- static async _getRecords({ collectionName, searchString, info }) {
- let collection = lazy.gFormAutofillStorage[collectionName];
+ static async getRecords({ searchString, collectionName, fieldName }) {
+ // Derive the collection name from field name if it doesn't exist
+ collectionName ||=
+ FormAutofillUtils.getCollectionNameFromFieldName(fieldName);
+
+ const collection = lazy.gFormAutofillStorage[collectionName];
if (!collection) {
return [];
}
- let recordsInCollection = await collection.getAll();
- if (!info || !info.fieldName || !recordsInCollection.length) {
- return recordsInCollection;
+ const records = await collection.getAll();
+ if (!fieldName || !records.length) {
+ return records;
}
- let isCC = collectionName == CREDITCARDS_COLLECTION_NAME;
// We don't filter "cc-number"
- if (isCC && info.fieldName == "cc-number") {
- recordsInCollection = recordsInCollection.filter(
- record => !!record["cc-number"]
- );
- return recordsInCollection;
+ if (collectionName == CREDITCARDS_COLLECTION_NAME) {
+ if (fieldName == "cc-number") {
+ return records.filter(record => !!record["cc-number"]);
+ }
}
- let records = [];
- let lcSearchString = searchString.toLowerCase();
-
- for (let record of recordsInCollection) {
- let fieldValue = record[info.fieldName];
+ const lcSearchString = searchString.toLowerCase();
+ return records.filter(record => {
+ const fieldValue = record[fieldName];
if (!fieldValue) {
- continue;
+ return false;
}
if (
@@ -493,19 +453,14 @@ export class FormAutofillParent extends JSWindowActorParent {
) {
// Address autofill isn't supported for the record's country so we don't
// want to attempt to potentially incorrectly fill the address fields.
- continue;
- }
-
- if (
- lcSearchString &&
- !String(fieldValue).toLowerCase().startsWith(lcSearchString)
- ) {
- continue;
+ return false;
}
- records.push(record);
- }
- return records;
+ return (
+ !lcSearchString ||
+ String(fieldValue).toLowerCase().startsWith(lcSearchString)
+ );
+ });
}
async _onAddressSubmit(address, browser) {
diff --git a/toolkit/components/formautofill/Helpers.ios.mjs b/toolkit/components/formautofill/Helpers.ios.mjs
index 56bb49f0e9..83137331f1 100644
--- a/toolkit/components/formautofill/Helpers.ios.mjs
+++ b/toolkit/components/formautofill/Helpers.ios.mjs
@@ -45,12 +45,6 @@ HTMLElement.prototype.getAutocompleteInfo = function () {
};
};
-// Bug 1835024. Webkit doesn't support `checkVisibility` API
-// https://drafts.csswg.org/cssom-view-1/#dom-element-checkvisibility
-HTMLElement.prototype.checkVisibility = function (_options) {
- throw new Error(`Not implemented: WebKit doesn't support checkVisibility `);
-};
-
// This function helps us debug better when an error occurs because a certain mock is missing
const withNotImplementedError = obj =>
new Proxy(obj, {
@@ -106,7 +100,7 @@ export const XPCOMUtils = withNotImplementedError({
prop,
pref,
defaultValue = null,
- onUpdate = null,
+ onUpdate,
transform = val => val
) => {
if (!Object.keys(IOSAppConstants.prefs).includes(pref)) {
diff --git a/toolkit/components/formautofill/ProfileAutoCompleteResult.sys.mjs b/toolkit/components/formautofill/ProfileAutoCompleteResult.sys.mjs
index 52ed8bed03..68df30f8b5 100644
--- a/toolkit/components/formautofill/ProfileAutoCompleteResult.sys.mjs
+++ b/toolkit/components/formautofill/ProfileAutoCompleteResult.sys.mjs
@@ -131,6 +131,12 @@ class ProfileAutoCompleteResult {
if (typeof label == "string") {
return label;
}
+
+ let type = this.getTypeOfIndex(index);
+ if (type == "clear" || type == "manage") {
+ return label.primary;
+ }
+
return JSON.stringify(label);
}
@@ -141,6 +147,16 @@ class ProfileAutoCompleteResult {
* @returns {string} The comment at the specified index
*/
getCommentAt(index) {
+ let type = this.getTypeOfIndex(index);
+ switch (type) {
+ case "clear":
+ return '{"fillMessageName": "FormAutofill:ClearForm"}';
+ case "manage":
+ return '{"fillMessageName": "FormAutofill:OpenPreferences"}';
+ case "insecure":
+ return '{"noLearnMore": true }';
+ }
+
const item = this.getAt(index);
return item.comment ?? JSON.stringify(this._matchingProfiles[index]);
}
@@ -157,14 +173,16 @@ class ProfileAutoCompleteResult {
return itemStyle;
}
- if (index == this._popupLabels.length - 1) {
- return "autofill-footer";
- }
- if (this._isInputAutofilled) {
- return "autofill-clear-button";
+ switch (this.getTypeOfIndex(index)) {
+ case "manage":
+ return "action";
+ case "clear":
+ return "action";
+ case "insecure":
+ return "insecureWarning";
+ default:
+ return "autofill";
}
-
- return "autofill-profile";
}
/**
@@ -205,6 +223,24 @@ class ProfileAutoCompleteResult {
removeValueAt(_index) {
// There is no plan to support removing profiles via autocomplete.
}
+
+ /**
+ * Returns a type string that identifies te type of row at the given index.
+ *
+ * @param {number} index The index of the result requested
+ * @returns {string} The type at the specified index
+ */
+ getTypeOfIndex(index) {
+ if (this._isInputAutofilled && index == 0) {
+ return "clear";
+ }
+
+ if (index == this._popupLabels.length - 1) {
+ return "manage";
+ }
+
+ return "item";
+ }
}
export class AddressResult extends ProfileAutoCompleteResult {
@@ -281,18 +317,26 @@ export class AddressResult extends ProfileAutoCompleteResult {
"autofill-manage-addresses-label"
);
+ let footerItem = {
+ primary: manageLabel,
+ secondary: "",
+ };
+
if (this._isInputAutofilled) {
- return [
- { primary: "", secondary: "" }, // Clear button
- // Footer
+ const clearLabel = lazy.l10n.formatValueSync("autofill-clear-form-label");
+
+ let labels = [
{
- primary: "",
- secondary: "",
- manageLabel,
+ primary: clearLabel,
},
];
+ labels.push(footerItem);
+ return labels;
}
+ let focusedCategory =
+ lazy.FormAutofillUtils.getCategoryFromFieldName(focusedFieldName);
+
// Skip results without a primary label.
let labels = profiles
.filter(profile => {
@@ -306,35 +350,88 @@ export class AddressResult extends ProfileAutoCompleteResult {
) {
primaryLabel = profile["-moz-street-address-one-line"];
}
+
+ let profileFields = allFieldNames.filter(
+ fieldName => !!profile[fieldName]
+ );
+
+ let categories =
+ lazy.FormAutofillUtils.getCategoriesFromFieldNames(profileFields);
+ let status = this.getStatusNote(categories, focusedCategory);
+ let secondary = this._getSecondaryLabel(
+ focusedFieldName,
+ allFieldNames,
+ profile
+ );
+ const ariaLabel = [primaryLabel, secondary, status]
+ .filter(chunk => !!chunk) // Exclude empty chunks.
+ .join(" ");
return {
primary: primaryLabel,
- secondary: this._getSecondaryLabel(
- focusedFieldName,
- allFieldNames,
- profile
- ),
+ secondary,
+ status,
+ ariaLabel,
};
});
- const focusedCategory =
- lazy.FormAutofillUtils.getCategoryFromFieldName(focusedFieldName);
+ let allCategories =
+ lazy.FormAutofillUtils.getCategoriesFromFieldNames(allFieldNames);
+
+ if (allCategories && allCategories.length) {
+ let statusItem = {
+ primary: "",
+ secondary: "",
+ status: this.getStatusNote(allCategories, focusedCategory),
+ style: "status",
+ };
+ labels.push(statusItem);
+ }
- // Add an empty result entry for footer. Its content will come from
- // the footer binding, so don't assign any value to it.
- // The additional properties: categories and focusedCategory are required of
- // the popup to generate autofill hint on the footer.
- labels.push({
- primary: "",
- secondary: "",
- manageLabel,
- categories: lazy.FormAutofillUtils.getCategoriesFromFieldNames(
- this._allFieldNames
- ),
- focusedCategory,
- });
+ labels.push(footerItem);
return labels;
}
+
+ getStatusNote(categories, focusedCategory) {
+ if (!categories || !categories.length) {
+ return "";
+ }
+
+ // If the length of categories is 1, that means all the fillable fields are in the same
+ // category. We will change the way to inform user according to this flag. When the value
+ // is true, we show "Also autofills ...", otherwise, show "Autofills ..." only.
+ let hasExtraCategories = categories.length > 1;
+ // Show the categories in certain order to conform with the spec.
+ let orderedCategoryList = [
+ "address",
+ "name",
+ "organization",
+ "tel",
+ "email",
+ ];
+ let showCategories = hasExtraCategories
+ ? orderedCategoryList.filter(
+ category =>
+ categories.includes(category) && category != focusedCategory
+ )
+ : [orderedCategoryList.find(category => category == focusedCategory)];
+
+ let formatter = new Intl.ListFormat(undefined, {
+ style: "narrow",
+ });
+
+ let categoriesText = showCategories.map(category =>
+ lazy.l10n.formatValueSync("autofill-category-" + category)
+ );
+ categoriesText = formatter.format(categoriesText);
+
+ let statusTextTmplKey = hasExtraCategories
+ ? "autofill-phishing-warningmessage-extracategory"
+ : "autofill-phishing-warningmessage";
+ return lazy.l10n.formatValueSync(statusTextTmplKey, {
+ categories: categoriesText,
+ });
+ }
}
export class CreditCardResult extends ProfileAutoCompleteResult {
@@ -401,16 +498,20 @@ export class CreditCardResult extends ProfileAutoCompleteResult {
"autofill-manage-payment-methods-label"
);
+ let footerItem = {
+ primary: manageLabel,
+ };
+
if (this._isInputAutofilled) {
- return [
- { primary: "", secondary: "" }, // Clear button
- // Footer
+ const clearLabel = lazy.l10n.formatValueSync("autofill-clear-form-label");
+
+ let labels = [
{
- primary: "",
- secondary: "",
- manageLabel,
+ primary: clearLabel,
},
];
+ labels.push(footerItem);
+ return labels;
}
// Skip results without a primary label.
@@ -446,37 +547,23 @@ 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,
};
});
- const focusedCategory =
- lazy.FormAutofillUtils.getCategoryFromFieldName(focusedFieldName);
-
- // Add an empty result entry for footer.
- labels.push({
- primary: "",
- secondary: "",
- manageLabel,
- focusedCategory,
- });
+ labels.push(footerItem);
return labels;
}
- getStyleAt(index) {
- const itemStyle = this.getAt(index).style;
- if (itemStyle) {
- return itemStyle;
- }
-
+ getTypeOfIndex(index) {
if (!this._isSecure) {
- return "autofill-insecureWarning";
+ return "insecure";
}
- return super.getStyleAt(index);
+ return super.getTypeOfIndex(index);
}
}
diff --git a/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs b/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs
index 964be31d06..17a50de7eb 100644
--- a/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs
+++ b/toolkit/components/formautofill/android/FormAutofillStorage.sys.mjs
@@ -68,7 +68,7 @@ class Addresses extends AddressesBase {
this._initializePromise = Promise.resolve();
}
- async _saveRecord(record, { sourceSync = false } = {}) {
+ async _saveRecord(record) {
lazy.GeckoViewAutocomplete.onAddressSave(lazy.Address.fromGecko(record));
}
@@ -136,7 +136,7 @@ class CreditCards extends CreditCardsBase {
this._initializePromise = Promise.resolve();
}
- async _saveRecord(record, { sourceSync = false } = {}) {
+ async _saveRecord(record) {
lazy.GeckoViewAutocomplete.onCreditCardSave(
lazy.CreditCard.fromGecko(record)
);
diff --git a/toolkit/components/formautofill/default/FormAutofillPrompter.sys.mjs b/toolkit/components/formautofill/default/FormAutofillPrompter.sys.mjs
index f166716de5..05dcf5bace 100644
--- a/toolkit/components/formautofill/default/FormAutofillPrompter.sys.mjs
+++ b/toolkit/components/formautofill/default/FormAutofillPrompter.sys.mjs
@@ -789,16 +789,15 @@ export class AddressEditDoorhanger extends AutofillDoorhanger {
input.setAttribute("id", inputId);
- const value = this.newRecord[fieldName] ?? "";
if (popup) {
- const menuitem = Array.from(popup.childNodes).find(
- item =>
- item.label.toLowerCase() === value?.toLowerCase() ||
- item.value.toLowerCase() === value?.toLowerCase()
- );
- input.selectedItem = menuitem;
+ input.selectedItem =
+ FormAutofillUtils.findAddressSelectOptionWithMenuPopup(
+ popup,
+ this.newRecord,
+ fieldName
+ );
} else {
- input.value = value;
+ input.value = this.newRecord[fieldName] ?? "";
}
div.appendChild(input);
diff --git a/toolkit/components/formautofill/shared/AddressComponent.sys.mjs b/toolkit/components/formautofill/shared/AddressComponent.sys.mjs
index 40e00b66a0..e83cd22251 100644
--- a/toolkit/components/formautofill/shared/AddressComponent.sys.mjs
+++ b/toolkit/components/formautofill/shared/AddressComponent.sys.mjs
@@ -412,7 +412,6 @@ class State extends AddressField {
const options = {
merge_whitespace: true,
- remove_punctuation: true,
};
this.#state = lazy.FormAutofillUtils.getAbbreviatedSubregionName(
this.normalizeUserValue(options),
@@ -991,7 +990,7 @@ export class AddressComparison {
* country, postal code, etc. The class provides a compare methods
* to compare another AddressComponent against the current instance.
*
- * Note. This class assumes records that pass to it have already been normalized.
+ * Note: This class assumes records that pass to it have already been normalized.
*/
export class AddressComponent {
/**
diff --git a/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs b/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs
index 7bda4c167b..1a5b3014c9 100644
--- a/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs
+++ b/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs
@@ -136,15 +136,15 @@ export class FormAutofillSection {
* specific case. Return the original value in the default case.
* @param {String} value
* The original field value.
- * @param {Object} fieldDetail
+ * @param {Object} _fieldName
* A fieldDetail of the related element.
- * @param {HTMLElement} element
+ * @param {HTMLElement} _element
* A element for checking converting value.
*
* @returns {String}
* A string of the converted value.
*/
- computeFillingValue(value, fieldName, element) {
+ computeFillingValue(value, _fieldName, _element) {
return value;
}
diff --git a/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs b/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs
index e86f14975c..c2b48a53a3 100644
--- a/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs
+++ b/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs
@@ -176,6 +176,12 @@ FormAutofillUtils = {
return Array.from(categories);
},
+ getCollectionNameFromFieldName(fieldName) {
+ return this.isCreditCardField(fieldName)
+ ? CREDITCARDS_COLLECTION_NAME
+ : ADDRESSES_COLLECTION_NAME;
+ },
+
getAddressSeparator() {
// The separator should be based on the L10N address format, and using a
// white space is a temporary solution.
@@ -799,6 +805,42 @@ FormAutofillUtils = {
return null;
},
+ /**
+ * Find the option element from xul menu popups, as used in address capture
+ * doorhanger.
+ *
+ * This is a proxy to `findAddressSelectOption`, which expects HTML select
+ * DOM nodes and operates on options instead of xul menuitems.
+ *
+ * NOTE: This is a temporary solution until Bug 1886949 is landed. This
+ * method will then be removed `findAddressSelectOption` will be used
+ * directly.
+ *
+ * @param {XULPopupElement} menupopup
+ * @param {object} address
+ * @param {string} fieldName
+ * @returns {XULElement}
+ */
+ findAddressSelectOptionWithMenuPopup(menupopup, address, fieldName) {
+ class MenuitemProxy {
+ constructor(menuitem) {
+ this.menuitem = menuitem;
+ }
+ get text() {
+ return this.menuitem.label;
+ }
+ get value() {
+ return this.menuitem.value;
+ }
+ }
+ const selectEl = {
+ options: Array.from(menupopup.childNodes).map(
+ menuitem => new MenuitemProxy(menuitem)
+ ),
+ };
+ return this.findAddressSelectOption(selectEl, address, fieldName)?.menuitem;
+ },
+
findCreditCardSelectOption(selectEl, creditCard, fieldName) {
let oneDigitMonth = creditCard["cc-exp-month"]
? creditCard["cc-exp-month"].toString()