diff --git a/Base/res/html/misc/events.html b/Base/res/html/misc/events.html index 47754874a0..d26f8d5245 100644 --- a/Base/res/html/misc/events.html +++ b/Base/res/html/misc/events.html @@ -16,5 +16,33 @@
Hello there!
+ +
+ CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK + ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME + CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME CLICK ME +
+

This text should be green, whether you click on the div border or the div text.

+

+ +

diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index 24166b3fb0..f5a098b6ee 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -190,7 +190,21 @@ bool EventHandler::handle_mouseup(Gfx::IntPoint const& position, unsigned button return nested_browsing_context->event_handler().handle_mouseup(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), button, modifiers); return false; } - auto offset = compute_mouse_event_offset(position, paintable->layout_node()); + + // Search for the first parent of the hit target that's an element. + // "The click event type MUST be dispatched on the topmost event target indicated by the pointer." (https://www.w3.org/TR/uievents/#event-type-click) + // "The topmost event target MUST be the element highest in the rendering order which is capable of being an event target." (https://www.w3.org/TR/uievents/#topmost-event-target) + auto* layout_node = &paintable->layout_node(); + while (layout_node && node && !node->is_element() && layout_node->parent()) { + layout_node = layout_node->parent(); + node = layout_node->dom_node(); + } + if (!node || !layout_node) { + // FIXME: This is pretty ugly but we need to bail out here. + goto after_node_use; + } + + auto offset = compute_mouse_event_offset(position, *layout_node); node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::mouseup, offset.x(), offset.y(), position.x(), position.y(), button)); handled_event = true; @@ -251,6 +265,7 @@ bool EventHandler::handle_mouseup(Gfx::IntPoint const& position, unsigned button } } +after_node_use: if (button == GUI::MouseButton::Primary) m_in_mouse_selection = false; return handled_event; @@ -306,8 +321,19 @@ bool EventHandler::handle_mousedown(Gfx::IntPoint const& position, unsigned butt if (auto* page = m_browsing_context.page()) page->set_focused_browsing_context({}, m_browsing_context); + // Search for the first parent of the hit target that's an element. + // "The click event type MUST be dispatched on the topmost event target indicated by the pointer." (https://www.w3.org/TR/uievents/#event-type-click) + // "The topmost event target MUST be the element highest in the rendering order which is capable of being an event target." (https://www.w3.org/TR/uievents/#topmost-event-target) + auto* layout_node = &paintable->layout_node(); + while (layout_node && node && !node->is_element() && layout_node->parent()) { + layout_node = layout_node->parent(); + node = layout_node->dom_node(); + } + if (!node || !layout_node) + return false; + m_mousedown_target = node; - auto offset = compute_mouse_event_offset(position, paintable->layout_node()); + auto offset = compute_mouse_event_offset(position, *layout_node); node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::mousedown, offset.x(), offset.y(), position.x(), position.y(), button)); } @@ -415,12 +441,26 @@ bool EventHandler::handle_mousemove(Gfx::IntPoint const& position, unsigned butt hovered_node_cursor = cursor_css_to_gfx(cursor); } - auto offset = compute_mouse_event_offset(position, paintable->layout_node()); + // Search for the first parent of the hit target that's an element. + // "The click event type MUST be dispatched on the topmost event target indicated by the pointer." (https://www.w3.org/TR/uievents/#event-type-click) + // "The topmost event target MUST be the element highest in the rendering order which is capable of being an event target." (https://www.w3.org/TR/uievents/#topmost-event-target) + auto* layout_node = &paintable->layout_node(); + while (layout_node && node && !node->is_element() && layout_node->parent()) { + layout_node = layout_node->parent(); + node = layout_node->dom_node(); + } + if (!node || !layout_node) { + // FIXME: This is pretty ugly but we need to bail out here. + goto after_node_use; + } + + auto offset = compute_mouse_event_offset(position, *layout_node); node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::mousemove, offset.x(), offset.y(), position.x(), position.y())); // NOTE: Dispatching an event may have disturbed the world. if (!paint_root() || paint_root() != node->document().paint_box()) return true; } + after_node_use: if (m_in_mouse_selection) { auto hit = paint_root()->hit_test(position.to_type(), Painting::HitTestType::TextCursor); if (start_index.has_value() && hit.has_value() && hit->dom_node()) {