summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-09-20 18:28:41 +0200
committerAndreas Kling <kling@serenityos.org>2022-09-20 18:28:41 +0200
commitaa4dd6c1bc4dc28cf096aff76b3487501fe7af1f (patch)
tree9e009fddbddc0f94913e3f8300b2461ec9a8081a /Userland/Libraries/LibWeb
parent287a9b552a017903d496cd3011142dad858749e9 (diff)
downloadserenity-aa4dd6c1bc4dc28cf096aff76b3487501fe7af1f.zip
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! :^)
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.cpp73
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.h2
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.idl2
-rw-r--r--Userland/Libraries/LibWeb/DOMParsing/InnerHTML.cpp2
-rw-r--r--Userland/Libraries/LibWeb/DOMParsing/InnerHTML.h2
5 files changed, 80 insertions, 1 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index a65dc23c56..c950801065 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -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 {};
+}
+
}
diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h
index 020fea56b1..603278c7d2 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.h
+++ b/Userland/Libraries/LibWeb/DOM/Element.h
@@ -108,6 +108,8 @@ public:
String inner_html() const;
ExceptionOr<void> set_inner_html(String const&);
+ ExceptionOr<void> insert_adjacent_html(String position, String text);
+
bool is_focused() const;
bool is_active() const;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl
index db169a4869..9d25de71b2 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.idl
+++ b/Userland/Libraries/LibWeb/DOM/Element.idl
@@ -52,6 +52,8 @@ interface Element : Node {
readonly attribute long clientLeft;
readonly attribute long clientWidth;
readonly attribute long clientHeight;
+
+ [CEReactions] undefined insertAdjacentHTML(DOMString position, DOMString text);
};
Element includes ParentNode;
diff --git a/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.cpp b/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.cpp
index a92e187aa2..245dbeb049 100644
--- a/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.cpp
+++ b/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.cpp
@@ -12,7 +12,7 @@
namespace Web::DOMParsing {
// https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm
-static DOM::ExceptionOr<JS::NonnullGCPtr<DOM::DocumentFragment>> parse_fragment(String const& markup, DOM::Element& context_element)
+DOM::ExceptionOr<JS::NonnullGCPtr<DOM::DocumentFragment>> parse_fragment(String const& markup, DOM::Element& context_element)
{
// FIXME: Handle XML documents.
diff --git a/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.h b/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.h
index 9689d4edcc..9619254e14 100644
--- a/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.h
+++ b/Userland/Libraries/LibWeb/DOMParsing/InnerHTML.h
@@ -16,4 +16,6 @@ namespace Web::DOMParsing {
// https://w3c.github.io/DOM-Parsing/#dom-innerhtml-innerhtml
DOM::ExceptionOr<void> inner_html_setter(JS::NonnullGCPtr<DOM::Node> context_object, String const& value);
+DOM::ExceptionOr<JS::NonnullGCPtr<DOM::DocumentFragment>> parse_fragment(String const& markup, DOM::Element& context_element);
+
}