Bug 1370429 - Part 5: Add tel-extension support. r=MattN draft
authorSean Lee <selee@mozilla.com>
Wed, 19 Jul 2017 10:18:57 +0800
changeset 613054 3f7d0d117317e4746b444e410c006df991944c38
parent 613053 61506eccd5ef42cdbf9eefcc7e94c24f4d92f4e1
child 613055 0a874d13c65463d4d499e72fe5cb442eb8180c28
child 613057 fdc8cccb9be866f07d6e2b4d2132a77dfcc5c5dd
push id69715
push userbmo:selee@mozilla.com
push dateFri, 21 Jul 2017 14:12:03 +0000
reviewersMattN
bugs1370429
milestone56.0a1
Bug 1370429 - Part 5: Add tel-extension support. r=MattN MozReview-Commit-ID: 7XdiwYWERBC
browser/extensions/formautofill/FormAutofillHeuristics.jsm
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/content/heuristicsRegexp.js
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -176,38 +176,16 @@ class FieldScanner {
     return this.fieldDetails.filter(f => f.fieldName && !f._duplicated);
   }
 }
 
 /**
  * Returns the autocomplete information of fields according to heuristics.
  */
 this.FormAutofillHeuristics = {
-  FIELD_GROUPS: {
-    NAME: [
-      "name",
-      "given-name",
-      "additional-name",
-      "family-name",
-    ],
-    ADDRESS: [
-      "organization",
-      "street-address",
-      "address-line1",
-      "address-line2",
-      "address-line3",
-      "address-level2",
-      "address-level1",
-      "postal-code",
-      "country",
-    ],
-    TEL: ["tel"],
-    EMAIL: ["email"],
-  },
-
   RULES: null,
 
   /**
    * This function tries to match the telephone related fields to the grammar
    * list to see if there is any valid telephone set and correct their
    * field names.
    *
    * @param {Object} fieldScanner
@@ -263,16 +241,22 @@ this.FormAutofillHeuristics = {
       for (let i = ruleFrom; i < ruleTo; i++) {
         fieldScanner.updateFieldName(detailStart, GRAMMARS[i][1]);
         fieldScanner.indexParsing++;
         detailStart++;
         parsedField = true;
       }
     }
 
+    let nextField = fieldScanner.getFieldDetailByIndex(fieldScanner.indexParsing);
+    if (nextField && nextField.fieldName == "tel-extension") {
+      fieldScanner.indexParsing++;
+      parsedField = true;
+    }
+
     return parsedField;
   },
 
   /**
    * This function tries to find the correct address-line[1-3] sequence and
    * correct their field names.
    *
    * @param {Object} fieldScanner
@@ -313,55 +297,16 @@ this.FormAutofillHeuristics = {
       // forward to the next one.
       if (!parsedPhoneFields && !parsedAddressFields) {
         fieldScanner.indexParsing++;
       }
     }
     return fieldScanner.trimmedFieldDetail;
   },
 
-  /**
-   * Get the autocomplete info (e.g. fieldName) determined by the regexp
-   * (this.RULES) matching to a feature string.
-   *
-   * @param {string} string a feature string to be determined.
-   * @returns {Object}
-   *          Provide the predicting result including the field name.
-   *
-   */
-  _matchStringToFieldName(string) {
-    let result = {
-      fieldName: "",
-      section: "",
-      addressType: "",
-      contactType: "",
-    };
-    if (this.RULES.email.test(string)) {
-      result.fieldName = "email";
-      return result;
-    }
-    if (this.RULES.tel.test(string)) {
-      result.fieldName = "tel";
-      return result;
-    }
-    for (let fieldName of this.FIELD_GROUPS.ADDRESS) {
-      if (this.RULES[fieldName].test(string)) {
-        result.fieldName = fieldName;
-        return result;
-      }
-    }
-    for (let fieldName of this.FIELD_GROUPS.NAME) {
-      if (this.RULES[fieldName].test(string)) {
-        result.fieldName = fieldName;
-        return result;
-      }
-    }
-    return null;
-  },
-
   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.
@@ -381,33 +326,42 @@ this.FormAutofillHeuristics = {
       return {
         fieldName: "email",
         section: "",
         addressType: "",
         contactType: "",
       };
     }
 
-    for (let elementString of [element.id, element.name]) {
-      let fieldNameResult = this._matchStringToFieldName(elementString);
-      if (fieldNameResult) {
-        return fieldNameResult;
+    let regexps = Object.keys(this.RULES);
+
+    let labelStrings;
+    let getElementStrings = {};
+    getElementStrings[Symbol.iterator] = function* () {
+      yield element.id;
+      yield element.name;
+      if (!labelStrings) {
+        labelStrings = [];
+        let labels = FormAutofillUtils.findLabelElements(element);
+        for (let label of labels) {
+          labelStrings.push(...FormAutofillUtils.extractLabelStrings(label));
+        }
       }
-    }
-    let labels = FormAutofillUtils.findLabelElements(element);
-    if (!labels || labels.length == 0) {
-      log.debug("No label found for", element);
-      return null;
-    }
-    for (let label of labels) {
-      let strings = FormAutofillUtils.extractLabelStrings(label);
-      for (let string of strings) {
-        let fieldNameResult = this._matchStringToFieldName(string);
-        if (fieldNameResult) {
-          return fieldNameResult;
+      yield *labelStrings;
+    };
+
+    for (let regexp of regexps) {
+      for (let string of getElementStrings) {
+        if (this.RULES[regexp].test(string)) {
+          return {
+            fieldName: regexp,
+            section: "",
+            addressType: "",
+            contactType: "",
+          };
         }
       }
     }
 
     return null;
   },
 
 /**
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -32,16 +32,17 @@ this.FormAutofillUtils = {
     "country-name": "address",
     "tel": "tel",
     "tel-country-code": "tel",
     "tel-national": "tel",
     "tel-area-code": "tel",
     "tel-local": "tel",
     "tel-local-prefix": "tel",
     "tel-local-suffix": "tel",
+    "tel-extension": "tel",
     "email": "email",
     "cc-name": "creditCard",
     "cc-number": "creditCard",
     "cc-exp-month": "creditCard",
     "cc-exp-year": "creditCard",
   },
   _addressDataLoaded: false,
 
--- a/browser/extensions/formautofill/content/heuristicsRegexp.js
+++ b/browser/extensions/formautofill/content/heuristicsRegexp.js
@@ -24,16 +24,21 @@ var HeuristicsRegExp = {
       "|Электронной.?Почты" +                       // ru
       "|邮件|邮箱" +                                // zh-CN
       "|電郵地址" +                                 // zh-TW
       "|(?:이메일|전자.?우편|[Ee]-?mail)(.?주소)?", // ko-KR
       "iu"
     ),
 
     // ==== Telephone ====
+    "tel-extension": new RegExp(
+      "\\bext|ext\\b|extension" +
+      "|ramal",                     // pt-BR, pt-PT
+      "iu"
+    ),
     "tel": new RegExp(
       "phone|mobile|contact.?number" +
       "|telefonnummer" +                             // de-DE
       "|telefono|teléfono" +                         // es
       "|telfixe" +                                   // fr-FR
       "|電話" +                                      // ja-JP
       "|telefone|telemovel" +                        // pt-BR, pt-PT
       "|телефон" +                                   // ru
@@ -150,16 +155,27 @@ var HeuristicsRegExp = {
       "|país|pais" + // es
       "|国" +        // ja-JP
       "|国家" +      // zh-CN
       "|국가|나라",  // ko-KR
       "iu"
     ),
 
     // ==== Name Fields ====
+    "name": new RegExp(
+      "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name" +
+      "|name.*first.*last|firstandlastname" +
+      "|nombre.*y.*apellidos" + // es
+      "|^nom" +                 // fr-FR
+      "|お名前|氏名" +          // ja-JP
+      "|^nome" +                // pt-BR, pt-PT
+      "|姓名" +                 // zh-CN
+      "|성명",                  // ko-KR
+      "iu"
+    ),
     "given-name": new RegExp(
       "first.*name|initials|fname|first$|given.*name" +
       "|vorname" +                // de-DE
       "|nombre" +                 // es
       "|forename|prénom|prenom" + // fr-FR
       "|名" +                     // ja-JP
       "|nome" +                   // pt-BR, pt-PT
       "|Имя" +                    // ru
@@ -181,21 +197,10 @@ var HeuristicsRegExp = {
       "|famille|^nom" +                       // fr-FR
       "|cognome" +                            // it-IT
       "|姓" +                                 // ja-JP
       "|morada|apelidos|surename|sobrenome" + // pt-BR, pt-PT
       "|Фамилия" +                            // ru
       "|\\b성(?:[^명]|\\b)",                  // ko-KR
       "iu"
     ),
-    "name": new RegExp(
-      "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name" +
-      "|name.*first.*last|firstandlastname" +
-      "|nombre.*y.*apellidos" + // es
-      "|^nom" +                 // fr-FR
-      "|お名前|氏名" +          // ja-JP
-      "|^nome" +                // pt-BR, pt-PT
-      "|姓名" +                 // zh-CN
-      "|성명",                  // ko-KR
-      "iu"
-    ),
   },
 };