From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../formautofill/shared/FormStateManager.sys.mjs | 157 +++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 toolkit/components/formautofill/shared/FormStateManager.sys.mjs (limited to 'toolkit/components/formautofill/shared/FormStateManager.sys.mjs') diff --git a/toolkit/components/formautofill/shared/FormStateManager.sys.mjs b/toolkit/components/formautofill/shared/FormStateManager.sys.mjs new file mode 100644 index 0000000000..064b4e5356 --- /dev/null +++ b/toolkit/components/formautofill/shared/FormStateManager.sys.mjs @@ -0,0 +1,157 @@ +/* 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/. */ + +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + FormLikeFactory: "resource://gre/modules/FormLikeFactory.sys.mjs", + FormAutofillHandler: + "resource://gre/modules/shared/FormAutofillHandler.sys.mjs", +}); + +export class FormStateManager { + constructor(onSubmit, onAutofillCallback) { + /** + * @type {WeakMap} mapping FormLike root HTML elements to FormAutofillHandler objects. + */ + this._formsDetails = new WeakMap(); + /** + * @type {object} The object where to store the active items, e.g. element, + * handler, section, and field detail. + */ + this._activeItems = {}; + + this.onSubmit = onSubmit; + + this.onAutofillCallback = onAutofillCallback; + } + + /** + * Get the active input's information from cache which is created after page + * identified. + * + * @returns {object | null} + * Return the active input's information that cloned from content cache + * (or return null if the information is not found in the cache). + */ + get activeFieldDetail() { + if (!this._activeItems.fieldDetail) { + let formDetails = this.activeFormDetails; + if (!formDetails) { + return null; + } + for (let detail of formDetails) { + let detailElement = detail.element; + if (detailElement && this.activeInput == detailElement) { + this._activeItems.fieldDetail = detail; + break; + } + } + } + return this._activeItems.fieldDetail; + } + + /** + * Get the active form's information from cache which is created after page + * identified. + * + * @returns {Array | null} + * Return target form's information from content cache + * (or return null if the information is not found in the cache). + * + */ + get activeFormDetails() { + let formHandler = this.activeHandler; + return formHandler ? formHandler.fieldDetails : null; + } + + get activeInput() { + return this._activeItems.elementWeakRef?.deref(); + } + + get activeHandler() { + const activeInput = this.activeInput; + if (!activeInput) { + return null; + } + + // XXX: We are recomputing the activeHandler every time to avoid keeping a + // reference on the active element. This might be called quite frequently + // so if _getFormHandler/findRootForField become more costly, we should + // look into caching this result (eg by adding a weakmap). + let handler = this._getFormHandler(activeInput); + if (handler) { + handler.focusedInput = activeInput; + } + return handler; + } + + get activeSection() { + let formHandler = this.activeHandler; + return formHandler ? formHandler.activeSection : null; + } + + /** + * Get the form's handler from cache which is created after page identified. + * + * @param {HTMLInputElement} element Focused input which triggered profile searching + * @returns {Array | null} + * Return target form's handler from content cache + * (or return null if the information is not found in the cache). + * + */ + _getFormHandler(element) { + if (!element) { + return null; + } + let rootElement = lazy.FormLikeFactory.findRootForField(element); + return this._formsDetails.get(rootElement); + } + + identifyAutofillFields(element) { + let formHandler = this._getFormHandler(element); + if (!formHandler) { + let formLike = lazy.FormLikeFactory.createFromField(element); + formHandler = new lazy.FormAutofillHandler( + formLike, + this.onSubmit, + this.onAutofillCallback + ); + } else if (!formHandler.updateFormIfNeeded(element)) { + return formHandler.fieldDetails; + } + this._formsDetails.set(formHandler.form.rootElement, formHandler); + return formHandler.collectFormFields(); + } + + updateActiveInput(element) { + if (!element) { + this._activeItems = {}; + return; + } + this._activeItems = { + elementWeakRef: new WeakRef(element), + fieldDetail: null, + }; + } + + getRecords(formElement, handler) { + handler = handler || this._formsDetails.get(formElement); + const records = handler?.createRecords(); + + if ( + !handler || + !records || + !Object.values(records).some(typeRecords => typeRecords.length) + ) { + return null; + } + return records; + } + + didDestroy() { + this._activeItems = null; + } +} + +export default FormStateManager; -- cgit v1.2.3