mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:37:46 +00:00
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.
This commit is contained in:
parent
457edaa4d2
commit
5eb65286b6
10 changed files with 39 additions and 2 deletions
|
@ -563,6 +563,8 @@ public:
|
||||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
|
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
|
||||||
} else if (pseudo_name.equals_ignoring_case("visited")) {
|
} else if (pseudo_name.equals_ignoring_case("visited")) {
|
||||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::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")) {
|
} else if (pseudo_name.equals_ignoring_case("hover")) {
|
||||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
|
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
|
||||||
} else if (pseudo_name.equals_ignoring_case("focus")) {
|
} else if (pseudo_name.equals_ignoring_case("focus")) {
|
||||||
|
|
|
@ -200,6 +200,8 @@ Vector<CSS::Selector::ComplexSelector> Parser::parse_selectors(Vector<String> pa
|
||||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
|
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
|
||||||
} else if (pseudo_name.equals_ignoring_case("visited")) {
|
} else if (pseudo_name.equals_ignoring_case("visited")) {
|
||||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::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")) {
|
} else if (pseudo_name.equals_ignoring_case("hover")) {
|
||||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
|
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
|
||||||
} else if (pseudo_name.equals_ignoring_case("focus")) {
|
} else if (pseudo_name.equals_ignoring_case("focus")) {
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
Enabled,
|
Enabled,
|
||||||
Checked,
|
Checked,
|
||||||
Not,
|
Not,
|
||||||
|
Active,
|
||||||
};
|
};
|
||||||
PseudoClass pseudo_class { PseudoClass::None };
|
PseudoClass pseudo_class { PseudoClass::None };
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,18 @@ static bool matches(const CSS::Selector::SimpleSelector& component, const DOM::E
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
|
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
|
||||||
// FIXME: Maybe match this selector sometimes?
|
// FIXME: Maybe match this selector sometimes?
|
||||||
return false;
|
return false;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoClass::Active:
|
||||||
|
if (!element.is_active())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Hover:
|
case CSS::Selector::SimpleSelector::PseudoClass::Hover:
|
||||||
if (!matches_hover_pseudo_class(element))
|
if (!matches_hover_pseudo_class(element))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Focus:
|
case CSS::Selector::SimpleSelector::PseudoClass::Focus:
|
||||||
// FIXME: Implement matches_focus_pseudo_class(element)
|
if (!element.is_focused())
|
||||||
return false;
|
return false;
|
||||||
|
break;
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::FirstChild:
|
case CSS::Selector::SimpleSelector::PseudoClass::FirstChild:
|
||||||
if (element.previous_element_sibling())
|
if (element.previous_element_sibling())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -876,6 +876,17 @@ void Document::set_focused_element(Element* element)
|
||||||
m_layout_root->set_needs_display();
|
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)
|
void Document::set_ready_state(const String& ready_state)
|
||||||
{
|
{
|
||||||
m_ready_state = ready_state;
|
m_ready_state = ready_state;
|
||||||
|
|
|
@ -208,6 +208,10 @@ public:
|
||||||
|
|
||||||
void set_focused_element(Element*);
|
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; }
|
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; }
|
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 };
|
bool m_editable { false };
|
||||||
|
|
||||||
WeakPtr<Element> m_focused_element;
|
WeakPtr<Element> m_focused_element;
|
||||||
|
WeakPtr<Element> m_active_element;
|
||||||
|
|
||||||
bool m_created_for_appropriate_template_contents { false };
|
bool m_created_for_appropriate_template_contents { false };
|
||||||
RefPtr<Document> m_associated_inert_template_document;
|
RefPtr<Document> m_associated_inert_template_document;
|
||||||
|
|
|
@ -327,6 +327,11 @@ bool Element::is_focused() const
|
||||||
return document().focused_element() == this;
|
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)
|
NonnullRefPtr<HTMLCollection> Element::get_elements_by_tag_name(FlyString const& tag_name)
|
||||||
{
|
{
|
||||||
// FIXME: Support "*" for tag_name
|
// FIXME: Support "*" for tag_name
|
||||||
|
|
|
@ -86,6 +86,8 @@ public:
|
||||||
bool is_focused() const;
|
bool is_focused() const;
|
||||||
virtual bool is_focusable() const { return false; }
|
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_tag_name(FlyString const&);
|
||||||
NonnullRefPtr<HTMLCollection> get_elements_by_class_name(FlyString const&);
|
NonnullRefPtr<HTMLCollection> get_elements_by_class_name(FlyString const&);
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,9 @@ void dump_selector(StringBuilder& builder, const CSS::Selector& selector)
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
|
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
|
||||||
pseudo_class_description = "Visited";
|
pseudo_class_description = "Visited";
|
||||||
break;
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoClass::Active:
|
||||||
|
pseudo_class_description = "Active";
|
||||||
|
break;
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::None:
|
case CSS::Selector::SimpleSelector::PseudoClass::None:
|
||||||
pseudo_class_description = "None";
|
pseudo_class_description = "None";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -237,6 +237,7 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt
|
||||||
auto anchor = href.substring_view(1, href.length() - 1);
|
auto anchor = href.substring_view(1, href.length() - 1);
|
||||||
m_frame.scroll_to_anchor(anchor);
|
m_frame.scroll_to_anchor(anchor);
|
||||||
} else {
|
} else {
|
||||||
|
document->set_active_element(link);
|
||||||
if (m_frame.is_top_level()) {
|
if (m_frame.is_top_level()) {
|
||||||
if (auto* page = m_frame.page())
|
if (auto* page = m_frame.page())
|
||||||
page->client().page_did_click_link(url, link->target(), modifiers);
|
page->client().page_did_click_link(url, link->target(), modifiers);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue