mirror of
https://github.com/SerenityOS/serenity
synced 2024-09-06 08:56:40 +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
|
@ -1,13 +1,13 @@
|
|||
> move pointer over #inner
|
||||
mouseover target.id=(inner) currentTarget.id=(inner)
|
||||
mouseover target.id=(inner) currentTarget.id=(outer)
|
||||
mouseenter target.id=(inner) currentTarget.id=(inner)
|
||||
mouseenter target.id=(outer) currentTarget.id=(outer)
|
||||
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)
|
||||
> move pointer over #outer
|
||||
mouseout target.id=(inner) currentTarget.id=(inner)
|
||||
mouseout target.id=(inner) currentTarget.id=(outer)
|
||||
mouseleave target.id=(inner) currentTarget.id=(inner)
|
||||
mouseover target.id=(outer) currentTarget.id=(outer)
|
||||
mouseout target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(outer)
|
||||
mouseout target.id=(inner) currentTarget.id=(outer), relatedTarget.id=(outer)
|
||||
mouseleave target.id=(inner) currentTarget.id=(inner), relatedTarget.id=(outer)
|
||||
mouseover target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(inner)
|
||||
> click document.body
|
||||
mouseout target.id=(outer) currentTarget.id=(outer)
|
||||
mouseleave target.id=(outer) currentTarget.id=(outer)
|
||||
mouseout target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(body)
|
||||
mouseleave target.id=(outer) currentTarget.id=(outer), relatedTarget.id=(body)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
body {
|
||||
margin: 0px;
|
||||
padding: 5px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
#outer {
|
||||
|
@ -17,22 +19,23 @@ body {
|
|||
background-color: magenta;
|
||||
}
|
||||
</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>
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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.onmouseout = handleMouseOut;
|
||||
outer.onmouseenter = handleMouseEnter;
|
||||
|
@ -51,6 +54,8 @@ const clickOnBody = () => {
|
|||
}
|
||||
|
||||
asyncTest(async done => {
|
||||
// First move the mouse outside #outer to populate the MouseEvent.relatedTarget property
|
||||
internals.movePointerTo(150, 150);
|
||||
println("> move pointer over #inner");
|
||||
internals.movePointerTo(10, 10);
|
||||
println("> move pointer over #outer");
|
||||
|
|
|
@ -1337,7 +1337,9 @@ void Document::set_hovered_node(Node* node)
|
|||
|
||||
// https://w3c.github.io/uievents/#mouseout
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1346,13 +1348,17 @@ void Document::set_hovered_node(Node* 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.
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1361,7 +1367,9 @@ void Document::set_hovered_node(Node* 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()) {
|
||||
// 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_button(event_init.button)
|
||||
, m_buttons(event_init.buttons)
|
||||
, m_related_target(event_init.related_target)
|
||||
{
|
||||
set_event_characteristics();
|
||||
}
|
||||
|
@ -57,6 +58,12 @@ void MouseEvent::initialize(JS::Realm& realm)
|
|||
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
|
||||
{
|
||||
if (key_arg == "Control")
|
||||
|
|
|
@ -22,6 +22,7 @@ struct MouseEventInit : public EventModifierInit {
|
|||
double movement_y = 0;
|
||||
i16 button = 0;
|
||||
u16 buttons = 0;
|
||||
JS::GCPtr<DOM::EventTarget> related_target = nullptr;
|
||||
};
|
||||
|
||||
class MouseEvent : public UIEvent {
|
||||
|
@ -61,6 +62,8 @@ public:
|
|||
i16 button() const { return m_button; }
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
virtual bool is_mouse_event() const override { return true; }
|
||||
|
@ -101,6 +105,7 @@ private:
|
|||
double m_movement_y { 0 };
|
||||
i16 m_button { 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 unsigned short buttons;
|
||||
|
||||
[FIXME] readonly attribute EventTarget? relatedTarget;
|
||||
readonly attribute EventTarget? relatedTarget;
|
||||
|
||||
boolean getModifierState(DOMString keyArg);
|
||||
};
|
||||
|
@ -48,5 +48,5 @@ dictionary MouseEventInit : EventModifierInit {
|
|||
|
||||
short button = 0;
|
||||
unsigned short buttons = 0;
|
||||
// FIXME: EventTarget? relatedTarget = null;
|
||||
EventTarget? relatedTarget = null;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue