summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-02-03 22:47:50 +0100
committerAndreas Kling <kling@serenityos.org>2021-02-03 23:03:05 +0100
commita59b1825ce3ba5d6e6adf51ab2745c7212789c31 (patch)
tree8d7a09b0705fa05bb1d0921bf8400ca7d0aaa241 /Userland/Libraries/LibWeb
parentb43db4cc5027c7aa1c4780a8ab2851f4a5f1cca0 (diff)
downloadserenity-a59b1825ce3ba5d6e6adf51ab2745c7212789c31.zip
LibWeb: Basic implementation of global event handlers :^)
Document and HTMLElement now inherit from HTML::GlobalEventHandlers which allows them to support "onfoo" event handler attributes. These are assignable both via IDL attributes and content attributes. Event listeners constructed this way get a special "attribute" flag on them so we know which one to replace if you reassign them. This also allows them to coexist with EventTarget.addEventListener(). This is all a bit sloppy, but it works decently for a first cut. The Window object should also inherit GlobalEventHandlers, but since we don't generate it from IDL, I haven't taken that step here. Also this would be a lot nicer if we supported IDL mixins.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp17
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.h5
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.idl71
-rw-r--r--Userland/Libraries/LibWeb/DOM/EventListener.h6
-rw-r--r--Userland/Libraries/LibWeb/DOM/EventTarget.h1
-rw-r--r--Userland/Libraries/LibWeb/Forward.h1
-rw-r--r--Userland/Libraries/LibWeb/HTML/EventHandler.h54
-rw-r--r--Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp99
-rw-r--r--Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.h25
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp7
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h3
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLElement.cpp19
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLElement.h12
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLElement.idl72
15 files changed, 391 insertions, 2 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt
index e61f263f26..14b458640c 100644
--- a/Userland/Libraries/LibWeb/CMakeLists.txt
+++ b/Userland/Libraries/LibWeb/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SOURCES
HTML/AttributeNames.cpp
HTML/CanvasRenderingContext2D.cpp
HTML/EventNames.cpp
+ HTML/GlobalEventHandlers.cpp
HTML/HTMLAnchorElement.cpp
HTML/HTMLAreaElement.cpp
HTML/HTMLAudioElement.cpp
diff --git a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp
index 39e8ac2bdd..06213342ad 100644
--- a/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp
+++ b/Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp
@@ -904,6 +904,7 @@ void generate_prototype_implementation(const IDL::Interface& interface)
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/EventListener.h>
#include <LibWeb/DOM/Window.h>
+#include <LibWeb/HTML/EventHandler.h>
#include <LibWeb/HTML/HTMLElement.h>
#include <LibWeb/NavigationTiming/PerformanceTiming.h>
#include <LibWeb/Origin.h>
@@ -1097,6 +1098,18 @@ static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_ob
if (vm.exception())
@return_statement@
)~~~");
+ } else if (parameter.type.name == "EventHandler") {
+ // x.onfoo = function() { ... }
+ scoped_generator.append(R"~~~(
+ HTML::EventHandler @cpp_name@;
+ if (@js_name@@js_suffix@.is_function()) {
+ @cpp_name@.callback = JS::make_handle(&@js_name@@js_suffix@.as_function());
+ } else if (@js_name@@js_suffix@.is_string()) {
+ @cpp_name@.string = @js_name@@js_suffix@.as_string().string();
+ } else {
+ @return_statement@
+ }
+)~~~");
} else {
dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name);
ASSERT_NOT_REACHED();
@@ -1174,6 +1187,10 @@ static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_ob
scoped_generator.append(R"~~~(
return retval;
)~~~");
+ } else if (return_type.name == "EventHandler") {
+ scoped_generator.append(R"~~~(
+ return retval.callback.cell();
+)~~~");
} else {
scoped_generator.append(R"~~~(
return wrap(global_object, const_cast<@return_type@&>(*retval));
diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h
index be7050b2cc..0f19fefdfd 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.h
+++ b/Userland/Libraries/LibWeb/DOM/Document.h
@@ -55,6 +55,7 @@ enum class QuirksMode {
class Document
: public ParentNode
, public NonElementParentNode<Document>
+ , public HTML::GlobalEventHandlers
, public Bindings::ScriptExecutionContext {
public:
using WrapperType = Bindings::DocumentWrapper;
@@ -233,8 +234,12 @@ public:
private:
explicit Document(const URL&);
+ // ^DOM::Node
virtual RefPtr<Layout::Node> create_layout_node() override;
+ // ^HTML::GlobalEventHandlers
+ virtual EventTarget& global_event_handlers_to_event_target() final { return *this; }
+
void tear_down_layout_tree();
void increment_referencing_node_count()
diff --git a/Userland/Libraries/LibWeb/DOM/Document.idl b/Userland/Libraries/LibWeb/DOM/Document.idl
index 9aa2878d62..bd405a48bb 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.idl
+++ b/Userland/Libraries/LibWeb/DOM/Document.idl
@@ -36,4 +36,75 @@ interface Document : Node {
attribute DOMString title;
+ // FIXME: These should all come from a GlobalEventHandlers mixin
+ attribute EventHandler onabort;
+ attribute EventHandler onauxclick;
+ attribute EventHandler onblur;
+ attribute EventHandler oncancel;
+ attribute EventHandler oncanplay;
+ attribute EventHandler oncanplaythrough;
+ attribute EventHandler onchange;
+ attribute EventHandler onclick;
+ attribute EventHandler onclose;
+ attribute EventHandler oncontextmenu;
+ attribute EventHandler oncuechange;
+ attribute EventHandler ondblclick;
+ attribute EventHandler ondrag;
+ attribute EventHandler ondragend;
+ attribute EventHandler ondragenter;
+ attribute EventHandler ondragleave;
+ attribute EventHandler ondragover;
+ attribute EventHandler ondragstart;
+ attribute EventHandler ondrop;
+ attribute EventHandler ondurationchange;
+ attribute EventHandler onemptied;
+ attribute EventHandler onended;
+
+ // FIXME: Should be an OnErrorEventHandler
+ attribute EventHandler onerror;
+
+ attribute EventHandler onfocus;
+ attribute EventHandler onformdata;
+ attribute EventHandler oninput;
+ attribute EventHandler oninvalid;
+ attribute EventHandler onkeydown;
+ attribute EventHandler onkeypress;
+ attribute EventHandler onkeyup;
+ attribute EventHandler onload;
+ attribute EventHandler onloadeddata;
+ attribute EventHandler onloadedmetadata;
+ attribute EventHandler onloadstart;
+ attribute EventHandler onmousedown;
+ [LegacyLenientThis] attribute EventHandler onmouseenter;
+ [LegacyLenientThis] attribute EventHandler onmouseleave;
+ attribute EventHandler onmousemove;
+ attribute EventHandler onmouseout;
+ attribute EventHandler onmouseover;
+ attribute EventHandler onmouseup;
+ attribute EventHandler onpause;
+ attribute EventHandler onplay;
+ attribute EventHandler onplaying;
+ attribute EventHandler onprogress;
+ attribute EventHandler onratechange;
+ attribute EventHandler onreset;
+ attribute EventHandler onresize;
+ attribute EventHandler onscroll;
+ attribute EventHandler onsecuritypolicyviolation;
+ attribute EventHandler onseeked;
+ attribute EventHandler onseeking;
+ attribute EventHandler onselect;
+ attribute EventHandler onslotchange;
+ attribute EventHandler onstalled;
+ attribute EventHandler onsubmit;
+ attribute EventHandler onsuspend;
+ attribute EventHandler ontimeupdate;
+ attribute EventHandler ontoggle;
+ attribute EventHandler onvolumechange;
+ attribute EventHandler onwaiting;
+ attribute EventHandler onwebkitanimationend;
+ attribute EventHandler onwebkitanimationiteration;
+ attribute EventHandler onwebkitanimationstart;
+ attribute EventHandler onwebkittransitionend;
+ attribute EventHandler onwheel;
+
};
diff --git a/Userland/Libraries/LibWeb/DOM/EventListener.h b/Userland/Libraries/LibWeb/DOM/EventListener.h
index 1d5705c2b6..377d3899be 100644
--- a/Userland/Libraries/LibWeb/DOM/EventListener.h
+++ b/Userland/Libraries/LibWeb/DOM/EventListener.h
@@ -38,8 +38,9 @@ class EventListener
public:
using WrapperType = Bindings::EventListenerWrapper;
- explicit EventListener(JS::Handle<JS::Function> function)
+ explicit EventListener(JS::Handle<JS::Function> function, bool is_attribute = false)
: m_function(move(function))
+ , m_attribute(is_attribute)
{
}
@@ -60,6 +61,8 @@ public:
bool removed() const { return m_removed; }
void set_removed(bool removed) { m_removed = removed; }
+ bool is_attribute() const { return m_attribute; }
+
private:
FlyString m_type;
JS::Handle<JS::Function> m_function;
@@ -67,6 +70,7 @@ private:
bool m_passive { false };
bool m_once { false };
bool m_removed { false };
+ bool m_attribute { false };
};
}
diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.h b/Userland/Libraries/LibWeb/DOM/EventTarget.h
index f03d4a4fb2..af1a1d7b0c 100644
--- a/Userland/Libraries/LibWeb/DOM/EventTarget.h
+++ b/Userland/Libraries/LibWeb/DOM/EventTarget.h
@@ -61,6 +61,7 @@ public:
NonnullRefPtr<EventListener> listener;
};
+ Vector<EventListenerRegistration>& listeners() { return m_listeners; }
const Vector<EventListenerRegistration>& listeners() const { return m_listeners; }
Function<void(const Event&)> activation_behaviour;
diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h
index 7e8ca5b9da..32ed362c1f 100644
--- a/Userland/Libraries/LibWeb/Forward.h
+++ b/Userland/Libraries/LibWeb/Forward.h
@@ -62,6 +62,7 @@ enum class QuirksMode;
namespace Web::HTML {
class CanvasRenderingContext2D;
+class EventHandler;
class HTMLAnchorElement;
class HTMLAreaElement;
class HTMLAudioElement;
diff --git a/Userland/Libraries/LibWeb/HTML/EventHandler.h b/Userland/Libraries/LibWeb/HTML/EventHandler.h
new file mode 100644
index 0000000000..1a6229a2ae
--- /dev/null
+++ b/Userland/Libraries/LibWeb/HTML/EventHandler.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ * 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 <AK/String.h>
+#include <LibJS/Heap/Handle.h>
+#include <LibJS/Runtime/Function.h>
+
+namespace Web::HTML {
+
+struct EventHandler {
+ EventHandler()
+ {
+ }
+
+ EventHandler(String s)
+ : string(move(s))
+ {
+ }
+
+ EventHandler(JS::Handle<JS::Function> c)
+ : callback(move(c))
+ {
+ }
+
+ String string;
+ JS::Handle<JS::Function> callback;
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp b/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp
new file mode 100644
index 0000000000..46585e80d9
--- /dev/null
+++ b/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ * 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 <LibJS/Interpreter.h>
+#include <LibJS/Parser.h>
+#include <LibJS/Runtime/ScriptFunction.h>
+#include <LibWeb/DOM/Document.h>
+#include <LibWeb/DOM/EventListener.h>
+#include <LibWeb/HTML/EventHandler.h>
+#include <LibWeb/HTML/EventNames.h>
+#include <LibWeb/HTML/GlobalEventHandlers.h>
+#include <LibWeb/UIEvents/EventNames.h>
+
+namespace Web::HTML {
+
+#undef __ENUMERATE
+#define __ENUMERATE(attribute_name, event_name) \
+ void GlobalEventHandlers::set_##attribute_name(HTML::EventHandler value) \
+ { \
+ set_event_handler_attribute(event_name, move(value)); \
+ } \
+ HTML::EventHandler GlobalEventHandlers::attribute_name() \
+ { \
+ return get_event_handler_attribute(event_name); \
+ }
+ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE)
+#undef __ENUMERATE
+
+GlobalEventHandlers::~GlobalEventHandlers()
+{
+}
+
+void GlobalEventHandlers::set_event_handler_attribute(const FlyString& name, HTML::EventHandler value)
+{
+ auto& self = global_event_handlers_to_event_target();
+
+ RefPtr<DOM::EventListener> listener;
+ if (!value.callback.is_null()) {
+ listener = adopt(*new DOM::EventListener(move(value.callback)));
+ } else {
+ StringBuilder builder;
+ builder.appendff("function {}(event) {{\n{}\n}}", name, value.string);
+ auto parser = JS::Parser(JS::Lexer(builder.string_view()));
+ auto program = parser.parse_function_node<JS::FunctionExpression>();
+ if (parser.has_errors()) {
+ dbgln("Failed to parse script in event handler attribute '{}'", name);
+ return;
+ }
+ auto* function = JS::ScriptFunction::create(self.script_execution_context()->interpreter().global_object(), name, program->body(), program->parameters(), program->function_length(), nullptr, false, false);
+ ASSERT(function);
+ listener = adopt(*new DOM::EventListener(JS::make_handle(static_cast<JS::Function*>(function))));
+ }
+ if (listener) {
+ for (auto& registered_listener : self.listeners()) {
+ if (registered_listener.event_name == name && registered_listener.listener->is_attribute()) {
+ self.remove_event_listener(name, registered_listener.listener);
+ break;
+ }
+ }
+ self.add_event_listener(name, listener.release_nonnull());
+ }
+}
+
+HTML::EventHandler GlobalEventHandlers::get_event_handler_attribute(const FlyString& name)
+{
+ auto& self = global_event_handlers_to_event_target();
+ for (auto& listener : self.listeners()) {
+ if (listener.event_name == name && listener.listener->is_attribute()) {
+ return HTML::EventHandler { JS::make_handle(&listener.listener->function()) };
+ }
+ }
+
+ return {};
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.h b/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.h
index 7cf05ecf4e..cb272d249b 100644
--- a/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.h
+++ b/Userland/Libraries/LibWeb/HTML/GlobalEventHandlers.h
@@ -26,6 +26,9 @@
#pragma once
+#include <AK/Forward.h>
+#include <LibWeb/Forward.h>
+
#define ENUMERATE_GLOBAL_EVENT_HANDLERS(E) \
E(onabort, HTML::EventNames::abort) \
E(onauxclick, "auxclick") \
@@ -93,3 +96,25 @@
E(onwebkitanimationstart, "webkitanimationstart") \
E(onwebkittransitionend, "webkittransitionend") \
E(onwheel, "wheel")
+
+namespace Web::HTML {
+
+class GlobalEventHandlers {
+public:
+ virtual ~GlobalEventHandlers();
+
+#undef __ENUMERATE
+#define __ENUMERATE(attribute_name, event_name) \
+ void set_##attribute_name(HTML::EventHandler); \
+ HTML::EventHandler attribute_name();
+ ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE)
+#undef __ENUMERATE
+
+ void set_event_handler_attribute(const FlyString& name, HTML::EventHandler);
+ HTML::EventHandler get_event_handler_attribute(const FlyString& name);
+
+protected:
+ virtual DOM::EventTarget& global_event_handlers_to_event_target() = 0;
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp
index e6b7272f8d..4e3277f396 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.cpp
@@ -27,6 +27,7 @@
#include <LibWeb/CSS/StyleProperties.h>
#include <LibWeb/CSS/StyleValue.h>
#include <LibWeb/DOM/Document.h>
+#include <LibWeb/DOM/Window.h>
#include <LibWeb/HTML/HTMLBodyElement.h>
namespace Web::HTML {
@@ -78,4 +79,10 @@ void HTMLBodyElement::parse_attribute(const FlyString& name, const String& value
}
}
+DOM::EventTarget& HTMLBodyElement::global_event_handlers_to_event_target()
+{
+ // NOTE: This is a little weird, but IIUC document.body.onload actually refers to window.onload
+ return document().window();
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h b/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h
index d8d41cbb7b..e5e169621a 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLBodyElement.h
@@ -41,6 +41,9 @@ public:
virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
private:
+ // ^HTML::GlobalEventHandlers
+ virtual EventTarget& global_event_handlers_to_event_target() override;
+
RefPtr<CSS::ImageStyleValue> m_background_style_value;
};
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
index eb5356a594..ac09cb1d7a 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
@@ -25,11 +25,17 @@
*/
#include <AK/StringBuilder.h>
+#include <LibJS/Interpreter.h>
+#include <LibJS/Parser.h>
+#include <LibJS/Runtime/ScriptFunction.h>
#include <LibWeb/DOM/Document.h>
+#include <LibWeb/DOM/EventListener.h>
+#include <LibWeb/HTML/EventHandler.h>
#include <LibWeb/HTML/HTMLAnchorElement.h>
#include <LibWeb/HTML/HTMLElement.h>
#include <LibWeb/Layout/BreakNode.h>
#include <LibWeb/Layout/TextNode.h>
+#include <LibWeb/UIEvents/EventNames.h>
namespace Web::HTML {
@@ -138,4 +144,17 @@ bool HTMLElement::cannot_navigate() const
return !is<HTML::HTMLAnchorElement>(this) && !is_connected();
}
+void HTMLElement::parse_attribute(const FlyString& name, const String& value)
+{
+ Element::parse_attribute(name, value);
+
+#undef __ENUMERATE
+#define __ENUMERATE(attribute_name, event_name) \
+ if (name == HTML::AttributeNames::attribute_name) { \
+ set_event_handler_attribute(event_name, EventHandler { value }); \
+ }
+ ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE)
+#undef __ENUMERATE
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.h b/Userland/Libraries/LibWeb/HTML/HTMLElement.h
index ee602a62b5..b070c13e49 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.h
@@ -27,10 +27,14 @@
#pragma once
#include <LibWeb/DOM/Element.h>
+#include <LibWeb/HTML/EventNames.h>
+#include <LibWeb/HTML/GlobalEventHandlers.h>
namespace Web::HTML {
-class HTMLElement : public DOM::Element {
+class HTMLElement
+ : public DOM::Element
+ , public HTML::GlobalEventHandlers {
public:
using WrapperType = Bindings::HTMLElementWrapper;
@@ -48,7 +52,13 @@ public:
bool cannot_navigate() const;
+protected:
+ virtual void parse_attribute(const FlyString& name, const String& value) override;
+
private:
+ // ^HTML::GlobalEventHandlers
+ virtual EventTarget& global_event_handlers_to_event_target() override { return *this; }
+
enum class ContentEditableState {
True,
False,
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLElement.idl
index 6b5de34cdb..5369c9a3cd 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.idl
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.idl
@@ -8,4 +8,76 @@ interface HTMLElement : Element {
attribute DOMString contentEditable;
[LegacyNullToEmptyString] attribute DOMString innerText;
+
+ // FIXME: These should all come from a GlobalEventHandlers mixin
+ attribute EventHandler onabort;
+ attribute EventHandler onauxclick;
+ attribute EventHandler onblur;
+ attribute EventHandler oncancel;
+ attribute EventHandler oncanplay;
+ attribute EventHandler oncanplaythrough;
+ attribute EventHandler onchange;
+ attribute EventHandler onclick;
+ attribute EventHandler onclose;
+ attribute EventHandler oncontextmenu;
+ attribute EventHandler oncuechange;
+ attribute EventHandler ondblclick;
+ attribute EventHandler ondrag;
+ attribute EventHandler ondragend;
+ attribute EventHandler ondragenter;
+ attribute EventHandler ondragleave;
+ attribute EventHandler ondragover;
+ attribute EventHandler ondragstart;
+ attribute EventHandler ondrop;
+ attribute EventHandler ondurationchange;
+ attribute EventHandler onemptied;
+ attribute EventHandler onended;
+
+ // FIXME: Should be an OnErrorEventHandler
+ attribute EventHandler onerror;
+
+ attribute EventHandler onfocus;
+ attribute EventHandler onformdata;
+ attribute EventHandler oninput;
+ attribute EventHandler oninvalid;
+ attribute EventHandler onkeydown;
+ attribute EventHandler onkeypress;
+ attribute EventHandler onkeyup;
+ attribute EventHandler onload;
+ attribute EventHandler onloadeddata;
+ attribute EventHandler onloadedmetadata;
+ attribute EventHandler onloadstart;
+ attribute EventHandler onmousedown;
+ [LegacyLenientThis] attribute EventHandler onmouseenter;
+ [LegacyLenientThis] attribute EventHandler onmouseleave;
+ attribute EventHandler onmousemove;
+ attribute EventHandler onmouseout;
+ attribute EventHandler onmouseover;
+ attribute EventHandler onmouseup;
+ attribute EventHandler onpause;
+ attribute EventHandler onplay;
+ attribute EventHandler onplaying;
+ attribute EventHandler onprogress;
+ attribute EventHandler onratechange;
+ attribute EventHandler onreset;
+ attribute EventHandler onresize;
+ attribute EventHandler onscroll;
+ attribute EventHandler onsecuritypolicyviolation;
+ attribute EventHandler onseeked;
+ attribute EventHandler onseeking;
+ attribute EventHandler onselect;
+ attribute EventHandler onslotchange;
+ attribute EventHandler onstalled;
+ attribute EventHandler onsubmit;
+ attribute EventHandler onsuspend;
+ attribute EventHandler ontimeupdate;
+ attribute EventHandler ontoggle;
+ attribute EventHandler onvolumechange;
+ attribute EventHandler onwaiting;
+ attribute EventHandler onwebkitanimationend;
+ attribute EventHandler onwebkitanimationiteration;
+ attribute EventHandler onwebkitanimationstart;
+ attribute EventHandler onwebkittransitionend;
+ attribute EventHandler onwheel;
+
};