Bug 1387988 - [Form Autofill] Move "findLabelElements" function to FormAutofillHeuristics.jsm. r=MattN

MozReview-Commit-ID: 93c9R7JaCLA

--HG--
extra : rebase_source : 2cb9276901c4f2ff91da55cc5d0dc095a74524dd
This commit is contained in:
Luke Chang 2017-08-07 18:34:27 +08:00
Родитель 179961b3c9
Коммит 04df87ad05
5 изменённых файлов: 86 добавлений и 83 удалений

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

@ -8,7 +8,7 @@
"use strict";
this.EXPORTED_SYMBOLS = ["FormAutofillHeuristics"];
this.EXPORTED_SYMBOLS = ["FormAutofillHeuristics", "LabelUtils"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
@ -182,6 +182,84 @@ class FieldScanner {
}
}
this.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"],
/**
* 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) {
let strings = [];
let _extractLabelStrings = (el) => {
if (this.EXCLUDED_TAGS.includes(el.tagName)) {
return;
}
if (el.nodeType == Ci.nsIDOMNode.TEXT_NODE ||
el.childNodes.length == 0) {
let trimmedText = el.textContent.trim();
if (trimmedText) {
strings.push(trimmedText);
}
return;
}
for (let node of el.childNodes) {
if (node.nodeType != Ci.nsIDOMNode.ELEMENT_NODE &&
node.nodeType != Ci.nsIDOMNode.TEXT_NODE) {
continue;
}
_extractLabelStrings(node);
}
};
_extractLabelStrings(element);
return strings;
},
findLabelElements(element) {
let document = element.ownerDocument;
let labels = [];
// TODO: querySelectorAll is inefficient here. However, bug 1339726 is for
// a more efficient implementation from DOM API perspective. This function
// should be refined after input.labels API landed.
for (let label of document.querySelectorAll("label[for]")) {
if (element.id == label.htmlFor) {
labels.push(label);
}
}
if (labels.length > 0) {
log.debug("Label found by ID", element.id);
return labels;
}
let parent = element.parentNode;
if (!parent) {
return [];
}
do {
if (parent.tagName == "LABEL" &&
parent.control == element &&
!parent.hasAttribute("for")) {
log.debug("Label found in input's parent or ancestor.");
return [parent];
}
parent = parent.parentNode;
} while (parent);
return [];
},
};
/**
* Returns the autocomplete information of fields according to heuristics.
*/
@ -370,9 +448,9 @@ this.FormAutofillHeuristics = {
yield element.name;
if (!labelStrings) {
labelStrings = [];
let labels = FormAutofillUtils.findLabelElements(element);
let labels = LabelUtils.findLabelElements(element);
for (let label of labels) {
labelStrings.push(...FormAutofillUtils.extractLabelStrings(label));
labelStrings.push(...LabelUtils.extractLabelStrings(label));
}
}
yield *labelStrings;

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

@ -128,82 +128,6 @@ this.FormAutofillUtils = {
return true;
},
// 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"],
/**
* 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) {
let strings = [];
let _extractLabelStrings = (el) => {
if (this.EXCLUDED_TAGS.includes(el.tagName)) {
return;
}
if (el.nodeType == Ci.nsIDOMNode.TEXT_NODE ||
el.childNodes.length == 0) {
let trimmedText = el.textContent.trim();
if (trimmedText) {
strings.push(trimmedText);
}
return;
}
for (let node of el.childNodes) {
if (node.nodeType != Ci.nsIDOMNode.ELEMENT_NODE &&
node.nodeType != Ci.nsIDOMNode.TEXT_NODE) {
continue;
}
_extractLabelStrings(node);
}
};
_extractLabelStrings(element);
return strings;
},
findLabelElements(element) {
let document = element.ownerDocument;
let labels = [];
// TODO: querySelectorAll is inefficient here. However, bug 1339726 is for
// a more efficient implementation from DOM API perspective. This function
// should be refined after input.labels API landed.
for (let label of document.querySelectorAll("label[for]")) {
if (element.id == label.htmlFor) {
labels.push(label);
}
}
if (labels.length > 0) {
log.debug("Label found by ID", element.id);
return labels;
}
let parent = element.parentNode;
if (!parent) {
return [];
}
do {
if (parent.tagName == "LABEL" &&
parent.control == element &&
!parent.hasAttribute("for")) {
log.debug("Label found in input's parent or ancestor.");
return [parent];
}
parent = parent.parentNode;
} while (parent);
return [];
},
loadDataFromScript(url, sandbox = {}) {
let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);

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

@ -1,6 +1,6 @@
"use strict";
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
const TESTCASES = [
{
@ -59,7 +59,7 @@ TESTCASES.forEach(testcase => {
"http://localhost:8080/test/", testcase.document);
let element = doc.getElementById(testcase.inputId);
let strings = FormAutofillUtils.extractLabelStrings(element);
let strings = LabelUtils.extractLabelStrings(element);
Assert.deepEqual(strings, testcase.expectedStrings);
});

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

@ -1,6 +1,6 @@
"use strict";
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
const TESTCASES = [
{
@ -83,7 +83,7 @@ TESTCASES.forEach(testcase => {
"http://localhost:8080/test/", testcase.document);
let input = doc.getElementById(testcase.inputId);
let labels = FormAutofillUtils.findLabelElements(input);
let labels = LabelUtils.findLabelElements(input);
Assert.deepEqual(labels.map(l => l.id), testcase.expectedLabelIds);
});

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

@ -77,6 +77,7 @@
"Finder.jsm": ["Finder", "GetClipboardSearchString"],
"forms.js": ["FormEngine", "FormRec", "FormValidator"],
"forms.jsm": ["FormData"],
"FormAutofillHeuristics.jsm": ["FormAutofillHeuristics", "LabelUtils"],
"FormAutofillSync.jsm": ["AddressesEngine", "CreditCardsEngine"],
"frame.js": ["Collector", "Runner", "events", "runTestFile", "log", "timers", "persisted", "shutdownApplication"],
"FrameScriptManager.jsm": ["getNewLoaderID"],