1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 03:27:44 +00:00

LibWeb: Implement Element.insertAdjacentHTML() from DOM Parsing

One edge case is left as a TODO() for now, since I'm not entirely sure
how to construct an element to those specifications.

With this patch, we can now run the Speedometer benchmark! :^)
This commit is contained in:
Andreas Kling 2022-09-20 18:28:41 +02:00
parent 287a9b552a
commit aa4dd6c1bc
5 changed files with 80 additions and 1 deletions

View file

@ -730,4 +730,77 @@ void Element::serialize_pseudo_elements_as_json(JsonArraySerializer<StringBuilde
}
}
// https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml
DOM::ExceptionOr<void> Element::insert_adjacent_html(String position, String text)
{
JS::GCPtr<Node> context;
// 1. Use the first matching item from this list:
// - If position is an ASCII case-insensitive match for the string "beforebegin"
// - If position is an ASCII case-insensitive match for the string "afterend"
if (position.equals_ignoring_case("beforebegin"sv) || position.equals_ignoring_case("afterend"sv)) {
// Let context be the context object's parent.
context = this->parent();
// If context is null or a Document, throw a "NoModificationAllowedError" DOMException.
if (!context || context->is_document())
return NoModificationAllowedError::create(window(), "insertAdjacentHTML: context is null or a Document"sv);
}
// - If position is an ASCII case-insensitive match for the string "afterbegin"
// - If position is an ASCII case-insensitive match for the string "beforeend"
else if (position.equals_ignoring_case("afterbegin"sv) || position.equals_ignoring_case("beforeend"sv)) {
// Let context be the context object.
context = this;
}
// Otherwise
else {
// Throw a "SyntaxError" DOMException.
return SyntaxError::create(window(), "insertAdjacentHTML: invalid position argument"sv);
}
// 2. If context is not an Element or the following are all true:
// - context's node document is an HTML document,
// - context's local name is "html", and
// - context's namespace is the HTML namespace;
if (!is<Element>(*context)
|| (context->document().document_type() == Document::Type::HTML
&& static_cast<Element const&>(*context).local_name() == "html"sv
&& static_cast<Element const&>(*context).namespace_() == Namespace::HTML)) {
// FIXME: let context be a new Element with
// - body as its local name,
// - The HTML namespace as its namespace, and
// - The context object's node document as its node document.
TODO();
}
// 3. Let fragment be the result of invoking the fragment parsing algorithm with text as markup, and context as the context element.
auto fragment = TRY(DOMParsing::parse_fragment(text, verify_cast<Element>(*context)));
// 4. Use the first matching item from this list:
// - If position is an ASCII case-insensitive match for the string "beforebegin"
if (position.equals_ignoring_case("beforebegin"sv)) {
// Insert fragment into the context object's parent before the context object.
parent()->insert_before(fragment, this);
}
// - If position is an ASCII case-insensitive match for the string "afterbegin"
else if (position.equals_ignoring_case("afterbegin"sv)) {
// Insert fragment into the context object before its first child.
insert_before(fragment, first_child());
}
// - If position is an ASCII case-insensitive match for the string "beforeend"
else if (position.equals_ignoring_case("beforeend"sv)) {
// Append fragment to the context object.
TRY(append_child(fragment));
}
// - If position is an ASCII case-insensitive match for the string "afterend"
else if (position.equals_ignoring_case("afterend"sv)) {
// Insert fragment into the context object's parent before the context object's next sibling.
parent()->insert_before(fragment, next_sibling());
}
return {};
}
}