Bug 1429703 - Identify the form fields in "startSearch" again to make sure the form states are up to date. r=lchang
MozReview-Commit-ID: 3pO8pCtDfcE
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -90,16 +90,19 @@ AutofillProfileAutoCompleteSearch.protot
* or asynchronously) of the result
*
* @param {string} searchString the string to search for
* @param {string} searchParam
* @param {Object} previousResult a previous result to use for faster searchinig
* @param {Object} listener the listener to notify when the search is complete
*/
startSearch(searchString, searchParam, previousResult, listener) {
+ if (FormAutofillContent.identifyAutofillFields(formFillController.focusedInput)) {
+ FormAutofillContent.updateActiveInput();
+ }
let {activeInput, activeSection, activeFieldDetail, savedFieldNames} = FormAutofillContent;
this.forceStop = false;
this.log.debug("startSearch: for", searchString, "with input", activeInput);
let isAddressField = FormAutofillUtils.isAddressField(activeFieldDetail.fieldName);
let isInputAutofilled = activeFieldDetail.state == FIELD_STATES.AUTO_FILLED;
let allFieldNames = activeSection.allFieldNames;
@@ -473,31 +476,35 @@ var FormAutofillContent = {
* handler, section, and field detail, can be retrieved by their own getters.
*
* @param {HTMLElement|null} element The active item should be updated based
* on this or `formFillController.focusedInput` will be taken.
*/
updateActiveInput(element) {
element = element || formFillController.focusedInput;
if (!element) {
- this._activeItems = {};
+ this.invalidateActiveInput();
return;
}
let handler = this._getFormHandler(element);
if (handler) {
handler.focusedInput = element;
}
this._activeItems = {
handler,
elementWeakRef: Cu.getWeakReference(element),
section: handler ? handler.activeSection : null,
fieldDetail: null,
};
},
+ invalidateActiveInput() {
+ this._activeItems = {};
+ },
+
get activeInput() {
let elementWeakRef = this._activeItems.elementWeakRef;
return elementWeakRef ? elementWeakRef.get() : null;
},
get activeHandler() {
return this._activeItems.handler;
},
@@ -526,41 +533,54 @@ var FormAutofillContent = {
this._activeItems.fieldDetail = detail;
break;
}
}
}
return this._activeItems.fieldDetail;
},
+ /**
+ * Give an element and all fields in the related form (or FormLike) will be
+ * recorded in FormAutofillSection objects for filling and other purpose.
+ *
+ * @param {HTMLElement} element
+ * A element for identifying the possible form fields in its form.
+ *
+ * @returns {boolean}
+ * True if the section objects are all new created, otherwise false.
+ */
identifyAutofillFields(element) {
this.log.debug("identifyAutofillFields:", "" + element.ownerDocument.location);
if (!this.savedFieldNames) {
this.log.debug("identifyAutofillFields: savedFieldNames are not known yet");
Services.cpmm.sendAsyncMessage("FormAutofill:InitStorage");
}
let formHandler = this._getFormHandler(element);
if (!formHandler) {
let formLike = FormLikeFactory.createFromField(element);
formHandler = new FormAutofillHandler(formLike);
} else if (!formHandler.updateFormIfNeeded(element)) {
this.log.debug("No control is removed or inserted since last collection.");
- return;
+ return false;
}
let validDetails = formHandler.collectFormFields();
this._formsDetails.set(formHandler.form.rootElement, formHandler);
this.log.debug("Adding form handler to _formsDetails:", formHandler);
validDetails.forEach(detail =>
this._markAsAutofillField(detail.elementWeakRef.get())
);
+
+ this.invalidateActiveInput();
+ return true;
},
clearForm() {
let focusedInput = this.activeInput || ProfileAutocomplete._lastAutoCompleteFocusedInput;
if (!focusedInput) {
return;
}
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -28,23 +28,24 @@ var FormAutofillFrameScript = {
_doIdentifyAutofillFields() {
if (this._hasPendingTask) {
return;
}
this._hasPendingTask = true;
setTimeout(() => {
- FormAutofillContent.identifyAutofillFields(this._nextHandleElement);
+ if (FormAutofillContent.identifyAutofillFields(this._nextHandleElement)) {
+ FormAutofillContent.updateActiveInput();
+ }
this._hasPendingTask = false;
this._nextHandleElement = null;
// This is for testing purpose only which sends a message to indicate that the
// form has been identified, and ready to open popup.
sendAsyncMessage("FormAutofill:FieldsIdentified");
- FormAutofillContent.updateActiveInput();
});
},
init() {
addEventListener("focusin", this);
addMessageListener("FormAutofill:PreviewProfile", this);
addMessageListener("FormAutofill:ClearForm", this);
addMessageListener("FormAutoComplete:PopupClosed", this);
--- a/browser/extensions/formautofill/test/mochitest/test_form_changes.html
+++ b/browser/extensions/formautofill/test/mochitest/test_form_changes.html
@@ -51,19 +51,19 @@ async function checkFormChangeHappened(f
await focusAndWaitForFieldsIdentified(`#${formId} input[name=tel]`);
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.tel, secondary: address.name})
));
// This is for checking the changes of element count.
+ await focusAndWaitForFieldsIdentified(`#${formId} input[name=name]`, true);
addInputField(document.querySelector(`#${formId}`), "address-level2");
- await focusAndWaitForFieldsIdentified(`#${formId} input[name=name]`);
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.name, secondary: address["address-level2"]})
));
// This is for checking the changes of element removed and added then.
document.querySelector(`#${formId} input[name=address-level2]`).remove();