mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #7965 - frewsxcv:labelable-elements-label-attribute, r=nox
Implement 'labels' attribute on 'labelable elements' <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7965) <!-- Reviewable:end -->
This commit is contained in:
commit
0e70a1f8a8
22 changed files with 184 additions and 63 deletions
|
@ -17,6 +17,7 @@ use dom::htmlfieldsetelement::HTMLFieldSetElement;
|
|||
use dom::htmlformelement::{FormControl, FormSubmitter};
|
||||
use dom::htmlformelement::{SubmittedFrom, HTMLFormElement};
|
||||
use dom::node::{Node, document_from_node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::validitystate::ValidityState;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use selectors::states::*;
|
||||
|
@ -131,6 +132,11 @@ impl HTMLButtonElementMethods for HTMLButtonElement {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-button-value
|
||||
make_setter!(SetValue, "value");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMethods for HTMLButtonElement {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use dom::attr::Attr;
|
||||
use dom::attr::AttrValue;
|
||||
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
use dom::bindings::codegen::Bindings::HTMLElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
|
||||
|
@ -12,7 +13,7 @@ use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
|||
use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, NodeTypeId};
|
||||
use dom::bindings::conversions::Castable;
|
||||
use dom::bindings::error::{Error, ErrorResult};
|
||||
use dom::bindings::js::{JS, MutNullableHeap, Root};
|
||||
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
|
||||
use dom::bindings::utils::Reflectable;
|
||||
use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration};
|
||||
use dom::document::Document;
|
||||
|
@ -23,8 +24,10 @@ use dom::htmlbodyelement::HTMLBodyElement;
|
|||
use dom::htmlframesetelement::HTMLFrameSetElement;
|
||||
use dom::htmlhtmlelement::HTMLHtmlElement;
|
||||
use dom::htmlinputelement::HTMLInputElement;
|
||||
use dom::htmllabelelement::HTMLLabelElement;
|
||||
use dom::node::{Node, SEQUENTIALLY_FOCUSABLE};
|
||||
use dom::node::{document_from_node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use msg::constellation_msg::FocusType;
|
||||
use selectors::states::*;
|
||||
|
@ -365,6 +368,45 @@ impl HTMLElement {
|
|||
to_camel_case(&raw_name)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
pub fn labels(&self) -> Root<NodeList> {
|
||||
debug_assert!(self.is_labelable_element());
|
||||
|
||||
let element = self.upcast::<Element>();
|
||||
let window = window_from_node(element);
|
||||
|
||||
// Traverse ancestors for implicitly associated <label> elements
|
||||
// https://html.spec.whatwg.org/multipage/#the-label-element:attr-label-for-4
|
||||
let ancestors =
|
||||
self.upcast::<Node>()
|
||||
.ancestors()
|
||||
.filter_map(Root::downcast::<HTMLElement>)
|
||||
// If we reach a labelable element, we have a guarantee no ancestors above it
|
||||
// will be a label for this HTMLElement
|
||||
.take_while(|elem| !elem.is_labelable_element())
|
||||
.filter_map(Root::downcast::<HTMLLabelElement>)
|
||||
.filter(|elem| !elem.upcast::<Element>().has_attribute(&atom!("for")))
|
||||
.filter(|elem| elem.first_labelable_descendant().r() == Some(self))
|
||||
.map(Root::upcast::<Node>);
|
||||
|
||||
let id = element.Id();
|
||||
let id = match &id as &str {
|
||||
"" => return NodeList::new_simple_list(window.r(), ancestors),
|
||||
id => id,
|
||||
};
|
||||
|
||||
// Traverse entire tree for <label> elements with `for` attribute matching `id`
|
||||
let root_element = element.get_root_element();
|
||||
let root_node = root_element.upcast::<Node>();
|
||||
let children = root_node.traverse_preorder()
|
||||
.filter_map(Root::downcast::<Element>)
|
||||
.filter(|elem| elem.is::<HTMLLabelElement>())
|
||||
.filter(|elem| elem.get_string_attribute(&atom!("for")) == id)
|
||||
.map(Root::upcast::<Node>);
|
||||
|
||||
NodeList::new_simple_list(window.r(), children.chain(ancestors))
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMethods for HTMLElement {
|
||||
|
|
|
@ -25,6 +25,7 @@ use dom::htmlformelement::{ResetFrom, SubmittedFrom};
|
|||
use dom::keyboardevent::KeyboardEvent;
|
||||
use dom::node::{Node, NodeDamage};
|
||||
use dom::node::{document_from_node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use selectors::states::*;
|
||||
|
@ -333,6 +334,16 @@ impl HTMLInputElementMethods for HTMLInputElement {
|
|||
fn SetIndeterminate(&self, val: bool) {
|
||||
self.upcast::<Element>().set_state(IN_INDETERMINATE_STATE, val)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
if self.Type() == "hidden" {
|
||||
let window = window_from_node(self);
|
||||
NodeList::empty(&window)
|
||||
} else {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ impl VirtualMethods for HTMLLabelElement {
|
|||
}
|
||||
|
||||
impl HTMLLabelElement {
|
||||
fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> {
|
||||
pub fn first_labelable_descendant(&self) -> Option<Root<HTMLElement>> {
|
||||
self.upcast::<Node>()
|
||||
.traverse_preorder()
|
||||
.filter_map(Root::downcast::<HTMLElement>)
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::HTMLMeterElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLMeterElementBinding::{self, HTMLMeterElementMethods};
|
||||
use dom::bindings::conversions::Castable;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::document::Document;
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::node::Node;
|
||||
use dom::nodelist::NodeList;
|
||||
use util::str::DOMString;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -31,3 +33,10 @@ impl HTMLMeterElement {
|
|||
Node::reflect_node(box element, document, HTMLMeterElementBinding::Wrap)
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLMeterElementMethods for HTMLMeterElement {
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
use dom::bindings::codegen::Bindings::HTMLOutputElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLOutputElementBinding::HTMLOutputElementMethods;
|
||||
use dom::bindings::conversions::Castable;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::document::Document;
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::htmlformelement::{FormControl, HTMLFormElement};
|
||||
use dom::node::{Node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::validitystate::ValidityState;
|
||||
use util::str::DOMString;
|
||||
|
||||
|
@ -47,6 +49,11 @@ impl HTMLOutputElementMethods for HTMLOutputElement {
|
|||
fn GetForm(&self) -> Option<Root<HTMLFormElement>> {
|
||||
self.form_owner()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
|
||||
impl FormControl for HTMLOutputElement {}
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::bindings::codegen::Bindings::HTMLProgressElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLProgressElementBinding::{self, HTMLProgressElementMethods};
|
||||
use dom::bindings::conversions::Castable;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::document::Document;
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::node::Node;
|
||||
use dom::nodelist::NodeList;
|
||||
use util::str::DOMString;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -32,3 +34,10 @@ impl HTMLProgressElement {
|
|||
Node::reflect_node(box element, document, HTMLProgressElementBinding::Wrap)
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLProgressElementMethods for HTMLProgressElement {
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ use dom::htmlfieldsetelement::HTMLFieldSetElement;
|
|||
use dom::htmlformelement::{FormControl, HTMLFormElement};
|
||||
use dom::htmloptionelement::HTMLOptionElement;
|
||||
use dom::node::{Node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::validitystate::ValidityState;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use selectors::states::*;
|
||||
|
@ -158,6 +159,11 @@ impl HTMLSelectElementMethods for HTMLSelectElement {
|
|||
"select-one".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMethods for HTMLSelectElement {
|
||||
|
|
|
@ -22,6 +22,7 @@ use dom::htmlformelement::{FormControl, HTMLFormElement};
|
|||
use dom::keyboardevent::KeyboardEvent;
|
||||
use dom::node::{ChildrenMutation, Node, NodeDamage};
|
||||
use dom::node::{document_from_node, window_from_node};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use msg::constellation_msg::ConstellationChan;
|
||||
use script_task::ScriptTaskEventCategory::InputEvent;
|
||||
|
@ -205,6 +206,11 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
|
|||
|
||||
self.force_relayout();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-lfe-labels
|
||||
fn Labels(&self) -> Root<NodeList> {
|
||||
self.upcast::<HTMLElement>().labels()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ impl NodeList {
|
|||
pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> {
|
||||
NodeList::new(window, NodeListType::Children(ChildrenList::new(node)))
|
||||
}
|
||||
|
||||
pub fn empty(window: &Window) -> Root<NodeList> {
|
||||
NodeList::new(window, NodeListType::Simple(vec![]))
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeListMethods for NodeList {
|
||||
|
|
|
@ -25,5 +25,5 @@ interface HTMLButtonElement : HTMLElement {
|
|||
//boolean reportValidity();
|
||||
//void setCustomValidity(DOMString error);
|
||||
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -57,7 +57,7 @@ interface HTMLInputElement : HTMLElement {
|
|||
//boolean reportValidity();
|
||||
//void setCustomValidity(DOMString error);
|
||||
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
|
||||
//void select();
|
||||
// attribute unsigned long selectionStart;
|
||||
|
|
|
@ -11,5 +11,5 @@ interface HTMLMeterElement : HTMLElement {
|
|||
// attribute double low;
|
||||
// attribute double high;
|
||||
// attribute double optimum;
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -20,5 +20,5 @@ interface HTMLOutputElement : HTMLElement {
|
|||
//boolean reportValidity();
|
||||
//void setCustomValidity(DOMString error);
|
||||
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -8,5 +8,5 @@ interface HTMLProgressElement : HTMLElement {
|
|||
// attribute double value;
|
||||
// attribute double max;
|
||||
//readonly attribute double position;
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -36,5 +36,5 @@ interface HTMLSelectElement : HTMLElement {
|
|||
//boolean reportValidity();
|
||||
//void setCustomValidity(DOMString error);
|
||||
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ interface HTMLTextAreaElement : HTMLElement {
|
|||
//boolean reportValidity();
|
||||
//void setCustomValidity(DOMString error);
|
||||
|
||||
//readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
|
||||
//void select();
|
||||
// attribute unsigned long selectionStart;
|
||||
|
|
|
@ -4968,9 +4968,6 @@
|
|||
[HTMLInputElement interface: operation setCustomValidity(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: operation select()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5103,9 +5100,6 @@
|
|||
[HTMLInputElement interface: calling setCustomValidity(DOMString) on document.createElement("input") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: document.createElement("input") must inherit property "labels" with the proper type (48)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLInputElement interface: document.createElement("input") must inherit property "select" with the proper type (49)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5169,9 +5163,6 @@
|
|||
[HTMLButtonElement interface: operation setCustomValidity(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLButtonElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLButtonElement interface: document.createElement("button") must inherit property "autofocus" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5199,9 +5190,6 @@
|
|||
[HTMLButtonElement interface: calling setCustomValidity(DOMString) on document.createElement("button") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLButtonElement interface: document.createElement("button") must inherit property "labels" with the proper type (18)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5256,9 +5244,6 @@
|
|||
[HTMLSelectElement interface: operation setCustomValidity(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: document.createElement("select") must inherit property "autocomplete" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5313,9 +5298,6 @@
|
|||
[HTMLSelectElement interface: calling setCustomValidity(DOMString) on document.createElement("select") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLSelectElement interface: document.createElement("select") must inherit property "labels" with the proper type (26)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLDataListElement interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5385,9 +5367,6 @@
|
|||
[HTMLTextAreaElement interface: operation setCustomValidity(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: operation select()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5451,9 +5430,6 @@
|
|||
[HTMLTextAreaElement interface: calling setCustomValidity(DOMString) on document.createElement("textarea") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "labels" with the proper type (25)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLTextAreaElement interface: document.createElement("textarea") must inherit property "select" with the proper type (26)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5622,9 +5598,6 @@
|
|||
[HTMLOutputElement interface: operation setCustomValidity(DOMString)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLOutputElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLOutputElement interface: document.createElement("output") must inherit property "htmlFor" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5658,9 +5631,6 @@
|
|||
[HTMLOutputElement interface: calling setCustomValidity(DOMString) on document.createElement("output") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLOutputElement interface: document.createElement("output") must inherit property "labels" with the proper type (12)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLProgressElement interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5673,9 +5643,6 @@
|
|||
[HTMLProgressElement interface: attribute position]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLProgressElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLProgressElement interface: document.createElement("progress") must inherit property "value" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5685,9 +5652,6 @@
|
|||
[HTMLProgressElement interface: document.createElement("progress") must inherit property "position" with the proper type (2)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLProgressElement interface: document.createElement("progress") must inherit property "labels" with the proper type (3)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMeterElement interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5709,9 +5673,6 @@
|
|||
[HTMLMeterElement interface: attribute optimum]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMeterElement interface: attribute labels]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMeterElement interface: document.createElement("meter") must inherit property "value" with the proper type (0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5730,9 +5691,6 @@
|
|||
[HTMLMeterElement interface: document.createElement("meter") must inherit property "optimum" with the proper type (5)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLMeterElement interface: document.createElement("meter") must inherit property "labels" with the proper type (6)]
|
||||
expected: FAIL
|
||||
|
||||
[HTMLFieldSetElement interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -3,12 +3,3 @@
|
|||
[A non-control follows by a control with same ID.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has multiple labels.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has no label 1.]
|
||||
expected: FAIL
|
||||
|
||||
[A form control has no label 2.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -3,3 +3,6 @@
|
|||
[Check if the keygen element is a labelable element]
|
||||
expected: FAIL
|
||||
|
||||
[Check if the keygen element can access 'labels']
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"A label element not in a document should not label an element in a document.");
|
||||
document.body.appendChild(label);
|
||||
assert_equals(label.control, document.getElementById("test1"));
|
||||
label.remove();
|
||||
}, "A label element not in a document can not label any element in the document.");
|
||||
|
||||
test(function () {
|
||||
|
@ -63,6 +64,7 @@
|
|||
document.getElementById("lbl1").insertBefore(input, document.getElementById("test2"));
|
||||
assert_equals(document.getElementById("lbl1").control, input,
|
||||
"The first labelable descendant of a label element in tree order should be its labeled control.");
|
||||
input.remove();
|
||||
}, "The labeled control for a label element that has no 'for' attribute is the first labelable element which is a descendant of that label element.");
|
||||
|
||||
test(function () {
|
||||
|
@ -95,12 +97,19 @@
|
|||
document.getElementById("fm").insertBefore(newLabel, document.getElementById("lbl0"));
|
||||
assert_array_equals(document.getElementById("test7").labels, [newLabel, document.getElementById("lbl5"), document.getElementById("lbl6")],
|
||||
"The labels for a form control should be returned in tree order.");
|
||||
newLabel.remove();
|
||||
}, "A form control has multiple labels.");
|
||||
|
||||
test(function () {
|
||||
var labels = document.getElementById("test3").labels;
|
||||
assert_true(labels instanceof NodeList, "A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels.length, 1, "The form control has an ancestor with no explicit associated label, and is the first labelable descendant.");
|
||||
}, "A form control has an implicit label.");
|
||||
|
||||
test(function () {
|
||||
var labels = document.getElementById("test4").labels;
|
||||
assert_true(labels instanceof NodeList, "A form control's 'labels' property should be an instance of a NodeList.");
|
||||
assert_equals(labels.length, 0, "The number of labels should be 0 if the associated form control isn't referenced by any <label>.");
|
||||
assert_equals(labels.length, 0, "The form control has an ancestor with no explicit associated label, but is *not* the first labelable descendant");
|
||||
}, "A form control has no label 1.");
|
||||
|
||||
test(function () {
|
||||
|
|
|
@ -36,61 +36,121 @@
|
|||
</form>
|
||||
|
||||
<script>
|
||||
function testLabelsAttr(formElementId, labelElementId, hasLabels) {
|
||||
var elem = document.getElementById(formElementId);
|
||||
if (labelElementId) {
|
||||
assert_equals(elem.labels.length, 1);
|
||||
assert_equals(elem.labels[0].id, labelElementId);
|
||||
} else {
|
||||
assert_equals(elem.labels.length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl0").control.id, "testoutput", "An output element should be labelable.");
|
||||
}, "Check if the output element is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testoutput", "lbl0");
|
||||
}, "Check if the output element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl1").control.id, "testprogress", "A progress element should be labelable.");
|
||||
}, "Check if the progress element is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testprogress", "lbl1");
|
||||
}, "Check if the progress element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl2").control.id, "testselect", "A select element should be labelable.");
|
||||
}, "Check if the select element is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testselect", "lbl2");
|
||||
}, "Check if the select element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl3").control.id, "testarea", "A textarea element should be labelable.");
|
||||
}, "Check if the textarea element is a labelable form-element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testarea", "lbl3");
|
||||
}, "Check if the textarea element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl4").control.id, "testButton", "A button element should be labelable.");
|
||||
}, "Check if the button element is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testButton", "lbl4");
|
||||
}, "Check if the button element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl5").control, null, "An input element in hidden state should not be labelable.");
|
||||
}, "Check if the hidden input element is not a labelable element.");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testHidden", null);
|
||||
}, "Check if the hidden input element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl6").control.id, "testRadio", "An input element in radio state should be labelable.");
|
||||
}, "Check if the input element in radio state is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testRadio", "lbl6");
|
||||
}, "Check if the input element in radio state can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl7").control.id, "testkeygen", "A keygen element should be labelable.");
|
||||
}, "Check if the keygen element is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testkeygen", "lbl7");
|
||||
}, "Check if the keygen element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl8").control.id, "testmeter", "A meter element should be labelable.");
|
||||
}, "Check if the meter element is a labelable element");
|
||||
|
||||
test(function() {
|
||||
testLabelsAttr("testmeter", "lbl8");
|
||||
}, "Check if the meter element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_not_equals(document.getElementById("lbl9").control, document.getElementById("testfieldset"));
|
||||
assert_equals(document.getElementById("lbl9").control, null, "A fieldset element should not be labelable.");
|
||||
}, "Check if the fieldset element is not a labelable element");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("testfieldset").labels, undefined);
|
||||
}, "Check if the fieldset element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_not_equals(document.getElementById("lbl9").control, document.getElementById("testlabel"));
|
||||
assert_equals(document.getElementById("lbl10").control, null, "A label element should not be labelable.");
|
||||
}, "Check if the label element is not a labelable element");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("testlabel").labels, undefined);
|
||||
}, "Check if the label element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_not_equals(document.getElementById("lbl9").control, document.getElementById("testobject"));
|
||||
assert_equals(document.getElementById("lbl11").control, null, "An object element should not be labelable.");
|
||||
}, "Check if the object element is not a labelable element");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("testobject").labels, undefined);
|
||||
}, "Check if the object element can access 'labels'");
|
||||
|
||||
test(function() {
|
||||
assert_not_equals(document.getElementById("lbl9").control, document.getElementById("testimg"));
|
||||
assert_equals(document.getElementById("lbl12").control, null, "An img element should not be labelable.");
|
||||
}, "Check if the img element is not a labelable element");
|
||||
|
||||
test(function() {
|
||||
assert_equals(document.getElementById("lbl9").labels, undefined);
|
||||
}, "Check if the img element can access 'labels'");
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue