From e15d58dfd149b3937c520375f8edd15bc6d1cf13 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Fri, 29 Oct 2021 22:06:39 +0200 Subject: [PATCH] [quickjs] element.c --- src/ecmascript/ecmascript.h | 9 + src/ecmascript/meson.build | 2 +- src/ecmascript/quickjs/collection.c | 8 +- src/ecmascript/quickjs/element.c | 1658 +++++++++++++++++++++++++++ src/ecmascript/quickjs/element.h | 10 + src/ecmascript/quickjs/meson.build | 2 +- 6 files changed, 1680 insertions(+), 9 deletions(-) create mode 100644 src/ecmascript/quickjs/element.c create mode 100644 src/ecmascript/quickjs/element.h diff --git a/src/ecmascript/ecmascript.h b/src/ecmascript/ecmascript.h index ec6abfe6..e6b43861 100644 --- a/src/ecmascript/ecmascript.h +++ b/src/ecmascript/ecmascript.h @@ -13,6 +13,10 @@ #include #endif +#ifdef CONFIG_QUICKJS +#include +#endif + #ifdef CONFIG_ECMASCRIPT #include "main/module.h" @@ -71,8 +75,13 @@ struct ecmascript_interpreter { unsigned int onload_snippets_cache_id; void *ac; void *ac2; +#ifdef CONFIG_QUICKJS + JSValue document_obj; + JSValue location_obj; +#else void *document_obj; void *location_obj; +#endif #ifdef CONFIG_ECMASCRIPT_SMJS JS::RootedValue fun; #endif diff --git a/src/ecmascript/meson.build b/src/ecmascript/meson.build index e4e76bbc..4501e0b2 100644 --- a/src/ecmascript/meson.build +++ b/src/ecmascript/meson.build @@ -18,5 +18,5 @@ endif if conf_data.get('CONFIG_QUICKJS') subdir('quickjs') - srcs += files('ecmascript.c', 'localstorage-db.c', 'quickjs.c', 'empty.cpp') + srcs += files('css2xpath.c', 'ecmascript.c', 'localstorage-db.c', 'quickjs.c', 'empty.cpp') endif diff --git a/src/ecmascript/quickjs/collection.c b/src/ecmascript/quickjs/collection.c index 91c2817c..03d41cc1 100644 --- a/src/ecmascript/quickjs/collection.c +++ b/src/ecmascript/quickjs/collection.c @@ -21,6 +21,7 @@ #include "document/view.h" #include "ecmascript/ecmascript.h" #include "ecmascript/quickjs/collection.h" +#include "ecmascript/quickjs/element.h" #include "intl/libintl.h" #include "main/select.h" #include "osdep/newwin.h" @@ -55,12 +56,6 @@ static JSClassID js_htmlCollection_class_id; -// Placeholder -JSValue getElement(JSContext *ctx, void *node) -{ - return JS_NULL; -} - static JSValue js_htmlCollection_get_property_length(JSContext *ctx, JSValueConst this_val) { @@ -271,7 +266,6 @@ js_htmlCollection_init(JSContext *ctx, JSValue global_obj) return 0; } - JSValue getCollection(JSContext *ctx, void *node) { diff --git a/src/ecmascript/quickjs/element.c b/src/ecmascript/quickjs/element.c new file mode 100644 index 00000000..4486247f --- /dev/null +++ b/src/ecmascript/quickjs/element.c @@ -0,0 +1,1658 @@ +/* The QuickJS html element objects implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#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/css2xpath.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/quickjs/attr.h" +#include "ecmascript/quickjs/attributes.h" +#include "ecmascript/quickjs/collection.h" +#include "ecmascript/quickjs/element.h" +#include "ecmascript/quickjs/nodelist.h" +#include "ecmascript/quickjs/window.h" +#include "intl/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.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 +#include +#include + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +static JSClassID js_element_class_id; + +static JSValue +js_element_get_property_attributes(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + xmlpp::Element::AttributeList *attrs = new xmlpp::Element::AttributeList; + + *attrs = el->get_attributes(); + + return getAttributes(ctx, attrs); +} + +static JSValue +js_element_get_property_children(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + auto nodes = el->get_children(); + if (nodes.empty()) { + return JS_NULL; + } + + xmlpp::Node::NodeSet *list = new xmlpp::Node::NodeSet; + + auto it = nodes.begin(); + auto end = nodes.end(); + + for (; it != end; ++it) { + const auto element = dynamic_cast(*it); + + if (element) { + list->push_back(reinterpret_cast(element)); + } + } + + if (list->empty()) { + delete list; + return JS_NULL; + } + + return getCollection(ctx, list); +} + +static JSValue +js_element_get_property_childElementCount(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + int res = el->get_children().size(); + + return JS_NewUint32(ctx, res); +} + +static JSValue +js_element_get_property_childNodes(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + xmlpp::Node::NodeList *nodes = new xmlpp::Node::NodeList; + + *nodes = el->get_children(); + if (nodes->empty()) { + delete nodes; + return JS_NULL; + } + + return getNodeList(ctx, nodes); +} + +static JSValue +js_element_get_property_className(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::ustring v = el->get_attribute_value("class"); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static JSValue +js_element_get_property_dir(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + xmlpp::ustring v = el->get_attribute_value("dir"); + + if (v != "auto" && v != "ltr" && v != "rtl") { + v = ""; + } + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static JSValue +js_element_get_property_firstChild(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + auto node = el->get_first_child(); + + if (!node) { + return JS_NULL; + } + + return getElement(ctx, node); +} + +static JSValue +js_element_get_property_firstElementChild(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + auto nodes = el->get_children(); + if (nodes.empty()) { + return JS_NULL; + } + + auto it = nodes.begin(); + auto end = nodes.end(); + + for (; it != end; ++it) { + const auto element = dynamic_cast(*it); + + if (element) { + return getElement(ctx, element); + } + } + return JS_NULL; +} + +static JSValue +js_element_get_property_id(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::ustring v = el->get_attribute_value("id"); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static JSValue +js_element_get_property_lang(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::ustring v = el->get_attribute_value("lang"); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static JSValue +js_element_get_property_lastChild(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + auto nodes = el->get_children(); + + if (nodes.empty()) { + return JS_NULL; + } + + return getElement(ctx, *(nodes.rbegin())); +} + +static JSValue +js_element_get_property_lastElementChild(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + auto nodes = el->get_children(); + + if (nodes.empty()) { + return JS_NULL; + } + + auto it = nodes.rbegin(); + auto end = nodes.rend(); + + for (; it != end; ++it) { + const auto element = dynamic_cast(*it); + + if (element) { + return getElement(ctx, element); + } + } + + return JS_NULL; +} + +static JSValue +js_element_get_property_nextElementSibling(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::Node *node = el; + + while (true) { + node = node->get_next_sibling(); + + if (!node) { + return JS_NULL; + } + xmlpp::Element *next = dynamic_cast(node); + + if (next) { + return getElement(ctx, next); + } + } + + return JS_NULL; +} + +static JSValue +js_element_get_property_nodeName(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Node *node = JS_GetOpaque(this_val, js_element_class_id); + + xmlpp::ustring v; + + if (!node) { + return JS_NewStringLen(ctx, "", 0); + } + auto el = dynamic_cast(node); + + if (el) { + v = el->get_name(); + std::transform(v.begin(), v.end(), v.begin(), ::toupper); + } else { + auto el = dynamic_cast(node); + if (el) { + v = el->get_name(); + } else if (dynamic_cast(node)) { + v = "#text"; + } else if (dynamic_cast(node)) { + v = "#comment"; + } + } + + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static JSValue +js_element_get_property_nodeType(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Node *node = JS_GetOpaque(this_val, js_element_class_id); + + if (!node) { + return JS_NULL; + } + + int ret = 8; + + if (dynamic_cast(node)) { + ret = 1; + } else if (dynamic_cast(node)) { + ret = 2; + } else if (dynamic_cast(node)) { + ret = 3; + } else if (dynamic_cast(node)) { + ret = 8; + } + return JS_NewUint32(ctx, ret); +} + +static JSValue +js_element_get_property_nodeValue(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Node *node = JS_GetOpaque(this_val, js_element_class_id); + + if (!node) { + return JS_NULL; + } + + if (dynamic_cast(node)) { + return JS_NULL; + } + + auto el = dynamic_cast(node); + + if (el) { + xmlpp::ustring v = el->get_value(); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); + } + + auto el2 = dynamic_cast(node); + + if (el2) { + xmlpp::ustring v = el2->get_content(); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); + } + + auto el3 = dynamic_cast(node); + + if (el3) { + xmlpp::ustring v = el3->get_content(); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); + } + + return JS_UNDEFINED; +} + +static JSValue +js_element_get_property_nextSibling(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + auto node = el->get_next_sibling(); + + if (!node) { + return JS_NULL; + } + + return getElement(ctx, node); +} + +static JSValue +js_element_get_property_ownerDocument(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + + return JS_DupValue(ctx, interpreter->document_obj); +} + +static JSValue +js_element_get_property_parentElement(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + + auto node = dynamic_cast(el->get_parent()); + + if (!node) { + return JS_NULL; + } + + return getElement(ctx, node); +} + +static JSValue +js_element_get_property_parentNode(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + auto node = el->get_parent(); + + if (!node) { + return JS_NULL; + } + + return getElement(ctx, node); +} + +static JSValue +js_element_get_property_previousElementSibling(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::Node *node = el; + + while (true) { + node = node->get_previous_sibling(); + + if (!node) { + return JS_NULL; + } + xmlpp::Element *next = dynamic_cast(node); + + if (next) { + return getElement(ctx, next); + } + } + + return JS_NULL; +} + +static JSValue +js_element_get_property_previousSibling(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + auto node = el->get_previous_sibling(); + + if (!node) { + return JS_NULL; + } + + return getElement(ctx, node); +} + +static JSValue +js_element_get_property_tagName(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::ustring v = el->get_name(); + std::transform(v.begin(), v.end(), v.begin(), ::toupper); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static JSValue +js_element_get_property_title(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + xmlpp::ustring v = el->get_attribute_value("title"); + + return JS_NewStringLen(ctx, v.c_str(), v.length()); +} + +static int was_el = 0; + +static void +dump_element(struct string *buf, xmlpp::Element *element, bool toSort = false) +{ + add_char_to_string(buf, '<'); + add_to_string(buf, element->get_name().c_str()); + auto attrs = element->get_attributes(); + if (toSort) { + attrs.sort([](const xmlpp::Attribute *a1, const xmlpp::Attribute *a2) + { + if (a1->get_name() == a2->get_name()) { + return a1->get_value() < a2->get_value(); + } + return a1->get_name() < a2->get_name(); + }); + } + auto it = attrs.begin(); + auto end = attrs.end(); + for (;it != end; ++it) { + add_char_to_string(buf, ' '); + add_to_string(buf, (*it)->get_name().c_str()); + add_char_to_string(buf, '='); + add_char_to_string(buf, '"'); + add_to_string(buf, (*it)->get_value().c_str()); + add_char_to_string(buf, '"'); + } + add_char_to_string(buf, '>'); +} + +void +walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false) +{ + xmlpp::Node *node = nod; + + if (!start) { + const auto textNode = dynamic_cast(node); + + if (textNode) { + add_to_string(buf, textNode->get_content().c_str()); + } else { + const auto element = dynamic_cast(node); + + if (element) { + dump_element(buf, element, toSortAttrs); + } + } + } + + auto childs = node->get_children(); + auto it = childs.begin(); + auto end = childs.end(); + + for (; it != end; ++it) { + walk_tree(buf, *it, false, toSortAttrs); + } + + if (!start) { + const auto element = dynamic_cast(node); + if (element) { + add_to_string(buf, "get_name().c_str()); + add_char_to_string(buf, '>'); + } + } +} + +static void +walk_tree_content(struct string *buf, xmlpp::Node *node) +{ + const auto nodeText = dynamic_cast(node); + + if (nodeText) { + add_to_string(buf, nodeText->get_content().c_str()); + } + + auto childs = node->get_children(); + auto it = childs.begin(); + auto end = childs.end(); + + for (; it != end; ++it) { + walk_tree_content(buf, *it); + } +} + +static JSValue +js_element_get_property_innerHtml(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + struct string buf; + init_string(&buf); + walk_tree(&buf, el); + JSValue ret = JS_NewStringLen(ctx, buf.source, buf.length); + done_string(&buf); + + return ret; +} + +static JSValue +js_element_get_property_outerHtml(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + struct string buf; + init_string(&buf); + walk_tree(&buf, el, false); + JSValue ret = JS_NewStringLen(ctx, buf.source, buf.length); + done_string(&buf); + + return ret; +} + +static JSValue +js_element_get_property_textContent(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + struct string buf; + init_string(&buf); + walk_tree_content(&buf, el); + JSValue ret = JS_NewStringLen(ctx, buf.source, buf.length); + done_string(&buf); + + return ret; +} + +static JSValue +js_element_set_property_className(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + assert(interpreter); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring value = str; + el->set_attribute("class", value); + interpreter->changed = true; + JS_FreeCString(ctx, str); + + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_dir(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + assert(interpreter); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring value = str; + + if (value == "ltr" || value == "rtl" || value == "auto") { + el->set_attribute("dir", value); + interpreter->changed = true; + } + JS_FreeCString(ctx, str); + + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_id(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + assert(interpreter); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring value = str; + el->set_attribute("id", value); + interpreter->changed = true; + JS_FreeCString(ctx, str); + + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_innerHtml(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + auto children = el->get_children(); + auto it = children.begin(); + auto end = children.end(); + + for (;it != end; ++it) { + xmlpp::Node::remove_node(*it); + } + xmlpp::ustring text = ""; + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + text += str; + text += ""; + JS_FreeCString(ctx, str); + + xmlDoc* doc = htmlReadDoc((xmlChar*)text.c_str(), NULL, NULL, HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); + // Encapsulate raw libxml document in a libxml++ wrapper + xmlpp::Document doc1(doc); + + auto root = doc1.get_root_node(); + auto root1 = root->find("//root")[0]; + auto children2 = root1->get_children(); + auto it2 = children2.begin(); + auto end2 = children2.end(); + for (; it2 != end2; ++it2) { + el->import_node(*it2); + } + interpreter->changed = true; + + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_innerText(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + auto children = el->get_children(); + auto it = children.begin(); + auto end = children.end(); + + for (;it != end; ++it) { + xmlpp::Node::remove_node(*it); + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + el->add_child_text(str); + interpreter->changed = true; + JS_FreeCString(ctx, str); + + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_lang(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring value = str; + el->set_attribute("lang", value); + interpreter->changed = true; + JS_FreeCString(ctx, str); + + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_outerHtml(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); +// TODO + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_textContent(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); +// TODO + return JS_UNDEFINED; +} + +static JSValue +js_element_set_property_title(JSContext *ctx, JSValueConst this_val, JSValue val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring value = str; + el->set_attribute("title", value); + interpreter->changed = true; + JS_FreeCString(ctx, str); + + return JS_UNDEFINED; +} + +// Common part of all add_child_element*() methods. +static xmlpp::Element* +el_add_child_element_common(xmlNode* child, xmlNode* node) +{ + if (!node) { + xmlFreeNode(child); + throw xmlpp::internal_error("Could not add child element node"); + } + xmlpp::Node::create_wrapper(node); + + return static_cast(node->_private); +} + +static void +check_contains(xmlpp::Node *node, xmlpp::Node *searched, bool *result_set, bool *result) +{ + if (*result_set) { + return; + } + + auto childs = node->get_children(); + auto it = childs.begin(); + auto end = childs.end(); + + for (; it != end; ++it) { + if (*it == searched) { + *result_set = true; + *result = true; + return; + } + check_contains(*it, searched, result_set, result); + } +} + +static JSValue +js_element_appendChild(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (argc != 1) { + return JS_NULL; + } + + if (!el) { + return JS_NULL; + } + xmlpp::Node *el2 = JS_GetOpaque(argv[0], js_element_class_id); + el->import_node(el2); + interpreter->changed = true; + + return getElement(ctx, el2); +} + +static JSValue +js_element_cloneNode(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_NULL; + } + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_NULL; + } + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + xmlpp::Document *doc2 = document->dom; + xmlDoc *docu = doc2->cobj(); + xmlNode *xmlnode = xmlNewDocFragment(docu); + + if (!xmlnode) { + return JS_NULL; + } + xmlpp::Node *node = new xmlpp::Node(xmlnode); + + try { + xmlpp::Node *node2 = node->import_node(el, JS_ToBool(ctx, argv[0])); + + if (!node2) { + return JS_NULL; + } + + return getElement(ctx, node2); + } catch (xmlpp::exception e) { + return JS_NULL; + } +} + +static JSValue +js_element_contains(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; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + xmlpp::Element *el2 = JS_GetOpaque(argv[0], js_element_class_id); + + if (!el2) { + return JS_FALSE; + } + + bool result_set = false; + bool result = false; + + check_contains(el, el2, &result_set, &result); + + return JS_NewBool(ctx, result); +} + +static JSValue +js_element_getAttribute(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; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_NULL; + } + xmlpp::ustring v = str; + xmlpp::Attribute *attr = el->get_attribute(v); + JS_FreeCString(ctx, str); + + if (!attr) { + return JS_NULL; + } + xmlpp::ustring val = attr->get_value(); + + return JS_NewStringLen(ctx, val.c_str(), val.length()); +} + +static JSValue +js_element_getAttributeNode(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; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_NULL; + } + xmlpp::ustring v = str; + xmlpp::Attribute *attr = el->get_attribute(v); + JS_FreeCString(ctx, str); + + return getAttr(ctx, attr); +} + +static JSValue +js_element_hasAttribute(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; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_NULL; + } + xmlpp::ustring v = str; + xmlpp::Attribute *attr = el->get_attribute(v); + JS_FreeCString(ctx, str); + + return JS_NewBool(ctx, (bool)attr); +} + +static JSValue +js_element_hasAttributes(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 0) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + auto attrs = el->get_attributes(); + + return JS_NewBool(ctx, (bool)attrs.size()); +} + +static JSValue +js_element_hasChildNodes(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 0) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + auto children = el->get_children(); + + return JS_NewBool(ctx, (bool)children.size()); +} + +static JSValue +js_element_insertBefore(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 2) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + + JSValue next_sibling1 = argv[1]; + JSValue child1 = argv[0]; + + xmlpp::Node *next_sibling = JS_GetOpaque(next_sibling1, js_element_class_id); + + if (!next_sibling) { + return JS_NULL; + } + + xmlpp::Node *child = JS_GetOpaque(child1, js_element_class_id); + auto node = xmlAddPrevSibling(next_sibling->cobj(), child->cobj()); + auto res = el_add_child_element_common(child->cobj(), node); + + interpreter->changed = true; + + return getElement(ctx, res); +} + +static JSValue +js_element_isEqualNode(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; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + + JSValue node = argv[0]; + xmlpp::Element *el2 = JS_GetOpaque(node, js_element_class_id); + + struct string first; + struct string second; + + init_string(&first); + init_string(&second); + + walk_tree(&first, el, false, true); + walk_tree(&second, el2, false, true); + + bool ret = !strcmp(first.source, second.source); + + done_string(&first); + done_string(&second); + + return JS_NewBool(ctx, ret); +} + +static JSValue +js_element_isSameNode(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; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + JSValue node = argv[0]; + xmlpp::Element *el2 = JS_GetOpaque(node, js_element_class_id); + + return JS_NewBool(ctx, (el == el2)); +} + +static JSValue +js_element_querySelector(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 1) { + return JS_UNDEFINED; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + const char *str; + size_t len; + str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring css = str; + xmlpp::ustring xpath = css2xpath(css); + JS_FreeCString(ctx, str); + xmlpp::Node::NodeSet elements; + + try { + elements = el->find(xpath); + } catch (xmlpp::exception) { + return JS_NULL; + } + + if (elements.size() == 0) { + return JS_NULL; + } + auto node = elements[0]; + + return getElement(ctx, node); +} + +static JSValue +js_element_querySelectorAll(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 1) { + return JS_FALSE; + } + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_FALSE; + } + const char *str; + size_t len; + str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_EXCEPTION; + } + xmlpp::ustring css = str; + xmlpp::ustring xpath = css2xpath(css); + JS_FreeCString(ctx, str); + xmlpp::Node::NodeSet *elements = new xmlpp::Node::NodeSet; + + try { + *elements = el->find(xpath); + } catch (xmlpp::exception) { + } + + return getCollection(ctx, elements); +} + +static JSValue +js_element_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 0) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + + xmlpp::Node::remove_node(el); + interpreter->changed = true; + + return JS_UNDEFINED; +} + +static JSValue +js_element_removeChild(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 = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el || !JS_IsObject(argv[0])) { + return JS_NULL; + } + JSValue node = argv[0]; + auto children = el->get_children(); + auto it = children.begin(); + auto end = children.end(); + xmlpp::Element *el2 = JS_GetOpaque(node, js_element_class_id); + + for (;it != end; ++it) { + if (*it == el2) { + xmlpp::Node::remove_node(el2); + interpreter->changed = true; + + return getElement(ctx, el2); + } + } + + return JS_NULL; +} + +static JSValue +js_element_setAttribute(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + if (argc != 2) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + struct ecmascript_interpreter *interpreter = JS_GetContextOpaque(ctx); + xmlpp::Element *el = JS_GetOpaque(this_val, js_element_class_id); + + if (!el) { + return JS_UNDEFINED; + } + const char *attr_c; + const char *value_c; + size_t len_attr, len_value; + attr_c = JS_ToCStringLen(ctx, &len_attr, argv[0]); + + if (!attr_c) { + return JS_EXCEPTION; + } + value_c = JS_ToCStringLen(ctx, &len_value, argv[1]); + + if (!value_c) { + JS_FreeCString(ctx, attr_c); + return JS_EXCEPTION; + } + + xmlpp::ustring attr = attr_c; + xmlpp::ustring value = value_c; + el->set_attribute(attr, value); + interpreter->changed = true; + JS_FreeCString(ctx, attr_c); + JS_FreeCString(ctx, value_c); + + return JS_UNDEFINED; +} + + +static const JSCFunctionListEntry js_element_proto_funcs[] = { + JS_CGETSET_DEF("attributes", js_element_get_property_attributes, nullptr), + JS_CGETSET_DEF("children", js_element_get_property_children, nullptr), + JS_CGETSET_DEF("childElementCount", js_element_get_property_childElementCount, nullptr), + JS_CGETSET_DEF("childNodes", js_element_get_property_childNodes, nullptr), + JS_CGETSET_DEF("className", js_element_get_property_className, js_element_set_property_className), + JS_CGETSET_DEF("dir", js_element_get_property_dir, js_element_set_property_dir), + JS_CGETSET_DEF("firstChild", js_element_get_property_firstChild, nullptr), + JS_CGETSET_DEF("firstElementChild", js_element_get_property_firstElementChild, nullptr), + JS_CGETSET_DEF("id", js_element_get_property_id, js_element_set_property_id), + JS_CGETSET_DEF("innerHTML", js_element_get_property_innerHtml, js_element_set_property_innerHtml), + JS_CGETSET_DEF("innerText", js_element_get_property_innerHtml, js_element_set_property_innerText), + JS_CGETSET_DEF("lang", js_element_get_property_lang, js_element_set_property_lang), + JS_CGETSET_DEF("lastChild", js_element_get_property_lastChild, nullptr), + JS_CGETSET_DEF("lastElementChild", js_element_get_property_lastElementChild, nullptr), + JS_CGETSET_DEF("nextElementSibling", js_element_get_property_nextElementSibling, nullptr), + JS_CGETSET_DEF("nextSibling", js_element_get_property_nextSibling, nullptr), + JS_CGETSET_DEF("nodeName", js_element_get_property_nodeName, nullptr), + JS_CGETSET_DEF("nodeType", js_element_get_property_nodeType, nullptr), + JS_CGETSET_DEF("nodeValue", js_element_get_property_nodeValue, nullptr), + JS_CGETSET_DEF("outerHTML", js_element_get_property_outerHtml, js_element_set_property_outerHtml), + JS_CGETSET_DEF("ownerDocument", js_element_get_property_ownerDocument, nullptr), + JS_CGETSET_DEF("parentElement", js_element_get_property_parentElement, nullptr), + JS_CGETSET_DEF("parentNode", js_element_get_property_parentNode, nullptr), + JS_CGETSET_DEF("previousElementSibling", js_element_get_property_previousElementSibling, nullptr), + JS_CGETSET_DEF("previousSibling", js_element_get_property_previousSibling, nullptr), + JS_CGETSET_DEF("tagName", js_element_get_property_tagName, nullptr), + JS_CGETSET_DEF("textContent", js_element_get_property_textContent, js_element_set_property_textContent), + JS_CGETSET_DEF("title", js_element_get_property_title, js_element_set_property_title), + JS_CFUNC_DEF("appendChild", 1, js_element_appendChild), + JS_CFUNC_DEF("cloneNode", 1, js_element_cloneNode), + JS_CFUNC_DEF("contains", 1, js_element_contains), + JS_CFUNC_DEF("getAttribute", 1, js_element_getAttribute), + JS_CFUNC_DEF("getAttributeNode",1, js_element_getAttributeNode), + JS_CFUNC_DEF("hasAttribute", 1, js_element_hasAttribute), + JS_CFUNC_DEF("hasAttributes", 0, js_element_hasAttributes), + JS_CFUNC_DEF("hasChildNodes", 0, js_element_hasChildNodes), + JS_CFUNC_DEF("insertBefore", 2, js_element_insertBefore), + JS_CFUNC_DEF("isEqualNode", 1, js_element_isEqualNode), + JS_CFUNC_DEF("isSameNode", 1, js_element_isSameNode), + JS_CFUNC_DEF("querySelector",1, js_element_querySelector), + JS_CFUNC_DEF("querySelectorAll",1, js_element_querySelectorAll), + JS_CFUNC_DEF("remove", 0, js_element_remove), + JS_CFUNC_DEF("removeChild",1, js_element_removeChild), + JS_CFUNC_DEF("setAttribute",2, js_element_setAttribute), +}; + +static JSClassDef js_element_class = { + "element", +}; + +static JSValue +js_element_ctor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) +{ + JSValue obj = JS_UNDEFINED; + JSValue proto; + /* using new_target to get the prototype is necessary when the + class is extended. */ + proto = JS_GetPropertyStr(ctx, new_target, "prototype"); + + if (JS_IsException(proto)) { + goto fail; + } + obj = JS_NewObjectProtoClass(ctx, proto, js_element_class_id); + JS_FreeValue(ctx, proto); + + if (JS_IsException(obj)) { + goto fail; + } + return obj; + +fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +int +js_element_init(JSContext *ctx, JSValue global_obj) +{ + JSValue element_proto, element_class; + + /* create the element class */ + JS_NewClassID(&js_element_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_element_class_id, &js_element_class); + + element_proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, element_proto, js_element_proto_funcs, countof(js_element_proto_funcs)); + + element_class = JS_NewCFunction2(ctx, js_element_ctor, "element", 0, JS_CFUNC_constructor, 0); + /* set proto.constructor and ctor.prototype */ + JS_SetConstructor(ctx, element_class, element_proto); + JS_SetClassProto(ctx, js_element_class_id, element_proto); + + JS_SetPropertyStr(ctx, global_obj, "element", element_proto); + return 0; +} + +JSValue +getElement(JSContext *ctx, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JSValue element_obj = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, element_obj, js_element_proto_funcs, countof(js_element_proto_funcs)); +// element_class = JS_NewCFunction2(ctx, js_element_ctor, "element", 0, JS_CFUNC_constructor, 0); +// JS_SetConstructor(ctx, element_class, element_obj); + JS_SetClassProto(ctx, js_element_class_id, element_obj); + JS_SetOpaque(element_obj, node); + + return element_obj; +} diff --git a/src/ecmascript/quickjs/element.h b/src/ecmascript/quickjs/element.h new file mode 100644 index 00000000..e9f4d056 --- /dev/null +++ b/src/ecmascript/quickjs/element.h @@ -0,0 +1,10 @@ +#ifndef EL__ECMASCRIPT_QUICKJS_ELEMENT_H +#define EL__ECMASCRIPT_QUICKJS_ELEMENT_H + +#include + +JSValue getElement(JSContext *ctx, void *node); + +void walk_tree(struct string *buf, void *nod, bool start = true, bool toSortAttrs = false); + +#endif diff --git a/src/ecmascript/quickjs/meson.build b/src/ecmascript/quickjs/meson.build index b9784ee6..5e1374fc 100644 --- a/src/ecmascript/quickjs/meson.build +++ b/src/ecmascript/quickjs/meson.build @@ -1 +1 @@ -srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'history.c', 'localstorage.c', 'location.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c') +srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'element.c', 'history.c', 'localstorage.c', 'location.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c')