diff --git a/Userland/Libraries/LibWeb/HTML/HTMLButtonElement.h b/Userland/Libraries/LibWeb/HTML/HTMLButtonElement.h index 1f7c0f27aeb..c18b443e3a7 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLButtonElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLButtonElement.h @@ -70,6 +70,8 @@ public: virtual bool has_activation_behavior() const override; virtual void activation_behavior(DOM::Event const&) override; + virtual bool is_child_node_selectable(DOM::Node const&) const override { return false; } + private: virtual bool is_html_button_element() const override { return true; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.h b/Userland/Libraries/LibWeb/HTML/HTMLElement.h index 230c7d85ede..f48c90c571e 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.h @@ -80,6 +80,8 @@ public: WebIDL::ExceptionOr set_popover(Optional value); Optional popover() const; + virtual bool is_child_node_selectable(DOM::Node const&) const { return true; } + protected: HTMLElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 23e5a3143b0..62762cce04c 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -2368,4 +2368,9 @@ HTMLInputElement::ValueAttributeMode HTMLInputElement::value_attribute_mode() co VERIFY_NOT_REACHED(); } +bool HTMLInputElement::is_child_node_selectable(DOM::Node const& node) const +{ + return !is_button() && (!m_placeholder_element || !m_placeholder_element->is_inclusive_ancestor_of(node)); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index 28a1569a50b..88978e1a80b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -204,6 +204,8 @@ public: WebIDL::ExceptionOr set_selection_end_for_bindings(Optional const&); Optional selection_end_for_bindings() const; + virtual bool is_child_node_selectable(DOM::Node const&) const override; + private: HTMLInputElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index d29cbf9372d..c5746e876fa 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -449,9 +449,19 @@ bool EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSPixelPoi HTML::run_unfocusing_steps(focused_element); } - // If we didn't focus anything, place the document text cursor at the mouse position. - // FIXME: This is all rather strange. Find a better solution. - if (!did_focus_something || dom_node->is_editable()) { + // Ask the next non-shadow parent element whether the node at the mouse position is selectable. + auto& root_node = dom_node->root(); + DOM::Element* non_shadow_parent_element; + if (root_node.is_shadow_root()) + non_shadow_parent_element = root_node.parent_or_shadow_host_element(); + else + non_shadow_parent_element = dom_node->parent_element(); + bool is_selectable = true; + if (non_shadow_parent_element && non_shadow_parent_element->is_html_element()) + is_selectable = static_cast(non_shadow_parent_element)->is_child_node_selectable(*dom_node); + + // If it is selectable, place the document text cursor at the mouse position. + if (is_selectable) { auto& realm = document->realm(); document->set_cursor_position(DOM::Position::create(realm, *dom_node, result->index_in_node)); if (auto selection = document->get_selection()) {