1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 17:47:44 +00:00

LibWeb: Make DOM::Event and all its subclasses GC-allocated

This commit is contained in:
Andreas Kling 2022-08-08 22:29:40 +02:00
parent a4ddb0ef87
commit 7c3db526b0
76 changed files with 892 additions and 565 deletions

View file

@ -39,7 +39,6 @@ interface CSSRule {
- It must have a public `using WrapperType = Bindings::HTMLDetailsElementWrapper;` - It must have a public `using WrapperType = Bindings::HTMLDetailsElementWrapper;`
7. Depending on what kind of thing your interface is, you may need to add it to the `WrapperFactory` of that kind: 7. Depending on what kind of thing your interface is, you may need to add it to the `WrapperFactory` of that kind:
- Events: [`LibWeb/Bindings/EventWrapperFactory.cpp`](../../Userland/Libraries/LibWeb/Bindings/EventWrapperFactory.cpp)
- Elements: [`LibWeb/Bindings/NodeWrapperFactory.cpp`](../../Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp) - Elements: [`LibWeb/Bindings/NodeWrapperFactory.cpp`](../../Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp)
Open the relevant wrapper factory file, and add `#include` directives and an `if` statement for your new type. Open the relevant wrapper factory file, and add `#include` directives and an `if` statement for your new type.

View file

@ -300,8 +300,6 @@ static void emit_includes_for_all_imports(auto& interface, auto& generator, bool
static bool should_emit_wrapper_factory(IDL::Interface const& interface) static bool should_emit_wrapper_factory(IDL::Interface const& interface)
{ {
// FIXME: This is very hackish. // FIXME: This is very hackish.
if (interface.name == "Event")
return false;
if (interface.name == "EventTarget") if (interface.name == "EventTarget")
return false; return false;
if (interface.name == "Node") if (interface.name == "Node")
@ -2042,6 +2040,7 @@ using namespace Web::IntersectionObserver;
using namespace Web::RequestIdleCallback; using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver; using namespace Web::ResizeObserver;
using namespace Web::Selection; using namespace Web::Selection;
using namespace Web::UIEvents;
using namespace Web::WebGL; using namespace Web::WebGL;
namespace Web::Bindings { namespace Web::Bindings {
@ -2904,7 +2903,6 @@ void generate_constructor_implementation(IDL::Interface const& interface)
#include <LibWeb/Bindings/@wrapper_class@.h> #include <LibWeb/Bindings/@wrapper_class@.h>
#endif #endif
#include <LibWeb/Bindings/EventTargetWrapperFactory.h> #include <LibWeb/Bindings/EventTargetWrapperFactory.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h> #include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/NodeWrapper.h> #include <LibWeb/Bindings/NodeWrapper.h>
#include <LibWeb/Bindings/NodeWrapperFactory.h> #include <LibWeb/Bindings/NodeWrapperFactory.h>
@ -3208,8 +3206,6 @@ void generate_prototype_implementation(IDL::Interface const& interface)
#if __has_include(<LibWeb/Bindings/@wrapper_class@.h>) #if __has_include(<LibWeb/Bindings/@wrapper_class@.h>)
#include <LibWeb/Bindings/@wrapper_class@.h> #include <LibWeb/Bindings/@wrapper_class@.h>
#endif #endif
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h> #include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/LocationObject.h> #include <LibWeb/Bindings/LocationObject.h>
#include <LibWeb/Bindings/WindowObject.h> #include <LibWeb/Bindings/WindowObject.h>
@ -3253,6 +3249,7 @@ using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver; using namespace Web::ResizeObserver;
using namespace Web::Selection; using namespace Web::Selection;
using namespace Web::SVG; using namespace Web::SVG;
using namespace Web::UIEvents;
using namespace Web::URL; using namespace Web::URL;
using namespace Web::WebSockets; using namespace Web::WebSockets;
using namespace Web::XHR; using namespace Web::XHR;
@ -3712,6 +3709,7 @@ using namespace Web::IntersectionObserver;
using namespace Web::RequestIdleCallback; using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver; using namespace Web::ResizeObserver;
using namespace Web::Selection; using namespace Web::Selection;
using namespace Web::UIEvents;
using namespace Web::WebGL; using namespace Web::WebGL;
namespace Web::Bindings { namespace Web::Bindings {
@ -3830,6 +3828,7 @@ using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver; using namespace Web::ResizeObserver;
using namespace Web::Selection; using namespace Web::Selection;
using namespace Web::XHR; using namespace Web::XHR;
using namespace Web::UIEvents;
using namespace Web::URL; using namespace Web::URL;
using namespace Web::WebGL; using namespace Web::WebGL;

View file

@ -1,56 +0,0 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/CloseEventWrapper.h>
#include <LibWeb/Bindings/CustomEventWrapper.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/KeyboardEventWrapper.h>
#include <LibWeb/Bindings/MediaQueryListEventWrapper.h>
#include <LibWeb/Bindings/MessageEventWrapper.h>
#include <LibWeb/Bindings/MouseEventWrapper.h>
#include <LibWeb/Bindings/PageTransitionEventWrapper.h>
#include <LibWeb/Bindings/ProgressEventWrapper.h>
#include <LibWeb/Bindings/PromiseRejectionEventWrapper.h>
#include <LibWeb/Bindings/SubmitEventWrapper.h>
#include <LibWeb/Bindings/WebGLContextEventWrapper.h>
namespace Web::Bindings {
EventWrapper* wrap(JS::Realm& realm, DOM::Event& event)
{
if (event.wrapper())
return static_cast<EventWrapper*>(event.wrapper());
if (is<DOM::CustomEvent>(event))
return static_cast<CustomEventWrapper*>(wrap_impl(realm, static_cast<DOM::CustomEvent&>(event)));
if (is<CSS::MediaQueryListEvent>(event))
return static_cast<MediaQueryListEventWrapper*>(wrap_impl(realm, static_cast<CSS::MediaQueryListEvent&>(event)));
if (is<HTML::CloseEvent>(event))
return static_cast<CloseEventWrapper*>(wrap_impl(realm, static_cast<HTML::CloseEvent&>(event)));
if (is<HTML::MessageEvent>(event))
return static_cast<MessageEventWrapper*>(wrap_impl(realm, static_cast<HTML::MessageEvent&>(event)));
if (is<HTML::PageTransitionEvent>(event))
return static_cast<PageTransitionEventWrapper*>(wrap_impl(realm, static_cast<HTML::PageTransitionEvent&>(event)));
if (is<HTML::PromiseRejectionEvent>(event))
return static_cast<PromiseRejectionEventWrapper*>(wrap_impl(realm, static_cast<HTML::PromiseRejectionEvent&>(event)));
if (is<HTML::SubmitEvent>(event))
return static_cast<SubmitEventWrapper*>(wrap_impl(realm, static_cast<HTML::SubmitEvent&>(event)));
if (is<UIEvents::KeyboardEvent>(event))
return static_cast<KeyboardEventWrapper*>(wrap_impl(realm, static_cast<UIEvents::KeyboardEvent&>(event)));
if (is<UIEvents::MouseEvent>(event))
return static_cast<MouseEventWrapper*>(wrap_impl(realm, static_cast<UIEvents::MouseEvent&>(event)));
if (is<XHR::ProgressEvent>(event))
return static_cast<ProgressEventWrapper*>(wrap_impl(realm, static_cast<XHR::ProgressEvent&>(event)));
if (is<UIEvents::UIEvent>(event))
return static_cast<UIEventWrapper*>(wrap_impl(realm, static_cast<UIEvents::UIEvent&>(event)));
if (is<WebGL::WebGLContextEvent>(event))
return static_cast<WebGLContextEventWrapper*>(wrap_impl(realm, static_cast<WebGL::WebGLContextEvent&>(event)));
return static_cast<EventWrapper*>(wrap_impl(realm, event));
}
}

View file

@ -1,16 +0,0 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Forward.h>
#include <LibWeb/Forward.h>
namespace Web::Bindings {
EventWrapper* wrap(JS::Realm&, DOM::Event&);
}

View file

@ -134,8 +134,8 @@ JS::VM& main_thread_vm()
/* .promise = */ promise, /* .promise = */ promise,
/* .reason = */ promise.cell()->result(), /* .reason = */ promise.cell()->result(),
}; };
auto promise_rejection_event = HTML::PromiseRejectionEvent::create(HTML::EventNames::rejectionhandled, event_init); auto promise_rejection_event = HTML::PromiseRejectionEvent::create(window, HTML::EventNames::rejectionhandled, event_init);
window.impl().dispatch_event(move(promise_rejection_event)); window.impl().dispatch_event(*promise_rejection_event);
}); });
break; break;
} }

View file

@ -19,8 +19,6 @@
#include <LibWeb/Bindings/ElementWrapper.h> #include <LibWeb/Bindings/ElementWrapper.h>
#include <LibWeb/Bindings/EventTargetConstructor.h> #include <LibWeb/Bindings/EventTargetConstructor.h>
#include <LibWeb/Bindings/EventTargetPrototype.h> #include <LibWeb/Bindings/EventTargetPrototype.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h> #include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/HistoryWrapper.h> #include <LibWeb/Bindings/HistoryWrapper.h>
#include <LibWeb/Bindings/LocationObject.h> #include <LibWeb/Bindings/LocationObject.h>

View file

@ -6,7 +6,6 @@ set(SOURCES
Bindings/CallbackType.cpp Bindings/CallbackType.cpp
Bindings/CrossOriginAbstractOperations.cpp Bindings/CrossOriginAbstractOperations.cpp
Bindings/EventTargetWrapperFactory.cpp Bindings/EventTargetWrapperFactory.cpp
Bindings/EventWrapperFactory.cpp
Bindings/IDLAbstractOperations.cpp Bindings/IDLAbstractOperations.cpp
Bindings/ImageConstructor.cpp Bindings/ImageConstructor.cpp
Bindings/LegacyPlatformObject.cpp Bindings/LegacyPlatformObject.cpp
@ -47,6 +46,7 @@ set(SOURCES
CSS/MediaList.cpp CSS/MediaList.cpp
CSS/MediaQuery.cpp CSS/MediaQuery.cpp
CSS/MediaQueryList.cpp CSS/MediaQueryList.cpp
CSS/MediaQueryListEvent.cpp
CSS/Parser/Block.cpp CSS/Parser/Block.cpp
CSS/Parser/ComponentValue.cpp CSS/Parser/ComponentValue.cpp
CSS/Parser/Declaration.cpp CSS/Parser/Declaration.cpp
@ -145,9 +145,11 @@ set(SOURCES
HTML/Canvas/CanvasState.cpp HTML/Canvas/CanvasState.cpp
HTML/CanvasGradient.cpp HTML/CanvasGradient.cpp
HTML/CanvasRenderingContext2D.cpp HTML/CanvasRenderingContext2D.cpp
HTML/CloseEvent.cpp
HTML/CrossOrigin/Reporting.cpp HTML/CrossOrigin/Reporting.cpp
HTML/DOMParser.cpp HTML/DOMParser.cpp
HTML/DOMStringMap.cpp HTML/DOMStringMap.cpp
HTML/ErrorEvent.cpp
HTML/EventHandler.cpp HTML/EventHandler.cpp
HTML/EventLoop/EventLoop.cpp HTML/EventLoop/EventLoop.cpp
HTML/EventLoop/Task.cpp HTML/EventLoop/Task.cpp
@ -232,7 +234,9 @@ set(SOURCES
HTML/HTMLVideoElement.cpp HTML/HTMLVideoElement.cpp
HTML/ImageData.cpp HTML/ImageData.cpp
HTML/MessageChannel.cpp HTML/MessageChannel.cpp
HTML/MessageEvent.cpp
HTML/MessagePort.cpp HTML/MessagePort.cpp
HTML/PageTransitionEvent.cpp
HTML/Parser/Entities.cpp HTML/Parser/Entities.cpp
HTML/Parser/HTMLEncodingDetection.cpp HTML/Parser/HTMLEncodingDetection.cpp
HTML/Parser/HTMLParser.cpp HTML/Parser/HTMLParser.cpp
@ -241,12 +245,14 @@ set(SOURCES
HTML/Parser/ListOfActiveFormattingElements.cpp HTML/Parser/ListOfActiveFormattingElements.cpp
HTML/Parser/StackOfOpenElements.cpp HTML/Parser/StackOfOpenElements.cpp
HTML/Path2D.cpp HTML/Path2D.cpp
HTML/PromiseRejectionEvent.cpp
HTML/Scripting/ClassicScript.cpp HTML/Scripting/ClassicScript.cpp
HTML/Scripting/Environments.cpp HTML/Scripting/Environments.cpp
HTML/Scripting/ExceptionReporter.cpp HTML/Scripting/ExceptionReporter.cpp
HTML/Scripting/Script.cpp HTML/Scripting/Script.cpp
HTML/Scripting/WindowEnvironmentSettingsObject.cpp HTML/Scripting/WindowEnvironmentSettingsObject.cpp
HTML/Storage.cpp HTML/Storage.cpp
HTML/SubmitEvent.cpp
HTML/SyntaxHighlighter/SyntaxHighlighter.cpp HTML/SyntaxHighlighter/SyntaxHighlighter.cpp
HTML/TagNames.cpp HTML/TagNames.cpp
HTML/TextMetrics.cpp HTML/TextMetrics.cpp
@ -371,6 +377,7 @@ set(SOURCES
UIEvents/FocusEvent.cpp UIEvents/FocusEvent.cpp
UIEvents/KeyboardEvent.cpp UIEvents/KeyboardEvent.cpp
UIEvents/MouseEvent.cpp UIEvents/MouseEvent.cpp
UIEvents/UIEvent.cpp
URL/URL.cpp URL/URL.cpp
URL/URLSearchParams.cpp URL/URLSearchParams.cpp
URL/URLSearchParamsIterator.cpp URL/URLSearchParamsIterator.cpp
@ -386,10 +393,12 @@ set(SOURCES
WebAssembly/WebAssemblyTableObject.cpp WebAssembly/WebAssemblyTableObject.cpp
WebAssembly/WebAssemblyTablePrototype.cpp WebAssembly/WebAssemblyTablePrototype.cpp
WebGL/WebGLContextAttributes.cpp WebGL/WebGLContextAttributes.cpp
WebGL/WebGLContextEvent.cpp
WebGL/WebGLRenderingContext.cpp WebGL/WebGLRenderingContext.cpp
WebGL/WebGLRenderingContextBase.cpp WebGL/WebGLRenderingContextBase.cpp
WebSockets/WebSocket.cpp WebSockets/WebSocket.cpp
XHR/EventNames.cpp XHR/EventNames.cpp
XHR/ProgressEvent.cpp
XHR/XMLHttpRequest.cpp XHR/XMLHttpRequest.cpp
XHR/XMLHttpRequestEventTarget.cpp XHR/XMLHttpRequestEventTarget.cpp
XML/XMLDocumentBuilder.cpp XML/XMLDocumentBuilder.cpp

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/MediaQueryListEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/CSS/MediaQueryListEvent.h>
namespace Web::CSS {
MediaQueryListEvent* MediaQueryListEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, MediaQueryListEventInit const& event_init)
{
return window_object.heap().allocate<MediaQueryListEvent>(window_object.realm(), window_object, event_name, event_init);
}
MediaQueryListEvent* MediaQueryListEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, MediaQueryListEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
MediaQueryListEvent::MediaQueryListEvent(Bindings::WindowObject& window_object, FlyString const& event_name, MediaQueryListEventInit const& event_init)
: DOM::Event(window_object, event_name, event_init)
, m_media(event_init.media)
, m_matches(event_init.matches)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::MediaQueryListEventPrototype>("MediaQueryListEvent"));
}
MediaQueryListEvent::~MediaQueryListEvent() = default;
}

View file

@ -15,33 +15,28 @@ struct MediaQueryListEventInit : public DOM::EventInit {
bool matches { false }; bool matches { false };
}; };
class MediaQueryListEvent : public DOM::Event { class MediaQueryListEvent final : public DOM::Event {
JS_OBJECT(MediaQueryListEvent, DOM::Event);
public: public:
using WrapperType = Bindings::MediaQueryListEventWrapper; static MediaQueryListEvent* create(Bindings::WindowObject&, FlyString const& event_name, MediaQueryListEventInit const& event_init = {});
static MediaQueryListEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, MediaQueryListEventInit const& event_init);
static NonnullRefPtr<MediaQueryListEvent> create(FlyString const& event_name, MediaQueryListEventInit const& event_init = {}) MediaQueryListEvent(Bindings::WindowObject&, FlyString const& event_name, MediaQueryListEventInit const& event_init);
{ virtual ~MediaQueryListEvent() override;
return adopt_ref(*new MediaQueryListEvent(event_name, event_init));
}
static NonnullRefPtr<MediaQueryListEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, MediaQueryListEventInit const& event_init)
{
return MediaQueryListEvent::create(event_name, event_init);
}
virtual ~MediaQueryListEvent() override = default; MediaQueryListEvent& impl() { return *this; }
String const& media() const { return m_media; } String const& media() const { return m_media; }
bool matches() const { return m_matches; } bool matches() const { return m_matches; }
protected: private:
MediaQueryListEvent(FlyString const& event_name, MediaQueryListEventInit const& event_init)
: DOM::Event(event_name, event_init)
, m_media(event_init.media)
, m_matches(event_init.matches)
{
}
String m_media; String m_media;
bool m_matches; bool m_matches;
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::CSS::MediaQueryListEvent& object) { return &object; }
using MediaQueryListEventWrapper = Web::CSS::MediaQueryListEvent;
}

View file

@ -1,5 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[NoInstanceWrapper]
interface MediaQueryListEvent : Event { interface MediaQueryListEvent : Event {
constructor(CSSOMString type, optional MediaQueryListEventInit eventInitDict = {}); constructor(CSSOMString type, optional MediaQueryListEventInit eventInitDict = {});

View file

@ -60,7 +60,7 @@ void AbortSignal::signal_abort(JS::Value reason)
m_abort_algorithms.clear(); m_abort_algorithms.clear();
// 5. Fire an event named abort at signal. // 5. Fire an event named abort at signal.
dispatch_event(Event::create(HTML::EventNames::abort)); dispatch_event(*Event::create(verify_cast<Bindings::WindowObject>(wrapper()->global_object()), HTML::EventNames::abort));
} }
void AbortSignal::set_onabort(Bindings::CallbackType* event_handler) void AbortSignal::set_onabort(Bindings::CallbackType* event_handler)

View file

@ -1,15 +1,44 @@
/* /*
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibWeb/Bindings/CustomEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/DOM/CustomEvent.h> #include <LibWeb/DOM/CustomEvent.h>
namespace Web::DOM { namespace Web::DOM {
CustomEvent* CustomEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, CustomEventInit const& event_init)
{
return window_object.heap().allocate<CustomEvent>(window_object.realm(), window_object, event_name, event_init);
}
CustomEvent* CustomEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, CustomEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
CustomEvent::CustomEvent(Bindings::WindowObject& window_object, FlyString const& event_name)
: Event(window_object, event_name)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::CustomEventPrototype>("CustomEvent"));
}
CustomEvent::CustomEvent(Bindings::WindowObject& window_object, FlyString const& event_name, CustomEventInit const& event_init)
: Event(window_object, event_name, event_init)
, m_detail(event_init.detail)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::CustomEventPrototype>("CustomEvent"));
}
CustomEvent::~CustomEvent() = default;
void CustomEvent::visit_edges(JS::Cell::Visitor& visitor) void CustomEvent::visit_edges(JS::Cell::Visitor& visitor)
{ {
Base::visit_edges(visitor);
visitor.visit(m_detail); visitor.visit(m_detail);
} }
@ -21,7 +50,7 @@ void CustomEvent::init_custom_event(String const& type, bool bubbles, bool cance
return; return;
// 2. Initialize this with type, bubbles, and cancelable. // 2. Initialize this with type, bubbles, and cancelable.
initialize(type, bubbles, cancelable); initialize_event(type, bubbles, cancelable);
// 3. Set thiss detail attribute to detail. // 3. Set thiss detail attribute to detail.
m_detail = detail; m_detail = detail;

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -16,41 +17,34 @@ struct CustomEventInit : public EventInit {
// https://dom.spec.whatwg.org/#customevent // https://dom.spec.whatwg.org/#customevent
class CustomEvent : public Event { class CustomEvent : public Event {
JS_OBJECT(CustomEvent, Event);
public: public:
using WrapperType = Bindings::CustomEventWrapper; static CustomEvent* create(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init = {});
static CustomEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init);
static NonnullRefPtr<CustomEvent> create(FlyString const& event_name, CustomEventInit const& event_init = {}) CustomEvent(Bindings::WindowObject&, FlyString const& event_name);
{ CustomEvent(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init);
return adopt_ref(*new CustomEvent(event_name, event_init));
}
static NonnullRefPtr<CustomEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init)
{
return CustomEvent::create(event_name, event_init);
}
virtual ~CustomEvent() override = default; virtual ~CustomEvent() override;
CustomEvent& impl() { return *this; }
// https://dom.spec.whatwg.org/#dom-customevent-detail // https://dom.spec.whatwg.org/#dom-customevent-detail
JS::Value detail() const { return m_detail; } JS::Value detail() const { return m_detail; }
void visit_edges(JS::Cell::Visitor&); virtual void visit_edges(JS::Cell::Visitor&) override;
void init_custom_event(String const& type, bool bubbles, bool cancelable, JS::Value detail); void init_custom_event(String const& type, bool bubbles, bool cancelable, JS::Value detail);
private: private:
explicit CustomEvent(FlyString const& event_name)
: Event(event_name)
{
}
CustomEvent(FlyString const& event_name, CustomEventInit const& event_init)
: Event(event_name, event_init)
, m_detail(event_init.detail)
{
}
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent-type-bubbles-cancelable-detail-detail // https://dom.spec.whatwg.org/#dom-customevent-initcustomevent-type-bubbles-cancelable-detail-detail
JS::Value m_detail { JS::js_null() }; JS::Value m_detail { JS::js_null() };
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::DOM::CustomEvent& object) { return &object; }
using CustomEventWrapper = Web::DOM::CustomEvent;
}

View file

@ -1,6 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[Exposed=(Window,Worker), CustomVisit] [Exposed=(Window,Worker), NoInstanceWrapper]
interface CustomEvent : Event { interface CustomEvent : Event {
constructor(DOMString type, optional CustomEventInit eventInitDict = {}); constructor(DOMString type, optional CustomEventInit eventInitDict = {});

View file

@ -1160,51 +1160,53 @@ NonnullRefPtr<Range> Document::create_range()
} }
// https://dom.spec.whatwg.org/#dom-document-createevent // https://dom.spec.whatwg.org/#dom-document-createevent
DOM::ExceptionOr<NonnullRefPtr<Event>> Document::create_event(String const& interface) DOM::ExceptionOr<JS::NonnullGCPtr<Event>> Document::create_event(String const& interface)
{ {
auto& window_object = preferred_window_object();
// NOTE: This is named event here, since we do step 5 and 6 as soon as possible for each case. // NOTE: This is named event here, since we do step 5 and 6 as soon as possible for each case.
// 1. Let constructor be null. // 1. Let constructor be null.
RefPtr<Event> event; JS::GCPtr<Event> event;
// 2. If interface is an ASCII case-insensitive match for any of the strings in the first column in the following table, // 2. If interface is an ASCII case-insensitive match for any of the strings in the first column in the following table,
// then set constructor to the interface in the second column on the same row as the matching string: // then set constructor to the interface in the second column on the same row as the matching string:
auto interface_lowercase = interface.to_lowercase(); auto interface_lowercase = interface.to_lowercase();
if (interface_lowercase == "beforeunloadevent") { if (interface_lowercase == "beforeunloadevent") {
event = Event::create(""); // FIXME: Create BeforeUnloadEvent event = Event::create(window_object, ""); // FIXME: Create BeforeUnloadEvent
} else if (interface_lowercase == "compositionevent") { } else if (interface_lowercase == "compositionevent") {
event = Event::create(""); // FIXME: Create CompositionEvent event = Event::create(window_object, ""); // FIXME: Create CompositionEvent
} else if (interface_lowercase == "customevent") { } else if (interface_lowercase == "customevent") {
event = CustomEvent::create(""); event = CustomEvent::create(window_object, "");
} else if (interface_lowercase == "devicemotionevent") { } else if (interface_lowercase == "devicemotionevent") {
event = Event::create(""); // FIXME: Create DeviceMotionEvent event = Event::create(window_object, ""); // FIXME: Create DeviceMotionEvent
} else if (interface_lowercase == "deviceorientationevent") { } else if (interface_lowercase == "deviceorientationevent") {
event = Event::create(""); // FIXME: Create DeviceOrientationEvent event = Event::create(window_object, ""); // FIXME: Create DeviceOrientationEvent
} else if (interface_lowercase == "dragevent") { } else if (interface_lowercase == "dragevent") {
event = Event::create(""); // FIXME: Create DragEvent event = Event::create(window_object, ""); // FIXME: Create DragEvent
} else if (interface_lowercase.is_one_of("event", "events")) { } else if (interface_lowercase.is_one_of("event", "events")) {
event = Event::create(""); event = Event::create(window_object, "");
} else if (interface_lowercase == "focusevent") { } else if (interface_lowercase == "focusevent") {
event = UIEvents::FocusEvent::create(""); event = UIEvents::FocusEvent::create(window_object, "");
} else if (interface_lowercase == "hashchangeevent") { } else if (interface_lowercase == "hashchangeevent") {
event = Event::create(""); // FIXME: Create HashChangeEvent event = Event::create(window_object, ""); // FIXME: Create HashChangeEvent
} else if (interface_lowercase == "htmlevents") { } else if (interface_lowercase == "htmlevents") {
event = Event::create(""); event = Event::create(window_object, "");
} else if (interface_lowercase == "keyboardevent") { } else if (interface_lowercase == "keyboardevent") {
event = UIEvents::KeyboardEvent::create(""); event = UIEvents::KeyboardEvent::create(window_object, "");
} else if (interface_lowercase == "messageevent") { } else if (interface_lowercase == "messageevent") {
event = HTML::MessageEvent::create(""); event = HTML::MessageEvent::create(window_object, "");
} else if (interface_lowercase.is_one_of("mouseevent", "mouseevents")) { } else if (interface_lowercase.is_one_of("mouseevent", "mouseevents")) {
event = UIEvents::MouseEvent::create(""); event = UIEvents::MouseEvent::create(window_object, "");
} else if (interface_lowercase == "storageevent") { } else if (interface_lowercase == "storageevent") {
event = Event::create(""); // FIXME: Create StorageEvent event = Event::create(window_object, ""); // FIXME: Create StorageEvent
} else if (interface_lowercase == "svgevents") { } else if (interface_lowercase == "svgevents") {
event = Event::create(""); event = Event::create(window_object, "");
} else if (interface_lowercase == "textevent") { } else if (interface_lowercase == "textevent") {
event = Event::create(""); // FIXME: Create CompositionEvent event = Event::create(window_object, ""); // FIXME: Create CompositionEvent
} else if (interface_lowercase == "touchevent") { } else if (interface_lowercase == "touchevent") {
event = Event::create(""); // FIXME: Create TouchEvent event = Event::create(window_object, ""); // FIXME: Create TouchEvent
} else if (interface_lowercase.is_one_of("uievent", "uievents")) { } else if (interface_lowercase.is_one_of("uievent", "uievents")) {
event = UIEvents::UIEvent::create(""); event = UIEvents::UIEvent::create(window_object, "");
} }
// 3. If constructor is null, then throw a "NotSupportedError" DOMException. // 3. If constructor is null, then throw a "NotSupportedError" DOMException.
@ -1228,7 +1230,7 @@ DOM::ExceptionOr<NonnullRefPtr<Event>> Document::create_event(String const& inte
event->set_initialized(false); event->set_initialized(false);
// 10. Return event. // 10. Return event.
return event.release_nonnull(); return JS::NonnullGCPtr(*event);
} }
void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script) void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
@ -1408,7 +1410,7 @@ void Document::update_readiness(HTML::DocumentReadyState readiness_value)
// FIXME: 3. Otherwise, if readinessValue is "interactive", and document's load timing info's DOM interactive time is 0, then set document's load timing info's DOM interactive time to now. // FIXME: 3. Otherwise, if readinessValue is "interactive", and document's load timing info's DOM interactive time is 0, then set document's load timing info's DOM interactive time to now.
// 3. Fire an event named readystatechange at document. // 3. Fire an event named readystatechange at document.
dispatch_event(Event::create(HTML::EventNames::readystatechange)); dispatch_event(*Event::create(preferred_window_object(), HTML::EventNames::readystatechange));
} }
Page* Document::page() Page* Document::page()
@ -1448,8 +1450,8 @@ void Document::completely_finish_loading()
} }
// Otherwise, if container is non-null, then queue an element task on the DOM manipulation task source given container to fire an event named load at container. // Otherwise, if container is non-null, then queue an element task on the DOM manipulation task source given container to fire an event named load at container.
else if (container) { else if (container) {
container->queue_an_element_task(HTML::Task::Source::DOMManipulation, [container]() mutable { container->queue_an_element_task(HTML::Task::Source::DOMManipulation, [container, this]() mutable {
container->dispatch_event(DOM::Event::create(HTML::EventNames::load)); container->dispatch_event(*DOM::Event::create(preferred_window_object(), HTML::EventNames::load));
}); });
} }
} }
@ -1560,7 +1562,7 @@ void Document::run_the_resize_steps()
return; return;
m_last_viewport_size = viewport_size; m_last_viewport_size = viewport_size;
window().dispatch_event(DOM::Event::create(UIEvents::EventNames::resize)); window().dispatch_event(*DOM::Event::create(preferred_window_object(), UIEvents::EventNames::resize));
update_layout(); update_layout();
} }
@ -1596,9 +1598,9 @@ void Document::evaluate_media_queries_and_report_changes()
CSS::MediaQueryListEventInit init; CSS::MediaQueryListEventInit init;
init.media = media_query_list->media(); init.media = media_query_list->media();
init.matches = now_matches; init.matches = now_matches;
auto event = CSS::MediaQueryListEvent::create(HTML::EventNames::change, init); auto event = CSS::MediaQueryListEvent::create(preferred_window_object(), HTML::EventNames::change, init);
event->set_is_trusted(true); event->set_is_trusted(true);
media_query_list->dispatch_event(event); media_query_list->dispatch_event(*event);
} }
} }

View file

@ -204,7 +204,7 @@ public:
NonnullRefPtr<Text> create_text_node(String const& data); NonnullRefPtr<Text> create_text_node(String const& data);
NonnullRefPtr<Comment> create_comment(String const& data); NonnullRefPtr<Comment> create_comment(String const& data);
NonnullRefPtr<Range> create_range(); NonnullRefPtr<Range> create_range();
ExceptionOr<NonnullRefPtr<Event>> create_event(String const& interface); ExceptionOr<JS::NonnullGCPtr<Event>> create_event(String const& interface);
void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*); void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; } HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }

View file

@ -1,17 +1,47 @@
/* /*
* Copyright (c) 2020, the SerenityOS developers. * Copyright (c) 2020, the SerenityOS developers.
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/TypeCasts.h> #include <AK/TypeCasts.h>
#include <LibWeb/Bindings/EventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/DOM/Event.h> #include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/Node.h> #include <LibWeb/DOM/Node.h>
#include <LibWeb/DOM/ShadowRoot.h> #include <LibWeb/DOM/ShadowRoot.h>
namespace Web::DOM { namespace Web::DOM {
JS::NonnullGCPtr<Event> Event::create(Bindings::WindowObject& window_object, FlyString const& event_name, EventInit const& event_init)
{
return *window_object.heap().allocate<Event>(window_object.realm(), window_object, event_name, event_init);
}
JS::NonnullGCPtr<Event> Event::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, EventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
Event::Event(Bindings::WindowObject& window_object, FlyString const& type)
: PlatformObject(window_object.ensure_web_prototype<Bindings::EventPrototype>("Event"))
, m_type(type)
, m_initialized(true)
{
}
Event::Event(Bindings::WindowObject& window_object, FlyString const& type, EventInit const& event_init)
: PlatformObject(window_object.ensure_web_prototype<Bindings::EventPrototype>("Event"))
, m_type(type)
, m_bubbles(event_init.bubbles)
, m_cancelable(event_init.cancelable)
, m_composed(event_init.composed)
, m_initialized(true)
{
}
// https://dom.spec.whatwg.org/#concept-event-path-append // https://dom.spec.whatwg.org/#concept-event-path-append
void Event::append_to_path(EventTarget& invocation_target, RefPtr<EventTarget> shadow_adjusted_target, RefPtr<EventTarget> related_target, TouchTargetList& touch_targets, bool slot_in_closed_tree) void Event::append_to_path(EventTarget& invocation_target, RefPtr<EventTarget> shadow_adjusted_target, RefPtr<EventTarget> related_target, TouchTargetList& touch_targets, bool slot_in_closed_tree)
{ {
@ -46,7 +76,7 @@ void Event::set_cancelled_flag()
} }
// https://dom.spec.whatwg.org/#concept-event-initialize // https://dom.spec.whatwg.org/#concept-event-initialize
void Event::initialize(String const& type, bool bubbles, bool cancelable) void Event::initialize_event(String const& type, bool bubbles, bool cancelable)
{ {
// 1. Set events initialized flag. // 1. Set events initialized flag.
m_initialized = true; m_initialized = true;
@ -80,7 +110,7 @@ void Event::init_event(String const& type, bool bubbles, bool cancelable)
return; return;
// 2. Initialize this with type, bubbles, and cancelable. // 2. Initialize this with type, bubbles, and cancelable.
initialize(type, bubbles, cancelable); initialize_event(type, bubbles, cancelable);
} }
// https://dom.spec.whatwg.org/#dom-event-timestamp // https://dom.spec.whatwg.org/#dom-event-timestamp

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -7,8 +7,8 @@
#pragma once #pragma once
#include <AK/FlyString.h> #include <AK/FlyString.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/WindowObject.h> #include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/Bindings/Wrappable.h>
#include <LibWeb/DOM/EventTarget.h> #include <LibWeb/DOM/EventTarget.h>
namespace Web::DOM { namespace Web::DOM {
@ -19,12 +19,10 @@ struct EventInit {
bool composed { false }; bool composed { false };
}; };
class Event class Event : public Bindings::PlatformObject {
: public RefCounted<Event> JS_OBJECT(Event, Bindings::PlatformObject);
, public Bindings::Wrappable {
public:
using WrapperType = Bindings::EventWrapper;
public:
enum Phase : u16 { enum Phase : u16 {
None = 0, None = 0,
CapturingPhase = 1, CapturingPhase = 1,
@ -47,17 +45,16 @@ public:
using Path = Vector<PathEntry>; using Path = Vector<PathEntry>;
static NonnullRefPtr<Event> create(FlyString const& event_name, EventInit const& event_init = {}) static JS::NonnullGCPtr<Event> create(Bindings::WindowObject&, FlyString const& event_name, EventInit const& event_init = {});
{ static JS::NonnullGCPtr<Event> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, EventInit const& event_init);
return adopt_ref(*new Event(event_name, event_init));
} Event(Bindings::WindowObject&, FlyString const& type);
static NonnullRefPtr<Event> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, EventInit const& event_init) Event(Bindings::WindowObject&, FlyString const& type, EventInit const& event_init);
{
return Event::create(event_name, event_init);
}
virtual ~Event() = default; virtual ~Event() = default;
Event& impl() { return *this; }
double time_stamp() const; double time_stamp() const;
FlyString const& type() const { return m_type; } FlyString const& type() const { return m_type; }
@ -149,21 +146,7 @@ public:
NonnullRefPtrVector<EventTarget> composed_path() const; NonnullRefPtrVector<EventTarget> composed_path() const;
protected: protected:
explicit Event(FlyString const& type) void initialize_event(String const&, bool, bool);
: m_type(type)
, m_initialized(true)
{
}
Event(FlyString const& type, EventInit const& event_init)
: m_type(type)
, m_bubbles(event_init.bubbles)
, m_cancelable(event_init.cancelable)
, m_composed(event_init.composed)
, m_initialized(true)
{
}
void initialize(String const&, bool, bool);
private: private:
FlyString m_type; FlyString m_type;
@ -195,3 +178,8 @@ private:
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::DOM::Event& object) { return &object; }
using EventWrapper = Web::DOM::Event;
}

View file

@ -1,5 +1,6 @@
#import <DOM/EventTarget.idl> #import <DOM/EventTarget.idl>
[NoInstanceWrapper]
interface Event { interface Event {
constructor(DOMString type, optional EventInit eventInitDict = {}); constructor(DOMString type, optional EventInit eventInitDict = {});

View file

@ -10,8 +10,6 @@
#include <LibJS/Runtime/FunctionObject.h> #include <LibJS/Runtime/FunctionObject.h>
#include <LibWeb/Bindings/EventTargetWrapper.h> #include <LibWeb/Bindings/EventTargetWrapper.h>
#include <LibWeb/Bindings/EventTargetWrapperFactory.h> #include <LibWeb/Bindings/EventTargetWrapperFactory.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/IDLAbstractOperations.h> #include <LibWeb/Bindings/IDLAbstractOperations.h>
#include <LibWeb/Bindings/WindowObject.h> #include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/DOM/AbortSignal.h> #include <LibWeb/DOM/AbortSignal.h>
@ -92,7 +90,7 @@ bool EventDispatcher::inner_invoke(Event& event, Vector<JS::Handle<DOM::DOMEvent
auto& global = realm.global_object(); auto& global = realm.global_object();
// 7. Let currentEvent be undefined. // 7. Let currentEvent be undefined.
RefPtr<Event> current_event; Event* current_event = nullptr;
// 8. If global is a Window object, then: // 8. If global is a Window object, then:
if (is<Bindings::WindowObject>(global)) { if (is<Bindings::WindowObject>(global)) {
@ -207,10 +205,10 @@ void EventDispatcher::invoke(Event::PathEntry& struct_, Event& event, Event::Pha
} }
// https://dom.spec.whatwg.org/#concept-event-dispatch // https://dom.spec.whatwg.org/#concept-event-dispatch
bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<Event> event, bool legacy_target_override) bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, Event& event, bool legacy_target_override)
{ {
// 1. Set events dispatch flag. // 1. Set events dispatch flag.
event->set_dispatched(true); event.set_dispatched(true);
// 2. Let targetOverride be target, if legacy target override flag is not given, and targets associated Document otherwise. [HTML] // 2. Let targetOverride be target, if legacy target override flag is not given, and targets associated Document otherwise. [HTML]
// NOTE: legacy target override flag is only used by HTML and only when target is a Window object. // NOTE: legacy target override flag is only used by HTML and only when target is a Window object.
@ -225,24 +223,24 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
RefPtr<EventTarget> activation_target; RefPtr<EventTarget> activation_target;
// 4. Let relatedTarget be the result of retargeting events relatedTarget against target. // 4. Let relatedTarget be the result of retargeting events relatedTarget against target.
RefPtr<EventTarget> related_target = retarget(event->related_target(), target); RefPtr<EventTarget> related_target = retarget(event.related_target(), target);
bool clear_targets = false; bool clear_targets = false;
// 5. If target is not relatedTarget or target is events relatedTarget, then: // 5. If target is not relatedTarget or target is events relatedTarget, then:
if (related_target != target || event->related_target() == target) { if (related_target != target || event.related_target() == target) {
// 1. Let touchTargets be a new list. // 1. Let touchTargets be a new list.
Event::TouchTargetList touch_targets; Event::TouchTargetList touch_targets;
// 2. For each touchTarget of events touch target list, append the result of retargeting touchTarget against target to touchTargets. // 2. For each touchTarget of events touch target list, append the result of retargeting touchTarget against target to touchTargets.
for (auto& touch_target : event->touch_target_list()) { for (auto& touch_target : event.touch_target_list()) {
touch_targets.append(retarget(touch_target, target)); touch_targets.append(retarget(touch_target, target));
} }
// 3. Append to an event path with event, target, targetOverride, relatedTarget, touchTargets, and false. // 3. Append to an event path with event, target, targetOverride, relatedTarget, touchTargets, and false.
event->append_to_path(*target, target_override, related_target, touch_targets, false); event.append_to_path(*target, target_override, related_target, touch_targets, false);
// 4. Let isActivationEvent be true, if event is a MouseEvent object and events type attribute is "click"; otherwise false. // 4. Let isActivationEvent be true, if event is a MouseEvent object and events type attribute is "click"; otherwise false.
bool is_activation_event = is<UIEvents::MouseEvent>(*event) && event->type() == HTML::EventNames::click; bool is_activation_event = is<UIEvents::MouseEvent>(event) && event.type() == HTML::EventNames::click;
// 5. If isActivationEvent is true and target has activation behavior, then set activationTarget to target. // 5. If isActivationEvent is true and target has activation behavior, then set activationTarget to target.
if (is_activation_event && target->activation_behavior) if (is_activation_event && target->activation_behavior)
@ -265,13 +263,13 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
// FIXME: 2. If parent is a slottable and is assigned, then set slottable to parent. // FIXME: 2. If parent is a slottable and is assigned, then set slottable to parent.
// 3. Let relatedTarget be the result of retargeting events relatedTarget against parent. // 3. Let relatedTarget be the result of retargeting events relatedTarget against parent.
related_target = retarget(event->related_target(), parent); related_target = retarget(event.related_target(), parent);
// 4. Let touchTargets be a new list. // 4. Let touchTargets be a new list.
touch_targets.clear(); touch_targets.clear();
// 5. For each touchTarget of events touch target list, append the result of retargeting touchTarget against parent to touchTargets. // 5. For each touchTarget of events touch target list, append the result of retargeting touchTarget against parent to touchTargets.
for (auto& touch_target : event->touch_target_list()) { for (auto& touch_target : event.touch_target_list()) {
touch_targets.append(retarget(touch_target, parent)); touch_targets.append(retarget(touch_target, parent));
} }
@ -279,11 +277,11 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
if (is<HTML::Window>(parent) if (is<HTML::Window>(parent)
|| (is<Node>(parent) && verify_cast<Node>(*target).root().is_shadow_including_inclusive_ancestor_of(verify_cast<Node>(*parent)))) { || (is<Node>(parent) && verify_cast<Node>(*target).root().is_shadow_including_inclusive_ancestor_of(verify_cast<Node>(*parent)))) {
// 1. If isActivationEvent is true, events bubbles attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent. // 1. If isActivationEvent is true, events bubbles attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent.
if (is_activation_event && event->bubbles() && !activation_target && parent->activation_behavior) if (is_activation_event && event.bubbles() && !activation_target && parent->activation_behavior)
activation_target = parent; activation_target = parent;
// 2. Append to an event path with event, parent, null, relatedTarget, touchTargets, and slot-in-closed-tree. // 2. Append to an event path with event, parent, null, relatedTarget, touchTargets, and slot-in-closed-tree.
event->append_to_path(*parent, nullptr, related_target, touch_targets, slot_in_closed_tree); event.append_to_path(*parent, nullptr, related_target, touch_targets, slot_in_closed_tree);
} }
// 7. Otherwise, if parent is relatedTarget, then set parent to null. // 7. Otherwise, if parent is relatedTarget, then set parent to null.
@ -299,7 +297,7 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
activation_target = target; activation_target = target;
// 2. Append to an event path with event, parent, target, relatedTarget, touchTargets, and slot-in-closed-tree. // 2. Append to an event path with event, parent, target, relatedTarget, touchTargets, and slot-in-closed-tree.
event->append_to_path(*parent, target, related_target, touch_targets, slot_in_closed_tree); event.append_to_path(*parent, target, related_target, touch_targets, slot_in_closed_tree);
} }
// 9. If parent is non-null, then set parent to the result of invoking parents get the parent with event. // 9. If parent is non-null, then set parent to the result of invoking parents get the parent with event.
@ -312,7 +310,7 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
} }
// 10. Let clearTargetsStruct be the last struct in events path whose shadow-adjusted target is non-null. // 10. Let clearTargetsStruct be the last struct in events path whose shadow-adjusted target is non-null.
auto clear_targets_struct = event->path().last_matching([](auto& entry) { auto clear_targets_struct = event.path().last_matching([](auto& entry) {
return !entry.shadow_adjusted_target.is_null(); return !entry.shadow_adjusted_target.is_null();
}); });
@ -349,32 +347,32 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
activation_target->legacy_pre_activation_behavior(); activation_target->legacy_pre_activation_behavior();
// 13. For each struct in events path, in reverse order: // 13. For each struct in events path, in reverse order:
for (auto& entry : event->path().in_reverse()) { for (auto& entry : event.path().in_reverse()) {
// 1. If structs shadow-adjusted target is non-null, then set events eventPhase attribute to AT_TARGET. // 1. If structs shadow-adjusted target is non-null, then set events eventPhase attribute to AT_TARGET.
if (entry.shadow_adjusted_target) if (entry.shadow_adjusted_target)
event->set_phase(Event::Phase::AtTarget); event.set_phase(Event::Phase::AtTarget);
// 2. Otherwise, set events eventPhase attribute to CAPTURING_PHASE. // 2. Otherwise, set events eventPhase attribute to CAPTURING_PHASE.
else else
event->set_phase(Event::Phase::CapturingPhase); event.set_phase(Event::Phase::CapturingPhase);
// 3. Invoke with struct, event, "capturing", and legacyOutputDidListenersThrowFlag if given. // 3. Invoke with struct, event, "capturing", and legacyOutputDidListenersThrowFlag if given.
invoke(entry, event, Event::Phase::CapturingPhase); invoke(entry, event, Event::Phase::CapturingPhase);
} }
// 14. For each struct in events path: // 14. For each struct in events path:
for (auto& entry : event->path()) { for (auto& entry : event.path()) {
// 1. If structs shadow-adjusted target is non-null, then set events eventPhase attribute to AT_TARGET. // 1. If structs shadow-adjusted target is non-null, then set events eventPhase attribute to AT_TARGET.
if (entry.shadow_adjusted_target) { if (entry.shadow_adjusted_target) {
event->set_phase(Event::Phase::AtTarget); event.set_phase(Event::Phase::AtTarget);
} }
// 2. Otherwise: // 2. Otherwise:
else { else {
// 1. If events bubbles attribute is false, then continue. // 1. If events bubbles attribute is false, then continue.
if (!event->bubbles()) if (!event.bubbles())
continue; continue;
// 2. Set events eventPhase attribute to BUBBLING_PHASE. // 2. Set events eventPhase attribute to BUBBLING_PHASE.
event->set_phase(Event::Phase::BubblingPhase); event.set_phase(Event::Phase::BubblingPhase);
} }
// 3. Invoke with struct, event, "bubbling", and legacyOutputDidListenersThrowFlag if given. // 3. Invoke with struct, event, "bubbling", and legacyOutputDidListenersThrowFlag if given.
@ -383,35 +381,35 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
} }
// 6. Set events eventPhase attribute to NONE. // 6. Set events eventPhase attribute to NONE.
event->set_phase(Event::Phase::None); event.set_phase(Event::Phase::None);
// 7. Set events currentTarget attribute to null. // 7. Set events currentTarget attribute to null.
event->set_current_target(nullptr); event.set_current_target(nullptr);
// 8. Set events path to the empty list. // 8. Set events path to the empty list.
event->clear_path(); event.clear_path();
// 9. Unset events dispatch flag, stop propagation flag, and stop immediate propagation flag. // 9. Unset events dispatch flag, stop propagation flag, and stop immediate propagation flag.
event->set_dispatched(false); event.set_dispatched(false);
event->set_stop_propagation(false); event.set_stop_propagation(false);
event->set_stop_immediate_propagation(false); event.set_stop_immediate_propagation(false);
// 10. If clearTargets, then: // 10. If clearTargets, then:
if (clear_targets) { if (clear_targets) {
// 1. Set events target to null. // 1. Set events target to null.
event->set_target(nullptr); event.set_target(nullptr);
// 2. Set events relatedTarget to null. // 2. Set events relatedTarget to null.
event->set_related_target(nullptr); event.set_related_target(nullptr);
// 3. Set events touch target list to the empty list. // 3. Set events touch target list to the empty list.
event->clear_touch_target_list(); event.clear_touch_target_list();
} }
// 11. If activationTarget is non-null, then: // 11. If activationTarget is non-null, then:
if (activation_target) { if (activation_target) {
// 1. If events canceled flag is unset, then run activationTargets activation behavior with event. // 1. If events canceled flag is unset, then run activationTargets activation behavior with event.
if (!event->cancelled()) { if (!event.cancelled()) {
activation_target->activation_behavior(event); activation_target->activation_behavior(event);
activation_target->legacy_cancelled_activation_behavior_was_not_called(); activation_target->legacy_cancelled_activation_behavior_was_not_called();
} }
@ -422,7 +420,7 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
} }
// 12. Return false if events canceled flag is set; otherwise true. // 12. Return false if events canceled flag is set; otherwise true.
return !event->cancelled(); return !event.cancelled();
} }
} }

View file

@ -14,7 +14,7 @@ namespace Web::DOM {
class EventDispatcher { class EventDispatcher {
public: public:
static bool dispatch(NonnullRefPtr<EventTarget>, NonnullRefPtr<Event>, bool legacy_target_override = false); static bool dispatch(NonnullRefPtr<EventTarget>, Event&, bool legacy_target_override = false);
private: private:
static void invoke(Event::PathEntry&, Event&, Event::Phase); static void invoke(Event::PathEntry&, Event&, Event::Phase);

View file

@ -15,8 +15,6 @@
#include <LibJS/Runtime/VM.h> #include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/DocumentWrapper.h> #include <LibWeb/Bindings/DocumentWrapper.h>
#include <LibWeb/Bindings/EventTargetWrapperFactory.h> #include <LibWeb/Bindings/EventTargetWrapperFactory.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/IDLAbstractOperations.h> #include <LibWeb/Bindings/IDLAbstractOperations.h>
#include <LibWeb/Bindings/MainThreadVM.h> #include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/DOM/AbortSignal.h> #include <LibWeb/DOM/AbortSignal.h>
@ -204,17 +202,17 @@ void EventTarget::remove_from_event_listener_list(DOMEventListener& listener)
} }
// https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent // https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
ExceptionOr<bool> EventTarget::dispatch_event_binding(NonnullRefPtr<Event> event) ExceptionOr<bool> EventTarget::dispatch_event_binding(Event& event)
{ {
// 1. If events dispatch flag is set, or if its initialized flag is not set, then throw an "InvalidStateError" DOMException. // 1. If events dispatch flag is set, or if its initialized flag is not set, then throw an "InvalidStateError" DOMException.
if (event->dispatched()) if (event.dispatched())
return DOM::InvalidStateError::create("The event is already being dispatched."); return DOM::InvalidStateError::create("The event is already being dispatched.");
if (!event->initialized()) if (!event.initialized())
return DOM::InvalidStateError::create("Cannot dispatch an uninitialized event."); return DOM::InvalidStateError::create("Cannot dispatch an uninitialized event.");
// 2. Initialize events isTrusted attribute to false. // 2. Initialize events isTrusted attribute to false.
event->set_is_trusted(false); event.set_is_trusted(false);
// 3. Return the result of dispatching event to this. // 3. Return the result of dispatching event to this.
return dispatch_event(event); return dispatch_event(event);
@ -736,9 +734,9 @@ void EventTarget::element_event_handler_attribute_changed(FlyString const& local
event_target->activate_event_handler(local_name, *event_handler); event_target->activate_event_handler(local_name, *event_handler);
} }
bool EventTarget::dispatch_event(NonnullRefPtr<Event> event) bool EventTarget::dispatch_event(Event& event)
{ {
return EventDispatcher::dispatch(*this, move(event)); return EventDispatcher::dispatch(*this, event);
} }
} }

View file

@ -36,8 +36,8 @@ public:
void add_event_listener_without_options(FlyString const& type, IDLEventListener& callback); void add_event_listener_without_options(FlyString const& type, IDLEventListener& callback);
void remove_event_listener_without_options(FlyString const& type, IDLEventListener& callback); void remove_event_listener_without_options(FlyString const& type, IDLEventListener& callback);
virtual bool dispatch_event(NonnullRefPtr<Event>); virtual bool dispatch_event(Event&);
ExceptionOr<bool> dispatch_event_binding(NonnullRefPtr<Event>); ExceptionOr<bool> dispatch_event_binding(Event&);
virtual JS::Object* create_wrapper(JS::Realm&) = 0; virtual JS::Object* create_wrapper(JS::Realm&) = 0;

View file

@ -10,7 +10,6 @@
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibJS/AST.h> #include <LibJS/AST.h>
#include <LibJS/Runtime/FunctionObject.h> #include <LibJS/Runtime/FunctionObject.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/MainThreadVM.h> #include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Bindings/NodeWrapper.h> #include <LibWeb/Bindings/NodeWrapper.h>
#include <LibWeb/Bindings/NodeWrapperFactory.h> #include <LibWeb/Bindings/NodeWrapperFactory.h>

View file

@ -455,10 +455,8 @@ class CanvasGradientWrapper;
class CanvasRenderingContext2DWrapper; class CanvasRenderingContext2DWrapper;
class CDATASectionWrapper; class CDATASectionWrapper;
class CharacterDataWrapper; class CharacterDataWrapper;
class CloseEventWrapper;
class CommentWrapper; class CommentWrapper;
class CryptoWrapper; class CryptoWrapper;
class CustomEventWrapper;
class DocumentFragmentWrapper; class DocumentFragmentWrapper;
class DocumentTypeWrapper; class DocumentTypeWrapper;
class DocumentWrapper; class DocumentWrapper;
@ -470,11 +468,8 @@ class DOMRectListWrapper;
class DOMRectReadOnlyWrapper; class DOMRectReadOnlyWrapper;
class DOMRectWrapper; class DOMRectWrapper;
class ElementWrapper; class ElementWrapper;
class ErrorEventWrapper;
class EventTargetWrapper; class EventTargetWrapper;
class EventWrapper;
class FileWrapper; class FileWrapper;
class FocusEventWrapper;
class HeadersWrapper; class HeadersWrapper;
class HeadersIteratorWrapper; class HeadersIteratorWrapper;
class HistoryWrapper; class HistoryWrapper;
@ -554,26 +549,19 @@ class HTMLVideoElementWrapper;
class IdleDeadlineWrapper; class IdleDeadlineWrapper;
class ImageDataWrapper; class ImageDataWrapper;
class IntersectionObserverWrapper; class IntersectionObserverWrapper;
class KeyboardEventWrapper;
class LocationObject; class LocationObject;
class MediaQueryListEventWrapper;
class MediaQueryListWrapper; class MediaQueryListWrapper;
class MessageChannelWrapper; class MessageChannelWrapper;
class MessageEventWrapper;
class MessagePortWrapper; class MessagePortWrapper;
class MouseEventWrapper;
class MutationObserverWrapper; class MutationObserverWrapper;
class MutationRecordWrapper; class MutationRecordWrapper;
class NodeListWrapper; class NodeListWrapper;
class NodeWrapper; class NodeWrapper;
class OptionConstructor; class OptionConstructor;
class PageTransitionEventWrapper;
class Path2DWrapper; class Path2DWrapper;
class PerformanceTimingWrapper; class PerformanceTimingWrapper;
class PerformanceWrapper; class PerformanceWrapper;
class ProcessingInstructionWrapper; class ProcessingInstructionWrapper;
class ProgressEventWrapper;
class PromiseRejectionEventWrapper;
class RangeConstructor; class RangeConstructor;
class RangePrototype; class RangePrototype;
class RangeWrapper; class RangeWrapper;
@ -582,7 +570,6 @@ class ScreenWrapper;
class SelectionWrapper; class SelectionWrapper;
class StaticRangeWrapper; class StaticRangeWrapper;
class StorageWrapper; class StorageWrapper;
class SubmitEventWrapper;
class SubtleCryptoWrapper; class SubtleCryptoWrapper;
class SVGAnimatedLengthWrapper; class SVGAnimatedLengthWrapper;
class SVGCircleElementWrapper; class SVGCircleElementWrapper;
@ -604,7 +591,6 @@ class TextDecoderWrapper;
class TextEncoderWrapper; class TextEncoderWrapper;
class TextMetricsWrapper; class TextMetricsWrapper;
class TextWrapper; class TextWrapper;
class UIEventWrapper;
class URLConstructor; class URLConstructor;
class URLPrototype; class URLPrototype;
class URLSearchParamsConstructor; class URLSearchParamsConstructor;
@ -613,7 +599,6 @@ class URLSearchParamsIteratorWrapper;
class URLSearchParamsPrototype; class URLSearchParamsPrototype;
class URLSearchParamsWrapper; class URLSearchParamsWrapper;
class URLWrapper; class URLWrapper;
class WebGLContextEventWrapper;
class WebGLRenderingContextWrapper; class WebGLRenderingContextWrapper;
class WebSocketWrapper; class WebSocketWrapper;
class WindowObject; class WindowObject;

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/CloseEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/CloseEvent.h>
namespace Web::HTML {
CloseEvent* CloseEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, CloseEventInit const& event_init)
{
return window_object.heap().allocate<CloseEvent>(window_object.realm(), window_object, event_name, event_init);
}
CloseEvent* CloseEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, CloseEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
CloseEvent::CloseEvent(Bindings::WindowObject& window_object, FlyString const& event_name, CloseEventInit const& event_init)
: DOM::Event(window_object, event_name, event_init)
, m_was_clean(event_init.was_clean)
, m_code(event_init.code)
, m_reason(event_init.reason)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::CloseEventPrototype>("CloseEvent"));
}
CloseEvent::~CloseEvent() = default;
}

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Dex <dexes.ttp@gmail.com> * Copyright (c) 2021, Dex <dexes.ttp@gmail.com>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -17,36 +18,31 @@ struct CloseEventInit : public DOM::EventInit {
}; };
class CloseEvent : public DOM::Event { class CloseEvent : public DOM::Event {
JS_OBJECT(CloseEvent, DOM::Event);
public: public:
using WrapperType = Bindings::CloseEventWrapper; static CloseEvent* create(Bindings::WindowObject&, FlyString const& event_name, CloseEventInit const& event_init = {});
static CloseEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, CloseEventInit const& event_init);
static NonnullRefPtr<CloseEvent> create(FlyString const& event_name, CloseEventInit const& event_init = {}) CloseEvent(Bindings::WindowObject&, FlyString const& event_name, CloseEventInit const& event_init);
{
return adopt_ref(*new CloseEvent(event_name, event_init));
}
static NonnullRefPtr<CloseEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, CloseEventInit const& event_init)
{
return CloseEvent::create(event_name, event_init);
}
virtual ~CloseEvent() override = default; virtual ~CloseEvent() override;
CloseEvent& impl() { return *this; }
bool was_clean() const { return m_was_clean; } bool was_clean() const { return m_was_clean; }
u16 code() const { return m_code; } u16 code() const { return m_code; }
String reason() const { return m_reason; } String reason() const { return m_reason; }
protected: private:
CloseEvent(FlyString const& event_name, CloseEventInit const& event_init)
: DOM::Event(event_name, event_init)
, m_was_clean(event_init.was_clean)
, m_code(event_init.code)
, m_reason(event_init.reason)
{
}
bool m_was_clean { false }; bool m_was_clean { false };
u16 m_code { 0 }; u16 m_code { 0 };
String m_reason; String m_reason;
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::HTML::CloseEvent& object) { return &object; }
using CloseEventWrapper = Web::HTML::CloseEvent;
}

View file

@ -1,5 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[NoInstanceWrapper]
interface CloseEvent : Event { interface CloseEvent : Event {
constructor(DOMString type, optional CloseEventInit eventInitDict = {}); constructor(DOMString type, optional CloseEventInit eventInitDict = {});

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/ErrorEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/ErrorEvent.h>
namespace Web::HTML {
ErrorEvent* ErrorEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, ErrorEventInit const& event_init)
{
return window_object.heap().allocate<ErrorEvent>(window_object.realm(), window_object, event_name, event_init);
}
ErrorEvent* ErrorEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, ErrorEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
ErrorEvent::ErrorEvent(Bindings::WindowObject& window_object, FlyString const& event_name, ErrorEventInit const& event_init)
: DOM::Event(window_object, event_name)
, m_message(event_init.message)
, m_filename(event_init.filename)
, m_lineno(event_init.lineno)
, m_colno(event_init.colno)
, m_error(event_init.error)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::ErrorEventPrototype>("ErrorEvent"));
}
ErrorEvent::~ErrorEvent() = default;
void ErrorEvent::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_error);
}
}

View file

@ -21,20 +21,17 @@ struct ErrorEventInit : public DOM::EventInit {
// https://html.spec.whatwg.org/multipage/webappapis.html#errorevent // https://html.spec.whatwg.org/multipage/webappapis.html#errorevent
class ErrorEvent final : public DOM::Event { class ErrorEvent final : public DOM::Event {
JS_OBJECT(ErrorEvent, DOM::Event);
public: public:
using WrapperType = Bindings::ErrorEventWrapper; static ErrorEvent* create(Bindings::WindowObject&, FlyString const& event_name, ErrorEventInit const& event_init = {});
static ErrorEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, ErrorEventInit const& event_init);
static NonnullRefPtr<ErrorEvent> create(FlyString const& event_name, ErrorEventInit const& event_init = {}) ErrorEvent(Bindings::WindowObject&, FlyString const& event_name, ErrorEventInit const& event_init);
{
return adopt_ref(*new ErrorEvent(event_name, event_init));
}
static NonnullRefPtr<ErrorEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, ErrorEventInit const& event_init) virtual ~ErrorEvent() override;
{
return ErrorEvent::create(event_name, event_init);
}
virtual ~ErrorEvent() override = default; ErrorEvent& impl() { return *this; }
// https://html.spec.whatwg.org/multipage/webappapis.html#dom-errorevent-message // https://html.spec.whatwg.org/multipage/webappapis.html#dom-errorevent-message
String const& message() const { return m_message; } String const& message() const { return m_message; }
@ -49,24 +46,21 @@ public:
u32 colno() const { return m_colno; } u32 colno() const { return m_colno; }
// https://html.spec.whatwg.org/multipage/webappapis.html#dom-errorevent-error // https://html.spec.whatwg.org/multipage/webappapis.html#dom-errorevent-error
JS::Value error() const { return m_error.value(); } JS::Value error() const { return m_error; }
private: private:
ErrorEvent(FlyString const& event_name, ErrorEventInit const& event_init) virtual void visit_edges(Cell::Visitor&) override;
: DOM::Event(event_name)
, m_message(event_init.message)
, m_filename(event_init.filename)
, m_lineno(event_init.lineno)
, m_colno(event_init.colno)
, m_error(JS::make_handle(event_init.error))
{
}
String m_message { "" }; String m_message { "" };
String m_filename { "" }; // FIXME: This should be a USVString. String m_filename { "" }; // FIXME: This should be a USVString.
u32 m_lineno { 0 }; u32 m_lineno { 0 };
u32 m_colno { 0 }; u32 m_colno { 0 };
JS::Handle<JS::Value> m_error; JS::Value m_error;
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::HTML::ErrorEvent& object) { return &object; }
using ErrorEventWrapper = Web::HTML::ErrorEvent;
}

View file

@ -247,9 +247,9 @@ static void run_focus_update_steps(NonnullRefPtrVector<DOM::Node> old_chain, Non
// with related blur target as the related target. // with related blur target as the related target.
if (blur_event_target) { if (blur_event_target) {
// FIXME: Implement the "fire a focus event" spec operation. // FIXME: Implement the "fire a focus event" spec operation.
auto blur_event = UIEvents::FocusEvent::create(HTML::EventNames::blur); auto blur_event = UIEvents::FocusEvent::create(verify_cast<DOM::Node>(*blur_event_target).document().preferred_window_object(), HTML::EventNames::blur);
blur_event->set_related_target(related_blur_target); blur_event->set_related_target(related_blur_target);
blur_event_target->dispatch_event(move(blur_event)); blur_event_target->dispatch_event(*blur_event);
} }
} }
@ -290,9 +290,9 @@ static void run_focus_update_steps(NonnullRefPtrVector<DOM::Node> old_chain, Non
// with related focus target as the related target. // with related focus target as the related target.
if (focus_event_target) { if (focus_event_target) {
// FIXME: Implement the "fire a focus event" spec operation. // FIXME: Implement the "fire a focus event" spec operation.
auto focus_event = UIEvents::FocusEvent::create(HTML::EventNames::focus); auto focus_event = UIEvents::FocusEvent::create(verify_cast<DOM::Node>(*focus_event_target).document().preferred_window_object(), HTML::EventNames::focus);
focus_event->set_related_target(related_focus_target); focus_event->set_related_target(related_focus_target);
focus_event_target->dispatch_event(move(focus_event)); focus_event_target->dispatch_event(*focus_event);
} }
} }
} }
@ -411,7 +411,7 @@ bool HTMLElement::fire_a_synthetic_pointer_event(FlyString const& type, DOM::Ele
// 1. Let event be the result of creating an event using PointerEvent. // 1. Let event be the result of creating an event using PointerEvent.
// 2. Initialize event's type attribute to e. // 2. Initialize event's type attribute to e.
// FIXME: Actually create a PointerEvent! // FIXME: Actually create a PointerEvent!
auto event = UIEvents::MouseEvent::create(type); auto event = UIEvents::MouseEvent::create(document().preferred_window_object(), type);
// 3. Initialize event's bubbles and cancelable attributes to true. // 3. Initialize event's bubbles and cancelable attributes to true.
event->set_bubbles(true); event->set_bubbles(true);
@ -433,7 +433,7 @@ bool HTMLElement::fire_a_synthetic_pointer_event(FlyString const& type, DOM::Ele
// FIXME: 8. event's getModifierState() method is to return values appropriately describing the current state of the key input device. // FIXME: 8. event's getModifierState() method is to return values appropriately describing the current state of the key input device.
// 9. Return the result of dispatching event at target. // 9. Return the result of dispatching event at target.
return target.dispatch_event(move(event)); return target.dispatch_event(*event);
} }
// https://html.spec.whatwg.org/multipage/interaction.html#dom-click // https://html.spec.whatwg.org/multipage/interaction.html#dom-click

View file

@ -65,10 +65,10 @@ void HTMLFormElement::submit_form(RefPtr<HTMLElement> submitter, bool from_submi
SubmitEventInit event_init {}; SubmitEventInit event_init {};
event_init.submitter = submitter_button; event_init.submitter = submitter_button;
auto submit_event = SubmitEvent::create(EventNames::submit, event_init); auto submit_event = SubmitEvent::create(document().preferred_window_object(), EventNames::submit, event_init);
submit_event->set_bubbles(true); submit_event->set_bubbles(true);
submit_event->set_cancelable(true); submit_event->set_cancelable(true);
bool continue_ = dispatch_event(submit_event); bool continue_ = dispatch_event(*submit_event);
m_firing_submission_events = false; m_firing_submission_events = false;

View file

@ -92,7 +92,7 @@ void run_iframe_load_event_steps(HTML::HTMLIFrameElement& element)
// FIXME: 4. Set childDocument's iframe load in progress flag. // FIXME: 4. Set childDocument's iframe load in progress flag.
// 5. Fire an event named load at element. // 5. Fire an event named load at element.
element.dispatch_event(DOM::Event::create(HTML::EventNames::load)); element.dispatch_event(*DOM::Event::create(element.document().preferred_window_object(), HTML::EventNames::load));
// FIXME: 6. Unset childDocument's iframe load in progress flag. // FIXME: 6. Unset childDocument's iframe load in progress flag.
} }

View file

@ -26,7 +26,7 @@ HTMLImageElement::HTMLImageElement(DOM::Document& document, DOM::QualifiedName q
set_needs_style_update(true); set_needs_style_update(true);
this->document().set_needs_layout(); this->document().set_needs_layout();
queue_an_element_task(HTML::Task::Source::DOMManipulation, [this] { queue_an_element_task(HTML::Task::Source::DOMManipulation, [this] {
dispatch_event(DOM::Event::create(EventNames::load)); dispatch_event(*DOM::Event::create(this->document().preferred_window_object(), EventNames::load));
}); });
}; };
@ -35,7 +35,7 @@ HTMLImageElement::HTMLImageElement(DOM::Document& document, DOM::QualifiedName q
set_needs_style_update(true); set_needs_style_update(true);
this->document().set_needs_layout(); this->document().set_needs_layout();
queue_an_element_task(HTML::Task::Source::DOMManipulation, [this] { queue_an_element_task(HTML::Task::Source::DOMManipulation, [this] {
dispatch_event(DOM::Event::create(EventNames::error)); dispatch_event(*DOM::Event::create(this->document().preferred_window_object(), EventNames::error));
}); });
}; };

View file

@ -90,15 +90,15 @@ void HTMLInputElement::run_input_activation_behavior()
return; return;
// 2. Fire an event named input at the element with the bubbles and composed attributes initialized to true. // 2. Fire an event named input at the element with the bubbles and composed attributes initialized to true.
auto input_event = DOM::Event::create(HTML::EventNames::input); auto input_event = DOM::Event::create(document().preferred_window_object(), HTML::EventNames::input);
input_event->set_bubbles(true); input_event->set_bubbles(true);
input_event->set_composed(true); input_event->set_composed(true);
dispatch_event(move(input_event)); dispatch_event(*input_event);
// 3. Fire an event named change at the element with the bubbles attribute initialized to true. // 3. Fire an event named change at the element with the bubbles attribute initialized to true.
auto change_event = DOM::Event::create(HTML::EventNames::change); auto change_event = DOM::Event::create(document().preferred_window_object(), HTML::EventNames::change);
change_event->set_bubbles(true); change_event->set_bubbles(true);
dispatch_event(move(change_event)); dispatch_event(*change_event);
} else if (type_state() == TypeAttributeState::SubmitButton) { } else if (type_state() == TypeAttributeState::SubmitButton) {
RefPtr<HTMLFormElement> form; RefPtr<HTMLFormElement> form;
// 1. If the element does not have a form owner, then return. // 1. If the element does not have a form owner, then return.
@ -112,7 +112,7 @@ void HTMLInputElement::run_input_activation_behavior()
// 3. Submit the form owner from the element. // 3. Submit the form owner from the element.
form->submit_form(this); form->submit_form(this);
} else { } else {
dispatch_event(DOM::Event::create(EventNames::change)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), EventNames::change));
} }
} }
@ -125,15 +125,15 @@ void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
// NOTE: This is a bit ad-hoc, but basically implements part of "4.10.5.5 Common event behaviors" // NOTE: This is a bit ad-hoc, but basically implements part of "4.10.5.5 Common event behaviors"
// https://html.spec.whatwg.org/multipage/input.html#common-input-element-events // https://html.spec.whatwg.org/multipage/input.html#common-input-element-events
queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { queue_an_element_task(HTML::Task::Source::UserInteraction, [this] {
auto input_event = DOM::Event::create(HTML::EventNames::input); auto input_event = DOM::Event::create(document().preferred_window_object(), HTML::EventNames::input);
input_event->set_bubbles(true); input_event->set_bubbles(true);
input_event->set_composed(true); input_event->set_composed(true);
dispatch_event(move(input_event)); dispatch_event(*input_event);
// FIXME: This should only fire when the input is "committed", whatever that means. // FIXME: This should only fire when the input is "committed", whatever that means.
auto change_event = DOM::Event::create(HTML::EventNames::change); auto change_event = DOM::Event::create(document().preferred_window_object(), HTML::EventNames::change);
change_event->set_bubbles(true); change_event->set_bubbles(true);
dispatch_event(move(change_event)); dispatch_event(*change_event);
}); });
} }

View file

@ -96,7 +96,7 @@ void HTMLObjectElement::queue_element_task_to_run_object_representation_steps()
// 3. If that failed, fire an event named error at the element, then jump to the step below labeled fallback. // 3. If that failed, fire an event named error at the element, then jump to the step below labeled fallback.
if (!url.is_valid()) { if (!url.is_valid()) {
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::error));
return run_object_representation_fallback_steps(); return run_object_representation_fallback_steps();
} }
@ -123,7 +123,7 @@ void HTMLObjectElement::queue_element_task_to_run_object_representation_steps()
void HTMLObjectElement::resource_did_fail() void HTMLObjectElement::resource_did_fail()
{ {
// 4.7. If the load failed (e.g. there was an HTTP 404 error, there was a DNS error), fire an event named error at the element, then jump to the step below labeled fallback. // 4.7. If the load failed (e.g. there was an HTTP 404 error, there was a DNS error), fire an event named error at the element, then jump to the step below labeled fallback.
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::error));
run_object_representation_fallback_steps(); run_object_representation_fallback_steps();
} }
@ -261,7 +261,7 @@ void HTMLObjectElement::run_object_representation_completed_steps(Representation
// 4.11. If the object element does not represent its nested browsing context, then once the resource is completely loaded, queue an element task on the DOM manipulation task source given the object element to fire an event named load at the element. // 4.11. If the object element does not represent its nested browsing context, then once the resource is completely loaded, queue an element task on the DOM manipulation task source given the object element to fire an event named load at the element.
if (representation != Representation::NestedBrowsingContext) { if (representation != Representation::NestedBrowsingContext) {
queue_an_element_task(HTML::Task::Source::DOMManipulation, [&]() { queue_an_element_task(HTML::Task::Source::DOMManipulation, [&]() {
dispatch_event(DOM::Event::create(HTML::EventNames::load)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::load));
}); });
} }

View file

@ -48,7 +48,7 @@ void HTMLScriptElement::execute_script()
// 3. If the script's script is null for scriptElement, then fire an event named error at scriptElement, and return. // 3. If the script's script is null for scriptElement, then fire an event named error at scriptElement, and return.
if (!m_script) { if (!m_script) {
dbgln("HTMLScriptElement: Refusing to run script because the script's script is null."); dbgln("HTMLScriptElement: Refusing to run script because the script's script is null.");
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::error));
return; return;
} }
@ -95,7 +95,7 @@ void HTMLScriptElement::execute_script()
// 7. If scriptElement is from an external file, then fire an event named load at scriptElement. // 7. If scriptElement is from an external file, then fire an event named load at scriptElement.
if (m_from_an_external_file) if (m_from_an_external_file)
dispatch_event(DOM::Event::create(HTML::EventNames::load)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::load));
} }
// https://mimesniff.spec.whatwg.org/#javascript-mime-type-essence-match // https://mimesniff.spec.whatwg.org/#javascript-mime-type-essence-match
@ -259,7 +259,7 @@ void HTMLScriptElement::prepare_script()
if (src.is_empty()) { if (src.is_empty()) {
dbgln("HTMLScriptElement: Refusing to run script because the src attribute is empty."); dbgln("HTMLScriptElement: Refusing to run script because the src attribute is empty.");
queue_an_element_task(HTML::Task::Source::Unspecified, [this] { queue_an_element_task(HTML::Task::Source::Unspecified, [this] {
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::error));
}); });
return; return;
} }
@ -272,7 +272,7 @@ void HTMLScriptElement::prepare_script()
if (!url.is_valid()) { if (!url.is_valid()) {
dbgln("HTMLScriptElement: Refusing to run script because the src URL '{}' is invalid.", url); dbgln("HTMLScriptElement: Refusing to run script because the src URL '{}' is invalid.", url);
queue_an_element_task(HTML::Task::Source::Unspecified, [this] { queue_an_element_task(HTML::Task::Source::Unspecified, [this] {
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(document().preferred_window_object(), HTML::EventNames::error));
}); });
return; return;
} }

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/MessageEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/MessageEvent.h>
namespace Web::HTML {
MessageEvent* MessageEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, MessageEventInit const& event_init)
{
return window_object.heap().allocate<MessageEvent>(window_object.realm(), window_object, event_name, event_init);
}
MessageEvent* MessageEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, MessageEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
MessageEvent::MessageEvent(Bindings::WindowObject& window_object, FlyString const& event_name, MessageEventInit const& event_init)
: DOM::Event(window_object, event_name, event_init)
, m_data(event_init.data)
, m_origin(event_init.origin)
, m_last_event_id(event_init.last_event_id)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::MessageEventPrototype>("MessageEvent"));
}
MessageEvent::~MessageEvent() = default;
void MessageEvent::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_data);
}
}

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Dex <dexes.ttp@gmail.com> * Copyright (c) 2021, Dex <dexes.ttp@gmail.com>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -17,36 +18,32 @@ struct MessageEventInit : public DOM::EventInit {
}; };
class MessageEvent : public DOM::Event { class MessageEvent : public DOM::Event {
JS_OBJECT(MessageEvent, DOM::Event);
public: public:
using WrapperType = Bindings::MessageEventWrapper; static MessageEvent* create(Bindings::WindowObject&, FlyString const& event_name, MessageEventInit const& event_init = {});
static MessageEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, MessageEventInit const& event_init);
static NonnullRefPtr<MessageEvent> create(FlyString const& event_name, MessageEventInit const& event_init = {}) MessageEvent(Bindings::WindowObject&, FlyString const& event_name, MessageEventInit const& event_init);
{ virtual ~MessageEvent() override;
return adopt_ref(*new MessageEvent(event_name, event_init));
}
static NonnullRefPtr<MessageEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, MessageEventInit const& event_init)
{
return MessageEvent::create(event_name, event_init);
}
virtual ~MessageEvent() override = default; MessageEvent& impl() { return *this; }
JS::Value data() const { return m_data.value(); } JS::Value data() const { return m_data; }
String const& origin() const { return m_origin; } String const& origin() const { return m_origin; }
String const& last_event_id() const { return m_last_event_id; } String const& last_event_id() const { return m_last_event_id; }
protected: private:
MessageEvent(FlyString const& event_name, MessageEventInit const& event_init) virtual void visit_edges(Cell::Visitor&) override;
: DOM::Event(event_name, event_init)
, m_data(JS::make_handle(event_init.data))
, m_origin(event_init.origin)
, m_last_event_id(event_init.last_event_id)
{
}
JS::Handle<JS::Value> m_data; JS::Value m_data;
String m_origin; String m_origin;
String m_last_event_id; String m_last_event_id;
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::HTML::MessageEvent& object) { return &object; }
using MessageEventWrapper = Web::HTML::MessageEvent;
}

View file

@ -1,5 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[NoInstanceWrapper]
interface MessageEvent : Event { interface MessageEvent : Event {
constructor(DOMString type, optional MessageEventInit eventInitDict = {}); constructor(DOMString type, optional MessageEventInit eventInitDict = {});

View file

@ -80,7 +80,7 @@ void MessagePort::post_message(JS::Value message)
MessageEventInit event_init {}; MessageEventInit event_init {};
event_init.data = message; event_init.data = message;
event_init.origin = "<origin>"; event_init.origin = "<origin>";
strong_port->dispatch_event(MessageEvent::create(HTML::EventNames::message, event_init)); strong_port->dispatch_event(*MessageEvent::create(verify_cast<Bindings::WindowObject>(strong_port->wrapper()->global_object()), HTML::EventNames::message, event_init));
})); }));
} }

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/PageTransitionEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/PageTransitionEvent.h>
namespace Web::HTML {
PageTransitionEvent* PageTransitionEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, PageTransitionEventInit const& event_init)
{
return window_object.heap().allocate<PageTransitionEvent>(window_object.realm(), window_object, event_name, event_init);
}
PageTransitionEvent* PageTransitionEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, PageTransitionEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
PageTransitionEvent::PageTransitionEvent(Bindings::WindowObject& window_object, FlyString const& event_name, PageTransitionEventInit const& event_init)
: DOM::Event(window_object, event_name, event_init)
, m_persisted(event_init.persisted)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::PageTransitionEventPrototype>("PageTransitionEvent"));
}
PageTransitionEvent::~PageTransitionEvent() = default;
}

View file

@ -15,30 +15,27 @@ struct PageTransitionEventInit : public DOM::EventInit {
}; };
class PageTransitionEvent final : public DOM::Event { class PageTransitionEvent final : public DOM::Event {
JS_OBJECT(PageTransitionEvent, DOM::Event);
public: public:
using WrapperType = Bindings::PageTransitionEventWrapper; static PageTransitionEvent* create(Bindings::WindowObject&, FlyString const& event_name, PageTransitionEventInit const& event_init);
static PageTransitionEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, PageTransitionEventInit const& event_init);
static NonnullRefPtr<PageTransitionEvent> create(FlyString const& event_name, PageTransitionEventInit const& event_init) PageTransitionEvent(Bindings::WindowObject&, FlyString const& event_name, PageTransitionEventInit const& event_init);
{
return adopt_ref(*new PageTransitionEvent(event_name, event_init));
}
static NonnullRefPtr<PageTransitionEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, PageTransitionEventInit const& event_init)
{
return PageTransitionEvent::create(event_name, event_init);
}
virtual ~PageTransitionEvent() override = default; virtual ~PageTransitionEvent() override;
PageTransitionEvent& impl() { return *this; }
bool persisted() const { return m_persisted; } bool persisted() const { return m_persisted; }
protected: private:
PageTransitionEvent(FlyString const& event_name, PageTransitionEventInit const& event_init)
: DOM::Event(event_name, event_init)
, m_persisted(event_init.persisted)
{
}
bool m_persisted { false }; bool m_persisted { false };
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::HTML::PageTransitionEvent& object) { return &object; }
using PageTransitionEventWrapper = Web::HTML::PageTransitionEvent;
}

View file

@ -236,9 +236,9 @@ void HTMLParser::the_end()
// FIXME: 1. Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object. // FIXME: 1. Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object.
// 2. Fire an event named DOMContentLoaded at the Document object, with its bubbles attribute initialized to true. // 2. Fire an event named DOMContentLoaded at the Document object, with its bubbles attribute initialized to true.
auto content_loaded_event = DOM::Event::create(HTML::EventNames::DOMContentLoaded); auto content_loaded_event = DOM::Event::create(document->preferred_window_object(), HTML::EventNames::DOMContentLoaded);
content_loaded_event->set_bubbles(true); content_loaded_event->set_bubbles(true);
document->dispatch_event(content_loaded_event); document->dispatch_event(*content_loaded_event);
// FIXME: 3. Set the Document's load timing info's DOM content loaded event end time to the current high resolution time given the Document's relevant global object. // FIXME: 3. Set the Document's load timing info's DOM content loaded event end time to the current high resolution time given the Document's relevant global object.
@ -275,7 +275,7 @@ void HTMLParser::the_end()
// 5. Fire an event named load at window, with legacy target override flag set. // 5. Fire an event named load at window, with legacy target override flag set.
// FIXME: The legacy target override flag is currently set by a virtual override of dispatch_event() // FIXME: The legacy target override flag is currently set by a virtual override of dispatch_event()
// We should reorganize this so that the flag appears explicitly here instead. // We should reorganize this so that the flag appears explicitly here instead.
window->dispatch_event(DOM::Event::create(HTML::EventNames::load)); window->dispatch_event(*DOM::Event::create(document->preferred_window_object(), HTML::EventNames::load));
// FIXME: 6. Invoke WebDriver BiDi load complete with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "complete", and url is the Document object's URL. // FIXME: 6. Invoke WebDriver BiDi load complete with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "complete", and url is the Document object's URL.

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/PromiseRejectionEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/PromiseRejectionEvent.h>
namespace Web::HTML {
PromiseRejectionEvent* PromiseRejectionEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, PromiseRejectionEventInit const& event_init)
{
return window_object.heap().allocate<PromiseRejectionEvent>(window_object.realm(), window_object, event_name, event_init);
}
PromiseRejectionEvent* PromiseRejectionEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, PromiseRejectionEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
PromiseRejectionEvent::PromiseRejectionEvent(Bindings::WindowObject& window_object, FlyString const& event_name, PromiseRejectionEventInit const& event_init)
: DOM::Event(window_object, event_name, event_init)
, m_promise(const_cast<JS::Promise*>(event_init.promise.cell()))
, m_reason(event_init.reason)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::PromiseRejectionEventPrototype>("PromiseRejectionEvent"));
}
PromiseRejectionEvent::~PromiseRejectionEvent() = default;
void PromiseRejectionEvent::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_promise);
visitor.visit(m_reason);
}
}

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org> * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -17,35 +18,33 @@ struct PromiseRejectionEventInit : public DOM::EventInit {
JS::Value reason; JS::Value reason;
}; };
class PromiseRejectionEvent : public DOM::Event { class PromiseRejectionEvent final : public DOM::Event {
JS_OBJECT(PromiseRejectionEvent, DOM::Event);
public: public:
using WrapperType = Bindings::PromiseRejectionEventWrapper; static PromiseRejectionEvent* create(Bindings::WindowObject&, FlyString const& event_name, PromiseRejectionEventInit const& event_init = {});
static PromiseRejectionEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, PromiseRejectionEventInit const& event_init);
static NonnullRefPtr<PromiseRejectionEvent> create(FlyString const& event_name, PromiseRejectionEventInit const& event_init = {}) PromiseRejectionEvent(Bindings::WindowObject&, FlyString const& event_name, PromiseRejectionEventInit const& event_init);
{
return adopt_ref(*new PromiseRejectionEvent(event_name, event_init));
}
static NonnullRefPtr<PromiseRejectionEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, PromiseRejectionEventInit const& event_init)
{
return PromiseRejectionEvent::create(event_name, event_init);
}
virtual ~PromiseRejectionEvent() override = default; virtual ~PromiseRejectionEvent() override;
PromiseRejectionEvent& impl() { return *this; }
// Needs to return a pointer for the generated JS bindings to work. // Needs to return a pointer for the generated JS bindings to work.
JS::Promise const* promise() const { return m_promise.cell(); } JS::Promise const* promise() const { return m_promise; }
JS::Value reason() const { return m_reason.value(); } JS::Value reason() const { return m_reason; }
protected: private:
PromiseRejectionEvent(FlyString const& event_name, PromiseRejectionEventInit const& event_init) virtual void visit_edges(Cell::Visitor&) override;
: DOM::Event(event_name, event_init)
, m_promise(event_init.promise)
, m_reason(JS::make_handle(event_init.reason))
{
}
JS::Handle<JS::Promise> m_promise; JS::Promise* m_promise { nullptr };
JS::Handle<JS::Value> m_reason; JS::Value m_reason;
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::HTML::PromiseRejectionEvent& object) { return &object; }
using PromiseRejectionEventWrapper = Web::HTML::PromiseRejectionEvent;
}

View file

@ -1,6 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[Exposed=(Window,Worker)] [Exposed=(Window,Worker), NoInstanceWrapper]
interface PromiseRejectionEvent : Event { interface PromiseRejectionEvent : Event {
constructor(DOMString type, PromiseRejectionEventInit eventInitDict); constructor(DOMString type, PromiseRejectionEventInit eventInitDict);

View file

@ -217,12 +217,12 @@ void EnvironmentSettingsObject::notify_about_rejected_promises(Badge<EventLoop>)
/* .promise = */ promise_handle, /* .promise = */ promise_handle,
/* .reason = */ promise.result(), /* .reason = */ promise.result(),
}; };
auto promise_rejection_event = PromiseRejectionEvent::create(HTML::EventNames::unhandledrejection, event_init);
// FIXME: This currently assumes that global is a WindowObject. // FIXME: This currently assumes that global is a WindowObject.
auto& window = verify_cast<Bindings::WindowObject>(*global.cell()); auto& window = verify_cast<Bindings::WindowObject>(*global.cell());
bool not_handled = window.impl().dispatch_event(move(promise_rejection_event)); auto promise_rejection_event = PromiseRejectionEvent::create(window, HTML::EventNames::unhandledrejection, event_init);
bool not_handled = window.impl().dispatch_event(*promise_rejection_event);
// 3. If notHandled is false, then the promise rejection is handled. Otherwise, the promise rejection is not handled. // 3. If notHandled is false, then the promise rejection is handled. Otherwise, the promise rejection is not handled.

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/SubmitEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/SubmitEvent.h>
namespace Web::HTML {
SubmitEvent* SubmitEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, SubmitEventInit const& event_init)
{
return window_object.heap().allocate<SubmitEvent>(window_object.realm(), window_object, event_name, event_init);
}
SubmitEvent* SubmitEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, SubmitEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
SubmitEvent::SubmitEvent(Bindings::WindowObject& window_object, FlyString const& event_name, SubmitEventInit const& event_init)
: DOM::Event(window_object, event_name, event_init)
, m_submitter(event_init.submitter)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::SubmitEventPrototype>("SubmitEvent"));
}
SubmitEvent::~SubmitEvent() = default;
}

View file

@ -17,29 +17,21 @@ struct SubmitEventInit : public DOM::EventInit {
}; };
class SubmitEvent final : public DOM::Event { class SubmitEvent final : public DOM::Event {
JS_OBJECT(SubmitEvent, DOM::Event);
public: public:
using WrapperType = Bindings::SubmitEventWrapper; static SubmitEvent* create(Bindings::WindowObject&, FlyString const& event_name, SubmitEventInit const& event_init);
static SubmitEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, SubmitEventInit const& event_init);
static NonnullRefPtr<SubmitEvent> create(FlyString const& event_name, SubmitEventInit const& event_init) virtual ~SubmitEvent() override;
{
return adopt_ref(*new SubmitEvent(event_name, event_init));
}
static NonnullRefPtr<SubmitEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, SubmitEventInit const& event_init)
{
return SubmitEvent::create(event_name, event_init);
}
virtual ~SubmitEvent() override = default; SubmitEvent(Bindings::WindowObject&, FlyString const& event_name, SubmitEventInit const& event_init);
SubmitEvent& impl() { return *this; }
RefPtr<HTMLElement> submitter() const { return m_submitter; } RefPtr<HTMLElement> submitter() const { return m_submitter; }
private: private:
SubmitEvent(FlyString const& event_name, SubmitEventInit const& event_init)
: DOM::Event(event_name, event_init)
, m_submitter(event_init.submitter)
{
}
RefPtr<HTMLElement> m_submitter; RefPtr<HTMLElement> m_submitter;
}; };

View file

@ -1,6 +1,7 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
#import <HTML/HTMLElement.idl> #import <HTML/HTMLElement.idl>
[NoInstanceWrapper]
interface SubmitEvent : Event { interface SubmitEvent : Event {
constructor(DOMString type, optional SubmitEventInit eventInitDict = {}); constructor(DOMString type, optional SubmitEventInit eventInitDict = {});

View file

@ -279,7 +279,7 @@ void Window::did_call_location_replace(Badge<Bindings::LocationObject>, String u
browsing_context->loader().load(move(new_url), FrameLoader::Type::Navigation); browsing_context->loader().load(move(new_url), FrameLoader::Type::Navigation);
} }
bool Window::dispatch_event(NonnullRefPtr<DOM::Event> event) bool Window::dispatch_event(DOM::Event& event)
{ {
return DOM::EventDispatcher::dispatch(*this, event, true); return DOM::EventDispatcher::dispatch(*this, event, true);
} }
@ -458,7 +458,7 @@ void Window::fire_a_page_transition_event(FlyString const& event_name, bool pers
// with the persisted attribute initialized to persisted, // with the persisted attribute initialized to persisted,
HTML::PageTransitionEventInit event_init {}; HTML::PageTransitionEventInit event_init {};
event_init.persisted = persisted; event_init.persisted = persisted;
auto event = HTML::PageTransitionEvent::create(event_name, event_init); auto event = HTML::PageTransitionEvent::create(associated_document().preferred_window_object(), event_name, event_init);
// ...the cancelable attribute initialized to true, // ...the cancelable attribute initialized to true,
event->set_cancelable(true); event->set_cancelable(true);
@ -467,7 +467,7 @@ void Window::fire_a_page_transition_event(FlyString const& event_name, bool pers
event->set_bubbles(true); event->set_bubbles(true);
// and legacy target override flag set. // and legacy target override flag set.
dispatch_event(move(event)); dispatch_event(*event);
} }
// https://html.spec.whatwg.org/#dom-queuemicrotask // https://html.spec.whatwg.org/#dom-queuemicrotask
@ -567,7 +567,9 @@ DOM::ExceptionOr<void> Window::post_message(JS::Value message, String const&)
HTML::MessageEventInit event_init {}; HTML::MessageEventInit event_init {};
event_init.data = message; event_init.data = message;
event_init.origin = "<origin>"; event_init.origin = "<origin>";
strong_this->dispatch_event(HTML::MessageEvent::create(HTML::EventNames::message, event_init)); auto* wrapper = static_cast<Bindings::WindowObject*>(strong_this->wrapper());
VERIFY(wrapper);
strong_this->dispatch_event(*HTML::MessageEvent::create(*wrapper, HTML::EventNames::message, event_init));
}); });
return {}; return {};
} }
@ -688,4 +690,9 @@ void Window::set_associated_document(DOM::Document& document)
m_associated_document = document; m_associated_document = document;
} }
void Window::set_current_event(DOM::Event* event)
{
m_current_event = JS::make_handle(event);
}
} }

