Browse Source

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*.
Andreas Kling 5 years ago
parent
commit
884ae80699

+ 4 - 0
Applications/Browser/main.cpp

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

+ 1 - 0
Libraries/LibHTML/DOM/Element.h

@@ -31,6 +31,7 @@ public:
 
     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;
     void set_attribute(const String& name, const String& value);
 

+ 13 - 1
Libraries/LibHTML/DOM/Node.cpp

@@ -21,7 +21,11 @@ Node::~Node()
 
 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
@@ -76,3 +80,11 @@ void Node::invalidate_style()
     });
     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");
+}

+ 2 - 0
Libraries/LibHTML/DOM/Node.h

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

+ 10 - 3
Libraries/LibHTML/HtmlView.cpp

@@ -142,16 +142,18 @@ void HtmlView::mousemove_event(GMouseEvent& event)
 
     bool hovered_node_changed = 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()));
+    const HTMLAnchorElement* hovered_link_element = nullptr;
     if (result.layout_node) {
         auto* node = result.layout_node->node();
         hovered_node_changed = node != m_document->hovered_node();
         m_document->set_hovered_node(const_cast<Node*>(node));
         if (node) {
-            if (auto* link = node->enclosing_link_element()) {
-                UNUSED_PARAM(link);
+            hovered_link_element = node->enclosing_link_element();
+            if (hovered_link_element) {
 #ifdef HTML_DEBUG
-                dbg() << "HtmlView: hovering over a link to " << link->href();
+                dbg() << "HtmlView: hovering over a link to " << hovered_link_element->href();
 #endif
                 is_hovering_link = true;
             }
@@ -169,6 +171,11 @@ void HtmlView::mousemove_event(GMouseEvent& event)
             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();
 }
 

+ 1 - 0
Libraries/LibHTML/HtmlView.h

@@ -29,6 +29,7 @@ public:
     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_hover;
     Function<void(const String&)> on_title_change;
     Function<void(const URL&)> on_load_start;