diff options
Diffstat (limited to 'browser/extensions/formautofill/FormAutofillChild.jsm')
-rw-r--r-- | browser/extensions/formautofill/FormAutofillChild.jsm | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/browser/extensions/formautofill/FormAutofillChild.jsm b/browser/extensions/formautofill/FormAutofillChild.jsm new file mode 100644 index 0000000000..58aa1c4a91 --- /dev/null +++ b/browser/extensions/formautofill/FormAutofillChild.jsm @@ -0,0 +1,198 @@ +/* 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/. */ + +"use strict"; + +var EXPORTED_SYMBOLS = ["FormAutofillChild"]; + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.defineModuleGetter( + this, + "setTimeout", + "resource://gre/modules/Timer.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "FormAutofill", + "resource://formautofill/FormAutofill.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "FormAutofillContent", + "resource://formautofill/FormAutofillContent.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "FormAutofillUtils", + "resource://formautofill/FormAutofillUtils.jsm" +); +ChromeUtils.defineModuleGetter( + this, + "AutoCompleteChild", + "resource://gre/actors/AutoCompleteChild.jsm" +); + +/** + * Handles content's interactions for the frame. + */ +class FormAutofillChild extends JSWindowActorChild { + constructor() { + super(); + + this._nextHandleElement = null; + this._alreadyDOMContentLoaded = false; + this._hasDOMContentLoadedHandler = false; + this._hasPendingTask = false; + this.testListener = null; + + AutoCompleteChild.addPopupStateListener(this); + } + + didDestroy() { + AutoCompleteChild.removePopupStateListener(this); + } + + popupStateChanged(messageName, data, target) { + let docShell; + try { + docShell = this.docShell; + } catch (ex) { + AutoCompleteChild.removePopupStateListener(this); + return; + } + + if (!FormAutofill.isAutofillEnabled) { + return; + } + + const { chromeEventHandler } = docShell; + + switch (messageName) { + case "FormAutoComplete:PopupClosed": { + FormAutofillContent.onPopupClosed(data.selectedRowStyle); + Services.tm.dispatchToMainThread(() => { + chromeEventHandler.removeEventListener( + "keydown", + FormAutofillContent._onKeyDown, + true + ); + }); + + break; + } + case "FormAutoComplete:PopupOpened": { + FormAutofillContent.onPopupOpened(); + chromeEventHandler.addEventListener( + "keydown", + FormAutofillContent._onKeyDown, + true + ); + break; + } + } + } + + _doIdentifyAutofillFields() { + if (this._hasPendingTask) { + return; + } + this._hasPendingTask = true; + + setTimeout(() => { + FormAutofillContent.identifyAutofillFields(this._nextHandleElement); + this._hasPendingTask = false; + this._nextHandleElement = null; + // This is for testing purpose only which sends a notification to indicate that the + // form has been identified, and ready to open popup. + this.sendAsyncMessage("FormAutofill:FieldsIdentified"); + FormAutofillContent.updateActiveInput(); + }); + } + + handleEvent(evt) { + if (!evt.isTrusted) { + return; + } + + switch (evt.type) { + case "focusin": { + if (FormAutofill.isAutofillEnabled) { + this.onFocusIn(evt); + } + break; + } + case "DOMFormBeforeSubmit": { + if (FormAutofill.isAutofillEnabled) { + this.onDOMFormBeforeSubmit(evt); + } + break; + } + + default: { + throw new Error("Unexpected event type"); + } + } + } + + onFocusIn(evt) { + FormAutofillContent.updateActiveInput(); + + let element = evt.target; + if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) { + return; + } + this._nextHandleElement = element; + + if (!this._alreadyDOMContentLoaded) { + let doc = element.ownerDocument; + if (doc.readyState === "loading") { + if (!this._hasDOMContentLoadedHandler) { + this._hasDOMContentLoadedHandler = true; + doc.addEventListener( + "DOMContentLoaded", + () => this._doIdentifyAutofillFields(), + { once: true } + ); + } + return; + } + this._alreadyDOMContentLoaded = true; + } + + this._doIdentifyAutofillFields(); + } + + /** + * Handle the DOMFormBeforeSubmit event. + * @param {Event} evt + */ + onDOMFormBeforeSubmit(evt) { + let formElement = evt.target; + + if (!FormAutofill.isAutofillEnabled) { + return; + } + + FormAutofillContent.formSubmitted(formElement); + } + + receiveMessage(message) { + if (!FormAutofill.isAutofillEnabled) { + return; + } + + const doc = this.document; + + switch (message.name) { + case "FormAutofill:PreviewProfile": { + FormAutofillContent.previewProfile(doc); + break; + } + case "FormAutofill:ClearForm": { + FormAutofillContent.clearForm(); + break; + } + } + } +} |