From 0bb9593041eb2ca8fdf7b73cf2dcea1e58096585 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Thu, 17 Nov 2022 18:41:40 +0100 Subject: [PATCH 1/4] [test] replaceWith testscase --- test/ecmascript/replaceWith.html | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 test/ecmascript/replaceWith.html diff --git a/test/ecmascript/replaceWith.html b/test/ecmascript/replaceWith.html new file mode 100644 index 00000000..3abe7213 --- /dev/null +++ b/test/ecmascript/replaceWith.html @@ -0,0 +1,10 @@ + From 72aa206ff74fa6e8746122c017280afc5a209942 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Thu, 17 Nov 2022 21:03:13 +0100 Subject: [PATCH 2/4] [spidermonkey] replaceWith It does not work without assignment in test case, but small progress. --- src/ecmascript/spidermonkey/element.cpp | 49 ++++++++++++++++++++++++- test/ecmascript/replaceWith.html | 9 ++--- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/ecmascript/spidermonkey/element.cpp b/src/ecmascript/spidermonkey/element.cpp index e8efb71f..53af4bbe 100644 --- a/src/ecmascript/spidermonkey/element.cpp +++ b/src/ecmascript/spidermonkey/element.cpp @@ -2343,6 +2343,7 @@ static bool element_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Valu static bool element_remove(JSContext *ctx, unsigned int argc, JS::Value *rval); static bool element_removeChild(JSContext *ctx, unsigned int argc, JS::Value *rval); static bool element_removeEventListener(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool element_replaceWith(JSContext *ctx, unsigned int argc, JS::Value *rval); static bool element_setAttribute(JSContext *ctx, unsigned int argc, JS::Value *rval); const spidermonkeyFunctionSpec element_funcs[] = { @@ -2365,6 +2366,7 @@ const spidermonkeyFunctionSpec element_funcs[] = { { "remove", element_remove, 0 }, { "removeChild", element_removeChild, 1 }, { "removeEventListener", element_removeEventListener, 3 }, + { "replaceWith", element_replaceWith, 1 }, { "setAttribute", element_setAttribute, 2 }, { NULL } }; @@ -2570,7 +2572,8 @@ element_appendChild(JSContext *ctx, unsigned int argc, JS::Value *rval) JS::RootedObject node(ctx, &args[0].toObject()); xmlpp::Node *el2 = JS::GetMaybePtrFromReservedSlot(node, 0); - el->import_node(el2); + + el2 = el->import_node(el2); interpreter->changed = true; JSObject *obj = getElement(ctx, el2); @@ -3418,6 +3421,50 @@ element_removeChild(JSContext *ctx, unsigned int argc, JS::Value *rval) return true; } +static bool +element_replaceWith(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp || argc < 1) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + JS::CallArgs args = CallArgsFromVp(argc, rval); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + if (!JS_InstanceOf(ctx, hobj, &element_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + xmlpp::Element *el = JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!el || !args[0].isObject()) { + args.rval().setUndefined(); + return true; + } + + JS::RootedObject replacement(ctx, &args[0].toObject()); + xmlpp::Node *rep = JS::GetMaybePtrFromReservedSlot(replacement, 0); + xmlAddPrevSibling(el->cobj(), rep->cobj()); + xmlpp::Node::remove_node(el); + interpreter->changed = true; + args.rval().setUndefined(); + + return true; +} + static bool element_setAttribute(JSContext *ctx, unsigned int argc, JS::Value *rval) { diff --git a/test/ecmascript/replaceWith.html b/test/ecmascript/replaceWith.html index 3abe7213..58f2421a 100644 --- a/test/ecmascript/replaceWith.html +++ b/test/ecmascript/replaceWith.html @@ -1,10 +1,9 @@ From e7b472fa42afdf71604183c821c9dfb22972ac18 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Fri, 18 Nov 2022 16:35:52 +0100 Subject: [PATCH 3/4] [quickjs] replaceWith --- src/ecmascript/quickjs/element.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ecmascript/quickjs/element.cpp b/src/ecmascript/quickjs/element.cpp index bd6c9093..44ff2abe 100644 --- a/src/ecmascript/quickjs/element.cpp +++ b/src/ecmascript/quickjs/element.cpp @@ -1181,7 +1181,7 @@ js_element_appendChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueC return JS_NULL; } xmlpp::Node *el2 = static_cast(js_getopaque(argv[0], js_element_class_id)); - el->import_node(el2); + el2 = el->import_node(el2); interpreter->changed = true; return getElement(ctx, el2); @@ -1767,6 +1767,33 @@ js_element_removeChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueC return JS_NULL; } +static JSValue +js_element_replaceWith(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc < 1) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); + xmlpp::Element *el = static_cast(js_getopaque(this_val, js_element_class_id)); + + if (!el || !JS_IsObject(argv[0])) { + return JS_UNDEFINED; + } + JSValue replacement = argv[0]; + xmlpp::Node *rep = static_cast(js_getopaque(replacement, js_element_class_id)); + xmlAddPrevSibling(el->cobj(), rep->cobj()); + xmlpp::Node::remove_node(el); + interpreter->changed = true; + + return JS_UNDEFINED; +} + static JSValue js_element_setAttribute(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -1867,6 +1894,7 @@ static const JSCFunctionListEntry js_element_proto_funcs[] = { JS_CFUNC_DEF("remove", 0, js_element_remove), JS_CFUNC_DEF("removeChild",1, js_element_removeChild), JS_CFUNC_DEF("removeEventListener", 3, js_element_removeEventListener), + JS_CFUNC_DEF("replaceWith",1, js_element_replaceWith), JS_CFUNC_DEF("setAttribute",2, js_element_setAttribute), JS_CFUNC_DEF("toString", 0, js_element_toString) From 2ad19e7e9584f1fcb39409ba006f8528d4dfbf5d Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Fri, 18 Nov 2022 16:43:16 +0100 Subject: [PATCH 4/4] [mujs] replaceWith --- src/ecmascript/mujs/element.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ecmascript/mujs/element.cpp b/src/ecmascript/mujs/element.cpp index 9a8e286e..4589e1a8 100644 --- a/src/ecmascript/mujs/element.cpp +++ b/src/ecmascript/mujs/element.cpp @@ -1,4 +1,4 @@ -/* The QuickJS html element objects implementation. */ +/* The MuJS html element objects implementation. */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -1153,7 +1153,7 @@ mjs_element_appendChild(js_State *J) return; } xmlpp::Node *el2 = static_cast(mjs_getprivate(J, 1)); - el->import_node(el2); + el2 = el->import_node(el2); interpreter->changed = true; mjs_push_element(J, el2); @@ -1632,6 +1632,27 @@ mjs_element_removeChild(js_State *J) js_pushnull(J); } +static void +mjs_element_replaceWith(js_State *J) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); + xmlpp::Element *el = static_cast(mjs_getprivate(J, 0)); + xmlpp::Node *rep = static_cast(mjs_getprivate(J, 1)); + + if (!el || !rep) { + js_pushundefined(J); + return; + } + xmlAddPrevSibling(el->cobj(), rep->cobj()); + xmlpp::Node::remove_node(el); + interpreter->changed = true; + + js_pushundefined(J); +} + static void mjs_element_setAttribute(js_State *J) { @@ -1742,6 +1763,7 @@ mjs_push_element(js_State *J, void *node) addmethod(J, "remove", mjs_element_remove, 0); addmethod(J, "removeChild", mjs_element_removeChild, 1); addmethod(J, "removeEventListener", mjs_element_removeEventListener, 3); + addmethod(J, "replaceWith", mjs_element_replaceWith, 1); addmethod(J, "setAttribute", mjs_element_setAttribute, 2); addmethod(J, "toString", mjs_element_toString, 0);