mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-23 01:38:56 +00:00
LibWeb: Implement the MouseEvent.relatedTarget
attribute
This returns the secondary target of a mouse event. For `onmouseenter` and `onmouseover` events, this is the EventTarget the mouse exited from. For `onmouseleave` and `onmouseout` events, this is the EventTarget the mouse entered to.
This commit is contained in:
parent
ddc622233f
commit
a6d6729034
Notes:
sideshowbarker
2024-07-17 18:49:10 +09:00
Author: https://github.com/tcl3
Commit: a6d6729034
Pull-request: https://github.com/SerenityOS/serenity/pull/24388
6 changed files with 46 additions and 21 deletions
|
@ -1,13 +1,13 @@
|
||||||
> move pointer over #inner
|
> move pointer over #inner
|
||||||
mouseover target.id=(inner) currentTarget.id=(inner)
|
mouseover target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(body)
|
||||||
mouseover target.id=(inner) currentTarget.id=(outer)
|
mouseover target.id=(inner) currentTarget.id=(outer), relatedTarget.id=(body)
|
||||||
mouseenter target.id=(inner) currentTarget.id=(inner)
|
mouseenter target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(body)
|
||||||
mouseenter target.id=(outer) currentTarget.id=(outer)
|
mouseenter target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(body)
|
||||||
> move pointer over #outer
|
> move pointer over #outer
|
||||||
mouseout target.id=(inner) currentTarget.id=(inner)
|
mouseout target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(outer)
|
||||||
mouseout target.id=(inner) currentTarget.id=(outer)
|
mouseout target.id=(inner) currentTarget.id=(outer), relatedTarget.id=(outer)
|
||||||
mouseleave target.id=(inner) currentTarget.id=(inner)
|
mouseleave target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(outer)
|
||||||
mouseover target.id=(outer) currentTarget.id=(outer)
|
mouseover target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(inner)
|
||||||
> click document.body
|
> click document.body
|
||||||
mouseout target.id=(outer) currentTarget.id=(outer)
|
mouseout target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(body)
|
||||||
mouseleave target.id=(outer) currentTarget.id=(outer)
|
mouseleave target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(body)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
body {
|
body {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#outer {
|
#outer {
|
||||||
|
@ -17,22 +19,23 @@ body {
|
||||||
background-color: magenta;
|
background-color: magenta;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div id="outer"><div id="inner"></div></div>
|
<body id="body"><div id="outer"><div id="inner"></div></div></body>
|
||||||
<script src="../include.js"></script>
|
<script src="../include.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function handleMouseOver(e) {
|
function handleMouseOver(e) {
|
||||||
println(`mouseover target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id})`);
|
println(`mouseover target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id}), relatedTarget.id=(${e.relatedTarget.id})`);
|
||||||
}
|
}
|
||||||
function handleMouseOut(e) {
|
function handleMouseOut(e) {
|
||||||
println(`mouseout target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id})`);
|
println(`mouseout target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id}), relatedTarget.id=(${e.relatedTarget.id})`);
|
||||||
}
|
}
|
||||||
function handleMouseEnter(e) {
|
function handleMouseEnter(e) {
|
||||||
println(`mouseenter target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id})`);
|
println(`mouseenter target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id}), relatedTarget.id=(${e.relatedTarget.id})`);
|
||||||
}
|
}
|
||||||
function handleMouseLeave(e) {
|
function handleMouseLeave(e) {
|
||||||
println(`mouseleave target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id})`);
|
println(`mouseleave target.id=(${e.target.id}) currentTarget.id=(${e.currentTarget.id}), relatedTarget.id=(${e.relatedTarget.id})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
outer.onmouseover = handleMouseOver;
|
outer.onmouseover = handleMouseOver;
|
||||||
outer.onmouseout = handleMouseOut;
|
outer.onmouseout = handleMouseOut;
|
||||||
outer.onmouseenter = handleMouseEnter;
|
outer.onmouseenter = handleMouseEnter;
|
||||||
|
@ -51,6 +54,8 @@ const clickOnBody = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
asyncTest(async done => {
|
asyncTest(async done => {
|
||||||
|
// First move the mouse outside #outer to populate the MouseEvent.relatedTarget property
|
||||||
|
internals.movePointerTo(150, 150);
|
||||||
println("> move pointer over #inner");
|
println("> move pointer over #inner");
|
||||||
internals.movePointerTo(10, 10);
|
internals.movePointerTo(10, 10);
|
||||||
println("> move pointer over #outer");
|
println("> move pointer over #outer");
|
||||||
|
|
|
@ -1337,7 +1337,9 @@ void Document::set_hovered_node(Node* node)
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#mouseout
|
// https://w3c.github.io/uievents/#mouseout
|
||||||
if (old_hovered_node && old_hovered_node != m_hovered_node) {
|
if (old_hovered_node && old_hovered_node != m_hovered_node) {
|
||||||
auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseout);
|
UIEvents::MouseEventInit mouse_event_init {};
|
||||||
|
mouse_event_init.related_target = m_hovered_node;
|
||||||
|
auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseout, mouse_event_init);
|
||||||
old_hovered_node->dispatch_event(event);
|
old_hovered_node->dispatch_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1346,13 +1348,17 @@ void Document::set_hovered_node(Node* node)
|
||||||
// FIXME: Check if we need to dispatch these events in a specific order.
|
// 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()) {
|
for (auto target = old_hovered_node; target && target.ptr() != common_ancestor; target = target->parent()) {
|
||||||
// FIXME: Populate the event with mouse coordinates, etc.
|
// FIXME: Populate the event with mouse coordinates, etc.
|
||||||
target->dispatch_event(UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseleave));
|
UIEvents::MouseEventInit mouse_event_init {};
|
||||||
|
mouse_event_init.related_target = m_hovered_node;
|
||||||
|
target->dispatch_event(UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseleave, mouse_event_init));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#mouseover
|
// https://w3c.github.io/uievents/#mouseover
|
||||||
if (m_hovered_node && m_hovered_node != old_hovered_node) {
|
if (m_hovered_node && m_hovered_node != old_hovered_node) {
|
||||||
auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseover);
|
UIEvents::MouseEventInit mouse_event_init {};
|
||||||
|
mouse_event_init.related_target = old_hovered_node;
|
||||||
|
auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseover, mouse_event_init);
|
||||||
m_hovered_node->dispatch_event(event);
|
m_hovered_node->dispatch_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1361,7 +1367,9 @@ void Document::set_hovered_node(Node* node)
|
||||||
// FIXME: Check if we need to dispatch these events in a specific order.
|
// 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()) {
|
for (auto target = m_hovered_node; target && target.ptr() != common_ancestor; target = target->parent()) {
|
||||||
// FIXME: Populate the event with mouse coordinates, etc.
|
// FIXME: Populate the event with mouse coordinates, etc.
|
||||||
target->dispatch_event(UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseenter));
|
UIEvents::MouseEventInit mouse_event_init {};
|
||||||
|
mouse_event_init.related_target = old_hovered_node;
|
||||||
|
target->dispatch_event(UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseenter, mouse_event_init));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ MouseEvent::MouseEvent(JS::Realm& realm, FlyString const& event_name, MouseEvent
|
||||||
, m_movement_y(event_init.movement_y)
|
, m_movement_y(event_init.movement_y)
|
||||||
, m_button(event_init.button)
|
, m_button(event_init.button)
|
||||||
, m_buttons(event_init.buttons)
|
, m_buttons(event_init.buttons)
|
||||||
|
, m_related_target(event_init.related_target)
|
||||||
{
|
{
|
||||||
set_event_characteristics();
|
set_event_characteristics();
|
||||||
}
|
}
|
||||||
|
@ -57,6 +58,12 @@ void MouseEvent::initialize(JS::Realm& realm)
|
||||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(MouseEvent);
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(MouseEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MouseEvent::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_related_target);
|
||||||
|
}
|
||||||
|
|
||||||
bool MouseEvent::get_modifier_state(String const& key_arg) const
|
bool MouseEvent::get_modifier_state(String const& key_arg) const
|
||||||
{
|
{
|
||||||
if (key_arg == "Control")
|
if (key_arg == "Control")
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct MouseEventInit : public EventModifierInit {
|
||||||
double movement_y = 0;
|
double movement_y = 0;
|
||||||
i16 button = 0;
|
i16 button = 0;
|
||||||
u16 buttons = 0;
|
u16 buttons = 0;
|
||||||
|
JS::GCPtr<DOM::EventTarget> related_target = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MouseEvent : public UIEvent {
|
class MouseEvent : public UIEvent {
|
||||||
|
@ -61,6 +62,8 @@ public:
|
||||||
i16 button() const { return m_button; }
|
i16 button() const { return m_button; }
|
||||||
u16 buttons() const { return m_buttons; }
|
u16 buttons() const { return m_buttons; }
|
||||||
|
|
||||||
|
JS::GCPtr<DOM::EventTarget> related_target() const { return m_related_target; }
|
||||||
|
|
||||||
bool get_modifier_state(String const& key_arg) const;
|
bool get_modifier_state(String const& key_arg) const;
|
||||||
|
|
||||||
virtual u32 which() const override { return m_button + 1; }
|
virtual u32 which() const override { return m_button + 1; }
|
||||||
|
@ -69,6 +72,7 @@ protected:
|
||||||
MouseEvent(JS::Realm&, FlyString const& event_name, MouseEventInit const& event_init, double page_x, double page_y, double offset_x, double offset_y);
|
MouseEvent(JS::Realm&, FlyString const& event_name, MouseEventInit const& event_init, double page_x, double page_y, double offset_x, double offset_y);
|
||||||
|
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool is_mouse_event() const override { return true; }
|
virtual bool is_mouse_event() const override { return true; }
|
||||||
|
@ -101,6 +105,7 @@ private:
|
||||||
double m_movement_y { 0 };
|
double m_movement_y { 0 };
|
||||||
i16 m_button { 0 };
|
i16 m_button { 0 };
|
||||||
u16 m_buttons { 0 };
|
u16 m_buttons { 0 };
|
||||||
|
JS::GCPtr<DOM::EventTarget> m_related_target { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ interface MouseEvent : UIEvent {
|
||||||
readonly attribute short button;
|
readonly attribute short button;
|
||||||
readonly attribute unsigned short buttons;
|
readonly attribute unsigned short buttons;
|
||||||
|
|
||||||
[FIXME] readonly attribute EventTarget? relatedTarget;
|
readonly attribute EventTarget? relatedTarget;
|
||||||
|
|
||||||
boolean getModifierState(DOMString keyArg);
|
boolean getModifierState(DOMString keyArg);
|
||||||
};
|
};
|
||||||
|
@ -48,5 +48,5 @@ dictionary MouseEventInit : EventModifierInit {
|
||||||
|
|
||||||
short button = 0;
|
short button = 0;
|
||||||
unsigned short buttons = 0;
|
unsigned short buttons = 0;
|
||||||
// FIXME: EventTarget? relatedTarget = null;
|
EventTarget? relatedTarget = null;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue