From e76e8e22b524da92b3404747b975f1c985ceff68 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 16 Feb 2022 20:43:24 +0100 Subject: [PATCH] LibWeb: Separate "event listener" from "EventListener" I can't imagine how this happened, but it seems we've managed to conflate the "event listener" and "EventListener" concepts from the DOM specification in some parts of the code. We previously had two things: - DOM::EventListener - DOM::EventTarget::EventListenerRegistration DOM::EventListener was roughly the "EventListener" IDL type, and DOM::EventTarget::EventListenerRegistration was roughly the "event listener" concept. However, they were used interchangeably (and incorrectly!) in many places. After this patch, we now have: - DOM::IDLEventListener - DOM::DOMEventListener DOM::IDLEventListener is the "EventListener" IDL type, and DOM::DOMEventListener is the "event listener" concept. This patch also updates the addEventListener() and removeEventListener() functions to follow the spec more closely, along with the "inner invoke" function in our EventDispatcher. --- .../LibWeb/WrapperGenerator.cpp | 7 +- .../LibWeb/Bindings/EventListenerWrapper.cpp | 4 +- .../LibWeb/Bindings/EventListenerWrapper.h | 8 +- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../Libraries/LibWeb/CSS/MediaQueryList.cpp | 6 +- .../Libraries/LibWeb/CSS/MediaQueryList.h | 4 +- .../Libraries/LibWeb/DOM/DOMEventListener.cpp | 20 ++++ .../Libraries/LibWeb/DOM/DOMEventListener.h | 42 +++++++ .../Libraries/LibWeb/DOM/EventDispatcher.cpp | 25 +++-- .../Libraries/LibWeb/DOM/EventDispatcher.h | 2 +- Userland/Libraries/LibWeb/DOM/EventListener.h | 55 --------- Userland/Libraries/LibWeb/DOM/EventTarget.cpp | 106 +++++++++++++----- Userland/Libraries/LibWeb/DOM/EventTarget.h | 20 ++-- .../Libraries/LibWeb/DOM/IDLEventListener.h | 35 ++++++ Userland/Libraries/LibWeb/DOM/Node.cpp | 2 +- Userland/Libraries/LibWeb/Forward.h | 3 +- Userland/Libraries/LibWeb/HTML/EventHandler.h | 4 +- .../LibWeb/HTML/GlobalEventHandlers.cpp | 2 +- .../Libraries/LibWeb/HTML/HTMLElement.cpp | 2 +- Userland/Libraries/LibWeb/HTML/WebSocket.cpp | 2 +- .../Libraries/LibWeb/XHR/XMLHttpRequest.cpp | 2 +- 21 files changed, 223 insertions(+), 129 deletions(-) create mode 100644 Userland/Libraries/LibWeb/DOM/DOMEventListener.cpp create mode 100644 Userland/Libraries/LibWeb/DOM/DOMEventListener.h delete mode 100644 Userland/Libraries/LibWeb/DOM/EventListener.h create mode 100644 Userland/Libraries/LibWeb/DOM/IDLEventListener.h diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp index 7f0e805aad..a4c9486ff8 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp @@ -1496,13 +1496,13 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter if (parameter.type->nullable) { scoped_generator.append(R"~~~( - RefPtr @cpp_name@; + RefPtr @cpp_name@; if (!@js_name@@js_suffix@.is_nullish()) { if (!@js_name@@js_suffix@.is_object()) return vm.throw_completion(global_object, JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects()); CallbackType callback_type(JS::make_handle(&@js_name@@js_suffix@.as_object()), HTML::incumbent_settings_object()); - @cpp_name@ = adopt_ref(*new EventListener(move(callback_type))); + @cpp_name@ = adopt_ref(*new IDLEventListener(move(callback_type))); } )~~~"); } else { @@ -1511,7 +1511,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter return vm.throw_completion(global_object, JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects()); CallbackType callback_type(JS::make_handle(&@js_name@@js_suffix@.as_object()), HTML::incumbent_settings_object()); - auto @cpp_name@ = adopt_ref(*new EventListener(move(callback_type))); + auto @cpp_name@ = adopt_ref(*new IDLEventListener(move(callback_type))); )~~~"); } } else if (IDL::is_wrappable_type(*parameter.type)) { @@ -3793,6 +3793,7 @@ void generate_prototype_implementation(IDL::Interface const& interface) #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.cpp b/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.cpp index 0726f3358a..33789472ba 100644 --- a/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.cpp +++ b/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.cpp @@ -7,12 +7,12 @@ #include #include #include -#include +#include namespace Web { namespace Bindings { -EventListenerWrapper::EventListenerWrapper(JS::GlobalObject& global_object, DOM::EventListener& impl) +EventListenerWrapper::EventListenerWrapper(JS::GlobalObject& global_object, DOM::IDLEventListener& impl) : Wrapper(*global_object.object_prototype()) , m_impl(impl) { diff --git a/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.h b/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.h index 1ba4c83d44..1994089590 100644 --- a/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.h +++ b/Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.h @@ -15,14 +15,14 @@ class EventListenerWrapper final : public Wrapper { JS_OBJECT(EventListenerWrapper, Wrapper); public: - EventListenerWrapper(JS::GlobalObject&, DOM::EventListener&); + EventListenerWrapper(JS::GlobalObject&, DOM::IDLEventListener&); virtual ~EventListenerWrapper() override; - DOM::EventListener& impl() { return *m_impl; } - const DOM::EventListener& impl() const { return *m_impl; } + DOM::IDLEventListener& impl() { return *m_impl; } + DOM::IDLEventListener const& impl() const { return *m_impl; } private: - NonnullRefPtr m_impl; + NonnullRefPtr m_impl; }; } diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 24ee3aee65..26b51ec814 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -63,6 +63,7 @@ set(SOURCES DOM/CharacterData.idl DOM/Comment.cpp DOM/CustomEvent.cpp + DOM/DOMEventListener.cpp DOM/DOMImplementation.cpp DOM/DOMTokenList.cpp DOM/DOMTokenList.idl diff --git a/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp b/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp index 11fad62317..583dff0594 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp +++ b/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include namespace Web::CSS { @@ -61,7 +61,7 @@ JS::Object* MediaQueryList::create_wrapper(JS::GlobalObject& global_object) } // https://www.w3.org/TR/cssom-view/#dom-mediaquerylist-addlistener -void MediaQueryList::add_listener(RefPtr listener) +void MediaQueryList::add_listener(RefPtr listener) { // 1. If listener is null, terminate these steps. if (!listener) @@ -75,7 +75,7 @@ void MediaQueryList::add_listener(RefPtr listener) } // https://www.w3.org/TR/cssom-view/#dom-mediaquerylist-removelistener -void MediaQueryList::remove_listener(RefPtr listener) +void MediaQueryList::remove_listener(RefPtr listener) { // 1. Remove an event listener from the associated list of event listeners, whose type is change, callback is listener, and capture is false. // NOTE: While the spec doesn't technically use remove_event_listener and instead manipulates the list directly, every major engine uses remove_event_listener. diff --git a/Userland/Libraries/LibWeb/CSS/MediaQueryList.h b/Userland/Libraries/LibWeb/CSS/MediaQueryList.h index 8b3c621251..c138255363 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQueryList.h +++ b/Userland/Libraries/LibWeb/CSS/MediaQueryList.h @@ -45,8 +45,8 @@ public: virtual void unref_event_target() override { unref(); } virtual JS::Object* create_wrapper(JS::GlobalObject&) override; - void add_listener(RefPtr listener); - void remove_listener(RefPtr listener); + void add_listener(RefPtr listener); + void remove_listener(RefPtr listener); void set_onchange(Optional); Bindings::CallbackType* onchange(); diff --git a/Userland/Libraries/LibWeb/DOM/DOMEventListener.cpp b/Userland/Libraries/LibWeb/DOM/DOMEventListener.cpp new file mode 100644 index 0000000000..5002a72a37 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/DOMEventListener.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::DOM { + +DOMEventListener::DOMEventListener() +{ +} +DOMEventListener::~DOMEventListener() +{ +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/DOMEventListener.h b/Userland/Libraries/LibWeb/DOM/DOMEventListener.h new file mode 100644 index 0000000000..cc26636195 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/DOMEventListener.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::DOM { + +// https://dom.spec.whatwg.org/#concept-event-listener +// NOTE: The spec calls this "event listener", and it's *importantly* not the same as "EventListener" +struct DOMEventListener : RefCounted { + DOMEventListener(); + ~DOMEventListener(); + + // type (a string) + FlyString type; + + // callback (null or an EventListener object) + RefPtr callback; + + // signal (null or an AbortSignal object) + RefPtr signal; + + // capture (a boolean, initially false) + bool capture { false }; + + // passive (a boolean, initially false) + bool passive { false }; + + // once (a boolean, initially false) + bool once { false }; + + // removed (a boolean for bookkeeping purposes, initially false) + bool removed { false }; +}; + +} diff --git a/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp b/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp index 52f4331926..37e3c2d484 100644 --- a/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Andreas Kling + * Copyright (c) 2020-2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -14,11 +14,12 @@ #include #include #include +#include #include #include #include -#include #include +#include #include #include #include @@ -50,37 +51,37 @@ static EventTarget* retarget(EventTarget* left, EventTarget* right) } // https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke -bool EventDispatcher::inner_invoke(Event& event, Vector& listeners, Event::Phase phase, bool invocation_target_in_shadow_tree) +bool EventDispatcher::inner_invoke(Event& event, Vector>& listeners, Event::Phase phase, bool invocation_target_in_shadow_tree) { // 1. Let found be false. bool found = false; // 2. For each listener in listeners, whose removed is false: for (auto& listener : listeners) { - if (listener.listener->removed()) + if (listener->removed) continue; // 1. If event’s type attribute value is not listener’s type, then continue. - if (event.type() != listener.listener->type()) + if (event.type() != listener->type) continue; // 2. Set found to true. found = true; // 3. If phase is "capturing" and listener’s capture is false, then continue. - if (phase == Event::Phase::CapturingPhase && !listener.listener->capture()) + if (phase == Event::Phase::CapturingPhase && !listener->capture) continue; // 4. If phase is "bubbling" and listener’s capture is true, then continue. - if (phase == Event::Phase::BubblingPhase && listener.listener->capture()) + if (phase == Event::Phase::BubblingPhase && listener->capture) continue; // 5. If listener’s once is true, then remove listener from event’s currentTarget attribute value’s event listener list. - if (listener.listener->once()) - event.current_target()->remove_from_event_listener_list(listener.listener); + if (listener->once) + event.current_target()->remove_from_event_listener_list(listener); // 6. Let global be listener callback’s associated Realm’s global object. - auto& callback = listener.listener->callback(); + auto& callback = listener->callback->callback(); auto& global = callback.callback.cell()->global_object(); // 7. Let currentEvent be undefined. @@ -100,7 +101,7 @@ bool EventDispatcher::inner_invoke(Event& event, Vectorpassive()) + if (listener->passive) event.set_in_passive_listener(true); // 10. Call a user object’s operation with listener’s callback, "handleEvent", « event », and event’s currentTarget attribute value. If this throws an exception, then: @@ -155,7 +156,7 @@ void EventDispatcher::invoke(Event::PathEntry& struct_, Event& event, Event::Pha event.set_current_target(struct_.invocation_target); // NOTE: This is an intentional copy. Any event listeners added after this point will not be invoked. - auto listeners = event.current_target()->listeners(); + auto listeners = event.current_target()->event_listener_list(); bool invocation_target_in_shadow_tree = struct_.invocation_target_in_shadow_tree; bool found = inner_invoke(event, listeners, phase, invocation_target_in_shadow_tree); diff --git a/Userland/Libraries/LibWeb/DOM/EventDispatcher.h b/Userland/Libraries/LibWeb/DOM/EventDispatcher.h index 55fb86d9d7..045bbaeb46 100644 --- a/Userland/Libraries/LibWeb/DOM/EventDispatcher.h +++ b/Userland/Libraries/LibWeb/DOM/EventDispatcher.h @@ -18,7 +18,7 @@ public: private: static void invoke(Event::PathEntry&, Event&, Event::Phase); - static bool inner_invoke(Event&, Vector&, Event::Phase, bool); + static bool inner_invoke(Event&, Vector>&, Event::Phase, bool); }; } diff --git a/Userland/Libraries/LibWeb/DOM/EventListener.h b/Userland/Libraries/LibWeb/DOM/EventListener.h deleted file mode 100644 index 7b76115a76..0000000000 --- a/Userland/Libraries/LibWeb/DOM/EventListener.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Web::DOM { - -class EventListener - : public RefCounted - , public Bindings::Wrappable { -public: - using WrapperType = Bindings::EventListenerWrapper; - - explicit EventListener(Bindings::CallbackType callback) - : m_callback(move(callback)) - { - } - - virtual ~EventListener() = default; - - Bindings::CallbackType& callback() { return m_callback; } - - const FlyString& type() const { return m_type; } - void set_type(const FlyString& type) { m_type = type; } - - bool capture() const { return m_capture; } - void set_capture(bool capture) { m_capture = capture; } - - bool passive() const { return m_passive; } - void set_passive(bool passive) { m_capture = passive; } - - bool once() const { return m_once; } - void set_once(bool once) { m_once = once; } - - bool removed() const { return m_removed; } - void set_removed(bool removed) { m_removed = removed; } - -private: - FlyString m_type; - Bindings::CallbackType m_callback; - bool m_capture { false }; - bool m_passive { false }; - bool m_once { false }; - bool m_removed { false }; -}; - -} diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp index ec32a62227..2c14ab95a0 100644 --- a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp @@ -19,11 +19,12 @@ #include #include #include +#include #include #include #include -#include #include +#include #include #include #include @@ -44,38 +45,87 @@ EventTarget::~EventTarget() { } -// https://dom.spec.whatwg.org/#add-an-event-listener -void EventTarget::add_event_listener(const FlyString& event_name, RefPtr listener) +// https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener +void EventTarget::add_event_listener(FlyString const& type, RefPtr callback) { - if (listener.is_null()) + // FIXME: 1. Let capture, passive, once, and signal be the result of flattening more options. + bool capture = false; + bool passive = false; + bool once = false; + RefPtr signal = nullptr; + + // 2. Add an event listener with this and an event listener whose type is type, callback is callback, capture is capture, passive is passive, + // once is once, and signal is signal. + auto event_listener = adopt_ref(*new DOMEventListener); + event_listener->type = type; + event_listener->callback = move(callback); + event_listener->signal = move(signal); + event_listener->capture = capture; + event_listener->passive = passive; + event_listener->once = once; + add_an_event_listener(move(event_listener)); +} + +// https://dom.spec.whatwg.org/#add-an-event-listener +void EventTarget::add_an_event_listener(NonnullRefPtr listener) +{ + // FIXME: 1. If eventTarget is a ServiceWorkerGlobalScope object, its service worker’s script resource’s has ever been evaluated flag is set, + // and listener’s type matches the type attribute value of any of the service worker events, then report a warning to the console + // that this might not give the expected results. [SERVICE-WORKERS] + + // 2. If listener’s signal is not null and is aborted, then return. + if (listener->signal && listener->signal->aborted()) return; - auto existing_listener = m_listeners.first_matching([&](auto& entry) { - return entry.listener->type() == event_name && entry.listener->callback().callback.cell() == listener->callback().callback.cell() && entry.listener->capture() == listener->capture(); + + // 3. If listener’s callback is null, then return. + if (listener->callback.is_null()) + return; + + // 4. If eventTarget’s event listener list does not contain an event listener whose type is listener’s type, callback is listener’s callback, + // and capture is listener’s capture, then append listener to eventTarget’s event listener list. + auto it = m_event_listener_list.find_if([&](auto& entry) { + return entry->type == listener->type + && entry->callback->callback().callback.cell() == listener->callback->callback().callback.cell() + && entry->capture == listener->capture; }); - if (existing_listener.has_value()) - return; - listener->set_type(event_name); - m_listeners.append({ event_name, listener.release_nonnull() }); + if (it == m_event_listener_list.end()) + m_event_listener_list.append(listener); + + // FIXME: 5. If listener’s signal is not null, then add the following abort steps to it: + // FIXME: 1. Remove an event listener with eventTarget and listener. +} + +// https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener +void EventTarget::remove_event_listener(FlyString const& type, RefPtr callback) +{ + // FIXME: 1. Let capture be the result of flattening options. + bool capture = false; + + // 2. If this’s event listener list contains an event listener whose type is type, callback is callback, and capture is capture, + // then remove an event listener with this and that event listener. + auto it = m_event_listener_list.find_if([&](auto& entry) { + return entry->type == type + && entry->callback->callback().callback.cell() == callback->callback().callback.cell() + && entry->capture == capture; + }); + if (it != m_event_listener_list.end()) + remove_an_event_listener(*it); } // https://dom.spec.whatwg.org/#remove-an-event-listener -void EventTarget::remove_event_listener(const FlyString& event_name, RefPtr listener) +void EventTarget::remove_an_event_listener(DOMEventListener& listener) { - if (listener.is_null()) - return; - m_listeners.remove_first_matching([&](auto& entry) { - auto matches = entry.event_name == event_name && entry.listener->callback().callback.cell() == listener->callback().callback.cell() && entry.listener->capture() == listener->capture(); - if (matches) - entry.listener->set_removed(true); - return matches; - }); + // FIXME: 1. If eventTarget is a ServiceWorkerGlobalScope object and its service worker’s set of event types to handle contains type, + // then report a warning to the console that this might not give the expected results. [SERVICE-WORKERS] + + // 2. Set listener’s removed to true and remove listener from eventTarget’s event listener list. + listener.removed = true; + m_event_listener_list.remove_first_matching([&](auto& entry) { return entry.ptr() == &listener; }); } -void EventTarget::remove_from_event_listener_list(NonnullRefPtr listener) +void EventTarget::remove_from_event_listener_list(DOMEventListener& listener) { - m_listeners.remove_first_matching([&](auto& entry) { - return entry.listener->type() == listener->type() && &entry.listener->callback() == &listener->callback() && entry.listener->capture() == listener->capture(); - }); + m_event_listener_list.remove_first_matching([&](auto& entry) { return entry.ptr() == &listener; }); } // https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent @@ -433,11 +483,12 @@ void EventTarget::activate_event_handler(FlyString const& name, HTML::EventHandl Bindings::CallbackType callback { JS::make_handle(static_cast(callback_function)), verify_cast(*global_object->associated_realm()->host_defined()) }; // 5. Let listener be a new event listener whose type is the event handler event type corresponding to eventHandler and callback is callback. - auto listener = adopt_ref(*new EventListener(move(callback))); + auto listener = adopt_ref(*new DOMEventListener); + listener->type = name; + listener->callback = adopt_ref(*new IDLEventListener(move(callback))); // 6. Add an event listener with eventTarget and listener. - // FIXME: Make add_event_listener follow the spec more tightly. (Namely, don't allow taking a name and having a separate bindings version) - add_event_listener(name, listener); + add_an_event_listener(listener); // 7. Set eventHandler's listener to listener. event_handler.listener = listener; @@ -460,8 +511,7 @@ void EventTarget::deactivate_event_handler(FlyString const& name) // 5. If listener is not null, then remove an event listener with eventTarget and listener. if (event_handler.listener) { - // FIXME: Make remove_event_listener follow the spec more tightly. (Namely, don't allow taking a name and having a separate bindings version) - remove_event_listener(name, event_handler.listener); + remove_an_event_listener(*event_handler.listener); } // 6. Set eventHandler's listener to null. diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.h b/Userland/Libraries/LibWeb/DOM/EventTarget.h index 1bc0ea84d0..59531200ae 100644 --- a/Userland/Libraries/LibWeb/DOM/EventTarget.h +++ b/Userland/Libraries/LibWeb/DOM/EventTarget.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -29,10 +30,8 @@ public: virtual bool is_focusable() const { return false; } - void add_event_listener(const FlyString& event_name, RefPtr); - void remove_event_listener(const FlyString& event_name, RefPtr); - - void remove_from_event_listener_list(NonnullRefPtr); + void add_event_listener(FlyString const& type, RefPtr callback); + void remove_event_listener(FlyString const& type, RefPtr callback); virtual bool dispatch_event(NonnullRefPtr); ExceptionOr dispatch_event_binding(NonnullRefPtr); @@ -41,13 +40,12 @@ public: virtual EventTarget* get_parent(const Event&) { return nullptr; } - struct EventListenerRegistration { - FlyString event_name; - NonnullRefPtr listener; - }; + void add_an_event_listener(NonnullRefPtr); + void remove_an_event_listener(DOMEventListener&); + void remove_from_event_listener_list(DOMEventListener&); - Vector& listeners() { return m_listeners; } - const Vector& listeners() const { return m_listeners; } + auto& event_listener_list() { return m_event_listener_list; } + auto const& event_listener_list() const { return m_event_listener_list; } Function activation_behavior; @@ -70,7 +68,7 @@ protected: void element_event_handler_attribute_changed(FlyString const& local_name, String const& value); private: - Vector m_listeners; + Vector> m_event_listener_list; // https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-map // Spec Note: The order of the entries of event handler map could be arbitrary. It is not observable through any algorithms that operate on the map. diff --git a/Userland/Libraries/LibWeb/DOM/IDLEventListener.h b/Userland/Libraries/LibWeb/DOM/IDLEventListener.h new file mode 100644 index 0000000000..ca18d2dab2 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/IDLEventListener.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::DOM { + +class IDLEventListener + : public RefCounted + , public Bindings::Wrappable { +public: + using WrapperType = Bindings::EventListenerWrapper; + + explicit IDLEventListener(Bindings::CallbackType callback) + : m_callback(move(callback)) + { + } + + virtual ~IDLEventListener() = default; + + Bindings::CallbackType& callback() { return m_callback; } + +private: + Bindings::CallbackType m_callback; +}; + +} diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 9c0371bcc7..d4c5ab7475 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 5b81293a02..43c2902631 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -84,15 +84,16 @@ class Document; class DocumentFragment; class DocumentLoadEventDelayer; class DocumentType; +class DOMEventListener; class DOMException; class DOMImplementation; class DOMTokenList; class Element; class Event; class EventHandler; -class EventListener; class EventTarget; class HTMLCollection; +class IDLEventListener; class LiveNodeList; class NamedNodeMap; class Node; diff --git a/Userland/Libraries/LibWeb/HTML/EventHandler.h b/Userland/Libraries/LibWeb/HTML/EventHandler.h index 26d0969495..888c6b8bb8 100644 --- a/Userland/Libraries/LibWeb/HTML/EventHandler.h +++ b/Userland/Libraries/LibWeb/HTML/EventHandler.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace Web::HTML { @@ -34,7 +34,7 @@ struct EventHandler { Variant value; // https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-listener - RefPtr listener; + RefPtr listener; }; } diff --git a/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp b/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp index e31a3a1d32..6ba4217d3e 100644 --- a/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp +++ b/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp index 344c3de16c..b19dfdc6fb 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/HTML/WebSocket.cpp b/Userland/Libraries/LibWeb/HTML/WebSocket.cpp index 2c79cf52db..e6b924fa78 100644 --- a/Userland/Libraries/LibWeb/HTML/WebSocket.cpp +++ b/Userland/Libraries/LibWeb/HTML/WebSocket.cpp @@ -16,8 +16,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp index 9b1e7dd9de..5bea6158cb 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include #include #include #include