Bug 1681985 - Extract LabelUtils to FormAutofillUtils.jsm. r=zbraniecki

We need it from both FormAutofillHeuristics and CreditCardRuleset, and it would make a circular import otherwise: FormAutofillHeuristics -> CreditCardRuleset -> FormAutofillHeuristics.

Differential Revision: https://phabricator.services.mozilla.com/D100140
This commit is contained in:
Erik Rose 2021-03-23 18:31:07 +00:00
Родитель fe5c743b15
Коммит 52703e294a
7 изменённых файлов: 124 добавлений и 119 удалений

Просмотреть файл

@ -8,7 +8,7 @@
"use strict";
var EXPORTED_SYMBOLS = ["FormAutofillHeuristics", "LabelUtils"];
var EXPORTED_SYMBOLS = ["FormAutofillHeuristics"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import(
@ -25,6 +25,8 @@ ChromeUtils.defineModuleGetter(
XPCOMUtils.defineLazyModuleGetters(this, {
CreditCard: "resource://gre/modules/CreditCard.jsm",
creditCardRuleset: "resource://formautofill/CreditCardRuleset.jsm",
LabelUtils: "resource://formautofill/FormAutofillUtils.jsm", // TODO: Is there a better way of importing multiple symbols from a single module? We already import from this one above.
});
this.log = null;
@ -332,116 +334,6 @@ class FieldScanner {
}
}
var LabelUtils = {
// The tag name list is from Chromium except for "STYLE":
// eslint-disable-next-line max-len
// https://cs.chromium.org/chromium/src/components/autofill/content/renderer/form_autofill_util.cc?l=216&rcl=d33a171b7c308a64dc3372fac3da2179c63b419e
EXCLUDED_TAGS: ["SCRIPT", "NOSCRIPT", "OPTION", "STYLE"],
// A map object, whose keys are the id's of form fields and each value is an
// array consisting of label elements correponding to the id.
// @type {Map<string, array>}
_mappedLabels: null,
// An array consisting of label elements whose correponding form field doesn't
// have an id attribute.
// @type {Array<HTMLLabelElement>}
_unmappedLabels: null,
// A weak map consisting of label element and extracted strings pairs.
// @type {WeakMap<HTMLLabelElement, array>}
_labelStrings: null,
/**
* Extract all strings of an element's children to an array.
* "element.textContent" is a string which is merged of all children nodes,
* and this function provides an array of the strings contains in an element.
*
* @param {Object} element
* A DOM element to be extracted.
* @returns {Array}
* All strings in an element.
*/
extractLabelStrings(element) {
if (this._labelStrings.has(element)) {
return this._labelStrings.get(element);
}
let strings = [];
let _extractLabelStrings = el => {
if (this.EXCLUDED_TAGS.includes(el.tagName)) {
return;
}
if (el.nodeType == el.TEXT_NODE || !el.childNodes.length) {
let trimmedText = el.textContent.trim();
if (trimmedText) {
strings.push(trimmedText);
}
return;
}
for (let node of el.childNodes) {
let nodeType = node.nodeType;
if (nodeType != node.ELEMENT_NODE && nodeType != node.TEXT_NODE) {
continue;
}
_extractLabelStrings(node);
}
};
_extractLabelStrings(element);
this._labelStrings.set(element, strings);
return strings;
},
generateLabelMap(doc) {
let mappedLabels = new Map();
let unmappedLabels = [];
for (let label of doc.querySelectorAll("label")) {
let id = label.htmlFor;
if (!id) {
let control = label.control;
if (!control) {
continue;
}
id = control.id;
}
if (id) {
let labels = mappedLabels.get(id);
if (labels) {
labels.push(label);
} else {
mappedLabels.set(id, [label]);
}
} else {
unmappedLabels.push(label);
}
}
this._mappedLabels = mappedLabels;
this._unmappedLabels = unmappedLabels;
this._labelStrings = new WeakMap();
},
clearLabelMap() {
this._mappedLabels = null;
this._unmappedLabels = null;
this._labelStrings = null;
},
findLabelElements(element) {
if (!this._mappedLabels) {
this.generateLabelMap(element.ownerDocument);
}
let id = element.id;
if (!id) {
return this._unmappedLabels.filter(label => label.control == element);
}
return this._mappedLabels.get(id) || [];
},
};
/**
* Returns the autocomplete information of fields according to heuristics.
*/

Просмотреть файл

@ -4,7 +4,7 @@
"use strict";
var EXPORTED_SYMBOLS = ["FormAutofillUtils", "AddressDataLoader"];
var EXPORTED_SYMBOLS = ["FormAutofillUtils", "AddressDataLoader", "LabelUtils"];
const ADDRESS_METADATA_PATH = "resource://formautofill/addressmetadata/";
const ADDRESS_REFERENCES = "addressReferences.js";
@ -1102,6 +1102,116 @@ this.FormAutofillUtils = {
},
};
const LabelUtils = {
// The tag name list is from Chromium except for "STYLE":
// eslint-disable-next-line max-len
// https://cs.chromium.org/chromium/src/components/autofill/content/renderer/form_autofill_util.cc?l=216&rcl=d33a171b7c308a64dc3372fac3da2179c63b419e
EXCLUDED_TAGS: ["SCRIPT", "NOSCRIPT", "OPTION", "STYLE"],
// A map object, whose keys are the id's of form fields and each value is an
// array consisting of label elements correponding to the id.
// @type {Map<string, array>}
_mappedLabels: null,
// An array consisting of label elements whose correponding form field doesn't
// have an id attribute.
// @type {Array<HTMLLabelElement>}
_unmappedLabels: null,
// A weak map consisting of label element and extracted strings pairs.
// @type {WeakMap<HTMLLabelElement, array>}
_labelStrings: null,
/**
* Extract all strings of an element's children to an array.
* "element.textContent" is a string which is merged of all children nodes,
* and this function provides an array of the strings contains in an element.
*
* @param {Object} element
* A DOM element to be extracted.
* @returns {Array}
* All strings in an element.
*/
extractLabelStrings(element) {
if (this._labelStrings.has(element)) {
return this._labelStrings.get(element);
}
let strings = [];
let _extractLabelStrings = el => {
if (this.EXCLUDED_TAGS.includes(el.tagName)) {
return;
}
if (el.nodeType == el.TEXT_NODE || !el.childNodes.length) {
let trimmedText = el.textContent.trim();
if (trimmedText) {
strings.push(trimmedText);
}
return;
}
for (let node of el.childNodes) {
let nodeType = node.nodeType;
if (nodeType != node.ELEMENT_NODE && nodeType != node.TEXT_NODE) {
continue;
}
_extractLabelStrings(node);
}
};
_extractLabelStrings(element);
this._labelStrings.set(element, strings);
return strings;
},
generateLabelMap(doc) {
let mappedLabels = new Map();
let unmappedLabels = [];
for (let label of doc.querySelectorAll("label")) {
let id = label.htmlFor;
if (!id) {
let control = label.control;
if (!control) {
continue;
}
id = control.id;
}
if (id) {
let labels = mappedLabels.get(id);
if (labels) {
labels.push(label);
} else {
mappedLabels.set(id, [label]);
}
} else {
unmappedLabels.push(label);
}
}
this._mappedLabels = mappedLabels;
this._unmappedLabels = unmappedLabels;
this._labelStrings = new WeakMap();
},
clearLabelMap() {
this._mappedLabels = null;
this._unmappedLabels = null;
this._labelStrings = null;
},
findLabelElements(element) {
if (!this._mappedLabels) {
this.generateLabelMap(element.ownerDocument);
}
let id = element.id;
if (!id) {
return this._unmappedLabels.filter(label => label.control == element);
}
return this._mappedLabels.get(id) || [];
},
};
this.log = null;
FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);

Просмотреть файл

@ -208,10 +208,10 @@ var AddressDataLoader, FormAutofillUtils;
async function runHeuristicsTest(patterns, fixturePathPrefix) {
add_task(async function setup() {
({ FormAutofillHeuristics, LabelUtils } = ChromeUtils.import(
({ FormAutofillHeuristics } = ChromeUtils.import(
"resource://formautofill/FormAutofillHeuristics.jsm"
));
({ AddressDataLoader, FormAutofillUtils } = ChromeUtils.import(
({ AddressDataLoader, FormAutofillUtils, LabelUtils } = ChromeUtils.import(
"resource://formautofill/FormAutofillUtils.jsm"
));
});

Просмотреть файл

@ -3,7 +3,7 @@
var LabelUtils;
add_task(async function() {
({ LabelUtils } = ChromeUtils.import(
"resource://formautofill/FormAutofillHeuristics.jsm"
"resource://formautofill/FormAutofillUtils.jsm"
));
});

Просмотреть файл

@ -3,7 +3,7 @@
var LabelUtils;
add_task(async function() {
({ LabelUtils } = ChromeUtils.import(
"resource://formautofill/FormAutofillHeuristics.jsm"
"resource://formautofill/FormAutofillUtils.jsm"
));
});

Просмотреть файл

@ -2,9 +2,12 @@
var FormAutofillHeuristics, LabelUtils;
add_task(async function() {
({ FormAutofillHeuristics, LabelUtils } = ChromeUtils.import(
({ FormAutofillHeuristics } = ChromeUtils.import(
"resource://formautofill/FormAutofillHeuristics.jsm"
));
({ LabelUtils } = ChromeUtils.import(
"resource://formautofill/FormAutofillUtils.jsm"
));
});
const TESTCASES = [

Просмотреть файл

@ -69,10 +69,10 @@
"Finder.jsm": ["Finder", "GetClipboardSearchString", "SetClipboardSearchString"],
"format.js": ["pprint", "truncate"],
"formautofill.jsm": ["Address", "CreditCard", "DumpAddresses", "DumpCreditCards"],
"FormAutofillHeuristics.jsm": ["FormAutofillHeuristics", "LabelUtils"],
"FormAutofillHeuristics.jsm": ["FormAutofillHeuristics"],
"FormAutofillStorage.jsm": ["formAutofillStorage"],
"FormAutofillSync.jsm": ["AddressesEngine", "CreditCardsEngine"],
"FormAutofillUtils.jsm": ["FormAutofillUtils", "AddressDataLoader"],
"FormAutofillUtils.jsm": ["FormAutofillUtils", "AddressDataLoader", "LabelUtils"],
"forms.js": ["FormEngine", "FormRec", "FormValidator"],
"forms.jsm": ["FormData"],
"FrameScriptManager.jsm": ["getNewLoaderID"],