diff options
author | Andreas Kling <kling@serenityos.org> | 2022-02-15 18:37:33 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-15 23:24:41 +0100 |
commit | f318045a8fa04126d378ecf214f00088113b2808 (patch) | |
tree | c171cfd6c7981006db270b5ee47dc1104fb6702e /Userland/Libraries/LibWeb | |
parent | 1a323ec8d4e493177e6e4ace995357d86b7016a2 (diff) | |
download | serenity-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.cpp | 45 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/Label.h | 2 |
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 }; }; |