Bug 1300996 - Part 3: Handle the highlight style if the filled fields being changed by user. r=MattN, lchang draft
authorRay Lin <ralin@mozilla.com>
Thu, 18 May 2017 10:11:22 +0800
changeset 591434 bfdab8771859c820704bb7f01d72c7782298a4b6
parent 591433 7394e1e0407829fcc4604d764e8cfd8afc326ef3
child 591435 d220049705df42fee5711971eb9fe1e7bbb83995
push id63058
push userbmo:ralin@mozilla.com
push dateFri, 09 Jun 2017 03:19:03 +0000
reviewersMattN, lchang
bugs1300996
milestone55.0a1
Bug 1300996 - Part 3: Handle the highlight style if the filled fields being changed by user. r=MattN, lchang MozReview-Commit-ID: ITzE1GJ8Yu2
browser/extensions/formautofill/FormAutofillHandler.jsm
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -129,18 +129,67 @@ FormAutofillHandler.prototype = {
             option.selected = true;
             element.dispatchEvent(new Event("input", {"bubbles": true}));
             element.dispatchEvent(new Event("change", {"bubbles": true}));
             this.changeFieldState(fieldDetail, "AUTO_FILLED");
             break;
           }
         }
       }
+
+      // Unlike using setUserInput directly, FormFillController dispatches an
+      // asynchronous "DOMAutoComplete" event with an "input" event follows right
+      // after. So, we need to suppress the first "input" event fired off from
+      // focused input to make sure the latter change handler won't be affected
+      // by auto filling.
+      if (element === focusedInput) {
+        const suppressFirstInputHandler = e => {
+          if (e.isTrusted) {
+            e.stopPropagation();
+            element.removeEventListener("input", suppressFirstInputHandler);
+          }
+        };
+
+        element.addEventListener("input", suppressFirstInputHandler);
+      }
       element.previewValue = "";
     }
+
+    // Handle the highlight style resetting caused by user's correction afterward.
+    log.debug("register change handler for filled form:", this.form);
+    const onChangeHandler = e => {
+      let hasFilledFields;
+
+      if (!e.isTrusted) {
+        return;
+      }
+
+      for (let fieldDetail of this.fieldDetails) {
+        let element = fieldDetail.elementWeakRef.get();
+
+        if (!element) {
+          return;
+        }
+
+        if (e.target == element || (e.target == element.form && e.type == "reset")) {
+          this.changeFieldState(fieldDetail, "NORMAL");
+        }
+
+        hasFilledFields |= (fieldDetail.state == "AUTO_FILLED");
+      }
+
+      // Unregister listeners once no field is in AUTO_FILLED state.
+      if (!hasFilledFields) {
+        this.form.rootElement.removeEventListener("input", onChangeHandler);
+        this.form.rootElement.removeEventListener("reset", onChangeHandler);
+      }
+    };
+
+    this.form.rootElement.addEventListener("input", onChangeHandler);
+    this.form.rootElement.addEventListener("reset", onChangeHandler);
   },
 
   /**
    * Populates result to the preview layers with given profile.
    *
    * @param {Object} profile
    *        A profile to be previewed with
    */