Skip to content

Commit 1f5f81f

Browse files
authored
Implement EventTarget and Event builtin (#220)
* Implement EventTarget builtin * implement policy-based design for builtin classes * Address code review feedback * Add TODO about exception reporting * Change subclass registry from vector to unordered_set * Replace listener instances with RefPtr in the EventTarget listener list * Remove "once" listeners before dispatch * Defer removing listeners to after the dispatch loop * Addres code review feedback
1 parent eecc00c commit 1f5f81f

32 files changed

+1771
-175
lines changed

builtins/web/blob.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -417,15 +417,6 @@ Blob::LineEndings Blob::line_endings(JSObject *self) {
417417
JS::GetReservedSlot(self, static_cast<size_t>(Blob::Slots::Endings)).toInt32());
418418
}
419419

420-
bool Blob::is_instance(const JSObject *obj) {
421-
return obj != nullptr &&
422-
(JS::GetClass(obj) == &Blob::class_ || JS::GetClass(obj) == &File::class_);
423-
}
424-
425-
bool Blob::is_instance(const Value val) {
426-
return val.isObject() && is_instance(&val.toObject());
427-
}
428-
429420
bool Blob::append_value(JSContext *cx, HandleObject self, HandleValue val) {
430421
auto blob = Blob::blob(self);
431422

builtins/web/blob.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
#include "builtin.h"
55
#include "extension-api.h"
66
#include "js/AllocPolicy.h"
7-
#include "js/TypeDecls.h"
87
#include "js/Vector.h"
98

109
namespace builtins {
1110
namespace web {
1211
namespace blob {
1312

14-
class Blob : public FinalizableBuiltinImpl<Blob> {
13+
class Blob : public BuiltinImpl<Blob, FinalizableClassPolicy> {
1514
static bool arrayBuffer(JSContext *cx, unsigned argc, JS::Value *vp);
1615
static bool bytes(JSContext *cx, unsigned argc, JS::Value *vp);
1716
static bool slice(JSContext *cx, unsigned argc, JS::Value *vp);
@@ -46,8 +45,6 @@ class Blob : public FinalizableBuiltinImpl<Blob> {
4645
static JSString *type(JSObject *self);
4746
static LineEndings line_endings(JSObject *self);
4847

49-
static bool is_instance(const JSObject *obj);
50-
static bool is_instance(const Value val);
5148
static bool append_value(JSContext *cx, HandleObject self, HandleValue val);
5249
static bool init_blob_parts(JSContext *cx, HandleObject self, HandleValue iterable);
5350
static bool init_options(JSContext *cx, HandleObject self, HandleValue opts);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "custom-event.h"
2+
3+
namespace builtins {
4+
namespace web {
5+
namespace event {
6+
7+
const JSFunctionSpec CustomEvent::static_methods[] = {
8+
JS_FS_END,
9+
};
10+
11+
const JSPropertySpec CustomEvent::static_properties[] = {
12+
JS_PS_END,
13+
};
14+
15+
const JSFunctionSpec CustomEvent::methods[] = {
16+
JS_FS_END,
17+
};
18+
19+
const JSPropertySpec CustomEvent::properties[] = {
20+
JS_PSG("detail", CustomEvent::detail_get, JSPROP_ENUMERATE),
21+
JS_STRING_SYM_PS(toStringTag, "CustomEvent", JSPROP_READONLY),
22+
JS_PS_END,
23+
};
24+
25+
bool CustomEvent::detail_get(JSContext *cx, unsigned argc, JS::Value *vp) {
26+
METHOD_HEADER(0);
27+
// TODO: Change this class so that its prototype isn't an instance of the class
28+
if (self == proto_obj) {
29+
return api::throw_error(cx, api::Errors::WrongReceiver, "name get", "CustomEvent");
30+
}
31+
32+
args.rval().set(JS::GetReservedSlot(self, Slots::Detail));
33+
return true;
34+
}
35+
36+
// https://dom.spec.whatwg.org/#interface-customevent
37+
bool CustomEvent::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
38+
CTOR_HEADER("CustomEvent", 2);
39+
40+
RootedValue type(cx, args.get(0));
41+
RootedValue opts(cx, args.get(1));
42+
RootedValue detail(cx);
43+
44+
RootedObject self(cx, JS_NewObjectForConstructor(cx, &class_, args));
45+
if (!self) {
46+
return false;
47+
}
48+
49+
if (!Event::init(cx, self, type, opts)) {
50+
return false;
51+
}
52+
53+
if (opts.isObject()) {
54+
JS::RootedObject obj(cx, &opts.toObject());
55+
if (!JS_GetProperty(cx, obj, "detail", &detail)) {
56+
return false;
57+
}
58+
}
59+
60+
SetReservedSlot(self, Slots::Detail, detail);
61+
62+
args.rval().setObject(*self);
63+
return true;
64+
}
65+
66+
bool CustomEvent::init_class(JSContext *cx, JS::HandleObject global) {
67+
Event::register_subclass(&class_);
68+
return init_class_impl(cx, global, Event::proto_obj);
69+
}
70+
71+
} // namespace event
72+
} // namespace web
73+
} // namespace builtins

builtins/web/event/custom-event.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef BUILTINS_WEB_CUSTOM_EVENT_H_
2+
#define BUILTINS_WEB_CUSTOM_EVENT_H_
3+
4+
#include "builtin.h"
5+
#include "event.h"
6+
7+
namespace builtins {
8+
namespace web {
9+
namespace event {
10+
11+
class CustomEvent : public BuiltinImpl<CustomEvent> {
12+
static bool detail_get(JSContext *cx, unsigned argc, JS::Value *vp);
13+
14+
public:
15+
static constexpr int ParentSlots = Event::Slots::Count;
16+
enum Slots { Detail = ParentSlots, Count };
17+
18+
static constexpr const char *class_name = "CustomEvent";
19+
static constexpr unsigned ctor_length = 2;
20+
21+
static const JSFunctionSpec static_methods[];
22+
static const JSPropertySpec static_properties[];
23+
static const JSFunctionSpec methods[];
24+
static const JSPropertySpec properties[];
25+
26+
static JSString *name(JSObject *self);
27+
28+
static bool init_class(JSContext *cx, HandleObject global);
29+
static bool constructor(JSContext *cx, unsigned argc, Value *vp);
30+
};
31+
32+
} // namespace event
33+
} // namespace web
34+
} // namespace builtins
35+
36+
#endif // BUILTINS_WEB_CUSTOM_EVENT_H_

0 commit comments

Comments
 (0)