Bug 1404773 - Part 3. (WIP) Implement clear populated form function for form autofill clear button. draft
authorRay Lin <ralin@mozilla.com>
Mon, 16 Oct 2017 13:52:30 +0800
changeset 680704 a45d93f0ff3e1a9af4e0c3eb1a9c194ea7e0ee5a
parent 680703 b7692df86064504f0748eff288ff8a4917ff591a
child 735938 bd3ac66662142dccc0af4d4b4e556296f55f1974
push id84592
push userbmo:ralin@mozilla.com
push dateMon, 16 Oct 2017 05:55:57 +0000
bugs1404773
milestone58.0a1
Bug 1404773 - Part 3. (WIP) Implement clear populated form function for form autofill clear button. MozReview-Commit-ID: 8No9FXWJv0p
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
browser/extensions/formautofill/content/FormAutofillFrameScript.js
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -106,27 +106,23 @@ AutofillProfileAutoCompleteSearch.protot
     let isInputAutofilled = info.state == FIELD_STATES.AUTO_FILLED;
     let handler = FormAutofillContent.getFormHandler(focusedInput);
     let allFieldNames = handler.allFieldNames;
     let filledRecordGUID = isAddressField ? handler.address.filledRecordGUID : handler.creditCard.filledRecordGUID;
     let searchPermitted = isAddressField ?
                           FormAutofillUtils.isAutofillAddressesEnabled :
                           FormAutofillUtils.isAutofillCreditCardsEnabled;
 
-    // TODO: This flag is used to temporarily hide clear form popup before the feature
-    // is done, and it should be removed in Bug 1404773.
-    const clearFormButtonDisabled = true;
-
     // Fallback to form-history if ...
     //   - specified autofill feature is pref off.
     //   - no profile can fill the currently-focused input.
     //   - the current form has already been populated.
     //   - (address only) less than 3 inputs are covered by all saved fields in the storage.
     if (!searchPermitted || !savedFieldNames.has(info.fieldName) ||
-        (!isInputAutofilled | clearFormButtonDisabled && filledRecordGUID) || (isAddressField &&
+        (!isInputAutofilled && filledRecordGUID) || (isAddressField &&
         allFieldNames.filter(field => savedFieldNames.has(field)).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD)) {
       if (focusedInput.autocomplete == "off") {
         // Create a dummy AddressResult as an empty search result.
         let result = new AddressResult("", "", [], [], {});
         listener.onSearchResult(this, result);
         return;
       }
       let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"]
@@ -145,17 +141,17 @@ AutofillProfileAutoCompleteSearch.protot
 
     let data = {
       collectionName: isAddressField ? ADDRESSES_COLLECTION_NAME : CREDITCARDS_COLLECTION_NAME,
       info: infoWithoutElement,
       searchString,
     };
 
     // Show clear form popup if click on filled fields.
-    if (isInputAutofilled && !clearFormButtonDisabled) {
+    if (isInputAutofilled) {
       let result = null;
       result = new ClearFormResult(searchString, info.fieldName, [], [], {});
       listener.onSearchResult(this, result);
       ProfileAutocomplete.setProfileAutoCompleteResult(result);
       return;
     }
 
     this._getRecords(data).then((records) => {
@@ -531,16 +527,28 @@ 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);
+    if (!formHandler) {
+      return;
+    }
+    formHandler.clearPopulatedForm(focusedInput);
+  },
+
   previewProfile(doc) {
     let docWin = doc.ownerGlobal;
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(docWin);
     let lastAutoCompleteResult = ProfileAutocomplete.getProfileAutoCompleteResult();
     let focusedInput = formFillController.focusedInput;
     let mm = this._messageManagerFromWindow(docWin);
 
     if (selectedIndex === -1 ||
@@ -595,13 +603,16 @@ var FormAutofillContent = {
 
     let selectedIndex = ProfileAutocomplete._getSelectedIndex(e.target.ownerGlobal);
     let selectedRowStyle = lastAutoCompleteResult.getStyleAt(selectedIndex);
     if (selectedRowStyle == "autofill-footer") {
       focusedInput.addEventListener("DOMAutoComplete", () => {
         Services.cpmm.sendAsyncMessage("FormAutofill:OpenPreferences");
       }, {once: true});
     }
+    if (selectedRowStyle == "autofill-clear-button") {
+      FormAutofillContent.clearForm();
+    }
   },
 };
 
 
 FormAutofillContent.init();
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -531,16 +531,33 @@ FormAutofillHandler.prototype = {
       if (fieldDetail.state == FIELD_STATES.AUTO_FILLED) {
         continue;
       }
 
       this.changeFieldState(fieldDetail, FIELD_STATES.NORMAL);
     }
   },
 
+  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;
+      }
+
+      if (fieldDetail.state == FIELD_STATES.AUTO_FILLED) {
+        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
    */
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -397,22 +397,22 @@ class ClearFormResult extends ProfileAut
   constructor(...args) {
     super(...args);
 
     this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
   }
 
   _generateLabels() {
     return [
-      {primary: "Clear Form", secondary: ""}, // clear form button
+      "", // clear form button
       {primary: "", secondary: ""}, // more options button
     ];
   }
 
   getStyleAt(index) {
     this._checkIndexBounds(index);
 
     if (index == this.matchCount - 1) {
       return "autofill-footer";
     }
-    return "autofill-profile";
+    return "autofill-clear-button";
   }
 }
--- a/browser/extensions/formautofill/content/FormAutofillFrameScript.js
+++ b/browser/extensions/formautofill/content/FormAutofillFrameScript.js
@@ -37,16 +37,17 @@ var FormAutofillFrameScript = {
       this._hasPendingTask = false;
       this._nextHandleElement = null;
     });
   },
 
   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;
     }
@@ -80,23 +81,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.previewProfile(doc);
         chromeEventHandler.removeEventListener("keydown", FormAutofillContent._onKeyDown,
                                                {capturing: true});
         break;
       }
       case "FormAutoComplete:PopupOpened": {
         chromeEventHandler.addEventListener("keydown", FormAutofillContent._onKeyDown,
                                             {capturing: true});
+        break;
       }
     }
   },
 };
 
 FormAutofillFrameScript.init();