From 1bdaff045ed07d42beb42dd3a399e5cb9aab01b9 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Sun, 26 Mar 2023 18:58:01 +0200 Subject: [PATCH] [quickjs] libdom version of collection --- src/ecmascript/libdom/quickjs/Makefile | 2 +- src/ecmascript/libdom/quickjs/collection.c | 311 +++++++++++++++++++++ src/ecmascript/libdom/quickjs/mapa.cpp | 16 ++ src/ecmascript/libdom/quickjs/mapa.h | 2 + src/ecmascript/libdom/quickjs/meson.build | 2 +- src/ecmascript/quickjs/collection.cpp | 3 + src/ecmascript/quickjs/collection.h | 8 + src/ecmascript/quickjs/element.cpp | 4 +- src/ecmascript/quickjs/element.h | 10 +- 9 files changed, 353 insertions(+), 5 deletions(-) create mode 100644 src/ecmascript/libdom/quickjs/collection.c diff --git a/src/ecmascript/libdom/quickjs/Makefile b/src/ecmascript/libdom/quickjs/Makefile index 5bc4f7069..7997221de 100644 --- a/src/ecmascript/libdom/quickjs/Makefile +++ b/src/ecmascript/libdom/quickjs/Makefile @@ -1,6 +1,6 @@ top_builddir=../../../.. include $(top_builddir)/Makefile.config -OBJS = attr.o attributes.o mapa.obj +OBJS = attr.o attributes.o collection.o mapa.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/libdom/quickjs/collection.c b/src/ecmascript/libdom/quickjs/collection.c new file mode 100644 index 000000000..f10b97f41 --- /dev/null +++ b/src/ecmascript/libdom/quickjs/collection.c @@ -0,0 +1,311 @@ +/* The QuickJS html collection object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifdef CONFIG_LIBDOM +#include +#include +#endif + +#include "elinks.h" + +#include "document/libdom/corestrings.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/libdom/quickjs/mapa.h" +#include "ecmascript/quickjs.h" +#include "ecmascript/quickjs/collection.h" +#include "ecmascript/quickjs/element.h" + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +void *map_collections; +void *map_rev_collections; + +static void * +js_htmlCollection_GetOpaque(JSValueConst this_val) +{ + REF_JS(this_val); + + return attr_find_in_map_rev(map_rev_collections, this_val); +} + +static void +js_htmlCollection_SetOpaque(JSValueConst this_val, void *node) +{ + REF_JS(this_val); + + if (!node) { + attr_erase_from_map_rev(map_rev_collections, this_val); + } else { + attr_save_in_map_rev(map_rev_collections, this_val, node); + } +} + +static JSValue +js_htmlCollection_get_property_length(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + dom_html_collection *ns = (dom_html_collection *)(js_htmlCollection_GetOpaque(this_val)); + uint32_t size; + + if (!ns) { + return JS_NewInt32(ctx, 0); + } + if (dom_html_collection_get_length(ns, &size) != DOM_NO_ERR) { + return JS_NewInt32(ctx, 0); + } + + return JS_NewInt32(ctx, size); +} + +static JSValue +js_htmlCollection_item2(JSContext *ctx, JSValueConst this_val, int idx) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + dom_html_collection *ns = (dom_html_collection *)(js_htmlCollection_GetOpaque(this_val)); + dom_node *node; + dom_exception err; + JSValue ret; + + if (!ns) { + return JS_UNDEFINED; + } + err = dom_html_collection_item(ns, idx, &node); + + if (err != DOM_NO_ERR) { + return JS_UNDEFINED; + } + ret = getElement(ctx, node); + dom_node_unref(node); + + return ret; +} + +static JSValue +js_htmlCollection_item(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + if (argc != 1) { + return JS_UNDEFINED; + } + + int index; + JS_ToInt32(ctx, &index, argv[0]); + + return js_htmlCollection_item2(ctx, this_val, index); +} + +static JSValue +js_htmlCollection_namedItem2(JSContext *ctx, JSValueConst this_val, const char *str) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + dom_html_collection *ns = (dom_html_collection *)(js_htmlCollection_GetOpaque(this_val)); + dom_exception err; + dom_string *name; + uint32_t size, i; + + if (!ns) { + return JS_UNDEFINED; + } + + if (dom_html_collection_get_length(ns, &size) != DOM_NO_ERR) { + return JS_UNDEFINED; + } + + err = dom_string_create((const uint8_t*)str, strlen(str), &name); + + if (err != DOM_NO_ERR) { + return JS_UNDEFINED; + } + + for (i = 0; i < size; i++) { + dom_node *element = NULL; + dom_string *val = NULL; + + err = dom_html_collection_item(ns, i, &element); + + if (err != DOM_NO_ERR || !element) { + continue; + } + + err = dom_element_get_attribute(element, corestring_dom_id, &val); + + if (err == DOM_NO_ERR && val) { + if (dom_string_caseless_isequal(name, val)) { + JSValue ret = getElement(ctx, element); + dom_string_unref(val); + dom_string_unref(name); + dom_node_unref(element); + + return ret; + } + dom_string_unref(val); + } + + err = dom_element_get_attribute(element, corestring_dom_name, &val); + + if (err == DOM_NO_ERR && val) { + if (dom_string_caseless_isequal(name, val)) { + JSValue ret = getElement(ctx, element); + dom_string_unref(val); + dom_string_unref(name); + dom_node_unref(element); + + return ret; + } + dom_string_unref(val); + } + dom_node_unref(element); + } + dom_string_unref(name); + + return JS_UNDEFINED; +} + +static JSValue +js_htmlCollection_namedItem(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + if (argc != 1) { + return JS_UNDEFINED; + } + + const char *str; + size_t len; + + str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_EXCEPTION; + } + + JSValue ret = js_htmlCollection_namedItem2(ctx, this_val, str); + JS_FreeCString(ctx, str); + + RETURN_JS(ret); +} + +static void +js_htmlCollection_set_items(JSContext *ctx, JSValue this_val, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + int counter = 0; + uint32_t size, i; + dom_html_collection *ns = (dom_html_collection *)(js_htmlCollection_GetOpaque(this_val)); + dom_exception err; + + if (!ns) { + return; + } + + if (dom_html_collection_get_length(ns, &size) != DOM_NO_ERR) { + return; + } + + for (i = 0; i < size; i++) { + dom_node *element = NULL; + dom_string *name = NULL; + err = dom_html_collection_item(ns, i, &element); + + if (err != DOM_NO_ERR || !element) { + continue; + } + JSValue obj = getElement(ctx, element); + + REF_JS(obj); + JS_SetPropertyUint32(ctx, this_val, counter, JS_DupValue(ctx, obj)); + err = dom_element_get_attribute(element, corestring_dom_id, &name); + + if (err != DOM_NO_ERR || !name) { + err = dom_element_get_attribute(element, corestring_dom_name, &name); + } + + if (err == DOM_NO_ERR && name) { + if (!dom_string_caseless_lwc_isequal(name, corestring_lwc_item) && !dom_string_caseless_lwc_isequal(name, corestring_lwc_nameditem)) { + JS_DefinePropertyValueStr(ctx, this_val, dom_string_data(name), JS_DupValue(ctx, obj), 0); + } + } + JS_FreeValue(ctx, obj); + counter++; + if (name) { + dom_string_unref(name); + } + dom_node_unref(element); + } +} + +static JSValue +js_htmlCollection_toString(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + return JS_NewString(ctx, "[htmlCollection object]"); +} + +static const JSCFunctionListEntry js_htmlCollection_proto_funcs[] = { + JS_CGETSET_DEF("length", js_htmlCollection_get_property_length, NULL), + JS_CFUNC_DEF("item", 1, js_htmlCollection_item), + JS_CFUNC_DEF("namedItem", 1, js_htmlCollection_namedItem), + JS_CFUNC_DEF("toString", 0, js_htmlCollection_toString) +}; + +JSValue +getCollection(JSContext *ctx, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + static int initialized; + JSValue second; + + if (!initialized) { + map_collections = attr_create_new_collections_map(); + map_rev_collections = attr_create_new_collections_map_rev(); + initialized = 1; + } + second = attr_find_in_map(map_collections, node); + + if (!JS_IsNull(second)) { + JSValue r = JS_DupValue(ctx, second); + + RETURN_JS(r); + } + JSValue htmlCollection_obj = JS_NewArray(ctx); + JS_SetPropertyFunctionList(ctx, htmlCollection_obj, js_htmlCollection_proto_funcs, countof(js_htmlCollection_proto_funcs)); + js_htmlCollection_SetOpaque(htmlCollection_obj, node); + js_htmlCollection_set_items(ctx, htmlCollection_obj, node); + attr_save_in_map(map_collections, node, htmlCollection_obj); + JSValue rr = JS_DupValue(ctx, htmlCollection_obj); + + RETURN_JS(rr); +} diff --git a/src/ecmascript/libdom/quickjs/mapa.cpp b/src/ecmascript/libdom/quickjs/mapa.cpp index 446fb8bda..38d78c5e2 100644 --- a/src/ecmascript/libdom/quickjs/mapa.cpp +++ b/src/ecmascript/libdom/quickjs/mapa.cpp @@ -40,6 +40,22 @@ attr_create_new_attributes_map_rev(void) return (void *)mapa; } +void * +attr_create_new_collections_map(void) +{ + std::map *mapa = new std::map; + + return (void *)mapa; +} + +void * +attr_create_new_collections_map_rev(void) +{ + std::map *mapa = new std::map; + + return (void *)mapa; +} + void attr_clear_map(void *m) { diff --git a/src/ecmascript/libdom/quickjs/mapa.h b/src/ecmascript/libdom/quickjs/mapa.h index 69b5dde4c..d5598d3d3 100644 --- a/src/ecmascript/libdom/quickjs/mapa.h +++ b/src/ecmascript/libdom/quickjs/mapa.h @@ -11,6 +11,8 @@ void attr_save_in_map(void *m, void *node, JSValueConst value); void *attr_create_new_attrs_map(void); void *attr_create_new_attributes_map(void); void *attr_create_new_attributes_map_rev(void); +void *attr_create_new_collections_map(void); +void *attr_create_new_collections_map_rev(void); void attr_clear_map(void *m); JSValue attr_find_in_map(void *m, void *node); diff --git a/src/ecmascript/libdom/quickjs/meson.build b/src/ecmascript/libdom/quickjs/meson.build index 7c6d8a515..0916723c7 100644 --- a/src/ecmascript/libdom/quickjs/meson.build +++ b/src/ecmascript/libdom/quickjs/meson.build @@ -1 +1 @@ -srcs += files('attr.c', 'attributes.c', 'mapa.cpp') +srcs += files('attr.c', 'attributes.c', 'collection.c', 'mapa.cpp') diff --git a/src/ecmascript/quickjs/collection.cpp b/src/ecmascript/quickjs/collection.cpp index afd2a4a3e..84344c13b 100644 --- a/src/ecmascript/quickjs/collection.cpp +++ b/src/ecmascript/quickjs/collection.cpp @@ -56,6 +56,8 @@ #define countof(x) (sizeof(x) / sizeof((x)[0])) +#ifndef CONFIG_LIBDOM + static std::map map_collections; static std::map map_rev_collections; @@ -366,3 +368,4 @@ getCollection(JSContext *ctx, void *node) RETURN_JS(rr); } +#endif diff --git a/src/ecmascript/quickjs/collection.h b/src/ecmascript/quickjs/collection.h index 463a8c36a..453964299 100644 --- a/src/ecmascript/quickjs/collection.h +++ b/src/ecmascript/quickjs/collection.h @@ -3,6 +3,14 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + JSValue getCollection(JSContext *ctx, void *node); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/ecmascript/quickjs/element.cpp b/src/ecmascript/quickjs/element.cpp index dbcac59ac..6d0af8df3 100644 --- a/src/ecmascript/quickjs/element.cpp +++ b/src/ecmascript/quickjs/element.cpp @@ -820,7 +820,7 @@ js_element_get_property_innerHtml(JSContext *ctx, JSValueConst this_val) if (!init_string(&buf)) { return JS_EXCEPTION; } - walk_tree(&buf, el); + walk_tree(&buf, el, true, false); JSValue ret = JS_NewStringLen(ctx, buf.source, buf.length); done_string(&buf); @@ -844,7 +844,7 @@ js_element_get_property_outerHtml(JSContext *ctx, JSValueConst this_val) if (!init_string(&buf)) { return JS_EXCEPTION; } - walk_tree(&buf, el, false); + walk_tree(&buf, el, false, false); JSValue ret = JS_NewStringLen(ctx, buf.source, buf.length); done_string(&buf); diff --git a/src/ecmascript/quickjs/element.h b/src/ecmascript/quickjs/element.h index 4f17b2295..25cea86c9 100644 --- a/src/ecmascript/quickjs/element.h +++ b/src/ecmascript/quickjs/element.h @@ -3,12 +3,20 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct term_event; JSValue getElement(JSContext *ctx, void *node); int js_element_init(JSContext *ctx); -void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false); +void walk_tree(struct string *buf, void *nod, bool start, bool toSortAttrs); void check_element_event(void *elem, const char *event_name, struct term_event *ev); +#ifdef __cplusplus +} +#endif + #endif