1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:28:12 +00:00

LibHTML: Add TreeNode::for_each_in_subtree_of_type<T>()

This allows you to iterate a subtree and get a callback for every node
where is<T>(node) == true. This makes for quite pleasant DOM traversal.
This commit is contained in:
Andreas Kling 2019-12-18 21:34:03 +01:00
parent 54bd322881
commit 1aea8f116b
5 changed files with 56 additions and 25 deletions

View file

@ -4,6 +4,15 @@
#include <AK/NonnullRefPtr.h>
#include <AK/Weakable.h>
// FIXME: I wish I didn't have to forward declare these, but I can't seem to avoid
// it if I still want to have for_each_in_subtree_of_type<U> inline here.
class Node;
class LayoutNode;
template<typename T>
bool is(const Node&);
template<typename T>
bool is(const LayoutNode&);
template<typename T>
class TreeNode : public Weakable<T> {
public:
@ -122,6 +131,34 @@ public:
return IterationDecision::Continue;
}
template<typename U, typename Callback>
IterationDecision for_each_in_subtree_of_type(Callback callback)
{
if (is<U>(static_cast<const T&>(*this))) {
if (callback(static_cast<U&>(*this)) == IterationDecision::Break)
return IterationDecision::Break;
}
for (auto* child = first_child(); child; child = child->next_sibling()) {
if (child->template for_each_in_subtree_of_type<U>(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
template<typename U, typename Callback>
IterationDecision for_each_in_subtree_of_type(Callback callback) const
{
if (is<U>(static_cast<const T&>(*this))) {
if (callback(static_cast<const U&>(*this)) == IterationDecision::Break)
return IterationDecision::Break;
}
for (auto* child = first_child(); child; child = child->next_sibling()) {
if (child->template for_each_in_subtree_of_type<U>(callback) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
protected:
TreeNode() {}