diff --git a/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp b/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp new file mode 100644 index 0000000000..4a6e6344e9 --- /dev/null +++ b/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +namespace Web::Bindings { + +EventTargetWrapper* wrap(JS::GlobalObject& global_object, DOM::EventTarget& target) +{ + return target.create_wrapper(global_object); +} + +} diff --git a/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h b/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h new file mode 100644 index 0000000000..c28c7724ca --- /dev/null +++ b/Libraries/LibWeb/Bindings/EventTargetWrapperFactory.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace Web::Bindings { + +EventTargetWrapper* wrap(JS::GlobalObject&, DOM::EventTarget&); + +} diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 87b2084f32..e2ab325e76 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES Bindings/EventListenerWrapper.cpp Bindings/EventWrapperFactory.cpp + Bindings/EventTargetWrapperFactory.cpp Bindings/LocationObject.cpp Bindings/NavigatorObject.cpp Bindings/NodeWrapperFactory.cpp @@ -31,6 +32,7 @@ set(SOURCES DOM/DocumentType.cpp DOM/Element.cpp DOM/ElementFactory.cpp + DOM/EventDispatcher.cpp DOM/EventListener.cpp DOM/EventTarget.cpp DOM/Node.cpp diff --git a/Libraries/LibWeb/DOM/EventDispatcher.cpp b/Libraries/LibWeb/DOM/EventDispatcher.cpp new file mode 100644 index 0000000000..45b30f008f --- /dev/null +++ b/Libraries/LibWeb/DOM/EventDispatcher.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace Web::DOM { + +void EventDispatcher::dispatch(EventTarget& target, NonnullRefPtr event) +{ + auto listeners = target.listeners(); + for (auto& listener : listeners) { + if (listener.event_name != event->type()) + continue; + auto& function = listener.listener->function(); + auto& global_object = function.global_object(); + auto* this_value = Bindings::wrap(global_object, target); + auto& interpreter = function.interpreter(); + (void)interpreter.call(function, this_value, Bindings::wrap(global_object, target)); + if (interpreter.exception()) + interpreter.clear_exception(); + } +} + +} diff --git a/Libraries/LibWeb/DOM/EventDispatcher.h b/Libraries/LibWeb/DOM/EventDispatcher.h new file mode 100644 index 0000000000..a50c55cace --- /dev/null +++ b/Libraries/LibWeb/DOM/EventDispatcher.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace Web::DOM { + +class EventDispatcher { +public: + static void dispatch(EventTarget&, NonnullRefPtr); +}; + +} diff --git a/Libraries/LibWeb/DOM/EventTarget.h b/Libraries/LibWeb/DOM/EventTarget.h index 9a15ceb0bb..7822064c75 100644 --- a/Libraries/LibWeb/DOM/EventTarget.h +++ b/Libraries/LibWeb/DOM/EventTarget.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace Web::DOM { @@ -47,6 +48,7 @@ public: void remove_event_listener(const FlyString& event_name, NonnullRefPtr); virtual void dispatch_event(NonnullRefPtr) = 0; + virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) = 0; struct EventListenerRegistration { FlyString event_name; diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 5ff11610df..42eae09d39 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -119,25 +120,7 @@ bool Node::is_link() const void Node::dispatch_event(NonnullRefPtr event) { - for (auto& listener : listeners()) { - if (listener.event_name == event->type()) { - auto& function = const_cast(*listener.listener).function(); -#ifdef EVENT_DEBUG - static_cast(function).body().dump(0); -#endif - auto& global_object = function.global_object(); - auto* this_value = wrap(global_object, *this); -#ifdef EVENT_DEBUG - dbg() << "calling event listener with this=" << this_value; -#endif - auto* event_wrapper = wrap(global_object, *event); - auto& interpreter = document().interpreter(); - (void)interpreter.call(function, this_value, event_wrapper); - if (interpreter.exception()) - interpreter.clear_exception(); - } - } - + EventDispatcher::dispatch(*this, event); // FIXME: This is a hack. We should follow the real rules of event bubbling. if (parent()) parent()->dispatch_event(move(event)); @@ -218,4 +201,9 @@ bool Node::is_editable() const return parent() && parent()->is_editable(); } +Bindings::EventTargetWrapper* Node::create_wrapper(JS::GlobalObject& global_object) +{ + return wrap(global_object, *this); +} + } diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index f5abb4ede0..a009cde6e8 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -61,6 +61,7 @@ public: virtual void ref_event_target() final { ref(); } virtual void unref_event_target() final { unref(); } virtual void dispatch_event(NonnullRefPtr) final; + virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override; virtual ~Node(); diff --git a/Libraries/LibWeb/DOM/XMLHttpRequest.cpp b/Libraries/LibWeb/DOM/XMLHttpRequest.cpp index cb95b89566..dfa9347328 100644 --- a/Libraries/LibWeb/DOM/XMLHttpRequest.cpp +++ b/Libraries/LibWeb/DOM/XMLHttpRequest.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -91,17 +92,12 @@ void XMLHttpRequest::send() void XMLHttpRequest::dispatch_event(NonnullRefPtr event) { - for (auto& listener : listeners()) { - if (listener.event_name == event->type()) { - auto& function = const_cast(*listener.listener).function(); - auto& global_object = function.global_object(); - auto* this_value = wrap(global_object, *this); - auto& interpreter = function.interpreter(); - (void)interpreter.call(function, this_value, wrap(global_object, *this)); - if (interpreter.exception()) - interpreter.clear_exception(); - } - } + DOM::EventDispatcher::dispatch(*this, move(event)); +} + +Bindings::EventTargetWrapper* XMLHttpRequest::create_wrapper(JS::GlobalObject& global_object) +{ + return wrap(global_object, *this); } } diff --git a/Libraries/LibWeb/DOM/XMLHttpRequest.h b/Libraries/LibWeb/DOM/XMLHttpRequest.h index 468e18fc5e..346898153b 100644 --- a/Libraries/LibWeb/DOM/XMLHttpRequest.h +++ b/Libraries/LibWeb/DOM/XMLHttpRequest.h @@ -66,6 +66,7 @@ private: virtual void ref_event_target() override { ref(); } virtual void unref_event_target() override { unref(); } virtual void dispatch_event(NonnullRefPtr) override; + virtual Bindings::EventTargetWrapper* create_wrapper(JS::GlobalObject&) override; void set_ready_state(ReadyState);