LibWeb: Dispatch mouseenter events from ancestors to descendents

This is the opposite order to mouseleave and pointerleave events.
This commit is contained in:
Tim Ledbetter 2026-01-24 01:05:25 +00:00 committed by Tim Ledbetter
parent aafaec36ee
commit e4f37293fc
2 changed files with 8 additions and 4 deletions

View file

@ -2119,7 +2119,6 @@ void Document::set_hovered_node(GC::Ptr<Node> node)
// https://w3c.github.io/uievents/#mouseleave
if (old_hovered_node && (!m_hovered_node || !m_hovered_node->is_descendant_of(*old_hovered_node))) {
// FIXME: Check if we need to dispatch these events in a specific order.
for (auto target = old_hovered_node; target && target.ptr() != common_ancestor; target = target->parent()) {
// FIXME: Populate the event with mouse coordinates, etc.
UIEvents::MouseEventInit mouse_event_init {};
@ -2142,9 +2141,14 @@ void Document::set_hovered_node(GC::Ptr<Node> node)
}
// https://w3c.github.io/uievents/#mouseenter
// Enter events are dispatched from ancestor to descendant.
// Leave events are dispatched in the opposite order.
if (m_hovered_node && (!old_hovered_node || !m_hovered_node->is_ancestor_of(*old_hovered_node))) {
// FIXME: Check if we need to dispatch these events in a specific order.
for (auto target = m_hovered_node; target && target.ptr() != common_ancestor; target = target->parent()) {
Vector<GC::Ref<Node>> entered_ancestors;
for (auto target = m_hovered_node; target && target.ptr() != common_ancestor; target = target->parent())
entered_ancestors.append(*target);
for (auto target : entered_ancestors.in_reverse()) {
// FIXME: Populate the event with mouse coordinates, etc.
UIEvents::MouseEventInit mouse_event_init {};
mouse_event_init.related_target = old_hovered_node;

View file

@ -1,8 +1,8 @@
> move pointer over #inner
mouseover target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(body)
mouseover target.id=(inner) currentTarget.id=(outer), relatedTarget.id=(body)
mouseenter target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(body)
mouseenter target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(body)
mouseenter target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(body)
> move pointer over #outer
mouseout target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(outer)
mouseout target.id=(inner) currentTarget.id=(outer), relatedTarget.id=(outer)