summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-02-15 18:37:33 +0100
committerAndreas Kling <kling@serenityos.org>2022-02-15 23:24:41 +0100
commitf318045a8fa04126d378ecf214f00088113b2808 (patch)
treec171cfd6c7981006db270b5ee47dc1104fb6702e /Userland/Libraries/LibWeb
parent1a323ec8d4e493177e6e4ace995357d86b7016a2 (diff)
downloadserenity-f318045a8fa04126d378ecf214f00088113b2808.zip
LibWeb: Support implicit <label> targets
We already supported "<input id=id><label for=id>". This patch implements the other labeling mode, where the first labelable descendant of the <label> element becomes the labeled control.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/Layout/Label.cpp45
-rw-r--r--Userland/Libraries/LibWeb/Layout/Label.h2
2 files changed, 28 insertions, 19 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/Label.cpp b/Userland/Libraries/LibWeb/Layout/Label.cpp
index 3de1f37dbf..07e5578d14 100644
--- a/Userland/Libraries/LibWeb/Layout/Label.cpp
+++ b/Userland/Libraries/LibWeb/Layout/Label.cpp
@@ -31,7 +31,7 @@ void Label::handle_mousedown_on_label(Badge<TextNode>, const Gfx::IntPoint&, uns
if (button != GUI::MouseButton::Primary)
return;
- if (auto* control = control_node(); control)
+ if (auto* control = labeled_control(); control)
control->handle_associated_label_mousedown({});
m_tracking_mouse = true;
@@ -45,7 +45,7 @@ void Label::handle_mouseup_on_label(Badge<TextNode>, const Gfx::IntPoint& positi
// NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node.
NonnullRefPtr protect = *this;
- if (auto* control = control_node(); control) {
+ if (auto* control = labeled_control(); control) {
bool is_inside_control = enclosing_int_rect(control->absolute_rect()).contains(position);
bool is_inside_label = enclosing_int_rect(absolute_rect()).contains(position);
@@ -61,7 +61,7 @@ void Label::handle_mousemove_on_label(Badge<TextNode>, const Gfx::IntPoint& posi
if (!m_tracking_mouse)
return;
- if (auto* control = control_node(); control) {
+ if (auto* control = labeled_control(); control) {
bool is_inside_control = enclosing_int_rect(control->absolute_rect()).contains(position);
bool is_inside_label = enclosing_int_rect(absolute_rect()).contains(position);
@@ -113,27 +113,36 @@ Label* Label::label_for_control_node(LabelableNode& control)
return label;
}
-LabelableNode* Label::control_node()
+// https://html.spec.whatwg.org/multipage/forms.html#labeled-control
+LabelableNode* Label::labeled_control()
{
- LabelableNode* control = nullptr;
-
if (!document().layout_node())
- return control;
+ return nullptr;
- String for_ = dom_node().for_();
- if (for_.is_empty())
+ LabelableNode* control = nullptr;
+
+ // 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 for_ = dom_node().for_(); !for_.is_null()) {
+ document().layout_node()->for_each_in_inclusive_subtree_of_type<LabelableNode>([&](auto& node) {
+ if (node.dom_node().attribute(HTML::AttributeNames::id) == for_) {
+ control = &node;
+ return IterationDecision::Break;
+ }
+ return IterationDecision::Continue;
+ });
return control;
+ }
- document().layout_node()->for_each_in_inclusive_subtree_of_type<LabelableNode>([&](auto& node) {
- if (node.dom_node().attribute(HTML::AttributeNames::id) == for_) {
- control = &node;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
+ // 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.
+ for_each_in_subtree_of_type<LabelableNode>([&](auto& labelable_node) {
+ control = &labelable_node;
+ return IterationDecision::Break;
});
-
- // FIXME: The spec also allows for associating a label with a labelable node by putting the
- // labelable node inside the label.
return control;
}
diff --git a/Userland/Libraries/LibWeb/Layout/Label.h b/Userland/Libraries/LibWeb/Layout/Label.h
index e79a3a6537..620365223c 100644
--- a/Userland/Libraries/LibWeb/Layout/Label.h
+++ b/Userland/Libraries/LibWeb/Layout/Label.h
@@ -30,7 +30,7 @@ private:
virtual bool is_label() const override { return true; }
static Label* label_for_control_node(LabelableNode&);
- LabelableNode* control_node();
+ LabelableNode* labeled_control();
bool m_tracking_mouse { false };
};