View file

@ -43,7 +43,7 @@ public:
virtual void ref_event_target() override { RefCounted::ref(); } virtual void ref_event_target() override { RefCounted::ref(); }
virtual void unref_event_target() override { RefCounted::unref(); } virtual void unref_event_target() override { RefCounted::unref(); }
virtual bool dispatch_event(NonnullRefPtr<DOM::Event>) override; virtual bool dispatch_event(DOM::Event&) override;
virtual JS::Object* create_wrapper(JS::Realm&) override; virtual JS::Object* create_wrapper(JS::Realm&) override;
Page* page(); Page* page();
@ -92,8 +92,9 @@ public:
CSS::Screen& screen() { return *m_screen; } CSS::Screen& screen() { return *m_screen; }
DOM::Event const* current_event() const { return m_current_event; } DOM::Event* current_event() { return m_current_event.cell(); }
void set_current_event(DOM::Event* event) { m_current_event = event; } DOM::Event const* current_event() const { return m_current_event.cell(); }
void set_current_event(DOM::Event* event);
CSS::CSSStyleDeclaration* get_computed_style(DOM::Element&) const; CSS::CSSStyleDeclaration* get_computed_style(DOM::Element&) const;
NonnullRefPtr<CSS::MediaQueryList> match_media(String); NonnullRefPtr<CSS::MediaQueryList> match_media(String);
@ -157,7 +158,7 @@ private:
NonnullOwnPtr<HighResolutionTime::Performance> m_performance; NonnullOwnPtr<HighResolutionTime::Performance> m_performance;
NonnullRefPtr<Crypto::Crypto> m_crypto; NonnullRefPtr<Crypto::Crypto> m_crypto;
NonnullOwnPtr<CSS::Screen> m_screen; NonnullOwnPtr<CSS::Screen> m_screen;
RefPtr<DOM::Event> m_current_event; JS::Handle<DOM::Event> m_current_event;
AnimationFrameCallbackDriver m_animation_frame_callback_driver; AnimationFrameCallbackDriver m_animation_frame_callback_driver;

View file

@ -148,7 +148,8 @@ void Worker::run_a_worker(AK::URL& url, EnvironmentSettingsObject& outside_setti
MessageEventInit event_init {}; MessageEventInit event_init {};
event_init.data = message; event_init.data = message;
event_init.origin = "<origin>"; event_init.origin = "<origin>";
dispatch_event(MessageEvent::create(HTML::EventNames::message, event_init)); // FIXME: The cast here is totally bogus, since workers don't have a WindowObject..
dispatch_event(*MessageEvent::create(verify_cast<Bindings::WindowObject>(*m_worker_scope), HTML::EventNames::message, event_init));
})); }));
return JS::js_undefined(); return JS::js_undefined();

View file

@ -205,12 +205,12 @@ bool EventHandler::handle_mouseup(Gfx::IntPoint const& position, unsigned button
} }
auto offset = compute_mouse_event_offset(position, *layout_node); auto offset = compute_mouse_event_offset(position, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::mouseup, offset.x(), offset.y(), position.x(), position.y(), button)); node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->document().preferred_window_object(), UIEvents::EventNames::mouseup, offset.x(), offset.y(), position.x(), position.y(), button));
handled_event = true; handled_event = true;
bool run_activation_behavior = true; bool run_activation_behavior = true;
if (node.ptr() == m_mousedown_target && button == GUI::MouseButton::Primary) { if (node.ptr() == m_mousedown_target && button == GUI::MouseButton::Primary) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::click, offset.x(), offset.y(), position.x(), position.y(), button)); run_activation_behavior = node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->document().preferred_window_object(), UIEvents::EventNames::click, offset.x(), offset.y(), position.x(), position.y(), button));
} }
if (run_activation_behavior) { if (run_activation_behavior) {
@ -334,7 +334,7 @@ bool EventHandler::handle_mousedown(Gfx::IntPoint const& position, unsigned butt
m_mousedown_target = node; m_mousedown_target = node;
auto offset = compute_mouse_event_offset(position, *layout_node); auto offset = compute_mouse_event_offset(position, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::mousedown, offset.x(), offset.y(), position.x(), position.y(), button)); node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->document().preferred_window_object(), UIEvents::EventNames::mousedown, offset.x(), offset.y(), position.x(), position.y(), button));
} }
// NOTE: Dispatching an event may have disturbed the world. // NOTE: Dispatching an event may have disturbed the world.
@ -455,7 +455,7 @@ bool EventHandler::handle_mousemove(Gfx::IntPoint const& position, unsigned butt
} }
auto offset = compute_mouse_event_offset(position, *layout_node); auto offset = compute_mouse_event_offset(position, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::mousemove, offset.x(), offset.y(), position.x(), position.y())); node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->document().preferred_window_object(), UIEvents::EventNames::mousemove, offset.x(), offset.y(), position.x(), position.y()));
// 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().paint_box()) if (!paint_root() || paint_root() != node->document().paint_box())
return true; return true;
@ -543,7 +543,7 @@ bool EventHandler::handle_doubleclick(Gfx::IntPoint const& position, unsigned bu
return false; return false;
auto offset = compute_mouse_event_offset(position, *layout_node); auto offset = compute_mouse_event_offset(position, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(UIEvents::EventNames::dblclick, offset.x(), offset.y(), position.x(), position.y(), button)); node->dispatch_event(*UIEvents::MouseEvent::create_from_platform_event(node->document().preferred_window_object(), UIEvents::EventNames::dblclick, offset.x(), offset.y(), position.x(), position.y(), button));
// 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().paint_box()) if (!paint_root() || paint_root() != node->document().paint_box())
@ -722,15 +722,15 @@ bool EventHandler::handle_keydown(KeyCode key, unsigned modifiers, u32 code_poin
return true; return true;
} }
auto event = UIEvents::KeyboardEvent::create_from_platform_event(UIEvents::EventNames::keydown, key, modifiers, code_point); auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->preferred_window_object(), UIEvents::EventNames::keydown, key, modifiers, code_point);
if (RefPtr<DOM::Element> focused_element = document->focused_element()) if (RefPtr<DOM::Element> focused_element = document->focused_element())
return focused_element->dispatch_event(move(event)); return focused_element->dispatch_event(*event);
if (RefPtr<HTML::HTMLElement> body = m_browsing_context.active_document()->body()) if (RefPtr<HTML::HTMLElement> body = m_browsing_context.active_document()->body())
return body->dispatch_event(move(event)); return body->dispatch_event(*event);
return document->root().dispatch_event(move(event)); return document->root().dispatch_event(*event);
} }
bool EventHandler::handle_keyup(KeyCode key, unsigned modifiers, u32 code_point) bool EventHandler::handle_keyup(KeyCode key, unsigned modifiers, u32 code_point)
@ -739,15 +739,15 @@ bool EventHandler::handle_keyup(KeyCode key, unsigned modifiers, u32 code_point)
if (!document) if (!document)
return false; return false;
auto event = UIEvents::KeyboardEvent::create_from_platform_event(UIEvents::EventNames::keyup, key, modifiers, code_point); auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->preferred_window_object(), UIEvents::EventNames::keyup, key, modifiers, code_point);
if (RefPtr<DOM::Element> focused_element = document->focused_element()) if (RefPtr<DOM::Element> focused_element = document->focused_element())
return document->focused_element()->dispatch_event(move(event)); return document->focused_element()->dispatch_event(*event);
if (RefPtr<HTML::HTMLElement> body = document->body()) if (RefPtr<HTML::HTMLElement> body = document->body())
return body->dispatch_event(move(event)); return body->dispatch_event(*event);
return document->root().dispatch_event(move(event)); return document->root().dispatch_event(*event);
} }
void EventHandler::set_mouse_event_tracking_layout_node(Layout::Node* layout_node) void EventHandler::set_mouse_event_tracking_layout_node(Layout::Node* layout_node)

View file

@ -4,13 +4,21 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibWeb/Bindings/FocusEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/UIEvents/FocusEvent.h> #include <LibWeb/UIEvents/FocusEvent.h>
namespace Web::UIEvents { namespace Web::UIEvents {
FocusEvent::FocusEvent(FlyString const& event_name, FocusEventInit const& event_init) FocusEvent* FocusEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, FocusEventInit const& event_init)
: UIEvent(event_name)
{ {
return window_object.heap().allocate<FocusEvent>(window_object.realm(), window_object, event_name, event_init);
}
FocusEvent::FocusEvent(Bindings::WindowObject& window_object, FlyString const& event_name, FocusEventInit const& event_init)
: UIEvent(window_object, event_name)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::FocusEventPrototype>("FocusEvent"));
set_related_target(const_cast<DOM::EventTarget*>(event_init.related_target.ptr())); set_related_target(const_cast<DOM::EventTarget*>(event_init.related_target.ptr()));
} }

View file

@ -15,18 +15,20 @@ struct FocusEventInit : public UIEventInit {
}; };
class FocusEvent final : public UIEvent { class FocusEvent final : public UIEvent {
public: JS_OBJECT(FocusEvent, UIEvent);
using WrapperType = Bindings::FocusEventWrapper;
public:
static FocusEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, FocusEventInit const& event_init);
FocusEvent(Bindings::WindowObject&, FlyString const& event_name, FocusEventInit const&);
virtual ~FocusEvent() override; virtual ~FocusEvent() override;
static NonnullRefPtr<FocusEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, FocusEventInit const& event_init) FocusEvent& impl() { return *this; }
{
return adopt_ref(*new FocusEvent(event_name, event_init));
}
private:
FocusEvent(FlyString const& event_name, FocusEventInit const&);
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::UIEvents::FocusEvent& object) { return &object; }
using FocusEventWrapper = Web::UIEvents::FocusEvent;
}

View file

