mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:07:35 +00:00
LibWeb: Implement Node.isEqualNode(Node? otherNode)
This commit is contained in:
parent
a0528598b5
commit
449cbd5ecc
4 changed files with 87 additions and 0 deletions
|
@ -774,4 +774,88 @@ bool Node::is_same_node(Node const* other_node) const
|
|||
return this == other_node;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-node-isequalnode
|
||||
bool Node::is_equal_node(Node const* other_node) const
|
||||
{
|
||||
// The isEqualNode(otherNode) method steps are to return true if otherNode is non-null and this equals otherNode; otherwise false.
|
||||
if (!other_node)
|
||||
return false;
|
||||
|
||||
// Fast path for testing a node against itself.
|
||||
if (this == other_node)
|
||||
return true;
|
||||
|
||||
// A node A equals a node B if all of the following conditions are true:
|
||||
|
||||
// A and B implement the same interfaces.
|
||||
if (node_name() != other_node->node_name())
|
||||
return false;
|
||||
|
||||
// The following are equal, switching on the interface A implements:
|
||||
switch (node_type()) {
|
||||
case (u16)NodeType::DOCUMENT_TYPE_NODE: {
|
||||
// Its name, public ID, and system ID.
|
||||
auto& this_doctype = verify_cast<DocumentType>(*this);
|
||||
auto& other_doctype = verify_cast<DocumentType>(*other_node);
|
||||
if (this_doctype.name() != other_doctype.name()
|
||||
|| this_doctype.public_id() != other_doctype.public_id()
|
||||
|| this_doctype.system_id() != other_doctype.system_id())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case (u16)NodeType::ELEMENT_NODE: {
|
||||
// Its namespace, namespace prefix, local name, and its attribute list’s size.
|
||||
auto& this_element = verify_cast<Element>(*this);
|
||||
auto& other_element = verify_cast<Element>(*other_node);
|
||||
if (this_element.namespace_() != other_element.namespace_()
|
||||
|| this_element.prefix() != other_element.prefix()
|
||||
|| this_element.local_name() != other_element.local_name()
|
||||
|| this_element.attribute_list_size() != other_element.attribute_list_size())
|
||||
return false;
|
||||
// If A is an element, each attribute in its attribute list has an attribute that equals an attribute in B’s attribute list.
|
||||
bool has_same_attributes = true;
|
||||
this_element.for_each_attribute([&](auto& name, auto& value) {
|
||||
if (other_element.get_attribute(name) != value)
|
||||
has_same_attributes = false;
|
||||
});
|
||||
if (!has_same_attributes)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case (u16)NodeType::COMMENT_NODE:
|
||||
case (u16)NodeType::TEXT_NODE: {
|
||||
// Its data.
|
||||
auto& this_cdata = verify_cast<CharacterData>(*this);
|
||||
auto& other_cdata = verify_cast<CharacterData>(*other_node);
|
||||
if (this_cdata.data() != other_cdata.data())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case (u16)NodeType::PROCESSING_INSTRUCTION_NODE:
|
||||
case (u16)NodeType::ATTRIBUTE_NODE:
|
||||
TODO();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// A and B have the same number of children.
|
||||
size_t this_child_count = child_count();
|
||||
size_t other_child_count = other_node->child_count();
|
||||
if (this_child_count != other_child_count)
|
||||
return false;
|
||||
|
||||
// Each child of A equals the child of B at the identical index.
|
||||
// FIXME: This can be made nicer. child_at_index() is O(n).
|
||||
for (size_t i = 0; i < this_child_count; ++i) {
|
||||
auto* this_child = child_at_index(i);
|
||||
auto* other_child = other_node->child_at_index(i);
|
||||
VERIFY(this_child);
|
||||
VERIFY(other_child);
|
||||
if (!this_child->is_equal_node(other_child))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue