From 072acebcc84629cd6157364710afce325a8d86d6 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Tue, 12 Mar 2024 17:38:31 +0100 Subject: [PATCH] [spidermonkey] CustomEvent --- src/ecmascript/spidermonkey.cpp | 12 +- src/ecmascript/spidermonkey/Makefile | 2 +- src/ecmascript/spidermonkey/customevent.cpp | 394 ++++++++++++++++++++ src/ecmascript/spidermonkey/customevent.h | 11 + src/ecmascript/spidermonkey/meson.build | 2 +- 5 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 src/ecmascript/spidermonkey/customevent.cpp create mode 100644 src/ecmascript/spidermonkey/customevent.h diff --git a/src/ecmascript/spidermonkey.cpp b/src/ecmascript/spidermonkey.cpp index 7994a231..0568d0eb 100644 --- a/src/ecmascript/spidermonkey.cpp +++ b/src/ecmascript/spidermonkey.cpp @@ -28,6 +28,7 @@ #include "ecmascript/ecmascript.h" #include "ecmascript/spidermonkey.h" #include "ecmascript/spidermonkey/console.h" +#include "ecmascript/spidermonkey/customevent.h" #include "ecmascript/spidermonkey/document.h" #include "ecmascript/spidermonkey/event.h" #include "ecmascript/spidermonkey/form.h" @@ -149,7 +150,7 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) JSContext *ctx; JSObject *console_obj, *document_obj, /* *forms_obj,*/ *history_obj, *statusbar_obj, *menubar_obj, *navigator_obj, *localstorage_obj, *screen_obj, - *xhr_obj, *event_obj, *keyboardEvent_obj, *messageEvent_obj; + *xhr_obj, *event_obj, *keyboardEvent_obj, *messageEvent_obj, *customEvent_obj; assert(interpreter); if (!js_module_init_ok) return NULL; @@ -318,6 +319,15 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) goto release_and_fail; } + customEvent_obj = spidermonkey_InitClass(ctx, global, NULL, + &customEvent_class, customEvent_constructor, 0, + customEvent_props, + customEvent_funcs, + NULL, NULL, "CustomEvent"); + + if (!customEvent_obj) { + goto release_and_fail; + } JS::SetRealmPrivate(js::GetContextRealm(ctx), interpreter); return ctx; diff --git a/src/ecmascript/spidermonkey/Makefile b/src/ecmascript/spidermonkey/Makefile index 9ea52b6b..d343d4a8 100644 --- a/src/ecmascript/spidermonkey/Makefile +++ b/src/ecmascript/spidermonkey/Makefile @@ -2,7 +2,7 @@ top_builddir=../../.. include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) -OBJS = attr.obj attributes.obj collection.obj console.obj css.obj document.obj element.obj event.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \ +OBJS = attr.obj attributes.obj collection.obj console.obj css.obj customevent.obj document.obj element.obj event.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \ keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj screen.obj style.obj unibar.obj window.obj xhr.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/spidermonkey/customevent.cpp b/src/ecmascript/spidermonkey/customevent.cpp new file mode 100644 index 00000000..55878454 --- /dev/null +++ b/src/ecmascript/spidermonkey/customevent.cpp @@ -0,0 +1,394 @@ +/* The SpiderMonkey CustomEvent object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/spidermonkey/util.h" +#include +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/spidermonkey.h" +#include "ecmascript/spidermonkey/customevent.h" +#include "ecmascript/spidermonkey/heartbeat.h" +#include "ecmascript/timer.h" +#include "intl/libintl.h" +#include "main/select.h" +#include "main/timer.h" +#include "network/connection.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/download.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +#include +#include +#include +#include +#include +#include + +struct eljscustom_event { + JS::RootedObject detail; + char *type_; + unsigned int bubbles:1; + unsigned int cancelable:1; + unsigned int composed:1; + unsigned int defaultPrevented:1; +}; + +static bool customEvent_get_property_bubbles(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool customEvent_get_property_cancelable(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool customEvent_get_property_composed(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool customEvent_get_property_defaultPrevented(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool customEvent_get_property_detail(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool customEvent_get_property_type(JSContext *ctx, unsigned int argc, JS::Value *vp); + +static bool customEvent_preventDefault(JSContext *ctx, unsigned int argc, JS::Value *vp); + +static void +customEvent_finalize(JS::GCContext *op, JSObject *customEvent_obj) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(customEvent_obj, 0); + + if (event) { + mem_free_if(event->type_); + mem_free(event); + } +} + +JSClassOps customEvent_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + customEvent_finalize, // finalize + nullptr, // call + nullptr, // construct + JS_GlobalObjectTraceHook // trace +}; + +JSClass customEvent_class = { + "CustomEvent", + JSCLASS_HAS_RESERVED_SLOTS(1), + &customEvent_ops +}; + +bool +customEvent_constructor(JSContext* ctx, unsigned argc, JS::Value* vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject newObj(ctx, JS_NewObjectForConstructor(ctx, &customEvent_class, args)); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + if (!newObj) { + return false; + } + struct eljscustom_event *event = (struct eljscustom_event *)mem_calloc(1, sizeof(*event)); + + if (!event) { + return false; + } + JS::SetReservedSlot(newObj, 0, JS::PrivateValue(event)); + + if (argc > 0) { + event->type_ = jsval_to_string(ctx, args[0]); + } + + if (argc > 1) { + JS::RootedValue v(ctx); + JS::RootedObject v_obj(ctx, &args[1].toObject()); + + if (JS_GetProperty(ctx, v_obj, "bubbles", &v)) { + event->bubbles = (unsigned int)v.toBoolean(); + } + if (JS_GetProperty(ctx, v_obj, "cancelable", &v)) { + event->cancelable = (unsigned int)v.toBoolean(); + } + if (JS_GetProperty(ctx, v_obj, "composed", &v)) { + event->composed = (unsigned int)v.toBoolean(); + } + if (JS_GetProperty(ctx, v_obj, "detail", &v)) { + JS::RootedObject vv(ctx, &v.toObject()); + event->detail = vv; + } + } + args.rval().setObject(*newObj); + + return true; +} + +JSPropertySpec customEvent_props[] = { + JS_PSG("bubbles", customEvent_get_property_bubbles, JSPROP_ENUMERATE), + JS_PSG("cancelable", customEvent_get_property_cancelable, JSPROP_ENUMERATE), + JS_PSG("composed", customEvent_get_property_composed, JSPROP_ENUMERATE), + JS_PSG("defaultPrevented", customEvent_get_property_defaultPrevented, JSPROP_ENUMERATE), + JS_PSG("detail", customEvent_get_property_detail, JSPROP_ENUMERATE), + JS_PSG("type", customEvent_get_property_type, JSPROP_ENUMERATE), + JS_PS_END +}; + +const spidermonkeyFunctionSpec customEvent_funcs[] = { + { "preventDefault", customEvent_preventDefault, 0 }, + { NULL } +}; + +static bool +customEvent_get_property_bubbles(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + args.rval().setBoolean(event->bubbles); + + return true; +} + +static bool +customEvent_get_property_cancelable(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + args.rval().setBoolean(event->cancelable); + + return true; +} + +static bool +customEvent_get_property_composed(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + args.rval().setBoolean(event->composed); + + return true; +} + +static bool +customEvent_get_property_defaultPrevented(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + args.rval().setBoolean(event->defaultPrevented); + + return true; +} + +static bool +customEvent_get_property_detail(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + if (!event->detail) { + args.rval().setNull(); + return true; + } + args.rval().setObject(*event->detail); + + return true; +} + +static bool +customEvent_preventDefault(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + if (event->cancelable) { + event->defaultPrevented = 1; + } + args.rval().setUndefined(); + + return true; +} + +static bool +customEvent_get_property_type(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct eljscustom_event *event = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!event) { + return false; + } + + if (!event->type_) { + args.rval().setString(JS_NewStringCopyZ(ctx, "")); + return true; + } + args.rval().setString(JS_NewStringCopyZ(ctx, event->type_)); + + return true; +} + +JSObject * +get_customEvent(JSContext *ctx) +{ + JSObject *k = JS_NewObject(ctx, &customEvent_class); + + if (!k) { + return NULL; + } + JS::RootedObject r_event(ctx, k); + JS_DefineProperties(ctx, r_event, (JSPropertySpec *)customEvent_props); + + struct eljscustom_event *event = (struct eljscustom_event *)mem_calloc(1, sizeof(*event)); + + if (!event) { + return NULL; + } + JS::SetReservedSlot(k, 0, JS::PrivateValue(event)); + + return k; +} diff --git a/src/ecmascript/spidermonkey/customevent.h b/src/ecmascript/spidermonkey/customevent.h new file mode 100644 index 00000000..d8c9a24a --- /dev/null +++ b/src/ecmascript/spidermonkey/customevent.h @@ -0,0 +1,11 @@ +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_CUSTOMEVENT_H +#define EL__ECMASCRIPT_SPIDERMONKEY_CUSTOMEVENT_H + +#include "ecmascript/spidermonkey/util.h" + +extern JSClass customEvent_class; +extern JSPropertySpec customEvent_props[]; +extern const spidermonkeyFunctionSpec customEvent_funcs[]; +bool customEvent_constructor(JSContext* ctx, unsigned argc, JS::Value* vp); + +#endif diff --git a/src/ecmascript/spidermonkey/meson.build b/src/ecmascript/spidermonkey/meson.build index 323e54a8..51cf694d 100644 --- a/src/ecmascript/spidermonkey/meson.build +++ b/src/ecmascript/spidermonkey/meson.build @@ -1,3 +1,3 @@ -srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'css.cpp', 'document.cpp', 'element.cpp', 'event.cpp', +srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'css.cpp', 'customevent.cpp', 'document.cpp', 'element.cpp', 'event.cpp', 'form.cpp', 'forms.cpp', 'heartbeat.cpp', 'history.cpp', 'implementation.cpp', 'input.cpp', 'keyboard.cpp', 'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'style.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp')