From e4d3a9aa68e4b1ca21d49b4bae469543a81c635a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 5 Sep 2023 15:15:28 -0400 Subject: [PATCH] LibWeb: Ensure DOM events on slottables are properly propagated Most events on a slottable are composed, meaning they propagate from the slottable and through its shadow tree before bubbling up to the parent of the slottable. --- .../Libraries/LibWeb/DOM/EventDispatcher.cpp | 33 +++++++++++++++---- Userland/Libraries/LibWeb/DOM/Node.cpp | 6 +++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp b/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp index 2599966bfc..f2e425762c 100644 --- a/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp @@ -10,13 +10,17 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include +#include #include #include #include @@ -241,7 +245,11 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr target, Event& even if (is_activation_event && target->activation_behavior) activation_target = target; - // FIXME: 6. Let slottable be target, if target is a slottable and is assigned, and null otherwise. + // 6. Let slottable be target, if target is a slottable and is assigned, and null otherwise. + JS::GCPtr slottable; + + if (is(*target) && is_an_assigned_slottable(static_cast(*target))) + slottable = target; // 7. Let slot-in-closed-tree be false bool slot_in_closed_tree = false; @@ -251,11 +259,24 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr target, Event& even // 9. While parent is non-null: while (parent) { - // FIXME: 1. If slottable is non-null: - // 1. Assert: parent is a slot. - // 2. Set slottable to null. - // 3. If parent’s root is a shadow root whose mode is "closed", then set slot-in-closed-tree to true. - // FIXME: 2. If parent is a slottable and is assigned, then set slottable to parent. + // 1. If slottable is non-null: + if (slottable != nullptr) { + // 1. Assert: parent is a slot. + VERIFY(is(parent)); + + // 2. Set slottable to null. + slottable = nullptr; + + // 3. If parent’s root is a shadow root whose mode is "closed", then set slot-in-closed-tree to true. + auto& parent_root = static_cast(*parent).root(); + + if (parent_root.is_shadow_root() && static_cast(parent_root).mode() == Bindings::ShadowRootMode::Closed) + slot_in_closed_tree = true; + } + + // 2. If parent is a slottable and is assigned, then set slottable to parent. + if (is(*parent) && is_an_assigned_slottable(static_cast(*parent))) + slottable = parent; // 3. Let relatedTarget be the result of retargeting event’s relatedTarget against parent. related_target = retarget(event.related_target(), parent); diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index f6ae00829e..d99a7a1a62 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -929,7 +929,11 @@ void Node::detach_layout_node(Badge) EventTarget* Node::get_parent(Event const&) { - // FIXME: returns the node’s assigned slot, if node is assigned, and node’s parent otherwise. + // A node’s get the parent algorithm, given an event, returns the node’s assigned slot, if node is assigned; + // otherwise node’s parent. + if (auto assigned_slot = assigned_slot_for_node(*this)) + return assigned_slot.ptr(); + return parent(); }