Bug 1429703 - Identify the form fields in "startSearch" again to make sure the form states are up to date. r=lchang draft
authorSean Lee <selee@mozilla.com>
Thu, 11 Jan 2018 17:17:34 +0800
changeset 721395 5d6f2eb7b1cfcc32ac425de0f37d094b024a5064
parent 721208 b2cb61e83ac50115a28f04aaa8a32d4db90aad23
child 746338 ab9d62e3c62aade076ca40a74029480fd4fcd840
push id95841
push userbmo:selee@mozilla.com
push dateWed, 17 Jan 2018 10:01:13 +0000
reviewerslchang
bugs1429703
milestone59.0a1
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
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/content/FormAutofillFrameScript.js
browser/extensions/formautofill/test/mochitest/test_form_changes.html
--- 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();