LibWeb: Implement the :open and :closed pseudo-classes

These apply to any elements that have some kind of open/closed state.
The spec suggests `<details>`, `<dialog>`, and `<select>`, so that's
what I've supported here. Only `<details>` is fleshed out right now,
but once the others are, these pseudo-classes should work
automatically. :^)
This commit is contained in:
Sam Atkins 2023-09-13 17:39:05 +01:00 committed by Andreas Kling
parent 29bb0f0ae6
commit 6bf107fc16
4 changed files with 64 additions and 0 deletions

View file

@ -0,0 +1,18 @@
<!doctype html>
<link rel="match" href="reference/css-open-closed-selectors-ref.html" />
<style>
:open {
color: green;
}
:closed {
color: red;
}
</style>
<details open>
<summary>Hi</summary>
Well hello friends!
</details>
<details>
<summary>Hi</summary>
Well hello friends!
</details>

View file

@ -0,0 +1,17 @@
<!doctype html>
<style>
.open {
color: green;
}
.closed {
color: red;
}
</style>
<details open class="open">
<summary>Hi</summary>
Well hello friends!
</details>
<details class="closed">
<summary>Hi</summary>
Well hello friends!
</details>

View file

@ -11,6 +11,9 @@
"checked": {
"argument": ""
},
"closed": {
"argument": ""
},
"defined": {
"argument": ""
},
@ -92,6 +95,9 @@
"only-of-type": {
"argument": ""
},
"open": {
"argument": ""
},
"paused": {
"argument": ""
},

View file

@ -16,6 +16,8 @@
#include <LibWeb/HTML/HTMLAnchorElement.h>
#include <LibWeb/HTML/HTMLAreaElement.h>
#include <LibWeb/HTML/HTMLButtonElement.h>
#include <LibWeb/HTML/HTMLDetailsElement.h>
#include <LibWeb/HTML/HTMLDialogElement.h>
#include <LibWeb/HTML/HTMLFieldSetElement.h>
#include <LibWeb/HTML/HTMLHtmlElement.h>
#include <LibWeb/HTML/HTMLInputElement.h>
@ -238,6 +240,24 @@ static bool matches_read_write_pseudo_class(DOM::Element const& element)
return element.is_editable();
}
// https://www.w3.org/TR/selectors-4/#open-state
static bool matches_open_state_pseudo_class(DOM::Element const& element, bool open)
{
// The :open pseudo-class represents an element that has both “open” and “closed” states,
// and which is currently in the “open” state.
// The :closed pseudo-class represents an element that has both “open” and “closed” states,
// and which is currently in the closed state.
// NOTE: Spec specifically suggests supporting <details>, <dialog>, and <select>.
// There may be others we want to treat as open or closed.
if (is<HTML::HTMLDetailsElement>(element) || is<HTML::HTMLDialogElement>(element))
return open == element.has_attribute(HTML::AttributeNames::open);
if (is<HTML::HTMLSelectElement>(element))
return open == static_cast<HTML::HTMLSelectElement const&>(element).is_open();
return false;
}
static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClassSelector const& pseudo_class, Optional<CSS::CSSStyleSheet const&> style_sheet_for_rule, DOM::Element const& element, JS::GCPtr<DOM::ParentNode const> scope)
{
switch (pseudo_class.type) {
@ -509,6 +529,9 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
// - FIXME: textarea elements that have a placeholder attribute whose value is currently being presented to the user.
return false;
}
case CSS::PseudoClass::Open:
case CSS::PseudoClass::Closed:
return matches_open_state_pseudo_class(element, pseudo_class.type == CSS::PseudoClass::Open);
}
return false;