зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1416664 - Identify the sections for the fields without the section part of autocomplete attr. r=lchang,ralin
MozReview-Commit-ID: 7La8Bn0TF1y --HG-- extra : rebase_source : 4864178cdfbb644912bcfb9dc1a45806f1cae46d
This commit is contained in:
Родитель
9ee1f72e41
Коммит
a7c09638b3
|
@ -21,6 +21,7 @@ FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
|
||||||
|
|
||||||
const PREF_HEURISTICS_ENABLED = "extensions.formautofill.heuristics.enabled";
|
const PREF_HEURISTICS_ENABLED = "extensions.formautofill.heuristics.enabled";
|
||||||
const PREF_SECTION_ENABLED = "extensions.formautofill.section.enabled";
|
const PREF_SECTION_ENABLED = "extensions.formautofill.section.enabled";
|
||||||
|
const DEFAULT_SECTION_NAME = "-moz-section-default";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scanner for traversing all elements in a form and retrieving the field
|
* A scanner for traversing all elements in a form and retrieving the field
|
||||||
|
@ -35,11 +36,13 @@ class FieldScanner {
|
||||||
* @param {Array.DOMElement} elements
|
* @param {Array.DOMElement} elements
|
||||||
* The elements from a form for each parser.
|
* The elements from a form for each parser.
|
||||||
*/
|
*/
|
||||||
constructor(elements) {
|
constructor(elements, {allowDuplicates = false, sectionEnabled = true}) {
|
||||||
this._elementsWeakRef = Cu.getWeakReference(elements);
|
this._elementsWeakRef = Cu.getWeakReference(elements);
|
||||||
this.fieldDetails = [];
|
this.fieldDetails = [];
|
||||||
this._parsingIndex = 0;
|
this._parsingIndex = 0;
|
||||||
this._sections = [];
|
this._sections = [];
|
||||||
|
this._allowDuplicates = allowDuplicates;
|
||||||
|
this._sectionEnabled = sectionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _elements() {
|
get _elements() {
|
||||||
|
@ -112,22 +115,63 @@ class FieldScanner {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getSectionFieldDetails(allowDuplicates) {
|
_classifySections() {
|
||||||
// TODO: [Bug 1416664] If there is only one section which is not defined by
|
let fieldDetails = this._sections[0].fieldDetails;
|
||||||
// `autocomplete` attribute, the sections should be classified by the
|
this._sections = [];
|
||||||
// heuristics.
|
let seenTypes = new Set();
|
||||||
return this._sections.map(section => {
|
let previousType;
|
||||||
if (allowDuplicates) {
|
let sectionCount = 0;
|
||||||
return section.fieldDetails;
|
|
||||||
|
for (let fieldDetail of fieldDetails) {
|
||||||
|
if (!fieldDetail.fieldName) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return this._trimFieldDetails(section.fieldDetails);
|
if (seenTypes.has(fieldDetail.fieldName) &&
|
||||||
});
|
previousType != fieldDetail.fieldName) {
|
||||||
|
seenTypes.clear();
|
||||||
|
sectionCount++;
|
||||||
|
}
|
||||||
|
previousType = fieldDetail.fieldName;
|
||||||
|
seenTypes.add(fieldDetail.fieldName);
|
||||||
|
delete fieldDetail._duplicated;
|
||||||
|
this._pushToSection(DEFAULT_SECTION_NAME + "-" + sectionCount, fieldDetail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result is an array contains the sections with its belonging field
|
||||||
|
* details. If `this._sections` contains one section only with the default
|
||||||
|
* section name (DEFAULT_SECTION_NAME), `this._classifySections` should be
|
||||||
|
* able to identify all sections in the heuristic way.
|
||||||
|
*
|
||||||
|
* @returns {Array<Object>}
|
||||||
|
* The array with the sections, and the belonging fieldDetails are in
|
||||||
|
* each section.
|
||||||
|
*/
|
||||||
|
getSectionFieldDetails() {
|
||||||
|
// When the section feature is disabled, `getSectionFieldDetails` should
|
||||||
|
// provide a single section result.
|
||||||
|
if (!this._sectionEnabled) {
|
||||||
|
return [this._getFinalDetails(this.fieldDetails)];
|
||||||
|
}
|
||||||
|
if (this._sections.length == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (this._sections.length == 1 && this._sections[0].name == DEFAULT_SECTION_NAME) {
|
||||||
|
this._classifySections();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._sections.map(section =>
|
||||||
|
this._getFinalDetails(section.fieldDetails)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function will prepare an autocomplete info object with getInfo
|
* This function will prepare an autocomplete info object with getInfo
|
||||||
* function and push the detail to fieldDetails property. Any duplicated
|
* function and push the detail to fieldDetails property. Any duplicated
|
||||||
* detail will be marked as _duplicated = true for the parser.
|
* detail will be marked as _duplicated = true for the parser.
|
||||||
|
* Any field will be pushed into `this._sections` based on the section name
|
||||||
|
* in `autocomplete` attribute.
|
||||||
*
|
*
|
||||||
* Any element without the related detail will be used for adding the detail
|
* Any element without the related detail will be used for adding the detail
|
||||||
* to the end of field details.
|
* to the end of field details.
|
||||||
|
@ -173,7 +217,7 @@ class FieldScanner {
|
||||||
if (info.addressType) {
|
if (info.addressType) {
|
||||||
names.push(info.addressType);
|
names.push(info.addressType);
|
||||||
}
|
}
|
||||||
return names.length ? names.join(" ") : "-moz-section-default";
|
return names.length ? names.join(" ") : DEFAULT_SECTION_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,7 +249,10 @@ class FieldScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide the field details without invalid field name and duplicated fields.
|
* Provide the final field details without invalid field name, and the
|
||||||
|
* duplicated fields will be removed as well. For the debugging purpose,
|
||||||
|
* the final `fieldDetails` will include the duplicated fields if
|
||||||
|
* `_allowDuplicates` is true.
|
||||||
*
|
*
|
||||||
* @param {Array<Object>} fieldDetails
|
* @param {Array<Object>} fieldDetails
|
||||||
* The field details for trimming.
|
* The field details for trimming.
|
||||||
|
@ -213,14 +260,13 @@ class FieldScanner {
|
||||||
* The array with the field details without invalid field name and
|
* The array with the field details without invalid field name and
|
||||||
* duplicated fields.
|
* duplicated fields.
|
||||||
*/
|
*/
|
||||||
_trimFieldDetails(fieldDetails) {
|
_getFinalDetails(fieldDetails) {
|
||||||
|
if (this._allowDuplicates) {
|
||||||
|
return fieldDetails.filter(f => f.fieldName);
|
||||||
|
}
|
||||||
return fieldDetails.filter(f => f.fieldName && !f._duplicated);
|
return fieldDetails.filter(f => f.fieldName && !f._duplicated);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFieldDetails(allowDuplicates) {
|
|
||||||
return allowDuplicates ? this.fieldDetails : this._trimFieldDetails(this.fieldDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
elementExisting(index) {
|
elementExisting(index) {
|
||||||
return index < this._elements.length;
|
return index < this._elements.length;
|
||||||
}
|
}
|
||||||
|
@ -651,7 +697,8 @@ this.FormAutofillHeuristics = {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let fieldScanner = new FieldScanner(eligibleFields);
|
let fieldScanner = new FieldScanner(eligibleFields,
|
||||||
|
{allowDuplicates, sectionEnabled: this._sectionEnabled});
|
||||||
while (!fieldScanner.parsingFinished) {
|
while (!fieldScanner.parsingFinished) {
|
||||||
let parsedPhoneFields = this._parsePhoneFields(fieldScanner);
|
let parsedPhoneFields = this._parsePhoneFields(fieldScanner);
|
||||||
let parsedAddressFields = this._parseAddressFields(fieldScanner);
|
let parsedAddressFields = this._parseAddressFields(fieldScanner);
|
||||||
|
@ -666,13 +713,7 @@ this.FormAutofillHeuristics = {
|
||||||
|
|
||||||
LabelUtils.clearLabelMap();
|
LabelUtils.clearLabelMap();
|
||||||
|
|
||||||
if (!this._sectionEnabled) {
|
return fieldScanner.getSectionFieldDetails();
|
||||||
// When the section feature is disabled, `getFormInfo` should provide a
|
|
||||||
// single section result.
|
|
||||||
return [fieldScanner.getFieldDetails(allowDuplicates)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return fieldScanner.getSectionFieldDetails(allowDuplicates);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_regExpTableHashValue(...signBits) {
|
_regExpTableHashValue(...signBits) {
|
||||||
|
|
|
@ -11,32 +11,69 @@
|
||||||
<label>Organization: <input id="organization" autocomplete="organization"></label><br/>
|
<label>Organization: <input id="organization" autocomplete="organization"></label><br/>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<label>Street Address: <input id="street-address" autocomplete="shipping street-address"></label><br/>
|
<label>Street Address: <input id="street-address-a" autocomplete="shipping street-address"></label><br/>
|
||||||
<label>Address Level 2: <input id="address-level2" autocomplete="shipping address-level2"></label><br/>
|
<label>Address Level 2: <input id="address-level2-a" autocomplete="shipping address-level2"></label><br/>
|
||||||
<label>Address Level 1: <input id="address-level1" autocomplete="shipping address-level1"></label><br/>
|
<label>Address Level 1: <input id="address-level1-a" autocomplete="shipping address-level1"></label><br/>
|
||||||
<label>Postal Code: <input id="postal-code" autocomplete="shipping postal-code"></label><br/>
|
<label>Postal Code: <input id="postal-code-a" autocomplete="shipping postal-code"></label><br/>
|
||||||
<label>Country: <input id="country" autocomplete="shipping country"></label><br/>
|
<label>Country: <input id="country-a" autocomplete="shipping country"></label><br/>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<label>Street Address: <input id="street-address" autocomplete="billing street-address"></label><br/>
|
<label>Street Address: <input id="street-address-b" autocomplete="billing street-address"></label><br/>
|
||||||
<label>Address Level 2: <input id="address-level2" autocomplete="billing address-level2"></label><br/>
|
<label>Address Level 2: <input id="address-level2-b" autocomplete="billing address-level2"></label><br/>
|
||||||
<label>Address Level 1: <input id="address-level1" autocomplete="billing address-level1"></label><br/>
|
<label>Address Level 1: <input id="address-level1-b" autocomplete="billing address-level1"></label><br/>
|
||||||
<label>Postal Code: <input id="postal-code" autocomplete="billing postal-code"></label><br/>
|
<label>Postal Code: <input id="postal-code-b" autocomplete="billing postal-code"></label><br/>
|
||||||
<label>Country: <input id="country" autocomplete="billing country"></label><br/>
|
<label>Country: <input id="country-b" autocomplete="billing country"></label><br/>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<label>Street Address: <input id="street-address" autocomplete="section-my street-address"></label><br/>
|
<label>Street Address: <input id="street-address-c" autocomplete="section-my street-address"></label><br/>
|
||||||
<label>Address Level 2: <input id="address-level2" autocomplete="section-my address-level2"></label><br/>
|
<label>Address Level 2: <input id="address-level2-c" autocomplete="section-my address-level2"></label><br/>
|
||||||
<label>Address Level 1: <input id="address-level1" autocomplete="section-my address-level1"></label><br/>
|
<label>Address Level 1: <input id="address-level1-c" autocomplete="section-my address-level1"></label><br/>
|
||||||
<label>Postal Code: <input id="postal-code" autocomplete="section-my postal-code"></label><br/>
|
<label>Postal Code: <input id="postal-code-c" autocomplete="section-my postal-code"></label><br/>
|
||||||
<label>Country: <input id="country" autocomplete="section-my country"></label><br/>
|
<label>Country: <input id="country-c" autocomplete="section-my country"></label><br/>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<label>Telephone: <input id="tel" autocomplete="work tel"></label><br/>
|
<label>Telephone: <input id="tel-a" autocomplete="work tel"></label><br/>
|
||||||
<label>Email: <input id="email" autocomplete="work email"></label><br/>
|
<label>Email: <input id="email-a" autocomplete="work email"></label><br/>
|
||||||
<br/>
|
<br/>
|
||||||
<label>Telephone: <input id="tel" autocomplete="home tel"></label><br/>
|
<label>Telephone: <input id="tel-b" autocomplete="home tel"></label><br/>
|
||||||
<label>Email: <input id="email" autocomplete="home email"></label><br/>
|
<label>Email: <input id="email-b" autocomplete="home email"></label><br/>
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
<button type="reset">Reset</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<label>Name: <input autocomplete="name"></label><br/>
|
||||||
|
<label>Organization: <input autocomplete="organization"></label><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<label>Street Address: <input autocomplete="street-address"></label><br/>
|
||||||
|
<label>Address Level 2: <input autocomplete="address-level2"></label><br/>
|
||||||
|
<label>Address Level 1: <input autocomplete="address-level1"></label><br/>
|
||||||
|
<label>Postal Code: <input autocomplete="postal-code"></label><br/>
|
||||||
|
<label>Country: <input autocomplete="country"></label><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<label>Street Address: <input autocomplete="street-address"></label><br/>
|
||||||
|
<label>Address Level 2: <input autocomplete="address-level2"></label><br/>
|
||||||
|
<label>Address Level 1: <input autocomplete="address-level1"></label><br/>
|
||||||
|
<label>Postal Code: <input autocomplete="postal-code"></label><br/>
|
||||||
|
<label>Country: <input autocomplete="country"></label><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<label>Street Address: <input autocomplete="street-address"></label><br/>
|
||||||
|
<label>Address Level 2: <input autocomplete="address-level2"></label><br/>
|
||||||
|
<label>Address Level 1: <input autocomplete="address-level1"></label><br/>
|
||||||
|
<label>Postal Code: <input autocomplete="postal-code"></label><br/>
|
||||||
|
<label>Country: <input autocomplete="country"></label><br/>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<label>Telephone: <input autocomplete="work tel"></label><br/>
|
||||||
|
<label>Email: <input autocomplete="work email"></label><br/>
|
||||||
|
<br/>
|
||||||
|
<label>Telephone: <input autocomplete="home tel"></label><br/>
|
||||||
|
<label>Email: <input autocomplete="home email"></label><br/>
|
||||||
<p>
|
<p>
|
||||||
<input type="submit" value="Submit">
|
<input type="submit" value="Submit">
|
||||||
<button type="reset">Reset</button>
|
<button type="reset">Reset</button>
|
||||||
|
|
|
@ -41,6 +41,37 @@ runHeuristicsTest([
|
||||||
{"section": "section-my", "addressType": "", "contactType": "", "fieldName": "country"},
|
{"section": "section-my", "addressType": "", "contactType": "", "fieldName": "country"},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "name"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "work", "fieldName": "tel"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "work", "fieldName": "email"},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"section": "", "addressType": "", "contactType": "home", "fieldName": "tel"},
|
||||||
|
{"section": "", "addressType": "", "contactType": "home", "fieldName": "email"},
|
||||||
|
],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
], "../../fixtures/");
|
], "../../fixtures/");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче