mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 04:13:11 +00:00
LibWeb: Implement reverse lookup to labels from their labelable nodes
This enables, for example, clicking on the check box, dragging the mouse over to the label, releasing the mouse to act as a click on the check box. This was implemented for labels / labelable nodes with the "for" attribute already. This implements the same for labelable nodes that are inside the label.
This commit is contained in:
parent
4b85866746
commit
4f19deb13b
|
@ -1,12 +1,29 @@
|
|||
<html>
|
||||
<input id=foo type=checkbox>
|
||||
<label for=foo>This is a checkbox</label>
|
||||
<pre id=bar></pre>
|
||||
<label for=foo>Checkbox 1 (with a "for" attribute)</label>
|
||||
<pre id=foo-status></pre>
|
||||
|
||||
<label>
|
||||
<input id=bar type=checkbox>
|
||||
Checkbox 2 (inside a label element)
|
||||
</label>
|
||||
<pre id=bar-status></pre>
|
||||
|
||||
<script>
|
||||
var foo = document.getElementById("foo");
|
||||
var fooStatus = document.getElementById("foo-status");
|
||||
fooStatus.innerHTML = `Checkbox 1: ${foo.checked}\n`;
|
||||
|
||||
var bar = document.getElementById("bar");
|
||||
var barStatus = document.getElementById("bar-status");
|
||||
barStatus.innerHTML = `Checkbox 2: ${bar.checked}\n`;
|
||||
|
||||
foo.addEventListener("change", function() {
|
||||
bar.innerHTML += foo.checked + "\n";
|
||||
fooStatus.innerHTML = `Checkbox 1: ${foo.checked}\n`;
|
||||
});
|
||||
|
||||
bar.addEventListener("change", function() {
|
||||
barStatus.innerHTML = `Checkbox 2: ${bar.checked}\n`;
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
|
|
|
@ -89,16 +89,19 @@ bool Label::is_associated_label_hovered(LabelableNode& control)
|
|||
return false;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#labeled-control
|
||||
Label* Label::label_for_control_node(LabelableNode& control)
|
||||
{
|
||||
Label* label = nullptr;
|
||||
|
||||
if (!control.document().layout_node())
|
||||
return label;
|
||||
return nullptr;
|
||||
|
||||
String id = control.dom_node().attribute(HTML::AttributeNames::id);
|
||||
if (id.is_empty())
|
||||
return label;
|
||||
// The for attribute may be specified to indicate a form control with which the caption is to be associated.
|
||||
// If the attribute is specified, the attribute's value must be the ID of a labelable element in the
|
||||
// same tree as the label element. If the attribute is specified and there is an element in the tree
|
||||
// whose ID is equal to the value of the for attribute, and the first such element in tree order is
|
||||
// a labelable element, then that element is the label element's labeled control.
|
||||
if (auto id = control.dom_node().attribute(HTML::AttributeNames::id); !id.is_empty()) {
|
||||
Label* label = nullptr;
|
||||
|
||||
control.document().layout_node()->for_each_in_inclusive_subtree_of_type<Label>([&](auto& node) {
|
||||
if (node.dom_node().for_() == id) {
|
||||
|
@ -108,11 +111,15 @@ Label* Label::label_for_control_node(LabelableNode& control)
|
|||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
// FIXME: The spec also allows for associating a label with a labelable node by putting the
|
||||
// labelable node inside the label.
|
||||
if (label)
|
||||
return label;
|
||||
}
|
||||
|
||||
// If the for attribute is not specified, but the label element has a labelable element descendant,
|
||||
// then the first such descendant in tree order is the label element's labeled control.
|
||||
return control.first_ancestor_of_type<Label>();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#labeled-control
|
||||
LabelableNode* Label::labeled_control()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue