Bug 1338420 - Part 2: Apply form history search at startSearch and clean up redundant code. r?MattN draft
authorsteveck-chung <schung@mozilla.com>
Thu, 02 Mar 2017 17:53:32 +0800
changeset 498991 ccfa7c934cce69353512126ddcc281e71a72c39e
parent 498990 a8b6a9839b2fad84d3a6282d06ec10a52d5d55cf
child 549249 b8e4c41e661609c03f1eb126148c4334ee7cc5b4
push id49304
push userbmo:schung@mozilla.com
push dateWed, 15 Mar 2017 09:03:48 +0000
reviewersMattN
bugs1338420
milestone55.0a1
Bug 1338420 - Part 2: Apply form history search at startSearch and clean up redundant code. r?MattN MozReview-Commit-ID: 2ITT2h6pco0
browser/extensions/formautofill/FormAutofillContent.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/test/unit/test_collectFormFields.js
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -86,17 +86,29 @@ AutofillProfileAutoCompleteSearch.protot
    * @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) {
     this.log.debug("startSearch: for", searchString, "with input", formFillController.focusedInput);
     let focusedInput = formFillController.focusedInput;
     this.forceStop = false;
-    let info = this._serializeInfo(FormAutofillContent.getInputDetails(focusedInput));
+    let info = FormAutofillContent.getInputDetails(focusedInput);
+
+    if (!FormAutofillContent.savedFieldNames.has(info.fieldName)) {
+      let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"]
+                          .createInstance(Ci.nsIAutoCompleteSearch);
+      formHistory.startSearch(searchString, searchParam, previousResult, {
+        onSearchResult: (search, result) => {
+          listener.onSearchResult(this, result);
+          ProfileAutocomplete.setProfileAutoCompleteResult(result);
+        },
+      });
+      return;
+    }
 
     this._getProfiles({info, searchString}).then((profiles) => {
       if (this.forceStop) {
         return;
       }
 
       let allFieldNames = FormAutofillContent.getAllFieldNames(focusedInput);
       let result = new ProfileAutoCompleteResult(searchString,
@@ -137,22 +149,16 @@ AutofillProfileAutoCompleteSearch.protot
       Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
         Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
         resolve(result.data);
       });
 
       Services.cpmm.sendAsyncMessage("FormAutofill:GetProfiles", data);
     });
   },
-
-  _serializeInfo(detail) {
-    let info = Object.assign({}, detail);
-    delete info.element;
-    return info;
-  },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AutofillProfileAutoCompleteSearch]);
 
 let ProfileAutocomplete = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   _lastAutoCompleteResult: null,
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -48,62 +48,50 @@ FormAutofillHandler.prototype = {
    * the same exact combination of these values.
    *
    * A direct reference to the associated element cannot be sent to the user
    * interface because processing may be done in the parent process.
    */
   fieldDetails: null,
 
   /**
-   * Returns information from the form about fields that can be autofilled, and
-   * populates the fieldDetails array on this object accordingly.
-   *
-   * @returns {Array<Object>} Serializable data structure that can be sent to the user
-   *          interface, or null if the operation failed because the constraints
-   *          on the allowed fields were not honored.
+   * Set fieldDetails from the form about fields that can be autofilled.
    */
   collectFormFields() {
-    let autofillData = [];
+    this.fieldDetails = [];
 
     for (let element of this.form.elements) {
       // Exclude elements to which no autocomplete field has been assigned.
       let info = FormAutofillHeuristics.getInfo(element);
       if (!info) {
         continue;
       }
 
       // Store the association between the field metadata and the element.
       if (this.fieldDetails.some(f => f.section == info.section &&
                                       f.addressType == info.addressType &&
                                       f.contactType == info.contactType &&
                                       f.fieldName == info.fieldName)) {
         // A field with the same identifier already exists.
         log.debug("Not collecting a field matching another with the same info:", info);
-        return null;
+        continue;
       }
 
-      let inputFormat = {
+      let formatWithElement = {
         section: info.section,
         addressType: info.addressType,
         contactType: info.contactType,
         fieldName: info.fieldName,
+        element, // TODO: Apply Cu.getWeakReference and use get API for strong ref.
       };
-      // Clone the inputFormat for caching the fields and elements together
-      let formatWithElement = Object.assign({}, inputFormat);
 
-      inputFormat.index = autofillData.length;
-      autofillData.push(inputFormat);
-
-      formatWithElement.element = element;
       this.fieldDetails.push(formatWithElement);
     }
 
-    log.debug("Collected details on", autofillData.length, "fields");
-
-    return autofillData;
+    log.debug("Collected details on", this.fieldDetails.length, "fields");
   },
 
   /**
    * Processes form fields that can be autofilled, and populates them with the
    * profile provided by backend.
    *
    * @param {Object} profile
    *        A profile to be filled in.
--- a/browser/extensions/formautofill/test/unit/test_collectFormFields.js
+++ b/browser/extensions/formautofill/test/unit/test_collectFormFields.js
@@ -19,23 +19,16 @@ const TESTCASES = [
     description: "Form with autocomplete properties and 1 token",
     document: `<form><input id="given-name" autocomplete="given-name">
                <input id="family-name" autocomplete="family-name">
                <input id="street-addr" autocomplete="street-address">
                <input id="city" autocomplete="address-level2">
                <input id="country" autocomplete="country">
                <input id="email" autocomplete="email">
                <input id="tel" autocomplete="tel"></form>`,
-    returnedFormat: [
-      {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address", "index": 0},
-      {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2", "index": 1},
-      {"section": "", "addressType": "", "contactType": "", "fieldName": "country", "index": 2},
-      {"section": "", "addressType": "", "contactType": "", "fieldName": "email", "index": 3},
-      {"section": "", "addressType": "", "contactType": "", "fieldName": "tel", "index": 4},
-    ],
     fieldDetails: [
       {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "", "contactType": "", "fieldName": "tel", "element": {}},
     ],
   },
@@ -43,23 +36,16 @@ const TESTCASES = [
     description: "Form with autocomplete properties and 2 tokens",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
                <input id="city" autocomplete="shipping address-level2">
                <input id="country" autocomplete="shipping country">
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    returnedFormat: [
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "index": 0},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "index": 1},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "index": 2},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "index": 3},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "index": 4},
-    ],
     fieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "element": {}},
     ],
   },
@@ -67,23 +53,16 @@ const TESTCASES = [
     description: "Form with autocomplete properties and profile is partly matched",
     document: `<form><input id="given-name" autocomplete="shipping given-name">
                <input id="family-name" autocomplete="shipping family-name">
                <input id="street-addr" autocomplete="shipping street-address">
                <input id="city" autocomplete="shipping address-level2">
                <input id="country" autocomplete="shipping country">
                <input id='email' autocomplete="shipping email">
                <input id="tel" autocomplete="shipping tel"></form>`,
-    returnedFormat: [
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "index": 0},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "index": 1},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "index": 2},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "index": 3},
-      {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "index": 4},
-    ],
     fieldDetails: [
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "street-address", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "address-level2", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "country", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "email", "element": {}},
       {"section": "", "addressType": "shipping", "contactType": "", "fieldName": "tel", "element": {}},
     ],
   },
@@ -95,16 +74,15 @@ for (let tc of TESTCASES) {
     add_task(function* () {
       do_print("Starting testcase: " + testcase.description);
 
       let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
                                                 testcase.document);
       let form = doc.querySelector("form");
       let handler = new FormAutofillHandler(form);
 
-      Assert.deepEqual(handler.collectFormFields(), testcase.returnedFormat,
-                         "Check the format of form autofill were returned correctly");
+      handler.collectFormFields();
 
       Assert.deepEqual(handler.fieldDetails, testcase.fieldDetails,
                          "Check the fieldDetails were set correctly");
     });
   })();
 }