@ -1,6 +1,6 @@
#import <UIEvents/UIEvent.idl> #import <UIEvents/UIEvent.idl>
[Exposed=Window] [Exposed=Window, NoInstanceWrapper]
interface FocusEvent : UIEvent { interface FocusEvent : UIEvent {
constructor(DOMString type, optional FocusEventInit eventInitDict = {}); constructor(DOMString type, optional FocusEventInit eventInitDict = {});

View file

@ -1,10 +1,12 @@
/* /*
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/CharacterTypes.h> #include <AK/CharacterTypes.h>
#include <LibWeb/Bindings/KeyboardEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/UIEvents/KeyboardEvent.h> #include <LibWeb/UIEvents/KeyboardEvent.h>
namespace Web::UIEvents { namespace Web::UIEvents {
@ -65,7 +67,7 @@ static unsigned long determine_key_code(KeyCode platform_key, u32 code_point)
return platform_key; return platform_key;
} }
NonnullRefPtr<KeyboardEvent> KeyboardEvent::create_from_platform_event(FlyString const& event_name, KeyCode platform_key, unsigned modifiers, u32 code_point) KeyboardEvent* KeyboardEvent::create_from_platform_event(Bindings::WindowObject& window_object, FlyString const& event_name, KeyCode platform_key, unsigned modifiers, u32 code_point)
{ {
// FIXME: Figure out what these should actually contain. // FIXME: Figure out what these should actually contain.
String event_key = key_code_to_string(platform_key); String event_key = key_code_to_string(platform_key);
@ -87,7 +89,7 @@ NonnullRefPtr<KeyboardEvent> KeyboardEvent::create_from_platform_event(FlyString
event_init.bubbles = true; event_init.bubbles = true;
event_init.cancelable = true; event_init.cancelable = true;
event_init.composed = true; event_init.composed = true;
return KeyboardEvent::create(event_name, event_init); return KeyboardEvent::create(window_object, event_name, event_init);
} }
bool KeyboardEvent::get_modifier_state(String const& key_arg) bool KeyboardEvent::get_modifier_state(String const& key_arg)
@ -102,4 +104,34 @@ bool KeyboardEvent::get_modifier_state(String const& key_arg)
return m_meta_key; return m_meta_key;
return false; return false;
} }
KeyboardEvent* KeyboardEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, KeyboardEventInit const& event_init)
{
return window_object.heap().allocate<KeyboardEvent>(window_object.realm(), window_object, event_name, event_init);
}
KeyboardEvent* KeyboardEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, KeyboardEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
KeyboardEvent::KeyboardEvent(Bindings::WindowObject& window_object, FlyString const& event_name, KeyboardEventInit const& event_init)
: UIEvent(window_object, event_name, event_init)
, m_key(event_init.key)
, m_code(event_init.code)
, m_location(event_init.location)
, m_ctrl_key(event_init.ctrl_key)
, m_shift_key(event_init.shift_key)
, m_alt_key(event_init.alt_key)
, m_meta_key(event_init.meta_key)
, m_repeat(event_init.repeat)
, m_is_composing(event_init.is_composing)
, m_key_code(event_init.key_code)
, m_char_code(event_init.char_code)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::KeyboardEventPrototype>("KeyboardEvent"));
}
KeyboardEvent::~KeyboardEvent() = default;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -25,21 +25,18 @@ struct KeyboardEventInit : public EventModifierInit {
// https://www.w3.org/TR/uievents/#interface-keyboardevent // https://www.w3.org/TR/uievents/#interface-keyboardevent
class KeyboardEvent final : public UIEvent { class KeyboardEvent final : public UIEvent {
JS_OBJECT(KeyboardEvent, UIEvent);
public: public:
using WrapperType = Bindings::KeyboardEventWrapper; static KeyboardEvent* create(Bindings::WindowObject&, FlyString const& event_name, KeyboardEventInit const& event_init = {});
static KeyboardEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, KeyboardEventInit const& event_init);
static KeyboardEvent* create_from_platform_event(Bindings::WindowObject&, FlyString const& event_name, KeyCode, unsigned modifiers, u32 code_point);
static NonnullRefPtr<KeyboardEvent> create(FlyString const& event_name, KeyboardEventInit const& event_init = {}) KeyboardEvent(Bindings::WindowObject&, FlyString const& event_name, KeyboardEventInit const& event_init);
{
return adopt_ref(*new KeyboardEvent(event_name, event_init));
}
static NonnullRefPtr<KeyboardEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, KeyboardEventInit const& event_init)
{
return KeyboardEvent::create(event_name, event_init);
}
static NonnullRefPtr<KeyboardEvent> create_from_platform_event(FlyString const& event_name, KeyCode, unsigned modifiers, u32 code_point); virtual ~KeyboardEvent() override;
virtual ~KeyboardEvent() override = default; KeyboardEvent& impl() { return *this; }
u32 key_code() const { return m_key_code; } u32 key_code() const { return m_key_code; }
u32 char_code() const { return m_char_code; } u32 char_code() const { return m_char_code; }
@ -61,20 +58,6 @@ public:
virtual u32 which() const override { return m_key_code; } virtual u32 which() const override { return m_key_code; }
private: private:
KeyboardEvent(FlyString const& event_name, KeyboardEventInit const& event_init)
: UIEvent(event_name, event_init)
, m_key(event_init.key)
, m_code(event_init.code)
, m_location(event_init.location)
, m_ctrl_key(event_init.ctrl_key)
, m_shift_key(event_init.shift_key)
, m_alt_key(event_init.alt_key)
, m_meta_key(event_init.meta_key)
, m_repeat(event_init.repeat)
, m_is_composing(event_init.is_composing)
, m_key_code(event_init.key_code)
, m_char_code(event_init.char_code) {};
String m_key; String m_key;
String m_code; String m_code;
u32 m_location { 0 }; u32 m_location { 0 };
@ -89,3 +72,8 @@ private:
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::UIEvents::KeyboardEvent& object) { return &object; }
using KeyboardEventWrapper = Web::UIEvents::KeyboardEvent;
}

View file

@ -1,6 +1,6 @@
#import <UIEvents/EventModifier.idl> #import <UIEvents/EventModifier.idl>
[Exposed=Window] [Exposed=Window, NoInstanceWrapper]
interface KeyboardEvent : UIEvent { interface KeyboardEvent : UIEvent {
constructor(DOMString type, optional KeyboardEventInit eventInitDict = {}); constructor(DOMString type, optional KeyboardEventInit eventInitDict = {});

View file

@ -1,27 +1,33 @@
/* /*
* Copyright (c) 2020, the SerenityOS developers. * Copyright (c) 2020, the SerenityOS developers.
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibGUI/Event.h> #include <LibGUI/Event.h>
#include <LibWeb/Bindings/MouseEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/HTML/EventNames.h> #include <LibWeb/HTML/EventNames.h>
#include <LibWeb/UIEvents/EventNames.h> #include <LibWeb/UIEvents/EventNames.h>
#include <LibWeb/UIEvents/MouseEvent.h> #include <LibWeb/UIEvents/MouseEvent.h>
namespace Web::UIEvents { namespace Web::UIEvents {
MouseEvent::MouseEvent(FlyString const& event_name, MouseEventInit const& event_init) MouseEvent::MouseEvent(Bindings::WindowObject& window_object, FlyString const& event_name, MouseEventInit const& event_init)
: UIEvent(event_name, event_init) : UIEvent(window_object, event_name, event_init)
, m_offset_x(event_init.offset_x) , m_offset_x(event_init.offset_x)
, m_offset_y(event_init.offset_y) , m_offset_y(event_init.offset_y)
, m_client_x(event_init.client_x) , m_client_x(event_init.client_x)
, m_client_y(event_init.client_y) , m_client_y(event_init.client_y)
, m_button(event_init.button) , m_button(event_init.button)
{ {
set_prototype(&window_object.ensure_web_prototype<Bindings::MouseEventPrototype>("MouseEvent"));
set_event_characteristics(); set_event_characteristics();
} }
MouseEvent::~MouseEvent() = default;
// https://www.w3.org/TR/uievents/#dom-mouseevent-button // https://www.w3.org/TR/uievents/#dom-mouseevent-button
static i16 determine_button(unsigned mouse_button) static i16 determine_button(unsigned mouse_button)
{ {
@ -41,7 +47,12 @@ static i16 determine_button(unsigned mouse_button)
} }
} }
NonnullRefPtr<MouseEvent> MouseEvent::create_from_platform_event(FlyString const& event_name, double offset_x, double offset_y, double client_x, double client_y, unsigned mouse_button) MouseEvent* MouseEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, MouseEventInit const& event_init)
{
return window_object.heap().allocate<MouseEvent>(window_object.realm(), window_object, event_name, event_init);
}
MouseEvent* MouseEvent::create_from_platform_event(Bindings::WindowObject& window_object, FlyString const& event_name, double offset_x, double offset_y, double client_x, double client_y, unsigned mouse_button)
{ {
MouseEventInit event_init {}; MouseEventInit event_init {};
event_init.offset_x = offset_x; event_init.offset_x = offset_x;
@ -49,7 +60,7 @@ NonnullRefPtr<MouseEvent> MouseEvent::create_from_platform_event(FlyString const
event_init.client_x = client_x; event_init.client_x = client_x;
event_init.client_y = client_y; event_init.client_y = client_y;
event_init.button = determine_button(mouse_button); event_init.button = determine_button(mouse_button);
return MouseEvent::create(event_name, event_init); return MouseEvent::create(window_object, event_name, event_init);
} }
void MouseEvent::set_event_characteristics() void MouseEvent::set_event_characteristics()

View file

@ -22,17 +22,17 @@ struct MouseEventInit : public EventModifierInit {
}; };
class MouseEvent final : public UIEvent { class MouseEvent final : public UIEvent {
JS_OBJECT(MouseEvent, UIEvent);
public: public:
using WrapperType = Bindings::MouseEventWrapper; static MouseEvent* create(Bindings::WindowObject&, FlyString const& event_name, MouseEventInit const& event_init = {});
static MouseEvent* create_from_platform_event(Bindings::WindowObject&, FlyString const& event_name, double offset_x, double offset_y, double client_x, double client_y, unsigned mouse_button = 1);
static NonnullRefPtr<MouseEvent> create(FlyString const& event_name, MouseEventInit const& event_init = {}) MouseEvent(Bindings::WindowObject&, FlyString const& event_name, MouseEventInit const& event_init);
{
return adopt_ref(*new MouseEvent(event_name, event_init));
}
static NonnullRefPtr<MouseEvent> create_from_platform_event(FlyString const& event_name, double offset_x, double offset_y, double client_x, double client_y, unsigned mouse_button = 1); virtual ~MouseEvent() override;
virtual ~MouseEvent() override = default; MouseEvent& impl() { return *this; }
double offset_x() const { return m_offset_x; } double offset_x() const { return m_offset_x; }
double offset_y() const { return m_offset_y; } double offset_y() const { return m_offset_y; }
@ -48,8 +48,6 @@ public:
virtual u32 which() const override { return m_button + 1; } virtual u32 which() const override { return m_button + 1; }
private: private:
MouseEvent(FlyString const& event_name, MouseEventInit const& event_init);
void set_event_characteristics(); void set_event_characteristics();
double m_offset_x { 0 }; double m_offset_x { 0 };
@ -60,3 +58,8 @@ private:
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::UIEvents::MouseEvent& object) { return &object; }
using MouseEventWrapper = Web::UIEvents::MouseEvent;
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/UIEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/UIEvents/UIEvent.h>
namespace Web::UIEvents {
UIEvent* UIEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name)
{
return window_object.heap().allocate<UIEvent>(window_object.realm(), window_object, event_name);
}
UIEvent* UIEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, UIEventInit const& event_init)
{
return window_object.heap().allocate<UIEvent>(window_object.realm(), window_object, event_name, event_init);
}
UIEvent::UIEvent(Bindings::WindowObject& window_object, FlyString const& event_name)
: Event(window_object, event_name)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::UIEventPrototype>("UIEvent"));
}
UIEvent::UIEvent(Bindings::WindowObject& window_object, FlyString const& event_name, UIEventInit const& event_init)
: Event(window_object, event_name, event_init)
, m_view(event_init.view)
, m_detail(event_init.detail)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::UIEventPrototype>("UIEvent"));
}
UIEvent::~UIEvent() = default;
}

View file

@ -18,20 +18,18 @@ struct UIEventInit : public DOM::EventInit {
}; };
class UIEvent : public DOM::Event { class UIEvent : public DOM::Event {
JS_OBJECT(UIEvent, DOM::Event);
public: public:
using WrapperType = Bindings::UIEventWrapper; static UIEvent* create(Bindings::WindowObject&, FlyString const& type);
static UIEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, UIEventInit const& event_init);
static NonnullRefPtr<UIEvent> create(FlyString const& type) UIEvent(Bindings::WindowObject&, FlyString const& event_name);
{ UIEvent(Bindings::WindowObject&, FlyString const& event_name, UIEventInit const& event_init);
return adopt_ref(*new UIEvent(type));
}
static NonnullRefPtr<UIEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, UIEventInit const& event_init) virtual ~UIEvent() override;
{
return adopt_ref(*new UIEvent(event_name, event_init));
}
virtual ~UIEvent() override = default; UIEvent& impl() { return *this; }
HTML::Window const* view() const { return m_view; } HTML::Window const* view() const { return m_view; }
int detail() const { return m_detail; } int detail() const { return m_detail; }
@ -45,19 +43,13 @@ public:
} }
protected: protected:
explicit UIEvent(FlyString const& event_name)
: Event(event_name)
{
}
UIEvent(FlyString const& event_name, UIEventInit const& event_init)
: Event(event_name, event_init)
, m_view(event_init.view)
, m_detail(event_init.detail)
{
}
RefPtr<HTML::Window> m_view; RefPtr<HTML::Window> m_view;
int m_detail { 0 }; int m_detail { 0 };
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::UIEvents::UIEvent& object) { return &object; }
using UIEventWrapper = Web::UIEvents::UIEvent;
}

View file

@ -1,5 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[NoInstanceWrapper]
interface UIEvent : Event { interface UIEvent : Event {
constructor(DOMString type, optional UIEventInit eventInitDict = {}); constructor(DOMString type, optional UIEventInit eventInitDict = {});
readonly attribute Window? view; readonly attribute Window? view;

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/WebGLContextEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/WebGL/WebGLContextEvent.h>
namespace Web::WebGL {
WebGLContextEvent* WebGLContextEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, WebGLContextEventInit const& event_init)
{
return window_object.heap().allocate<WebGLContextEvent>(window_object.realm(), window_object, event_name, event_init);
}
WebGLContextEvent* WebGLContextEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, WebGLContextEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
WebGLContextEvent::WebGLContextEvent(Bindings::WindowObject& window_object, FlyString const& type, WebGLContextEventInit const& event_init)
: DOM::Event(window_object, type, event_init)
, m_status_message(event_init.status_message)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::WebGLContextEventPrototype>("WebGLContextEvent"));
}
WebGLContextEvent::~WebGLContextEvent() = default;
}

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -15,31 +16,27 @@ struct WebGLContextEventInit final : public DOM::EventInit {
}; };
class WebGLContextEvent final : public DOM::Event { class WebGLContextEvent final : public DOM::Event {
JS_OBJECT(WebGLContextEvent, DOM::Event);
public: public:
using WrapperType = Bindings::WebGLContextEventWrapper; static WebGLContextEvent* create(Bindings::WindowObject&, FlyString const& type, WebGLContextEventInit const& event_init);
static WebGLContextEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& type, WebGLContextEventInit const& event_init);
static NonnullRefPtr<WebGLContextEvent> create(FlyString const& type, WebGLContextEventInit const& event_init) WebGLContextEvent(Bindings::WindowObject&, FlyString const& type, WebGLContextEventInit const& event_init);
{
return adopt_ref(*new WebGLContextEvent(type, event_init));
}
static NonnullRefPtr<WebGLContextEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& type, WebGLContextEventInit const& event_init) virtual ~WebGLContextEvent() override;
{
return adopt_ref(*new WebGLContextEvent(type, event_init));
}
virtual ~WebGLContextEvent() override = default; WebGLContextEvent& impl() { return *this; }
String const& status_message() const { return m_status_message; } String const& status_message() const { return m_status_message; }
private: private:
WebGLContextEvent(FlyString const& type, WebGLContextEventInit const& event_init)
: DOM::Event(type, event_init)
, m_status_message(event_init.status_message)
{
}
String m_status_message { String::empty() }; String m_status_message { String::empty() };
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::WebGL::WebGLContextEvent& object) { return &object; }
using WebGLContextEventWrapper = Web::WebGL::WebGLContextEvent;
}

View file

@ -5,6 +5,7 @@
*/ */
#include <LibWeb/Bindings/Wrapper.h> #include <LibWeb/Bindings/Wrapper.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/HTMLCanvasElement.h> #include <LibWeb/HTML/HTMLCanvasElement.h>
#include <LibWeb/WebGL/WebGLContextEvent.h> #include <LibWeb/WebGL/WebGLContextEvent.h>
#include <LibWeb/WebGL/WebGLRenderingContext.h> #include <LibWeb/WebGL/WebGLRenderingContext.h>
@ -16,10 +17,10 @@ static void fire_webgl_context_event(HTML::HTMLCanvasElement& canvas_element, Fl
{ {
// To fire a WebGL context event named e means that an event using the WebGLContextEvent interface, with its type attribute [DOM4] initialized to e, its cancelable attribute initialized to true, and its isTrusted attribute [DOM4] initialized to true, is to be dispatched at the given object. // To fire a WebGL context event named e means that an event using the WebGLContextEvent interface, with its type attribute [DOM4] initialized to e, its cancelable attribute initialized to true, and its isTrusted attribute [DOM4] initialized to true, is to be dispatched at the given object.
// FIXME: Consider setting a status message. // FIXME: Consider setting a status message.
auto event = WebGLContextEvent::create(type, WebGLContextEventInit {}); auto event = WebGLContextEvent::create(canvas_element.document().preferred_window_object(), type, WebGLContextEventInit {});
event->set_is_trusted(true); event->set_is_trusted(true);
event->set_cancelable(true); event->set_cancelable(true);
canvas_element.dispatch_event(move(event)); canvas_element.dispatch_event(*event);
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#fire-a-webgl-context-creation-error // https://www.khronos.org/registry/webgl/specs/latest/1.0/#fire-a-webgl-context-creation-error

View file

@ -8,7 +8,6 @@
#include <LibJS/Parser.h> #include <LibJS/Parser.h>
#include <LibJS/Runtime/ArrayBuffer.h> #include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/FunctionObject.h> #include <LibJS/Runtime/FunctionObject.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/WebSocketWrapper.h> #include <LibWeb/Bindings/WebSocketWrapper.h>
#include <LibWeb/DOM/DOMException.h> #include <LibWeb/DOM/DOMException.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
@ -173,13 +172,13 @@ void WebSocket::on_open()
// 1. Change the readyState attribute's value to OPEN (1). // 1. Change the readyState attribute's value to OPEN (1).
// 2. Change the extensions attribute's value to the extensions in use, if it is not the null value. [WSP] // 2. Change the extensions attribute's value to the extensions in use, if it is not the null value. [WSP]
// 3. Change the protocol attribute's value to the subprotocol in use, if it is not the null value. [WSP] // 3. Change the protocol attribute's value to the subprotocol in use, if it is not the null value. [WSP]
dispatch_event(DOM::Event::create(HTML::EventNames::open)); dispatch_event(*DOM::Event::create(*m_window->wrapper(), HTML::EventNames::open));
} }
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol // https://websockets.spec.whatwg.org/#feedback-from-the-protocol
void WebSocket::on_error() void WebSocket::on_error()
{ {
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(*m_window->wrapper(), HTML::EventNames::error));
} }
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol // https://websockets.spec.whatwg.org/#feedback-from-the-protocol
@ -191,7 +190,7 @@ void WebSocket::on_close(u16 code, String reason, bool was_clean)
event_init.was_clean = was_clean; event_init.was_clean = was_clean;
event_init.code = code; event_init.code = code;
event_init.reason = move(reason); event_init.reason = move(reason);
dispatch_event(HTML::CloseEvent::create(HTML::EventNames::close, event_init)); dispatch_event(*HTML::CloseEvent::create(*m_window->wrapper(), HTML::EventNames::close, event_init));
} }
// https://websockets.spec.whatwg.org/#feedback-from-the-protocol // https://websockets.spec.whatwg.org/#feedback-from-the-protocol
@ -204,7 +203,7 @@ void WebSocket::on_message(ByteBuffer message, bool is_text)
HTML::MessageEventInit event_init; HTML::MessageEventInit event_init;
event_init.data = JS::js_string(wrapper()->vm(), text_message); event_init.data = JS::js_string(wrapper()->vm(), text_message);
event_init.origin = url(); event_init.origin = url();
dispatch_event(HTML::MessageEvent::create(HTML::EventNames::message, event_init)); dispatch_event(*HTML::MessageEvent::create(*m_window->wrapper(), HTML::EventNames::message, event_init));
return; return;
} }
@ -218,7 +217,7 @@ void WebSocket::on_message(ByteBuffer message, bool is_text)
HTML::MessageEventInit event_init; HTML::MessageEventInit event_init;
event_init.data = JS::ArrayBuffer::create(realm, message); event_init.data = JS::ArrayBuffer::create(realm, message);
event_init.origin = url(); event_init.origin = url();
dispatch_event(HTML::MessageEvent::create(HTML::EventNames::message, event_init)); dispatch_event(*HTML::MessageEvent::create(*m_window->wrapper(), HTML::EventNames::message, event_init));
return; return;
} }

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/ProgressEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/XHR/ProgressEvent.h>
namespace Web::XHR {
ProgressEvent* ProgressEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, ProgressEventInit const& event_init)
{
return window_object.heap().allocate<ProgressEvent>(window_object.realm(), window_object, event_name, event_init);
}
ProgressEvent* ProgressEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, ProgressEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
ProgressEvent::ProgressEvent(Bindings::WindowObject& window_object, FlyString const& event_name, ProgressEventInit const& event_init)
: Event(window_object, event_name, event_init)
, m_length_computable(event_init.length_computable)
, m_loaded(event_init.loaded)
, m_total(event_init.total)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::ProgressEventPrototype>("ProgressEvent"));
}
ProgressEvent::~ProgressEvent() = default;
}

