diff options
author | Linus Groh <mail@linusgroh.de> | 2021-04-14 01:25:10 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-14 09:30:29 +0200 |
commit | 5da4c9bf1e538e73b947652e61f2e8ffcb31005c (patch) | |
tree | 33e4ecdd869d9a22d1cbd243c2f08f078f8b7452 /Userland/Libraries | |
parent | d721c93beb339678bd965179104fb6647553cd6d (diff) | |
download | serenity-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.cpp | 66 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Node.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Node.idl | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ProcessingInstruction.h | 2 |
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; } |