LibHTML+Browser: Show target URL of hovered links in Browser statusbar

HtmlView will now invoke the on_link_hover hook when the cursor enters
or leaves a DOM node that has an enclosing link element.

This patch also updates the meaning of Node::enclosing_link_element()
to find the nearest HTMLAnchorElementAncestor *with an href attribute*.
This commit is contained in:
Andreas Kling 2019-10-19 21:21:29 +02:00
parent 73af2f8d02
commit 884ae80699
Notes: sideshowbarker 2024-07-19 11:37:36 +09:00
6 changed files with 31 additions and 4 deletions

View file

@ -105,6 +105,10 @@ int main(int argc, char** argv)
auto statusbar = GStatusBar::construct(widget); auto statusbar = GStatusBar::construct(widget);
html_widget->on_link_hover = [&](auto& href) {
statusbar->set_text(href);
};
ResourceLoader::the().on_load_counter_change = [&] { ResourceLoader::the().on_load_counter_change = [&] {
if (ResourceLoader::the().pending_loads() == 0) { if (ResourceLoader::the().pending_loads() == 0) {
statusbar->set_text(""); statusbar->set_text("");

View file

@ -31,6 +31,7 @@ public:
virtual String tag_name() const final { return m_tag_name; } virtual String tag_name() const final { return m_tag_name; }
bool has_attribute(const String& name) const { return !attribute(name).is_null(); }
String attribute(const String& name) const; String attribute(const String& name) const;
void set_attribute(const String& name, const String& value); void set_attribute(const String& name, const String& value);

View file

@ -21,7 +21,11 @@ Node::~Node()
const HTMLAnchorElement* Node::enclosing_link_element() const const HTMLAnchorElement* Node::enclosing_link_element() const
{ {
return first_ancestor_of_type<HTMLAnchorElement>(); for (auto* node = this; node; node = node->parent()) {
if (is<HTMLAnchorElement>(*node) && to<HTMLAnchorElement>(*node).has_attribute("href"))
return to<HTMLAnchorElement>(node);
}
return nullptr;
} }
const HTMLElement* Node::enclosing_html_element() const const HTMLElement* Node::enclosing_html_element() const
@ -76,3 +80,11 @@ void Node::invalidate_style()
}); });
document().schedule_style_update(); document().schedule_style_update();
} }
bool Node::is_link() const
{
auto* enclosing_link = enclosing_link_element();
if (!enclosing_link)
return false;
return enclosing_link->has_attribute("href");
}

View file

@ -75,6 +75,8 @@ public:
void invalidate_style(); void invalidate_style();
bool is_link() const;
protected: protected:
Node(Document&, NodeType); Node(Document&, NodeType);

View file

@ -142,16 +142,18 @@ void HtmlView::mousemove_event(GMouseEvent& event)
bool hovered_node_changed = false; bool hovered_node_changed = false;
bool is_hovering_link = false; bool is_hovering_link = false;
bool was_hovering_link = m_document->hovered_node() && m_document->hovered_node()->is_link();
auto result = layout_root()->hit_test(to_content_position(event.position())); auto result = layout_root()->hit_test(to_content_position(event.position()));
const HTMLAnchorElement* hovered_link_element = nullptr;
if (result.layout_node) { if (result.layout_node) {
auto* node = result.layout_node->node(); auto* node = result.layout_node->node();
hovered_node_changed = node != m_document->hovered_node(); hovered_node_changed = node != m_document->hovered_node();
m_document->set_hovered_node(const_cast<Node*>(node)); m_document->set_hovered_node(const_cast<Node*>(node));
if (node) { if (node) {
if (auto* link = node->enclosing_link_element()) { hovered_link_element = node->enclosing_link_element();
UNUSED_PARAM(link); if (hovered_link_element) {
#ifdef HTML_DEBUG #ifdef HTML_DEBUG
dbg() << "HtmlView: hovering over a link to " << link->href(); dbg() << "HtmlView: hovering over a link to " << hovered_link_element->href();
#endif #endif
is_hovering_link = true; is_hovering_link = true;
} }
@ -169,6 +171,11 @@ void HtmlView::mousemove_event(GMouseEvent& event)
GApplication::the().hide_tooltip(); GApplication::the().hide_tooltip();
} }
} }
if (is_hovering_link != was_hovering_link) {
if (on_link_hover) {
on_link_hover(hovered_link_element ? m_document->complete_url(hovered_link_element->href()).to_string() : String());
}
}
event.accept(); event.accept();
} }

View file

@ -29,6 +29,7 @@ public:
void set_should_show_line_box_borders(bool value) { m_should_show_line_box_borders = value; } void set_should_show_line_box_borders(bool value) { m_should_show_line_box_borders = value; }
Function<void(const String&)> on_link_click; Function<void(const String&)> on_link_click;
Function<void(const String&)> on_link_hover;
Function<void(const String&)> on_title_change; Function<void(const String&)> on_title_change;
Function<void(const URL&)> on_load_start; Function<void(const URL&)> on_load_start;