LibWeb: Ensure UIEventInit.view is set for mouse and pointer events

This commit is contained in:
Tim Ledbetter 2025-08-20 00:59:03 +01:00 committed by Jelle Raaijmakers
commit 83b1ead1e7
Notes: github-actions[bot] 2025-08-20 07:14:35 +00:00
10 changed files with 81 additions and 18 deletions

View file

@ -1908,6 +1908,8 @@ void Document::set_hovered_node(GC::Ptr<Node> node)
mouse_event_init.cancelable = true; mouse_event_init.cancelable = true;
mouse_event_init.composed = true; mouse_event_init.composed = true;
mouse_event_init.related_target = m_hovered_node; mouse_event_init.related_target = m_hovered_node;
if (auto navigable = this->navigable())
mouse_event_init.view = navigable->active_window_proxy();
auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseout, mouse_event_init); auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseout, mouse_event_init);
old_hovered_node->dispatch_event(event); old_hovered_node->dispatch_event(event);
} }
@ -1930,6 +1932,8 @@ void Document::set_hovered_node(GC::Ptr<Node> node)
mouse_event_init.cancelable = true; mouse_event_init.cancelable = true;
mouse_event_init.composed = true; mouse_event_init.composed = true;
mouse_event_init.related_target = old_hovered_node; mouse_event_init.related_target = old_hovered_node;
if (auto navigable = this->navigable())
mouse_event_init.view = navigable->active_window_proxy();
auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseover, mouse_event_init); auto event = UIEvents::MouseEvent::create(realm(), UIEvents::EventNames::mouseover, mouse_event_init);
m_hovered_node->dispatch_event(event); m_hovered_node->dispatch_event(event);
} }

View file

@ -433,7 +433,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
auto page_offset = compute_mouse_event_page_offset(viewport_position); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable());
if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::wheel, screen_position, page_offset, viewport_position, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) { if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::wheel, screen_position, page_offset, viewport_position, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) {
m_navigable->active_window()->scroll_by(wheel_delta_x, wheel_delta_y); m_navigable->active_window()->scroll_by(wheel_delta_x, wheel_delta_y);
} }
@ -498,22 +498,22 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
auto page_offset = compute_mouse_event_page_offset(viewport_position); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable());
auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::pointerup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors(); auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::pointerup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors();
light_dismiss_activities(pointer_event, node); light_dismiss_activities(pointer_event, node);
node->dispatch_event(pointer_event); node->dispatch_event(pointer_event);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::mouseup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
handled_event = EventResult::Handled; handled_event = EventResult::Handled;
bool run_activation_behavior = false; bool run_activation_behavior = false;
if (node.ptr() == m_mousedown_target) { if (node.ptr() == m_mousedown_target) {
if (button == UIEvents::MouseButton::Primary) { if (button == UIEvents::MouseButton::Primary) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} else if (button == UIEvents::MouseButton::Middle) { } else if (button == UIEvents::MouseButton::Middle) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::auxclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::auxclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} else if (button == UIEvents::MouseButton::Secondary) { } else if (button == UIEvents::MouseButton::Secondary) {
// Allow the user to bypass custom context menus by holding shift, like Firefox. // Allow the user to bypass custom context menus by holding shift, like Firefox.
if ((modifiers & UIEvents::Mod_Shift) == 0) if ((modifiers & UIEvents::Mod_Shift) == 0)
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
else else
run_activation_behavior = true; run_activation_behavior = true;
} }
@ -576,7 +576,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (auto input_control = input_control_associated_with_ancestor_label_element(*paintable)) { if (auto input_control = input_control_associated_with_ancestor_label_element(*paintable)) {
if (button == UIEvents::MouseButton::Primary && input_control != node) { if (button == UIEvents::MouseButton::Primary && input_control != node) {
input_control->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); input_control->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} }
} }
} }
@ -651,10 +651,10 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
m_mousedown_target = node.ptr(); m_mousedown_target = node.ptr();
auto page_offset = compute_mouse_event_page_offset(viewport_position); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable());
auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::pointerdown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors(); auto pointer_event = UIEvents::PointerEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::pointerdown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors();
light_dismiss_activities(pointer_event, node); light_dismiss_activities(pointer_event, node);
node->dispatch_event(pointer_event); node->dispatch_event(pointer_event);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::mousedown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} }
// NOTE: Dispatching an event may have disturbed the world. // NOTE: Dispatching an event may have disturbed the world.
@ -802,10 +802,10 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
m_mousemove_previous_screen_position = screen_position; m_mousemove_previous_screen_position = screen_position;
bool continue_ = node->dispatch_event(UIEvents::PointerEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::pointermove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); bool continue_ = node->dispatch_event(UIEvents::PointerEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::pointermove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
if (!continue_) if (!continue_)
return EventResult::Cancelled; return EventResult::Cancelled;
continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::mousemove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
if (!continue_) if (!continue_)
return EventResult::Cancelled; return EventResult::Cancelled;
@ -959,7 +959,7 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
auto page_offset = compute_mouse_event_page_offset(viewport_position); auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable()); auto offset = compute_mouse_event_offset(page_offset, *layout_node->first_paintable());
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors()); node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), m_navigable->active_window_proxy(), UIEvents::EventNames::dblclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
// NOTE: Dispatching an event may have disturbed the world. // NOTE: Dispatching an event may have disturbed the world.
if (!paint_root() || paint_root() != node->document().paintable_box()) if (!paint_root() || paint_root() != node->document().paintable_box())

