mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:17: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
|
@ -52,6 +52,7 @@ public:
|
||||||
String get_attribute(const FlyString& name) const { return attribute(name); }
|
String get_attribute(const FlyString& name) const { return attribute(name); }
|
||||||
ExceptionOr<void> set_attribute(const FlyString& name, const String& value);
|
ExceptionOr<void> set_attribute(const FlyString& name, const String& value);
|
||||||
void remove_attribute(const FlyString& name);
|
void remove_attribute(const FlyString& name);
|
||||||
|
size_t attribute_list_size() const { return m_attributes.size(); }
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_attribute(Callback callback) const
|
void for_each_attribute(Callback callback) const
|
||||||
|
|
|
@ -774,4 +774,88 @@ bool Node::is_same_node(Node const* other_node) const
|
||||||
return this == other_node;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,7 @@ public:
|
||||||
void string_replace_all(String const&);
|
void string_replace_all(String const&);
|
||||||
|
|
||||||
bool is_same_node(Node const*) const;
|
bool is_same_node(Node const*) const;
|
||||||
|
bool is_equal_node(Node const*) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Node(Document&, NodeType);
|
Node(Document&, NodeType);
|
||||||
|
|
|
@ -26,6 +26,7 @@ interface Node : EventTarget {
|
||||||
[ImplementedAs=pre_remove] Node removeChild(Node child);
|
[ImplementedAs=pre_remove] Node removeChild(Node child);
|
||||||
[ImplementedAs=clone_node_binding] Node cloneNode(optional boolean deep = false);
|
[ImplementedAs=clone_node_binding] Node cloneNode(optional boolean deep = false);
|
||||||
boolean contains(Node? other);
|
boolean contains(Node? other);
|
||||||
|
boolean isEqualNode(Node? otherNode);
|
||||||
boolean isSameNode(Node? otherNode);
|
boolean isSameNode(Node? otherNode);
|
||||||
|
|
||||||
const unsigned short ELEMENT_NODE = 1;
|
const unsigned short ELEMENT_NODE = 1;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue