summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2021-04-14 01:25:10 +0200
committerAndreas Kling <kling@serenityos.org>2021-04-14 09:30:29 +0200
commit5da4c9bf1e538e73b947652e61f2e8ffcb31005c (patch)
tree33e4ecdd869d9a22d1cbd243c2f08f078f8b7452 /Userland/Libraries
parentd721c93beb339678bd965179104fb6647553cd6d (diff)
downloadserenity-5da4c9bf1e538e73b947652e61f2e8ffcb31005c.zip
LibWeb: Implement Node.cloneNode()
With this we can now successfully run a Vue.js 2 hello world! :^)
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWeb/DOM/Node.cpp66
-rw-r--r--Userland/Libraries/LibWeb/DOM/Node.h3
-rw-r--r--Userland/Libraries/LibWeb/DOM/Node.idl1
-rw-r--r--Userland/Libraries/LibWeb/DOM/ProcessingInstruction.h2
4 files changed, 71 insertions, 1 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp
index 90ccf5ef2d..c4ff744ece 100644
--- a/Userland/Libraries/LibWeb/DOM/Node.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Node.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +44,7 @@
#include <LibWeb/Layout/InitialContainingBlockBox.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Layout/TextNode.h>
+#include <LibWeb/Origin.h>
namespace Web::DOM {
@@ -363,6 +365,70 @@ void Node::remove(bool suppress_observers)
parent->children_changed();
}
+// https://dom.spec.whatwg.org/#concept-node-clone
+NonnullRefPtr<Node> Node::clone_node(Document* document, bool clone_children) const
+{
+ if (!document)
+ document = m_document;
+ RefPtr<Node> copy;
+ if (is<Element>(this)) {
+ auto& element = *downcast<Element>(this);
+ auto qualified_name = QualifiedName(element.local_name(), element.prefix(), element.namespace_());
+ auto element_copy = adopt(*new Element(*document, move(qualified_name)));
+ element.for_each_attribute([&](auto& name, auto& value) {
+ element_copy->set_attribute(name, value);
+ });
+ copy = move(element_copy);
+ } else if (is<Document>(this)) {
+ auto document_ = downcast<Document>(this);
+ auto document_copy = Document::create(document_->url());
+ document_copy->set_encoding(document_->encoding());
+ document_copy->set_content_type(document_->content_type());
+ document_copy->set_origin(document_->origin());
+ document_copy->set_quirks_mode(document_->mode());
+ // FIXME: Set type ("xml" or "html")
+ copy = move(document_copy);
+ } else if (is<DocumentType>(this)) {
+ auto document_type = downcast<DocumentType>(this);
+ auto document_type_copy = adopt(*new DocumentType(*document));
+ document_type_copy->set_name(document_type->name());
+ document_type_copy->set_public_id(document_type->public_id());
+ document_type_copy->set_system_id(document_type->system_id());
+ copy = move(document_type_copy);
+ } else if (is<Text>(this)) {
+ auto text = downcast<Text>(this);
+ auto text_copy = adopt(*new Text(*document, text->data()));
+ copy = move(text_copy);
+ } else if (is<Comment>(this)) {
+ auto comment = downcast<Comment>(this);
+ auto comment_copy = adopt(*new Comment(*document, comment->data()));
+ copy = move(comment_copy);
+ } else if (is<ProcessingInstruction>(this)) {
+ auto processing_instruction = downcast<ProcessingInstruction>(this);
+ auto processing_instruction_copy = adopt(*new ProcessingInstruction(*document, processing_instruction->data(), processing_instruction->target()));
+ copy = move(processing_instruction_copy);
+ } else {
+ dbgln("clone_node() not implemented for NodeType {}", (u16)m_type);
+ TODO();
+ }
+ // FIXME: 4. Set copy’s node document and document to copy, if copy is a document, and set copy’s node document to document otherwise.
+ // FIXME: 5. Run any cloning steps defined for node in other applicable specifications and pass copy, node, document and the clone children flag if set, as parameters.
+ if (clone_children) {
+ for_each_child([&](auto& child) {
+ copy->append_child(child.clone_node(document, true));
+ });
+ }
+ return copy.release_nonnull();
+}
+
+// https://dom.spec.whatwg.org/#dom-node-clonenode
+ExceptionOr<NonnullRefPtr<Node>> Node::clone_node_binding(bool deep) const
+{
+ if (is<ShadowRoot>(*this))
+ return NotSupportedError::create("Cannot clone shadow root");
+ return clone_node(nullptr, deep);
+}
+
void Node::set_document(Badge<Document>, Document& document)
{
if (m_document == &document)
diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h
index e4a2927c51..0dd64b5bf7 100644
--- a/Userland/Libraries/LibWeb/DOM/Node.h
+++ b/Userland/Libraries/LibWeb/DOM/Node.h
@@ -102,6 +102,9 @@ public:
void remove_all_children(bool suppress_observers = false);
u16 compare_document_position(RefPtr<Node> other);
+ NonnullRefPtr<Node> clone_node(Document* document = nullptr, bool clone_children = false) const;
+ ExceptionOr<NonnullRefPtr<Node>> clone_node_binding(bool deep) const;
+
// NOTE: This is intended for the JS bindings.
bool has_child_nodes() const { return has_children(); }
NonnullRefPtrVector<Node> child_nodes() const;
diff --git a/Userland/Libraries/LibWeb/DOM/Node.idl b/Userland/Libraries/LibWeb/DOM/Node.idl
index 34de218746..7c17fc8bad 100644
--- a/Userland/Libraries/LibWeb/DOM/Node.idl
+++ b/Userland/Libraries/LibWeb/DOM/Node.idl
@@ -18,6 +18,7 @@ interface Node : EventTarget {
Node appendChild(Node node);
[ImplementedAs=pre_insert] Node insertBefore(Node node, Node? child);
[ImplementedAs=pre_remove] Node removeChild(Node child);
+ [ImplementedAs=clone_node_binding] Node cloneNode(optional boolean deep = false);
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2;
diff --git a/Userland/Libraries/LibWeb/DOM/ProcessingInstruction.h b/Userland/Libraries/LibWeb/DOM/ProcessingInstruction.h
index 0ff536994d..cd433a88de 100644
--- a/Userland/Libraries/LibWeb/DOM/ProcessingInstruction.h
+++ b/Userland/Libraries/LibWeb/DOM/ProcessingInstruction.h
@@ -35,7 +35,7 @@ class ProcessingInstruction final : public CharacterData {
public:
using WrapperType = Bindings::ProcessingInstructionWrapper;
- ProcessingInstruction(Document&, const String&, const String&);
+ ProcessingInstruction(Document&, const String& data, const String& target);
virtual ~ProcessingInstruction() override;
virtual FlyString node_name() const override { return m_target; }