mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 06:58:11 +00:00
LibHTML: Add Document::get_element_by_id() and get_elements_by_name()
These will be useful for implementing various things. They don't do any caching at the moment, but that might become valuable in the future. To facilitate this change, I also made it possible to abort a tree walk with for_each_in_subtree() by returning IterationDecision::Break from the callback.
This commit is contained in:
parent
465a33443c
commit
4d9740ecef
5 changed files with 57 additions and 11 deletions
|
@ -193,9 +193,9 @@ void Document::layout()
|
||||||
void Document::update_style()
|
void Document::update_style()
|
||||||
{
|
{
|
||||||
for_each_in_subtree([&](Node& node) {
|
for_each_in_subtree([&](Node& node) {
|
||||||
if (!node.needs_style_update())
|
if (node.needs_style_update())
|
||||||
return;
|
to<Element>(node).recompute_style();
|
||||||
to<Element>(node).recompute_style();
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
update_layout();
|
update_layout();
|
||||||
}
|
}
|
||||||
|
@ -242,3 +242,27 @@ void Document::set_hovered_node(Node* node)
|
||||||
|
|
||||||
invalidate_style();
|
invalidate_style();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Element* Document::get_element_by_id(const String& id) const
|
||||||
|
{
|
||||||
|
const Element* element = nullptr;
|
||||||
|
for_each_in_subtree([&](auto& node) {
|
||||||
|
if (is<Element>(node) && to<Element>(node).attribute("id") == id) {
|
||||||
|
element = &to<Element>(node);
|
||||||
|
return IterationDecision::Break;
|
||||||
|
}
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<const Element*> Document::get_elements_by_name(const String& name) const
|
||||||
|
{
|
||||||
|
Vector<const Element*> elements;
|
||||||
|
for_each_in_subtree([&](auto& node) {
|
||||||
|
if (is<Element>(node) && to<Element>(node).attribute("name") == name)
|
||||||
|
elements.append(&to<Element>(node));
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
|
@ -80,6 +80,9 @@ public:
|
||||||
|
|
||||||
void schedule_style_update();
|
void schedule_style_update();
|
||||||
|
|
||||||
|
const Element* get_element_by_id(const String&) const;
|
||||||
|
Vector<const Element*> get_elements_by_name(const String&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
|
virtual RefPtr<LayoutNode> create_layout_node(const StyleProperties* parent_style) const override;
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@ void Node::invalidate_style()
|
||||||
for_each_in_subtree([&](auto& node) {
|
for_each_in_subtree([&](auto& node) {
|
||||||
if (is<Element>(node))
|
if (is<Element>(node))
|
||||||
node.set_needs_style_update(true);
|
node.set_needs_style_update(true);
|
||||||
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
document().schedule_style_update();
|
document().schedule_style_update();
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,11 +321,14 @@ void HtmlView::scroll_to_anchor(const StringView& name)
|
||||||
|
|
||||||
HTMLAnchorElement* element = nullptr;
|
HTMLAnchorElement* element = nullptr;
|
||||||
document()->for_each_in_subtree([&](auto& node) {
|
document()->for_each_in_subtree([&](auto& node) {
|
||||||
if (!is<HTMLAnchorElement>(node))
|
if (is<HTMLAnchorElement>(node)) {
|
||||||
return;
|
auto& anchor_element = to<HTMLAnchorElement>(node);
|
||||||
auto& anchor_element = to<HTMLAnchorElement>(node);
|
if (anchor_element.name() == name) {
|
||||||
if (anchor_element.name() == name)
|
element = &anchor_element;
|
||||||
element = &anchor_element;
|
return IterationDecision::Break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!element) {
|
if (!element) {
|
||||||
|
|
|
@ -54,12 +54,27 @@ public:
|
||||||
bool is_child_allowed(const T&) const { return true; }
|
bool is_child_allowed(const T&) const { return true; }
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_in_subtree(Callback callback)
|
IterationDecision for_each_in_subtree(Callback callback) const
|
||||||
{
|
{
|
||||||
callback(static_cast<T&>(*this));
|
if (callback(static_cast<const T&>(*this)) == IterationDecision::Break)
|
||||||
|
return IterationDecision::Break;
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
||||||
child->for_each_in_subtree(callback);
|
if (child->for_each_in_subtree(callback) == IterationDecision::Break)
|
||||||
|
return IterationDecision::Break;
|
||||||
}
|
}
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
IterationDecision for_each_in_subtree(Callback callback)
|
||||||
|
{
|
||||||
|
if (callback(static_cast<T&>(*this)) == IterationDecision::Break)
|
||||||
|
return IterationDecision::Break;
|
||||||
|
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
||||||
|
if (child->for_each_in_subtree(callback) == IterationDecision::Break)
|
||||||
|
return IterationDecision::Break;
|
||||||
|
}
|
||||||
|
return IterationDecision::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue