Bug 1347176 - Implement label element extraction logic of an input field for filling form.; r?MattN
MozReview-Commit-ID: 5uGo1jBBFsC
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -28,9 +28,47 @@ this.FormAutofillUtils = {
if (middleName) {
fullName += " " + middleName;
}
if (lastName) {
fullName += " " + lastName;
}
return fullName;
},
+
+ 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 [];
+ },
};
+
+this.log = null;
+this.FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
+
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/test_findLabelElements.js
@@ -0,0 +1,90 @@
+"use strict";
+
+Cu.import("resource://formautofill/FormAutofillUtils.jsm");
+
+const TESTCASES = [
+ {
+ description: "Input contains in a label element.",
+ document: `<form>
+ <label id="labelA"> label type A
+ <input id="typeA" type="text">
+ </label>
+ </form>`,
+ inputId: "typeA",
+ expectedLabelIds: ["labelA"],
+ },
+ {
+ description: "Input contains in a label element.",
+ document: `<label id="labelB"> label type B
+ <div> inner div
+ <input id="typeB" type="text">
+ </div>
+ </label>`,
+ inputId: "typeB",
+ expectedLabelIds: ["labelB"],
+ },
+ {
+ description: "\"for\" attribute used to indicate input by one label.",
+ document: `<label id="labelC" for="typeC">label type C</label>
+ <input id="typeC" type="text">`,
+ inputId: "typeC",
+ expectedLabelIds: ["labelC"],
+ },
+ {
+ description: "\"for\" attribute used to indicate input by multiple labels.",
+ document: `<form>
+ <label id="labelD1" for="typeD">label type D1</label>
+ <label id="labelD2" for="typeD">label type D2</label>
+ <label id="labelD3" for="typeD">label type D3</label>
+ <input id="typeD" type="text">
+ </form>`,
+ inputId: "typeD",
+ expectedLabelIds: ["labelD1", "labelD2", "labelD3"],
+ },
+ {
+ description: "\"for\" attribute used to indicate input by multiple labels with space prefix/postfix.",
+ document: `<label id="labelE1" for="typeE">label type E1</label>
+ <label id="labelE2" for="typeE ">label type E2</label>
+ <label id="labelE3" for=" TYPEe">label type E3</label>
+ <label id="labelE4" for=" typeE ">label type E4</label>
+ <input id=" typeE " type="text">`,
+ inputId: " typeE ",
+ expectedLabelIds: [],
+ },
+ {
+ description: "Input contains in a label element.",
+ document: `<label id="labelF"> label type F
+ <label for="dummy"> inner label
+ <input id="typeF" type="text">
+ <input id="dummy" type="text">
+ </div>
+ </label>`,
+ inputId: "typeF",
+ expectedLabelIds: ["labelF"],
+ },
+ {
+ description: "\"for\" attribute used to indicate input by labels out of the form.",
+ document: `<label id="labelG1" for="typeG">label type G1</label>
+ <form>
+ <label id="labelG2" for="typeG">label type G2</label>
+ <input id="typeG" type="text">
+ </form>
+ <label id="labelG3" for="typeG">label type G3</label>`,
+ inputId: "typeG",
+ expectedLabelIds: ["labelG1", "labelG2", "labelG3"],
+ },
+];
+
+TESTCASES.forEach(testcase => {
+ add_task(function* () {
+ do_print("Starting testcase: " + testcase.description);
+
+ let doc = MockDocument.createTestDocument(
+ "http://localhost:8080/test/", testcase.document);
+
+ let input = doc.getElementById(testcase.inputId);
+ let labels = FormAutofillUtils.findLabelElements(input);
+
+ Assert.deepEqual(labels.map(l => l.id), testcase.expectedLabelIds);
+ });
+});
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -1,14 +1,15 @@
[DEFAULT]
firefox-appdir = browser
head = head.js
support-files =
[test_autofillFormFields.js]
[test_collectFormFields.js]
[test_enabledStatus.js]
+[test_findLabelElements.js]
[test_getFormInputDetails.js]
[test_markAsAutofillField.js]
[test_profileAutocompleteResult.js]
[test_profileStorage.js]
[test_savedFieldNames.js]