Bug 1370429 - Part 4: Implement grammar list matching algorithm for telephone fields. r=MattN draft
authorSean Lee <selee@mozilla.com>
Wed, 19 Jul 2017 10:18:06 +0800
changeset 613053 61506eccd5ef42cdbf9eefcc7e94c24f4d92f4e1
parent 613052 6eeda223a01a1d903143bdb2c3ea643d8eadff2d
child 613054 3f7d0d117317e4746b444e410c006df991944c38
push id69715
push userbmo:selee@mozilla.com
push dateFri, 21 Jul 2017 14:12:03 +0000
reviewersMattN
bugs1370429
milestone56.0a1
Bug 1370429 - Part 4: Implement grammar list matching algorithm for telephone fields. r=MattN MozReview-Commit-ID: K81o3XSqxKO
browser/extensions/formautofill/FormAutofillHeuristics.jsm
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -201,16 +201,82 @@ this.FormAutofillHeuristics = {
     ],
     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
+   *        The current parsing status for all elements
+   * @returns {boolean}
+   *          Return true if there is any field can be recognized in the parser,
+   *          otherwise false.
+   */
+  _parsePhoneFields(fieldScanner) {
+    let matchingResult;
+
+    const GRAMMARS = this.PHONE_FIELD_GRAMMARS;
+    for (let i = 0; i < GRAMMARS.length; i++) {
+      let detailStart = fieldScanner.indexParsing;
+      let ruleStart = i;
+      for (; i < GRAMMARS.length && GRAMMARS[i][0]; i++, detailStart++) {
+        let detail = fieldScanner.getFieldDetailByIndex(detailStart);
+        if (!detail || GRAMMARS[i][0] != detail.fieldName) {
+          break;
+        }
+        let element = detail.elementWeakRef.get();
+        if (!element) {
+          break;
+        }
+        if (GRAMMARS[i][2] && (!element.maxLength || GRAMMARS[i][2] < element.maxLength)) {
+          break;
+        }
+      }
+      if (i >= GRAMMARS.length) {
+        break;
+      }
+
+      if (!GRAMMARS[i][0]) {
+        matchingResult = {
+          ruleFrom: ruleStart,
+          ruleTo: i,
+        };
+        break;
+      }
+
+      // Fast rewinding to the next rule.
+      for (; i < GRAMMARS.length; i++) {
+        if (!GRAMMARS[i][0]) {
+          break;
+        }
+      }
+    }
+
+    let parsedField = false;
+    if (matchingResult) {
+      let {ruleFrom, ruleTo} = matchingResult;
+      let detailStart = fieldScanner.indexParsing;
+      for (let i = ruleFrom; i < ruleTo; i++) {
+        fieldScanner.updateFieldName(detailStart, GRAMMARS[i][1]);
+        fieldScanner.indexParsing++;
+        detailStart++;
+        parsedField = true;
+      }
+    }
+
+    return parsedField;
+  },
+
+  /**
    * This function tries to find the correct address-line[1-3] sequence and
    * correct their field names.
    *
    * @param {Object} fieldScanner
    *        The current parsing status for all elements
    * @returns {boolean}
    *          Return true if there is any field can be recognized in the parser,
    *          otherwise false.
@@ -235,21 +301,22 @@ this.FormAutofillHeuristics = {
 
   getFormInfo(form) {
     if (form.autocomplete == "off" || form.elements.length <= 0) {
       return [];
     }
 
     let fieldScanner = new FieldScanner(form.elements);
     while (!fieldScanner.parsingFinished) {
+      let parsedPhoneFields = this._parsePhoneFields(fieldScanner);
       let parsedAddressFields = this._parseAddressFields(fieldScanner);
 
       // If there is no any field parsed, the parsing cursor can be moved
       // forward to the next one.
-      if (!parsedAddressFields) {
+      if (!parsedPhoneFields && !parsedAddressFields) {
         fieldScanner.indexParsing++;
       }
     }
     return fieldScanner.trimmedFieldDetail;
   },
 
   /**
    * Get the autocomplete info (e.g. fieldName) determined by the regexp
@@ -377,21 +444,21 @@ this.FormAutofillHeuristics = {
     // Phone: <cc> <ac>:3 - <phone>:3 - <suffix>:4 (Ext: <ext>)?
       // {REGEX_PHONE, FIELD_COUNTRY_CODE, 0},
       // {REGEX_PHONE, FIELD_AREA_CODE, 3},
       // {REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3},
       // {REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4},
       // {REGEX_SEPARATOR, FIELD_NONE, 0},
 
     // Phone: <cc>:3 <ac>:3 <phone>:3 <suffix>:4 (Ext: <ext>)?
-      // {REGEX_PHONE, FIELD_COUNTRY_CODE, 3},
-      // {REGEX_PHONE, FIELD_AREA_CODE, 3},
-      // {REGEX_PHONE, FIELD_PHONE, 3},
-      // {REGEX_PHONE, FIELD_SUFFIX, 4},
-      // {REGEX_SEPARATOR, FIELD_NONE, 0},
+    ["tel", "tel-country-code", 3],
+    ["tel", "tel-area-code", 3],
+    ["tel", "tel-local-prefix", 3],
+    ["tel", "tel-local-suffix", 4],
+    [null, null, 0],
 
     // Area Code: <ac> Phone: <phone> (- <suffix> (Ext: <ext>)?)?
       // {REGEX_AREA, FIELD_AREA_CODE, 0},
       // {REGEX_PHONE, FIELD_PHONE, 0},
       // {REGEX_SEPARATOR, FIELD_NONE, 0},
 
     // Phone: <ac> <phone>:3 <suffix>:4 (Ext: <ext>)?
       // {REGEX_PHONE, FIELD_AREA_CODE, 0},
@@ -426,20 +493,20 @@ this.FormAutofillHeuristics = {
 
     // Phone: <ac> Prefix: <phone> Suffix: <suffix> (Ext: <ext>)?
       // {REGEX_PHONE, FIELD_AREA_CODE, 0},
       // {REGEX_PREFIX, FIELD_PHONE, 0},
       // {REGEX_SUFFIX, FIELD_SUFFIX, 0},
       // {REGEX_SEPARATOR, FIELD_NONE, 0},
 
     // Phone: <ac> - <phone>:3 - <suffix>:4 (Ext: <ext>)?
-      // {REGEX_PHONE, FIELD_AREA_CODE, 0},
-      // {REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3},
-      // {REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4},
-      // {REGEX_SEPARATOR, FIELD_NONE, 0},
+    ["tel", "tel-area-code", 0],
+    ["tel", "tel-local-prefix", 3],
+    ["tel", "tel-local-suffix", 4],
+    [null, null, 0],
 
     // Phone: <cc> - <ac> - <phone> (Ext: <ext>)?
       // {REGEX_PHONE, FIELD_COUNTRY_CODE, 0},
       // {REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE, 0},
       // {REGEX_SUFFIX_SEPARATOR, FIELD_PHONE, 0},
       // {REGEX_SEPARATOR, FIELD_NONE, 0},
 
     // Phone: <ac> - <phone> (Ext: <ext>)?