summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Irwin <paulirwin@gmail.com>2021-06-18 16:42:34 -0600
committerAndreas Kling <kling@serenityos.org>2021-06-25 01:02:29 +0200
commit5eb65286b63d5d2698af8b289c2b7372f49e53c6 (patch)
treedd9bf0f87715985f2ea7e807c548415695d060e4
parent457edaa4d28c6d26a8f6091642129c5980ec6824 (diff)
downloadserenity-5eb65286b63d5d2698af8b289c2b7372f49e53c6.zip
LibWeb: Support :active pseudo-class for hyperlinks, :focus possibly
Adds support for the :active pseudo-class for hyperlinks (<a> tags only). Also, since it was very similar to :focus and an element having a focused state was already implemented, I went ahead and implemented that pseudo-class too, although I cannot come up with a working example to validate it.
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp2
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp2
-rw-r--r--Userland/Libraries/LibWeb/CSS/Selector.h1
-rw-r--r--Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp9
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.cpp11
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.h5
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.cpp5
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.h2
-rw-r--r--Userland/Libraries/LibWeb/Dump.cpp3
-rw-r--r--Userland/Libraries/LibWeb/Page/EventHandler.cpp1
10 files changed, 39 insertions, 2 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp
index cd48a1b2a0..5c72d24598 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp
@@ -563,6 +563,8 @@ public:
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
} else if (pseudo_name.equals_ignoring_case("visited")) {
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Visited;
+ } else if (pseudo_name.equals_ignoring_case("active")) {
+ simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Active;
} else if (pseudo_name.equals_ignoring_case("hover")) {
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
} else if (pseudo_name.equals_ignoring_case("focus")) {
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index 0ed2a9e7be..dce9f251ad 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -200,6 +200,8 @@ Vector<CSS::Selector::ComplexSelector> Parser::parse_selectors(Vector<String> pa
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
} else if (pseudo_name.equals_ignoring_case("visited")) {
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Visited;
+ } else if (pseudo_name.equals_ignoring_case("active")) {
+ simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Active;
} else if (pseudo_name.equals_ignoring_case("hover")) {
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
} else if (pseudo_name.equals_ignoring_case("focus")) {
diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h
index eb648bde8c..2a4eb11be0 100644
--- a/Userland/Libraries/LibWeb/CSS/Selector.h
+++ b/Userland/Libraries/LibWeb/CSS/Selector.h
@@ -43,6 +43,7 @@ public:
Enabled,
Checked,
Not,
+ Active,
};
PseudoClass pseudo_class { PseudoClass::None };
diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
index 7669a57f6f..99916b6303 100644
--- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
+++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
@@ -44,13 +44,18 @@ static bool matches(const CSS::Selector::SimpleSelector& component, const DOM::E
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
// FIXME: Maybe match this selector sometimes?
return false;
+ case CSS::Selector::SimpleSelector::PseudoClass::Active:
+ if (!element.is_active())
+ return false;
+ break;
case CSS::Selector::SimpleSelector::PseudoClass::Hover:
if (!matches_hover_pseudo_class(element))
return false;
break;
case CSS::Selector::SimpleSelector::PseudoClass::Focus:
- // FIXME: Implement matches_focus_pseudo_class(element)
- return false;
+ if (!element.is_focused())
+ return false;
+ break;
case CSS::Selector::SimpleSelector::PseudoClass::FirstChild:
if (element.previous_element_sibling())
return false;
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp
index 712c963f12..68824b541a 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Document.cpp
@@ -876,6 +876,17 @@ void Document::set_focused_element(Element* element)
m_layout_root->set_needs_display();
}
+void Document::set_active_element(Element* element)
+{
+ if (m_active_element == element)
+ return;
+
+ m_active_element = element;
+
+ if (m_layout_root)
+ m_layout_root->set_needs_display();
+}
+
void Document::set_ready_state(const String& ready_state)
{
m_ready_state = ready_state;
diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h
index d9934f3421..74c184e032 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.h
+++ b/Userland/Libraries/LibWeb/DOM/Document.h
@@ -208,6 +208,10 @@ public:
void set_focused_element(Element*);
+ const Element* active_element() const { return m_active_element; }
+
+ void set_active_element(Element*);
+
bool created_for_appropriate_template_contents() const { return m_created_for_appropriate_template_contents; }
void set_created_for_appropriate_template_contents(bool value) { m_created_for_appropriate_template_contents = value; }
@@ -323,6 +327,7 @@ private:
bool m_editable { false };
WeakPtr<Element> m_focused_element;
+ WeakPtr<Element> m_active_element;
bool m_created_for_appropriate_template_contents { false };
RefPtr<Document> m_associated_inert_template_document;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index 26f5e0af68..b7ef8fba34 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -327,6 +327,11 @@ bool Element::is_focused() const
return document().focused_element() == this;
}
+bool Element::is_active() const
+{
+ return document().active_element() == this;
+}
+
NonnullRefPtr<HTMLCollection> Element::get_elements_by_tag_name(FlyString const& tag_name)
{
// FIXME: Support "*" for tag_name
diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h
index 2b320c7e51..c4b360f84e 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.h
+++ b/Userland/Libraries/LibWeb/DOM/Element.h
@@ -86,6 +86,8 @@ public:
bool is_focused() const;
virtual bool is_focusable() const { return false; }
+ bool is_active() const;
+
NonnullRefPtr<HTMLCollection> get_elements_by_tag_name(FlyString const&);
NonnullRefPtr<HTMLCollection> get_elements_by_class_name(FlyString const&);
diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp
index 8d806c6bd3..0b4bb29d12 100644
--- a/Userland/Libraries/LibWeb/Dump.cpp
+++ b/Userland/Libraries/LibWeb/Dump.cpp
@@ -341,6 +341,9 @@ void dump_selector(StringBuilder& builder, const CSS::Selector& selector)
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
pseudo_class_description = "Visited";
break;
+ case CSS::Selector::SimpleSelector::PseudoClass::Active:
+ pseudo_class_description = "Active";
+ break;
case CSS::Selector::SimpleSelector::PseudoClass::None:
pseudo_class_description = "None";
break;
diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp
index 14d14d596d..1fca7e74bd 100644
--- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp
+++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp
@@ -237,6 +237,7 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt
auto anchor = href.substring_view(1, href.length() - 1);
m_frame.scroll_to_anchor(anchor);
} else {
+ document->set_active_element(link);
if (m_frame.is_top_level()) {
if (auto* page = m_frame.page())
page->client().page_did_click_link(url, link->target(), modifiers);