Bug 1407759 - SELECT element supports some fieldNames only. (e.g. cc-exp*, country, address-level*) r=lchang,ralin draft
authorSean Lee <selee@mozilla.com>
Wed, 11 Oct 2017 17:12:09 +0800
changeset 686021 049df5c5c7653e0b67878d44c2461cf12bce57fd
parent 685608 a124f4901430f6db74cfc7fe3b07957a1c691b40
child 737278 9fa9b3055ce135e4465b895b8098a83f486bdcb5
push id86073
push userbmo:selee@mozilla.com
push dateWed, 25 Oct 2017 09:49:33 +0000
reviewerslchang, ralin
bugs1407759
milestone58.0a1
Bug 1407759 - SELECT element supports some fieldNames only. (e.g. cc-exp*, country, address-level*) r=lchang,ralin MozReview-Commit-ID: KtGO4TseJwH
browser/extensions/formautofill/FormAutofillHeuristics.jsm
browser/extensions/formautofill/test/unit/test_getInfo.js
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -560,16 +560,79 @@ this.FormAutofillHeuristics = {
 
     if (allowDuplicates) {
       return fieldScanner.fieldDetails;
     }
 
     return fieldScanner.trimmedFieldDetail;
   },
 
+  _regExpTableHashValue(...signBits) {
+    return signBits.reduce((p, c, i) => p | !!c << i, 0);
+  },
+
+  _setRegExpListCache(regexps, b0, b1, b2) {
+    if (!this._regexpList) {
+      this._regexpList = [];
+    }
+    this._regexpList[this._regExpTableHashValue(b0, b1, b2)] = regexps;
+  },
+
+  _getRegExpListCache(b0, b1, b2) {
+    if (!this._regexpList) {
+      return null;
+    }
+    return this._regexpList[this._regExpTableHashValue(b0, b1, b2)];
+  },
+
+  _getRegExpList(isAutoCompleteOff, elementTagName) {
+    let isSelectElem = elementTagName == "SELECT";
+    let regExpListCache = this._getRegExpListCache(
+      isAutoCompleteOff,
+      FormAutofillUtils.isAutofillCreditCardsAvailable,
+      isSelectElem
+    );
+    if (regExpListCache) {
+      return regExpListCache;
+    }
+    const FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF = [
+      "cc-name",
+      "cc-number",
+      "cc-exp-month",
+      "cc-exp-year",
+      "cc-exp",
+    ];
+    let regexps = isAutoCompleteOff ? FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF : Object.keys(this.RULES);
+
+    if (!FormAutofillUtils.isAutofillCreditCardsAvailable) {
+      regexps = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
+    }
+
+    if (isSelectElem) {
+      const FIELDNAMES_FOR_SELECT_ELEMENT = [
+        "address-level1",
+        "address-level2",
+        "country",
+        "cc-exp-month",
+        "cc-exp-year",
+        "cc-exp",
+      ];
+      regexps = regexps.filter(name => FIELDNAMES_FOR_SELECT_ELEMENT.includes(name));
+    }
+
+    this._setRegExpListCache(
+      regexps,
+      isAutoCompleteOff,
+      FormAutofillUtils.isAutofillCreditCardsAvailable,
+      isSelectElem
+    );
+
+    return regexps;
+  },
+
   getInfo(element) {
     if (!FormAutofillUtils.isFieldEligibleForAutofill(element)) {
       return null;
     }
 
     let info = element.getAutocompleteInfo();
     // An input[autocomplete="on"] will not be early return here since it stll
     // needs to find the field name.
@@ -593,38 +656,17 @@ this.FormAutofillHeuristics = {
       return {
         fieldName: "email",
         section: "",
         addressType: "",
         contactType: "",
       };
     }
 
-    const FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF = [
-      "cc-name",
-      "cc-number",
-      "cc-exp-month",
-      "cc-exp-year",
-      "cc-exp",
-    ];
-    let regexps = isAutoCompleteOff ? FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF : Object.keys(this.RULES);
-
-    if (!FormAutofillUtils.isAutofillCreditCardsAvailable) {
-      if (isAutoCompleteOff) {
-        if (!this._regexpListOf_CcUnavailable_AcOff) {
-          this._regexpListOf_CcUnavailable_AcOff = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
-        }
-        regexps = this._regexpListOf_CcUnavailable_AcOff;
-      } else {
-        if (!this._regexpListOf_CcUnavailable_AcOn) {
-          this._regexpListOf_CcUnavailable_AcOn = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
-        }
-        regexps = this._regexpListOf_CcUnavailable_AcOn;
-      }
-    }
+    let regexps = this._getRegExpList(isAutoCompleteOff, element.tagName);
     if (regexps.length == 0) {
       return null;
     }
 
     let labelStrings;
     let getElementStrings = {};
     getElementStrings[Symbol.iterator] = function* () {
       yield element.id;
--- a/browser/extensions/formautofill/test/unit/test_getInfo.js
+++ b/browser/extensions/formautofill/test/unit/test_getInfo.js
@@ -250,8 +250,58 @@ TESTCASES.forEach(testcase => {
 
     let element = doc.getElementById(testcase.elementId);
     let value = FormAutofillHeuristics.getInfo(element);
 
     Assert.deepEqual(value, testcase.expectedReturnValue);
     LabelUtils.clearLabelMap();
   });
 });
+
+add_task(async function test_regexp_list() {
+  do_print("Verify the fieldName support for select element.");
+  let SUPPORT_LIST = {
+    "email": null, // email
+    "tel-extension": null, // tel-extension
+    "phone": null, // tel
+    "organization": null, // organization
+    "street-address": null, // street-address
+    "address1": null, // address-line1
+    "address2": null, // address-line2
+    "address3": null, // address-line3
+    "city": "address-level2",
+    "region": "address-level1",
+    "postal-code": null, // postal-code
+    "country": "country",
+    "fullname": null, // name
+    "fname": null, // given-name
+    "mname": null, // additional-name
+    "lname": null, // family-name
+    "cardholder": null, // cc-name
+    "cc-number": null, // cc-number
+    "addmonth": "cc-exp-month",
+    "addyear": "cc-exp-year",
+  };
+  for (let label of Object.keys(SUPPORT_LIST)) {
+    let testcase = {
+      description: `A select element supports ${label} or not`,
+      document: `<select id="${label}"></select>`,
+      elementId: label,
+      expectedReturnValue: (SUPPORT_LIST[label] ? {
+        fieldName: SUPPORT_LIST[label],
+        section: "",
+        addressType: "",
+        contactType: "",
+      } : null),
+    };
+    do_print(testcase.description);
+    do_print(testcase.document);
+    let doc = MockDocument.createTestDocument(
+      "http://localhost:8080/test/", testcase.document);
+
+    let element = doc.getElementById(testcase.elementId);
+    let value = FormAutofillHeuristics.getInfo(element);
+
+    Assert.deepEqual(value, testcase.expectedReturnValue, label);
+  }
+  LabelUtils.clearLabelMap();
+});
+