mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 20:42:43 +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
	
	 Paul Irwin
						Paul Irwin