From 16cbdc25019c162fc171fd61c9ae49f37c647551 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Wed, 8 May 2024 18:57:11 +0200 Subject: [PATCH] [mujs] element.outerHTML setter --- src/ecmascript/mujs/element.c | 146 +++++++++++++++++- test/ecmascript/assert/element.outerHTML.html | 4 +- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/src/ecmascript/mujs/element.c b/src/ecmascript/mujs/element.c index 764b85ff..904b02ff 100644 --- a/src/ecmascript/mujs/element.c +++ b/src/ecmascript/mujs/element.c @@ -1854,6 +1854,150 @@ mjs_element_set_property_lang(js_State *J) js_pushundefined(J); } +static void +mjs_element_set_property_outerHtml(js_State *J) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)js_getcontext(J); + struct view_state *vs = interpreter->vs; + if (!vs) { + js_pushundefined(J); + return; + } + dom_node *el = (dom_node *)(mjs_getprivate(J, 0)); + + if (!el) { + js_pushundefined(J); + return; + } + dom_node *parent = NULL; + dom_exception exc = dom_node_get_parent_node(el, &parent); + + if (exc != DOM_NO_ERR) { + js_pushundefined(J); + return; + } + size_t size; + const char *s = js_tostring(J, 1); + + if (!s) { + js_error(J, "out of memory"); + return; + } + size = strlen(s); + struct dom_node *cref = NULL; + + dom_hubbub_parser_params parse_params; + dom_hubbub_error error; + dom_hubbub_parser *parser = NULL; + struct dom_document *doc = NULL; + struct dom_document_fragment *fragment = NULL; + struct dom_node *child = NULL, *html = NULL, *body = NULL; + struct dom_nodelist *bodies = NULL; + + exc = dom_node_get_owner_document(el, &doc); + if (exc != DOM_NO_ERR) goto out; + + parse_params.enc = "UTF-8"; + parse_params.fix_enc = true; + parse_params.enable_script = false; + parse_params.msg = NULL; + parse_params.script = NULL; + parse_params.ctx = NULL; + parse_params.daf = NULL; + + error = dom_hubbub_fragment_parser_create(&parse_params, + doc, + &parser, + &fragment); + if (error != DOM_HUBBUB_OK) { + fprintf(stderr, "Unable to create fragment parser!"); + goto out; + } + + error = dom_hubbub_parser_parse_chunk(parser, (const uint8_t*)s, size); + if (error != DOM_HUBBUB_OK) { + fprintf(stderr, "Unable to parse HTML chunk"); + goto out; + } + error = dom_hubbub_parser_completed(parser); + if (error != DOM_HUBBUB_OK) { + fprintf(stderr, "Unable to complete parser"); + goto out; + } + + /* The first child in the fragment will be an HTML element + * because that's how hubbub works, walk through that to the body + * element hubbub will have created, we want to migrate that element's + * children into ourself. + */ + exc = dom_node_get_first_child(fragment, &html); + if (exc != DOM_NO_ERR) goto out; + + /* We can then ask that HTML element to give us its body */ + exc = dom_element_get_elements_by_tag_name(html, corestring_dom_BODY, &bodies); + if (exc != DOM_NO_ERR) goto out; + + /* And now we can get the body which will be the zeroth body */ + exc = dom_nodelist_item(bodies, 0, &body); + if (exc != DOM_NO_ERR) goto out; + + /* Migrate the children */ + exc = dom_node_get_first_child(body, &child); + if (exc != DOM_NO_ERR) goto out; + while (child != NULL) { + exc = dom_node_remove_child(body, child, &cref); + if (exc != DOM_NO_ERR) goto out; + dom_node_unref(cref); + + dom_node *spare = NULL; + exc = dom_node_insert_before(parent, child, el, &spare); + + if (exc != DOM_NO_ERR) goto out; + dom_node_unref(spare); + dom_node_unref(cref); + dom_node_unref(child); + child = NULL; + exc = dom_node_get_first_child(body, &child); + if (exc != DOM_NO_ERR) goto out; + } + exc = dom_node_remove_child(parent, el, &cref); + + if (exc != DOM_NO_ERR) goto out; +out: + if (parser != NULL) { + dom_hubbub_parser_destroy(parser); + } + if (doc != NULL) { + dom_node_unref(doc); + } + if (fragment != NULL) { + dom_node_unref(fragment); + } + if (child != NULL) { + dom_node_unref(child); + } + if (html != NULL) { + dom_node_unref(html); + } + if (bodies != NULL) { + dom_nodelist_unref(bodies); + } + if (body != NULL) { + dom_node_unref(body); + } + if (cref != NULL) { + dom_node_unref(cref); + } + dom_node_unref(parent); + interpreter->changed = 1; + + js_pushundefined(J); +} + + static void mjs_element_set_property_title(js_State *J) { @@ -3023,7 +3167,7 @@ mjs_push_element(js_State *J, void *node) addproperty(J, "offsetParent", mjs_element_get_property_offsetParent, NULL); // addproperty(J, "offsetTop", mjs_element_get_property_offsetTop, NULL); // addproperty(J, "offsetWidth", mjs_element_get_property_offsetWidth, NULL); - addproperty(J, "outerHTML", mjs_element_get_property_outerHtml, NULL); + addproperty(J, "outerHTML", mjs_element_get_property_outerHtml, mjs_element_set_property_outerHtml); addproperty(J, "ownerDocument", mjs_element_get_property_ownerDocument, NULL); addproperty(J, "parentElement", mjs_element_get_property_parentElement, NULL); addproperty(J, "parentNode", mjs_element_get_property_parentNode, NULL); diff --git a/test/ecmascript/assert/element.outerHTML.html b/test/ecmascript/assert/element.outerHTML.html index 61bf594e..339e69d6 100644 --- a/test/ecmascript/assert/element.outerHTML.html +++ b/test/ecmascript/assert/element.outerHTML.html @@ -15,8 +15,8 @@ function aa() function bb() { - const container = document.getElementById("container"); - const d = document.getElementById("d"); + var container = document.getElementById("container"); + var d = document.getElementById("d"); console.assert(container.firstElementChild.nodeName === 'DIV', 'DIV'); d.outerHTML = '

' + d.outerHTML + '

'; console.assert(container.firstElementChild.nodeName === 'P', 'P');