From 46a213ae49c079ce232544512e22c2ec12fb4024 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Wed, 8 May 2024 18:32:59 +0200 Subject: [PATCH] [spidermonkey] element.outerHTML --- src/ecmascript/spidermonkey/element.cpp | 129 +++++++++++++++++- test/ecmascript/assert/element.outerHTML.html | 3 +- 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/src/ecmascript/spidermonkey/element.cpp b/src/ecmascript/spidermonkey/element.cpp index 008b4166e..136fe7cf2 100644 --- a/src/ecmascript/spidermonkey/element.cpp +++ b/src/ecmascript/spidermonkey/element.cpp @@ -3380,11 +3380,138 @@ element_set_property_outerHtml(JSContext *ctx, unsigned int argc, JS::Value *vp) #endif return false; } -// TODO + args.rval().setUndefined(); + struct view_state *vs = interpreter->vs; if (!vs) { return true; } + dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!el) { + return true; + } + dom_node *parent = NULL; + dom_exception exc = dom_node_get_parent_node(el, &parent); + + if (exc != DOM_NO_ERR) { + return true; + } + + char *s = jsval_to_string(ctx, args[0]); + + if (!s) { + return false; + } + size_t 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); + + mem_free(s); + interpreter->changed = 1; return true; } diff --git a/test/ecmascript/assert/element.outerHTML.html b/test/ecmascript/assert/element.outerHTML.html index 20acb00b9..61bf594ea 100644 --- a/test/ecmascript/assert/element.outerHTML.html +++ b/test/ecmascript/assert/element.outerHTML.html @@ -18,8 +18,9 @@ function bb() const container = document.getElementById("container"); const d = document.getElementById("d"); console.assert(container.firstElementChild.nodeName === 'DIV', 'DIV'); - d.outerHTML = "

This paragraph replaced the original div.

"; + d.outerHTML = '

' + d.outerHTML + '

'; console.assert(container.firstElementChild.nodeName === 'P', 'P'); + console.assert(container.innerHTML === '\n

This is a div.

\n', 'div p div'); } console.error('element.outerHTML.html');