LibWeb: Implement ChildNode.before

This commit is contained in:
Luke Wilde 2022-01-29 21:33:12 +00:00 committed by Andreas Kling
parent d1bc9358c1
commit 1bbe40c5af
Notes: sideshowbarker 2024-07-17 19:56:20 +09:00
4 changed files with 71 additions and 3 deletions

View File

@ -6,7 +6,8 @@ interface CharacterData : Node {
readonly attribute Element? nextElementSibling;
readonly attribute Element? previousElementSibling;
// FIXME: This should come from a ChildNode mixin
// FIXME: These should come from a ChildNode mixin
[CEReactions, Unscopable] undefined before((Node or DOMString)... nodes);
[CEReactions, Unscopable, ImplementedAs=remove_binding] undefined remove();
};

View File

@ -6,12 +6,51 @@
#pragma once
#include <LibWeb/DOM/ExceptionOr.h>
#include <LibWeb/DOM/NodeOperations.h>
namespace Web::DOM {
// https://dom.spec.whatwg.org/#childnode
template<typename NodeType>
class ChildNode {
public:
// https://dom.spec.whatwg.org/#dom-childnode-before
ExceptionOr<void> before(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes)
{
auto* node = static_cast<NodeType*>(this);
// 1. Let parent be thiss parent.
auto* parent = node->parent();
// 2. If parent is null, then return.
if (!parent)
return {};
// 3. Let viablePreviousSibling be thiss first preceding sibling not in nodes; otherwise null.
auto viable_previous_sibling = viable_previous_sibling_for_insertion(nodes);
// 4. Let node be the result of converting nodes into a node, given nodes and thiss node document.
auto node_or_exception = convert_nodes_to_single_node(nodes, node->document());
if (node_or_exception.is_exception())
return node_or_exception.exception();
auto node_to_insert = node_or_exception.release_value();
// 5. If viablePreviousSibling is null, then set it to parents first child; otherwise to viablePreviousSiblings next sibling.
if (!viable_previous_sibling)
viable_previous_sibling = parent->first_child();
else
viable_previous_sibling = viable_previous_sibling->next_sibling();
// 6. Pre-insert node into parent before viablePreviousSibling.
auto result = parent->pre_insert(node_to_insert, viable_previous_sibling);
if (result.is_exception())
return result.exception();
return {};
}
// https://dom.spec.whatwg.org/#dom-childnode-remove
void remove_binding()
{
@ -27,6 +66,32 @@ public:
protected:
ChildNode() = default;
private:
RefPtr<Node> viable_previous_sibling_for_insertion(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes) const
{
auto* node = static_cast<NodeType const*>(this);
while (auto* previous_sibling = node->previous_sibling()) {
bool contained_in_nodes = false;
for (auto const& node_or_string : nodes) {
if (!node_or_string.template has<NonnullRefPtr<Node>>())
continue;
auto node_in_vector = node_or_string.template get<NonnullRefPtr<Node>>();
if (node_in_vector.ptr() == previous_sibling) {
contained_in_nodes = true;
break;
}
}
if (!contained_in_nodes)
return previous_sibling;
}
return nullptr;
}
};
}

View File

@ -4,7 +4,8 @@ interface DocumentType : Node {
readonly attribute DOMString publicId;
readonly attribute DOMString systemId;
// FIXME: This should come from a ChildNode mixin
// FIXME: These should come from a ChildNode mixin
[CEReactions, Unscopable] undefined before((Node or DOMString)... nodes);
[CEReactions, Unscopable, ImplementedAs=remove_binding] undefined remove();
};

View File

@ -54,7 +54,8 @@ interface Element : Node {
readonly attribute long clientWidth;
readonly attribute long clientHeight;
// FIXME: This should come from a ChildNode mixin
// FIXME: These should come from a ChildNode mixin
[CEReactions, Unscopable] undefined before((Node or DOMString)... nodes);
[CEReactions, Unscopable, ImplementedAs=remove_binding] undefined remove();
};