diff options
Diffstat (limited to 'browser/extensions/formautofill/content/FormAutofillContent.jsm')
-rw-r--r-- | browser/extensions/formautofill/content/FormAutofillContent.jsm | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/browser/extensions/formautofill/content/FormAutofillContent.jsm b/browser/extensions/formautofill/content/FormAutofillContent.jsm new file mode 100644 index 000000000..bde397580 --- /dev/null +++ b/browser/extensions/formautofill/content/FormAutofillContent.jsm @@ -0,0 +1,134 @@ +/* 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/. */ + +/* + * Implements a service used by DOM content to request Form Autofill. + */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +/** + * Handles profile autofill for a DOM Form element. + * @param {HTMLFormElement} form Form that need to be auto filled + */ +function FormAutofillHandler(form) { + this.form = form; + this.fieldDetails = []; +} + +FormAutofillHandler.prototype = { + /** + * DOM Form element to which this object is attached. + */ + form: null, + + /** + * Array of collected data about relevant form fields. Each item is an object + * storing the identifying details of the field and a reference to the + * originally associated element from the form. + * + * The "section", "addressType", "contactType", and "fieldName" values are + * used to identify the exact field when the serializable data is received + * from the backend. There cannot be multiple fields which have + * the same exact combination of these values. + * + * A direct reference to the associated element cannot be sent to the user + * interface because processing may be done in the parent process. + */ + fieldDetails: null, + + /** + * Returns information from the form about fields that can be autofilled, and + * populates the fieldDetails array on this object accordingly. + * + * @returns {Array<Object>} Serializable data structure that can be sent to the user + * interface, or null if the operation failed because the constraints + * on the allowed fields were not honored. + */ + collectFormFields() { + let autofillData = []; + + for (let element of this.form.elements) { + // Query the interface and exclude elements that cannot be autocompleted. + if (!(element instanceof Ci.nsIDOMHTMLInputElement)) { + continue; + } + + // Exclude elements to which no autocomplete field has been assigned. + let info = element.getAutocompleteInfo(); + if (!info.fieldName || ["on", "off"].includes(info.fieldName)) { + continue; + } + + // Store the association between the field metadata and the element. + if (this.fieldDetails.some(f => f.section == info.section && + f.addressType == info.addressType && + f.contactType == info.contactType && + f.fieldName == info.fieldName)) { + // A field with the same identifier already exists. + return null; + } + + let inputFormat = { + section: info.section, + addressType: info.addressType, + contactType: info.contactType, + fieldName: info.fieldName, + }; + // Clone the inputFormat for caching the fields and elements together + let formatWithElement = Object.assign({}, inputFormat); + + inputFormat.index = autofillData.length; + autofillData.push(inputFormat); + + formatWithElement.element = element; + this.fieldDetails.push(formatWithElement); + } + + return autofillData; + }, + + /** + * Processes form fields that can be autofilled, and populates them with the + * data provided by backend. + * + * @param {Array<Object>} autofillResult + * Data returned by the user interface. + * [{ + * section: Value originally provided to the user interface. + * addressType: Value originally provided to the user interface. + * contactType: Value originally provided to the user interface. + * fieldName: Value originally provided to the user interface. + * value: String with which the field should be updated. + * index: Index to match the input in fieldDetails + * }], + * } + */ + autofillFormFields(autofillResult) { + for (let field of autofillResult) { + // Get the field details, if it was processed by the user interface. + let fieldDetail = this.fieldDetails[field.index]; + + // Avoid the invalid value set + if (!fieldDetail || !field.value) { + continue; + } + + let info = fieldDetail.element.getAutocompleteInfo(); + if (field.section != info.section || + field.addressType != info.addressType || + field.contactType != info.contactType || + field.fieldName != info.fieldName) { + Cu.reportError("Autocomplete tokens mismatched"); + continue; + } + + fieldDetail.element.setUserInput(field.value); + } + }, +}; + +this.EXPORTED_SYMBOLS = ["FormAutofillHandler"]; |