Bug 1415077 - Classify the field details with autocomplete attr into multiple groups. r=lchang,ralin
authorSean Lee <selee@mozilla.com>
Tue, 07 Nov 2017 18:08:44 +0800
changeset 393085 e1667b83dc102e673ddcc0a58ac64df28901b033
parent 393084 11865acd385763e5c7c4c87d6f4e7785a0f28269
child 393086 e78023ba8b130b3c6fe0b8ee0018e0c9ef231136
push id55843
push userryanvm@gmail.com
push dateWed, 22 Nov 2017 17:23:20 +0000
treeherderautoland@d827c67e862e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslchang, ralin
bugs1415077
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1415077 - Classify the field details with autocomplete attr into multiple groups. r=lchang,ralin MozReview-Commit-ID: lt8AVNzpRk
browser/extensions/formautofill/FormAutofillHeuristics.jsm
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -34,16 +34,17 @@ class FieldScanner {
    *
    * @param {Array.DOMElement} elements
    *        The elements from a form for each parser.
    */
   constructor(elements) {
     this._elementsWeakRef = Cu.getWeakReference(elements);
     this.fieldDetails = [];
     this._parsingIndex = 0;
+    this._sections = [];
   }
 
   get _elements() {
     return this._elementsWeakRef.get();
   }
 
   /**
    * This cursor means the index of the element which is waiting for parsing.
@@ -93,16 +94,41 @@ class FieldScanner {
 
     return this.fieldDetails[index];
   }
 
   get parsingFinished() {
     return this.parsingIndex >= this._elements.length;
   }
 
+  _pushToSection(name, fieldDetail) {
+    for (let section of this._sections) {
+      if (section.name == name) {
+        section.fieldDetails.push(fieldDetail);
+        return;
+      }
+    }
+    this._sections.push({
+      name,
+      fieldDetails: [fieldDetail],
+    });
+  }
+
+  getSectionFieldDetails(allowDuplicates) {
+    // TODO: [Bug 1416664] If there is only one section which is not defined by
+    // `autocomplete` attribute, the sections should be classified by the
+    // heuristics.
+    return this._sections.map(section => {
+      if (allowDuplicates) {
+        return section.fieldDetails;
+      }
+      return this._trimFieldDetails(section.fieldDetails);
+    });
+  }
+
   /**
    * This function will prepare an autocomplete info object with getInfo
    * function and push the detail to fieldDetails property. Any duplicated
    * detail will be marked as _duplicated = true for the parser.
    *
    * Any element without the related detail will be used for adding the detail
    * to the end of field details.
    */
@@ -131,16 +157,28 @@ class FieldScanner {
     // Store the association between the field metadata and the element.
     if (this.findSameField(info) != -1) {
       // A field with the same identifier already exists.
       log.debug("Not collecting a field matching another with the same info:", info);
       fieldInfo._duplicated = true;
     }
 
     this.fieldDetails.push(fieldInfo);
+    this._pushToSection(this._getSectionName(fieldInfo), fieldInfo);
+  }
+
+  _getSectionName(info) {
+    let names = [];
+    if (info.section) {
+      names.push(info.section);
+    }
+    if (info.addressType) {
+      names.push(info.addressType);
+    }
+    return names.length ? names.join(" ") : "-moz-section-default";
   }
 
   /**
    * When a field detail should be changed its fieldName after parsing, use
    * this function to update the fieldName which is at a specific index.
    *
    * @param {number} index
    *        The index indicates a field detail to be updated.
@@ -165,22 +203,28 @@ class FieldScanner {
                                        f.addressType == info.addressType &&
                                        f.contactType == info.contactType &&
                                        f.fieldName == info.fieldName);
   }
 
   /**
    * Provide the field details without invalid field name and duplicated fields.
    *
+   * @param   {Array<Object>} fieldDetails
+   *          The field details for trimming.
    * @returns {Array<Object>}
    *          The array with the field details without invalid field name and
    *          duplicated fields.
    */
-  get trimmedFieldDetail() {
-    return this.fieldDetails.filter(f => f.fieldName && !f._duplicated);
+  _trimFieldDetails(fieldDetails) {
+    return fieldDetails.filter(f => f.fieldName && !f._duplicated);
+  }
+
+  getFieldDetails(allowDuplicates) {
+    return allowDuplicates ? this.fieldDetails : this._trimFieldDetails(this.fieldDetails);
   }
 
   elementExisting(index) {
     return index < this._elements.length;
   }
 }
 
 this.LabelUtils = {
@@ -621,26 +665,20 @@ this.FormAutofillHeuristics = {
       }
     }
 
     LabelUtils.clearLabelMap();
 
     if (!this._sectionEnabled) {
       // When the section feature is disabled, `getFormInfo` should provide a
       // single section result.
-      return [allowDuplicates ? fieldScanner.fieldDetails : fieldScanner.trimmedFieldDetail];
+      return [fieldScanner.getFieldDetails(allowDuplicates)];
     }
 
-    return this._groupingFields(fieldScanner, allowDuplicates);
-  },
-
-  _groupingFields(fieldScanner, allowDuplicates) {
-    // TODO [Bug 1415077] This function should be able to handle the section
-    // part of autocomplete attr.
-    return [allowDuplicates ? fieldScanner.fieldDetails : fieldScanner.trimmedFieldDetail];
+    return fieldScanner.getSectionFieldDetails(allowDuplicates);
   },
 
   _regExpTableHashValue(...signBits) {
     return signBits.reduce((p, c, i) => p | !!c << i, 0);
   },
 
   _setRegExpListCache(regexps, b0, b1, b2) {
     if (!this._regexpList) {