diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 4f66b7de38..43bab85987 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -200,4 +200,16 @@ RefPtr Node::append_child(NonnullRefPtr node, bool notify) return node; } +RefPtr Node::insert_before(NonnullRefPtr node, RefPtr child, bool notify) +{ + if (!child) + return append_child(move(node), notify); + if (child->parent_node() != this) { + dbg() << "FIXME: Trying to insert_before() a bogus child"; + return nullptr; + } + TreeNode::insert_before(node, child, notify); + return node; +} + } diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 30504abcaf..eab5b49a70 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -83,6 +83,7 @@ public: bool is_parent_node() const { return is_element() || is_document() || is_document_fragment(); } RefPtr append_child(NonnullRefPtr, bool notify = true); + RefPtr insert_before(NonnullRefPtr node, RefPtr child, bool notify = true); virtual RefPtr create_layout_node(const StyleProperties* parent_style) const; diff --git a/Libraries/LibWeb/DOM/Node.idl b/Libraries/LibWeb/DOM/Node.idl index 3bb148197d..33c883049d 100644 --- a/Libraries/LibWeb/DOM/Node.idl +++ b/Libraries/LibWeb/DOM/Node.idl @@ -9,5 +9,7 @@ interface Node : EventTarget { readonly attribute Element? parentElement; Node appendChild(Node node); + Node insertBefore(Node node, Node? child); + } diff --git a/Libraries/LibWeb/TreeNode.h b/Libraries/LibWeb/TreeNode.h index 30b7bbe83d..65fc2f5134 100644 --- a/Libraries/LibWeb/TreeNode.h +++ b/Libraries/LibWeb/TreeNode.h @@ -110,6 +110,7 @@ public: void prepend_child(NonnullRefPtr node); void append_child(NonnullRefPtr node, bool notify = true); + void insert_before(NonnullRefPtr node, RefPtr child, bool notify = true); NonnullRefPtr remove_child(NonnullRefPtr node); void donate_all_children_to(T& node); @@ -252,6 +253,33 @@ inline void TreeNode::append_child(NonnullRefPtr node, bool notify) static_cast(this)->children_changed(); } +template +inline void TreeNode::insert_before(NonnullRefPtr node, RefPtr child, bool notify) +{ + if (!child) + return append_child(move(node), notify); + + ASSERT(!node->m_parent); + ASSERT(child->parent() == this); + + if (!static_cast(this)->is_child_allowed(*node)) + return; + + node->m_previous_sibling = child->m_previous_sibling; + node->m_next_sibling = child; + + if (m_first_child == child) + m_first_child = node; + + node->m_parent = static_cast(this); + if (notify) + node->inserted_into(static_cast(*this)); + (void)node.leak_ref(); + + if (notify) + static_cast(this)->children_changed(); +} + template inline void TreeNode::prepend_child(NonnullRefPtr node) {