Bug 1407508 - Part 4. Implement clear populated form function for form autofill clear button. r=lchang, seanlee draft
authorRay Lin <ralin@mozilla.com>
Mon, 16 Oct 2017 13:52:30 +0800
changeset 701013 391e32465b31614063ea5067c1a5e4ad7fca1896
parent 701012 0fbaa60a8f7ae4dd8b9023bdd907ddf4b2ed17e0
child 701014 44e0dc1c9e2a4e9d47d9985c0aeb866e2f1e90b4
push id90027
push userbmo:ralin@mozilla.com
push dateTue, 21 Nov 2017 03:27:05 +0000
reviewerslchang, seanlee
bugs1407508
milestone59.0a1
Bug 1407508 - Part 4. Implement clear populated form function for form autofill clear button. r=lchang, seanlee With this patch, we're able to clear the populated form already. However, we need some ways to invalidate mResults in AutoCompleteController to get new results instead of cached one for clear button once the form has been populated. MozReview-Commit-ID: 8No9FXWJv0p
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/content/FormAutofillFrameScript.js
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -508,16 +508,26 @@ var FormAutofillContent = {
     this._formsDetails.set(formHandler.form.rootElement, formHandler);
     this.log.debug("Adding form handler to _formsDetails:", formHandler);
 
     validDetails.forEach(detail =>
       this._markAsAutofillField(detail.elementWeakRef.get())
     );
   },
 
+  clearForm() {
+    let focusedInput = formFillController.focusedInput || ProfileAutocomplete._lastAutoCompleteFocusedInput;
+    if (!focusedInput) {
+      return;
+    }
+
+    let formHandler = this.getFormHandler(focusedInput);
+    formHandler.clearPopulatedForm(focusedInput);
+  },
+
   previewProfile(doc) {
     let docWin = doc.ownerGlobal;
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(docWin);
     let lastAutoCompleteResult = ProfileAutocomplete.lastProfileAutoCompleteResult;
     let focusedInput = formFillController.focusedInput;
     let mm = this._messageManagerFromWindow(docWin);
 
     if (selectedIndex === -1 ||
@@ -572,18 +582,20 @@ var FormAutofillContent = {
 
     if (e.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_RETURN || !lastAutoCompleteResult ||
         !focusedInput || focusedInput != ProfileAutocomplete.lastProfileAutoCompleteFocusedInput) {
       return;
     }
 
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(e.target.ownerGlobal);
     let selectedRowStyle = lastAutoCompleteResult.getStyleAt(selectedIndex);
-    if (selectedRowStyle == "autofill-footer") {
-      focusedInput.addEventListener("DOMAutoComplete", () => {
+    focusedInput.addEventListener("DOMAutoComplete", () => {
+      if (selectedRowStyle == "autofill-footer") {
         Services.cpmm.sendAsyncMessage("FormAutofill:OpenPreferences");
-      }, {once: true});
-    }
+      } else if (selectedRowStyle == "autofill-clear-button") {
+        FormAutofillContent.clearForm();
+      }
+    }, {once: true});
   },
 };
 
 
 FormAutofillContent.init();
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -489,16 +489,40 @@ class FormAutofillSection {
         continue;
       }
 
       this.changeFieldState(fieldDetail, FIELD_STATES.NORMAL);
     }
   }
 
   /**
+   * Clear value and highlight style of all filled fields.
+   *
+   * @param {Object} focusedInput
+   *        A focused input element for determining credit card or address fields.
+   */
+  clearPopulatedForm(focusedInput) {
+    let fieldDetails = this.getFieldDetailsByElement(focusedInput);
+    for (let fieldDetail of fieldDetails) {
+      let element = fieldDetail.elementWeakRef.get();
+      if (!element) {
+        log.warn(fieldDetail.fieldName, "is unreachable");
+        continue;
+      }
+
+      // Only reset value for input element.
+      if (fieldDetail.state == FIELD_STATES.AUTO_FILLED &&
+          element instanceof Ci.nsIDOMHTMLInputElement) {
+        element.setUserInput("");
+      }
+      this.changeFieldState(fieldDetail, FIELD_STATES.NORMAL);
+    }
+  }
+
+  /**
    * Change the state of a field to correspond with different presentations.
    *
    * @param {Object} fieldDetail
    *        A fieldDetail of which its element is about to update the state.
    * @param {string} nextState
    *        Used to determine the next state
    */
   changeFieldState(fieldDetail, nextState) {
@@ -868,16 +892,21 @@ class FormAutofillHandler {
     section.previewFormFields(profile, focusedInput);
   }
 
   clearPreviewedFormFields(focusedInput) {
     let section = this.getSectionByElement(focusedInput);
     section.clearPreviewedFormFields(focusedInput);
   }
 
+  clearPopulatedForm(focusedInput) {
+    let section = this.getSectionByElement(focusedInput);
+    section.clearPopulatedForm(focusedInput);
+  }
+
   getFilledRecordGUID(focusedInput) {
     let section = this.getSectionByElement(focusedInput);
     return section.getFilledRecordGUID(focusedInput);
   }
 
   getAdaptedProfiles(originalProfiles, focusedInput) {
     let section = this.getSectionByElement(focusedInput);
     section.getAdaptedProfiles(originalProfiles);
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -40,16 +40,17 @@ var FormAutofillFrameScript = {
       // form has been identified, and ready to open popup.
       sendAsyncMessage("FormAutofill:FieldsIdentified");
     });
   },
 
   init() {
     addEventListener("focusin", this);
     addMessageListener("FormAutofill:PreviewProfile", this);
+    addMessageListener("FormAutofill:ClearForm", this);
     addMessageListener("FormAutoComplete:PopupClosed", this);
     addMessageListener("FormAutoComplete:PopupOpened", this);
   },
 
   handleEvent(evt) {
     if (!evt.isTrusted || !FormAutofillUtils.isAutofillEnabled) {
       return;
     }
@@ -83,23 +84,28 @@ var FormAutofillFrameScript = {
     const doc = content.document;
     const {chromeEventHandler} = doc.ownerGlobal.getInterface(Ci.nsIDocShell);
 
     switch (message.name) {
       case "FormAutofill:PreviewProfile": {
         FormAutofillContent.previewProfile(doc);
         break;
       }
+      case "FormAutofill:ClearForm": {
+        FormAutofillContent.clearForm();
+        break;
+      }
       case "FormAutoComplete:PopupClosed": {
         FormAutofillContent.onPopupClosed();
         chromeEventHandler.removeEventListener("keydown", FormAutofillContent._onKeyDown,
                                                {capturing: true});
         break;
       }
       case "FormAutoComplete:PopupOpened": {
         chromeEventHandler.addEventListener("keydown", FormAutofillContent._onKeyDown,
                                             {capturing: true});
+        break;
       }
     }
   },
 };
 
 FormAutofillFrameScript.init();