View file

@ -19,37 +19,32 @@ struct ProgressEventInit : public DOM::EventInit {
u32 total { 0 }; u32 total { 0 };
}; };
class ProgressEvent : public DOM::Event { class ProgressEvent final : public DOM::Event {
JS_OBJECT(ProgressEvent, DOM::Event);
public: public:
using WrapperType = Bindings::ProgressEventWrapper; static ProgressEvent* create(Bindings::WindowObject&, FlyString const& event_name, ProgressEventInit const& event_init);
static ProgressEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, ProgressEventInit const& event_init);
static NonnullRefPtr<ProgressEvent> create(FlyString const& event_name, ProgressEventInit const& event_init) ProgressEvent(Bindings::WindowObject&, FlyString const& event_name, ProgressEventInit const& event_init);
{
return adopt_ref(*new ProgressEvent(event_name, event_init));
}
static NonnullRefPtr<ProgressEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, ProgressEventInit const& event_init)
{
return ProgressEvent::create(event_name, event_init);
}
virtual ~ProgressEvent() override = default; virtual ~ProgressEvent() override;
ProgressEvent& impl() { return *this; }
bool length_computable() const { return m_length_computable; } bool length_computable() const { return m_length_computable; }
u64 loaded() const { return m_loaded; } u64 loaded() const { return m_loaded; }
u64 total() const { return m_total; } u64 total() const { return m_total; }
protected: private:
ProgressEvent(FlyString const& event_name, ProgressEventInit const& event_init)
: Event(event_name, event_init)
, m_length_computable(event_init.length_computable)
, m_loaded(event_init.loaded)
, m_total(event_init.total)
{
}
bool m_length_computable { false }; bool m_length_computable { false };
u64 m_loaded { 0 }; u64 m_loaded { 0 };
u64 m_total { 0 }; u64 m_total { 0 };
}; };
} }
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::XHR::ProgressEvent& object) { return &object; }
using ProgressEventWrapper = Web::XHR::ProgressEvent;
}

View file

@ -1,5 +1,6 @@
#import <DOM/Event.idl> #import <DOM/Event.idl>
[NoInstanceWrapper]
interface ProgressEvent : Event { interface ProgressEvent : Event {
constructor(DOMString type, optional ProgressEventInit eventInitDict = {}); constructor(DOMString type, optional ProgressEventInit eventInitDict = {});

View file

@ -16,7 +16,6 @@
#include <LibJS/Runtime/FunctionObject.h> #include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibTextCodec/Decoder.h> #include <LibTextCodec/Decoder.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/IDLAbstractOperations.h> #include <LibWeb/Bindings/IDLAbstractOperations.h>
#include <LibWeb/Bindings/XMLHttpRequestWrapper.h> #include <LibWeb/Bindings/XMLHttpRequestWrapper.h>
#include <LibWeb/DOM/DOMException.h> #include <LibWeb/DOM/DOMException.h>
@ -53,7 +52,7 @@ XMLHttpRequest::~XMLHttpRequest() = default;
void XMLHttpRequest::set_ready_state(ReadyState ready_state) void XMLHttpRequest::set_ready_state(ReadyState ready_state)
{ {
m_ready_state = ready_state; m_ready_state = ready_state;
dispatch_event(DOM::Event::create(EventNames::readystatechange)); dispatch_event(*DOM::Event::create(verify_cast<Bindings::WindowObject>(wrapper()->global_object()), EventNames::readystatechange));
} }
void XMLHttpRequest::fire_progress_event(String const& event_name, u64 transmitted, u64 length) void XMLHttpRequest::fire_progress_event(String const& event_name, u64 transmitted, u64 length)
@ -62,7 +61,7 @@ void XMLHttpRequest::fire_progress_event(String const& event_name, u64 transmitt
event_init.length_computable = true; event_init.length_computable = true;
event_init.loaded = transmitted; event_init.loaded = transmitted;
event_init.total = length; event_init.total = length;
dispatch_event(ProgressEvent::create(event_name, event_init)); dispatch_event(*ProgressEvent::create(verify_cast<Bindings::WindowObject>(wrapper()->global_object()), event_name, event_init));
} }
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetext // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetext
@ -469,7 +468,7 @@ DOM::ExceptionOr<void> XMLHttpRequest::send(Optional<XMLHttpRequestBodyInit> bod
if (should_enforce_same_origin_policy && !m_window->associated_document().origin().is_same_origin(request_url_origin)) { if (should_enforce_same_origin_policy && !m_window->associated_document().origin().is_same_origin(request_url_origin)) {
dbgln("XHR failed to load: Same-Origin Policy violation: {} may not load {}", m_window->associated_document().url(), request_url); dbgln("XHR failed to load: Same-Origin Policy violation: {} may not load {}", m_window->associated_document().url(), request_url);
set_ready_state(ReadyState::Done); set_ready_state(ReadyState::Done);
dispatch_event(DOM::Event::create(HTML::EventNames::error)); dispatch_event(*DOM::Event::create(verify_cast<Bindings::WindowObject>(wrapper()->global_object()), HTML::EventNames::error));
return {}; return {};
} }
@ -539,7 +538,7 @@ DOM::ExceptionOr<void> XMLHttpRequest::send(Optional<XMLHttpRequestBodyInit> bod
xhr.m_status = status_code.value_or(0); xhr.m_status = status_code.value_or(0);
xhr.m_response_headers = move(response_headers); xhr.m_response_headers = move(response_headers);
xhr.m_send = false; xhr.m_send = false;
xhr.dispatch_event(DOM::Event::create(EventNames::readystatechange)); xhr.dispatch_event(*DOM::Event::create(verify_cast<Bindings::WindowObject>(xhr.wrapper()->global_object()), EventNames::readystatechange));
xhr.fire_progress_event(EventNames::load, transmitted, length); xhr.fire_progress_event(EventNames::load, transmitted, length);
xhr.fire_progress_event(EventNames::loadend, transmitted, length); xhr.fire_progress_event(EventNames::loadend, transmitted, length);
}, },
@ -551,7 +550,7 @@ DOM::ExceptionOr<void> XMLHttpRequest::send(Optional<XMLHttpRequestBodyInit> bod
auto& xhr = const_cast<XMLHttpRequest&>(*strong_this); auto& xhr = const_cast<XMLHttpRequest&>(*strong_this);
xhr.set_ready_state(ReadyState::Done); xhr.set_ready_state(ReadyState::Done);
xhr.set_status(status_code.value_or(0)); xhr.set_status(status_code.value_or(0));
xhr.dispatch_event(DOM::Event::create(HTML::EventNames::error)); xhr.dispatch_event(*DOM::Event::create(verify_cast<Bindings::WindowObject>(xhr.wrapper()->global_object()), HTML::EventNames::error));
}, },
m_timeout, m_timeout,
[weak_this = make_weak_ptr()] { [weak_this = make_weak_ptr()] {
@ -559,7 +558,7 @@ DOM::ExceptionOr<void> XMLHttpRequest::send(Optional<XMLHttpRequestBodyInit> bod
if (!strong_this) if (!strong_this)
return; return;
auto& xhr = const_cast<XMLHttpRequest&>(*strong_this); auto& xhr = const_cast<XMLHttpRequest&>(*strong_this);
xhr.dispatch_event(DOM::Event::create(EventNames::timeout)); xhr.dispatch_event(*DOM::Event::create(verify_cast<Bindings::WindowObject>(xhr.wrapper()->global_object()), EventNames::timeout));
}); });
} else { } else {
TODO(); TODO();

View file

@ -175,9 +175,9 @@ void XMLDocumentBuilder::document_end()
// FIXME: Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object. // FIXME: Set the Document's load timing info's DOM content loaded event start time to the current high resolution time given the Document's relevant global object.
// Fire an event named DOMContentLoaded at the Document object, with its bubbles attribute initialized to true. // Fire an event named DOMContentLoaded at the Document object, with its bubbles attribute initialized to true.
auto content_loaded_event = DOM::Event::create(HTML::EventNames::DOMContentLoaded); auto content_loaded_event = DOM::Event::create(document->preferred_window_object(), HTML::EventNames::DOMContentLoaded);
content_loaded_event->set_bubbles(true); content_loaded_event->set_bubbles(true);
document->dispatch_event(content_loaded_event); document->dispatch_event(*content_loaded_event);
// FIXME: Set the Document's load timing info's DOM content loaded event end time to the current high resolution time given the Document's relevant global object. // FIXME: Set the Document's load timing info's DOM content loaded event end time to the current high resolution time given the Document's relevant global object.
@ -213,7 +213,7 @@ void XMLDocumentBuilder::document_end()
// Fire an event named load at window, with legacy target override flag set. // Fire an event named load at window, with legacy target override flag set.
// FIXME: The legacy target override flag is currently set by a virtual override of dispatch_event() // FIXME: The legacy target override flag is currently set by a virtual override of dispatch_event()
// We should reorganize this so that the flag appears explicitly here instead. // We should reorganize this so that the flag appears explicitly here instead.
window->dispatch_event(DOM::Event::create(HTML::EventNames::load)); window->dispatch_event(*DOM::Event::create(document->preferred_window_object(), HTML::EventNames::load));
// FIXME: Invoke WebDriver BiDi load complete with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "complete", and url is the Document object's URL. // FIXME: Invoke WebDriver BiDi load complete with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "complete", and url is the Document object's URL.

View file

@ -16,7 +16,7 @@ libweb_js_wrapper(CSS/CSSStyleSheet NO_INSTANCE)
libweb_js_wrapper(CSS/CSSSupportsRule NO_INSTANCE) libweb_js_wrapper(CSS/CSSSupportsRule NO_INSTANCE)
libweb_js_wrapper(CSS/MediaList NO_INSTANCE) libweb_js_wrapper(CSS/MediaList NO_INSTANCE)
libweb_js_wrapper(CSS/MediaQueryList) libweb_js_wrapper(CSS/MediaQueryList)
libweb_js_wrapper(CSS/MediaQueryListEvent) libweb_js_wrapper(CSS/MediaQueryListEvent NO_INSTANCE)
libweb_js_wrapper(CSS/Screen) libweb_js_wrapper(CSS/Screen)
libweb_js_wrapper(CSS/StyleSheet NO_INSTANCE) libweb_js_wrapper(CSS/StyleSheet NO_INSTANCE)
libweb_js_wrapper(CSS/StyleSheetList NO_INSTANCE) libweb_js_wrapper(CSS/StyleSheetList NO_INSTANCE)
@ -27,7 +27,7 @@ libweb_js_wrapper(DOM/AbortSignal)
libweb_js_wrapper(DOM/CDATASection) libweb_js_wrapper(DOM/CDATASection)
libweb_js_wrapper(DOM/CharacterData) libweb_js_wrapper(DOM/CharacterData)
libweb_js_wrapper(DOM/Comment) libweb_js_wrapper(DOM/Comment)
libweb_js_wrapper(DOM/CustomEvent) libweb_js_wrapper(DOM/CustomEvent NO_INSTANCE)
libweb_js_wrapper(DOM/Document) libweb_js_wrapper(DOM/Document)
libweb_js_wrapper(DOM/DocumentFragment) libweb_js_wrapper(DOM/DocumentFragment)
libweb_js_wrapper(DOM/DocumentType) libweb_js_wrapper(DOM/DocumentType)
@ -35,7 +35,7 @@ libweb_js_wrapper(DOM/DOMException)
libweb_js_wrapper(DOM/DOMImplementation NO_INSTANCE) libweb_js_wrapper(DOM/DOMImplementation NO_INSTANCE)
libweb_js_wrapper(DOM/DOMTokenList NO_INSTANCE) libweb_js_wrapper(DOM/DOMTokenList NO_INSTANCE)
libweb_js_wrapper(DOM/Element) libweb_js_wrapper(DOM/Element)
libweb_js_wrapper(DOM/Event) libweb_js_wrapper(DOM/Event NO_INSTANCE)
libweb_js_wrapper(DOM/EventTarget) libweb_js_wrapper(DOM/EventTarget)
libweb_js_wrapper(DOM/HTMLCollection) libweb_js_wrapper(DOM/HTMLCollection)
libweb_js_wrapper(DOM/MutationRecord) libweb_js_wrapper(DOM/MutationRecord)
@ -63,10 +63,10 @@ libweb_js_wrapper(Geometry/DOMRectList)
libweb_js_wrapper(Geometry/DOMRectReadOnly) libweb_js_wrapper(Geometry/DOMRectReadOnly)
libweb_js_wrapper(HTML/CanvasGradient) libweb_js_wrapper(HTML/CanvasGradient)
libweb_js_wrapper(HTML/CanvasRenderingContext2D) libweb_js_wrapper(HTML/CanvasRenderingContext2D)
libweb_js_wrapper(HTML/CloseEvent) libweb_js_wrapper(HTML/CloseEvent NO_INSTANCE)
libweb_js_wrapper(HTML/DOMParser) libweb_js_wrapper(HTML/DOMParser)
libweb_js_wrapper(HTML/DOMStringMap NO_INSTANCE) libweb_js_wrapper(HTML/DOMStringMap NO_INSTANCE)
libweb_js_wrapper(HTML/ErrorEvent) libweb_js_wrapper(HTML/ErrorEvent NO_INSTANCE)
libweb_js_wrapper(HTML/History) libweb_js_wrapper(HTML/History)
libweb_js_wrapper(HTML/HTMLAnchorElement) libweb_js_wrapper(HTML/HTMLAnchorElement)
libweb_js_wrapper(HTML/HTMLAreaElement) libweb_js_wrapper(HTML/HTMLAreaElement)
@ -142,13 +142,13 @@ libweb_js_wrapper(HTML/HTMLUnknownElement)
libweb_js_wrapper(HTML/HTMLVideoElement) libweb_js_wrapper(HTML/HTMLVideoElement)
libweb_js_wrapper(HTML/ImageData) libweb_js_wrapper(HTML/ImageData)
libweb_js_wrapper(HTML/MessageChannel) libweb_js_wrapper(HTML/MessageChannel)
libweb_js_wrapper(HTML/MessageEvent) libweb_js_wrapper(HTML/MessageEvent NO_INSTANCE)
libweb_js_wrapper(HTML/MessagePort) libweb_js_wrapper(HTML/MessagePort)
libweb_js_wrapper(HTML/PageTransitionEvent) libweb_js_wrapper(HTML/PageTransitionEvent NO_INSTANCE)
libweb_js_wrapper(HTML/Path2D) libweb_js_wrapper(HTML/Path2D)
libweb_js_wrapper(HTML/PromiseRejectionEvent) libweb_js_wrapper(HTML/PromiseRejectionEvent NO_INSTANCE)
libweb_js_wrapper(HTML/Storage) libweb_js_wrapper(HTML/Storage)
libweb_js_wrapper(HTML/SubmitEvent) libweb_js_wrapper(HTML/SubmitEvent NO_INSTANCE)
libweb_js_wrapper(HTML/TextMetrics) libweb_js_wrapper(HTML/TextMetrics)
libweb_js_wrapper(HTML/Worker) libweb_js_wrapper(HTML/Worker)
libweb_js_wrapper(HTML/WorkerGlobalScope) libweb_js_wrapper(HTML/WorkerGlobalScope)
@ -176,15 +176,15 @@ libweb_js_wrapper(SVG/SVGRectElement)
libweb_js_wrapper(SVG/SVGSVGElement) libweb_js_wrapper(SVG/SVGSVGElement)
libweb_js_wrapper(SVG/SVGTextContentElement) libweb_js_wrapper(SVG/SVGTextContentElement)
libweb_js_wrapper(Selection/Selection) libweb_js_wrapper(Selection/Selection)
libweb_js_wrapper(UIEvents/FocusEvent) libweb_js_wrapper(UIEvents/FocusEvent NO_INSTANCE)
libweb_js_wrapper(UIEvents/KeyboardEvent) libweb_js_wrapper(UIEvents/KeyboardEvent NO_INSTANCE)
libweb_js_wrapper(UIEvents/MouseEvent) libweb_js_wrapper(UIEvents/MouseEvent NO_INSTANCE)
libweb_js_wrapper(UIEvents/UIEvent) libweb_js_wrapper(UIEvents/UIEvent NO_INSTANCE)
libweb_js_wrapper(URL/URL) libweb_js_wrapper(URL/URL)
libweb_js_wrapper(URL/URLSearchParams ITERABLE) libweb_js_wrapper(URL/URLSearchParams ITERABLE)
libweb_js_wrapper(WebGL/WebGLContextEvent) libweb_js_wrapper(WebGL/WebGLContextEvent NO_INSTANCE)
libweb_js_wrapper(WebGL/WebGLRenderingContext) libweb_js_wrapper(WebGL/WebGLRenderingContext)
libweb_js_wrapper(WebSockets/WebSocket) libweb_js_wrapper(WebSockets/WebSocket)
libweb_js_wrapper(XHR/ProgressEvent) libweb_js_wrapper(XHR/ProgressEvent NO_INSTANCE)
libweb_js_wrapper(XHR/XMLHttpRequest) libweb_js_wrapper(XHR/XMLHttpRequest)
libweb_js_wrapper(XHR/XMLHttpRequestEventTarget) libweb_js_wrapper(XHR/XMLHttpRequestEventTarget)