View file

@ -133,7 +133,7 @@ WebIDL::ExceptionOr<GC::Ref<MouseEvent>> MouseEvent::construct_impl(JS::Realm& r
return create(realm, event_name, event_init); return create(realm, event_name, event_init);
} }
WebIDL::ExceptionOr<GC::Ref<MouseEvent>> MouseEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers) WebIDL::ExceptionOr<GC::Ref<MouseEvent>> MouseEvent::create_from_platform_event(JS::Realm& realm, GC::Ptr<HTML::WindowProxy> window_proxy, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers)
{ {
MouseEventInit event_init {}; MouseEventInit event_init {};
event_init.ctrl_key = modifiers & Mod_Ctrl; event_init.ctrl_key = modifiers & Mod_Ctrl;
@ -144,6 +144,7 @@ WebIDL::ExceptionOr<GC::Ref<MouseEvent>> MouseEvent::create_from_platform_event(
event_init.screen_y = screen.y().to_double(); event_init.screen_y = screen.y().to_double();
event_init.client_x = client.x().to_double(); event_init.client_x = client.x().to_double();
event_init.client_y = client.y().to_double(); event_init.client_y = client.y().to_double();
event_init.view = window_proxy;
if (movement.has_value()) { if (movement.has_value()) {
event_init.movement_x = movement.value().x().to_double(); event_init.movement_x = movement.value().x().to_double();
event_init.movement_y = movement.value().y().to_double(); event_init.movement_y = movement.value().y().to_double();

View file

@ -31,7 +31,7 @@ class MouseEvent : public UIEvent {
public: public:
[[nodiscard]] static GC::Ref<MouseEvent> create(JS::Realm&, FlyString const& event_name, MouseEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); [[nodiscard]] static GC::Ref<MouseEvent> create(JS::Realm&, FlyString const& event_name, MouseEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0);
static WebIDL::ExceptionOr<GC::Ref<MouseEvent>> create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers); static WebIDL::ExceptionOr<GC::Ref<MouseEvent>> create_from_platform_event(JS::Realm&, GC::Ptr<HTML::WindowProxy>, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers);
static WebIDL::ExceptionOr<GC::Ref<MouseEvent>> construct_impl(JS::Realm&, FlyString const& event_name, MouseEventInit const&); static WebIDL::ExceptionOr<GC::Ref<MouseEvent>> construct_impl(JS::Realm&, FlyString const& event_name, MouseEventInit const&);
virtual ~MouseEvent() override; virtual ~MouseEvent() override;

View file

@ -11,7 +11,7 @@ namespace Web::UIEvents {
GC_DEFINE_ALLOCATOR(PointerEvent); GC_DEFINE_ALLOCATOR(PointerEvent);
WebIDL::ExceptionOr<GC::Ref<PointerEvent>> PointerEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers) WebIDL::ExceptionOr<GC::Ref<PointerEvent>> PointerEvent::create_from_platform_event(JS::Realm& realm, GC::Ptr<HTML::WindowProxy> window_proxy, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers)
{ {
PointerEventInit event_init {}; PointerEventInit event_init {};
event_init.ctrl_key = modifiers & Mod_Ctrl; event_init.ctrl_key = modifiers & Mod_Ctrl;
@ -22,6 +22,7 @@ WebIDL::ExceptionOr<GC::Ref<PointerEvent>> PointerEvent::create_from_platform_ev
event_init.screen_y = screen.y().to_double(); event_init.screen_y = screen.y().to_double();
event_init.client_x = client.x().to_double(); event_init.client_x = client.x().to_double();
event_init.client_y = client.y().to_double(); event_init.client_y = client.y().to_double();
event_init.view = window_proxy;
if (movement.has_value()) { if (movement.has_value()) {
event_init.movement_x = movement.value().x().to_double(); event_init.movement_x = movement.value().x().to_double();
event_init.movement_y = movement.value().y().to_double(); event_init.movement_y = movement.value().y().to_double();

View file

@ -36,7 +36,7 @@ class PointerEvent : public MouseEvent {
public: public:
[[nodiscard]] static GC::Ref<PointerEvent> create(JS::Realm&, FlyString const& type, PointerEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); [[nodiscard]] static GC::Ref<PointerEvent> create(JS::Realm&, FlyString const& type, PointerEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0);
[[nodiscard]] static WebIDL::ExceptionOr<GC::Ref<PointerEvent>> create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers); [[nodiscard]] static WebIDL::ExceptionOr<GC::Ref<PointerEvent>> create_from_platform_event(JS::Realm&, GC::Ptr<HTML::WindowProxy>, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers);
static WebIDL::ExceptionOr<GC::Ref<PointerEvent>> construct_impl(JS::Realm&, FlyString const& type, PointerEventInit const&); static WebIDL::ExceptionOr<GC::Ref<PointerEvent>> construct_impl(JS::Realm&, FlyString const& type, PointerEventInit const&);
virtual ~PointerEvent() override; virtual ~PointerEvent() override;

View file

@ -43,7 +43,7 @@ GC::Ref<WheelEvent> WheelEvent::create(JS::Realm& realm, FlyString const& event_
return realm.create<WheelEvent>(realm, event_name, event_init, page_x, page_y, offset_x, offset_y); return realm.create<WheelEvent>(realm, event_name, event_init, page_x, page_y, offset_x, offset_y);
} }
WebIDL::ExceptionOr<GC::Ref<WheelEvent>> WheelEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers) WebIDL::ExceptionOr<GC::Ref<WheelEvent>> WheelEvent::create_from_platform_event(JS::Realm& realm, GC::Ptr<HTML::WindowProxy> window_proxy, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers)
{ {
WheelEventInit event_init {}; WheelEventInit event_init {};
event_init.ctrl_key = modifiers & Mod_Ctrl; event_init.ctrl_key = modifiers & Mod_Ctrl;
@ -59,6 +59,7 @@ WebIDL::ExceptionOr<GC::Ref<WheelEvent>> WheelEvent::create_from_platform_event(
event_init.delta_x = delta_x; event_init.delta_x = delta_x;
event_init.delta_y = delta_y; event_init.delta_y = delta_y;
event_init.delta_mode = WheelDeltaMode::DOM_DELTA_PIXEL; event_init.delta_mode = WheelDeltaMode::DOM_DELTA_PIXEL;
event_init.view = window_proxy;
auto event = WheelEvent::create(realm, event_name, event_init, page.x().to_double(), page.y().to_double(), offset.x().to_double(), offset.y().to_double()); auto event = WheelEvent::create(realm, event_name, event_init, page.x().to_double(), page.y().to_double(), offset.x().to_double(), offset.y().to_double());
event->set_is_trusted(true); event->set_is_trusted(true);
event->set_bubbles(true); event->set_bubbles(true);

View file

@ -34,7 +34,7 @@ public:
[[nodiscard]] static GC::Ref<WheelEvent> create(JS::Realm&, FlyString const& event_name, WheelEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); [[nodiscard]] static GC::Ref<WheelEvent> create(JS::Realm&, FlyString const& event_name, WheelEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0);
[[nodiscard]] static GC::Ref<WheelEvent> construct_impl(JS::Realm&, FlyString const& event_name, WheelEventInit const& = {}); [[nodiscard]] static GC::Ref<WheelEvent> construct_impl(JS::Realm&, FlyString const& event_name, WheelEventInit const& = {});
static WebIDL::ExceptionOr<GC::Ref<WheelEvent>> create_from_platform_event(JS::Realm&, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers); static WebIDL::ExceptionOr<GC::Ref<WheelEvent>> create_from_platform_event(JS::Realm&, GC::Ptr<HTML::WindowProxy>, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, double delta_x, double delta_y, unsigned button, unsigned buttons, unsigned modifiers);
virtual ~WheelEvent() override; virtual ~WheelEvent() override;

View file

@ -0,0 +1,11 @@
click event view is set to the active window: true
dblclick event view is set to the active window: true
mousedown event view is set to the active window: true
pointerdown event view is set to the active window: true
mouseup event view is set to the active window: true
pointerup event view is set to the active window: true
mousemove event view is set to the active window: true
pointermove event view is set to the active window: true
mouseover event view is set to the active window: true
mouseout event view is set to the active window: true
wheel event view is set to the active window: true

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
}
</style>
<script src="../include.js"></script>
<body></body>
<script>
asyncTest(async done => {
let events = [
{ name: "click", trigger: (x, y) => internals.click(x, y) },
{ name: "dblclick", trigger: (x, y) => internals.doubleclick(x, y) },
{ name: "mousedown", trigger: (x, y) => internals.click(x, y) },
{ name: "pointerdown", trigger: (x, y) => internals.click(x, y) },
{ name: "mouseup", trigger: (x, y) => internals.click(x, y) },
{ name: "pointerup", trigger: (x, y) => internals.click(x, y) },
{ name: "mousemove", trigger: (x, y) => internals.movePointerTo(x, y) },
{ name: "pointermove", trigger: (x, y) => internals.movePointerTo(x, y) },
{ name: "mouseover", trigger: (x, y) => internals.movePointerTo(x, y) },
{ name: "mouseout", trigger: (x, y) => { internals.movePointerTo(x, y); internals.movePointerTo(x + 100, y + 100); } },
{ name: "wheel", trigger: (x, y) => internals.wheel(x, y, 1, 0) },
];
for (const event of events) {
const target = document.createElement("div");
document.body.appendChild(target);
let promise = new Promise(resolve => {
target.addEventListener(event.name, (e) => {
println(`${event.name} event view is set to the active window: ${e.view === window}`);
resolve();
});
});
const rect = target.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
event.trigger(x, y);
await promise;
target.remove();
}
done();
});
</script>