Bug 1300996 - Part 3: Handle the highlight style if the filled fields being changed by user. r=MattN draft
authorRay Lin <ralin@mozilla.com>
Thu, 18 May 2017 10:11:22 +0800
changeset 581025 e9645ff76e7579d269563e0cda9d20f68427618a
parent 581024 0337cbeae0aa268ae130092d7dd442968ca081d4
child 581026 503c94245f011845636de897bdb959c669c5f0ee
push id59751
push userbmo:ralin@mozilla.com
push dateFri, 19 May 2017 07:11:03 +0000
reviewersMattN
bugs1300996
milestone55.0a1
Bug 1300996 - Part 3: Handle the highlight style if the filled fields being changed by user. r=MattN MozReview-Commit-ID: ITzE1GJ8Yu2
browser/extensions/formautofill/FormAutofillHandler.jsm
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -92,39 +92,82 @@ FormAutofillHandler.prototype = {
    * @param {Object} profile
    *        A profile to be filled in.
    * @param {Object} focusedInput
    *        A focused input element which is skipped for filling.
    */
   autofillFormFields(profile, focusedInput) {
     log.debug("profile in autofillFormFields:", profile);
 
+    let pendingFilledPromises = [];
     this.filledProfileGUID = profile.guid;
     for (let fieldDetail of this.fieldDetails) {
       // Avoid filling field value in the following cases:
       // 1. the focused input which is filled in FormFillController.
       // 2. a non-empty input field
       // 3. the invalid value set
 
       let element = fieldDetail.elementWeakRef.get();
       if (!element || element.value) {
         continue;
       }
 
       let value = profile[fieldDetail.fieldName];
       if (value) {
+        pendingFilledPromises.push(new Promise(resolve => {
+          element.addEventListener("input", e => {
+            // Transition state once the field is correctly filled.
+            this.transitionFieldState(fieldDetail, "AUTO_FILLED");
+            resolve();
+          }, {once: true, mozSystemGroup: true});
+        }));
+
         if (element !== focusedInput) {
           element.setUserInput(value);
         }
-
-        this.transitionFieldState(fieldDetail, "AUTO_FILLED");
       }
 
       element.previewValue = "";
     }
+
+    // Since SetUserInput asynchronously dispatches input event, we need to
+    // wait for all fields are auto-filled first and then start handle the
+    // highlight style for user might correct the filled fields afterward.
+    Promise.all(pendingFilledPromises).then(() => {
+      log.debug("register change handler for filled form:", this.form);
+
+      const onChangeHandler = e => {
+        let autofilledCount = 0;
+
+        for (let fieldDetail of this.fieldDetails) {
+          let element = fieldDetail.elementWeakRef.get();
+
+          if (!element) {
+            return;
+          }
+
+          if (e.target === element || e.type === "reset") {
+            this.transitionFieldState(fieldDetail, "NORMAL");
+          }
+
+          if (fieldDetail.state === "AUTO_FILLED") {
+            autofilledCount++;
+          }
+        };
+
+        // Unregister listeners once no fields is in AUTO_FILLED state.
+        if (autofilledCount === 0) {
+          this.form.rootElement.removeEventListener("input", onChangeHandler, {mozSystemGroup: true});
+          this.form.rootElement.removeEventListener("reset", onChangeHandler, {mozSystemGroup: true});
+        }
+      }
+
+      this.form.rootElement.addEventListener("input", onChangeHandler, {mozSystemGroup: true});
+      this.form.rootElement.addEventListener("reset", onChangeHandler, {mozSystemGroup: true});
+    });
   },
 
   /**
    * Populates result to the preview layers with given profile.
    *
    * @param {Object} profile
    *        A profile to be previewed with
    */