diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index 265b8df8aa..1752676817 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -222,17 +222,13 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla case CSS::Selector::SimpleSelector::PseudoClass::Type::Lang: return matches_lang_pseudo_class(element, pseudo_class.languages); case CSS::Selector::SimpleSelector::PseudoClass::Type::Disabled: - if (!is(element)) - return false; - if (!element.has_attribute(HTML::AttributeNames::disabled)) - return false; - return true; + // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-disabled + // The :disabled pseudo-class must match any element that is actually disabled. + return element.is_actually_disabled(); case CSS::Selector::SimpleSelector::PseudoClass::Type::Enabled: - if (!is(element)) - return false; - if (element.has_attribute(HTML::AttributeNames::disabled)) - return false; - return true; + // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-enabled + // The :enabled pseudo-class must match any button, input, select, textarea, optgroup, option, fieldset element, or form-associated custom element that is not actually disabled. + return !element.is_actually_disabled(); case CSS::Selector::SimpleSelector::PseudoClass::Type::Checked: return matches_checked_pseudo_class(element); case CSS::Selector::SimpleSelector::PseudoClass::Type::Is: diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index dd9461e574..b9d8a62d9c 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -24,7 +24,15 @@ #include #include #include +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include #include @@ -728,6 +736,37 @@ void Element::serialize_pseudo_elements_as_json(JsonArraySerializer(this) || is(this) || is(this) || is(this)) { + auto const* form_associated_element = dynamic_cast(this); + VERIFY(form_associated_element); + + return !form_associated_element->enabled(); + } + + // - an optgroup element that has a disabled attribute + if (is(this)) + return has_attribute(HTML::AttributeNames::disabled); + + // - an option element that is disabled + if (is(this)) + return static_cast(*this).disabled(); + + // - a fieldset element that is a disabled fieldset + if (is(this)) + return static_cast(*this).is_disabled(); + + // FIXME: - a form-associated custom element that is disabled + return false; +} + // https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml WebIDL::ExceptionOr Element::insert_adjacent_html(String position, String text) { diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index d7d77f2c4e..451dc3daea 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -142,6 +142,8 @@ public: void clear_pseudo_element_nodes(Badge); void serialize_pseudo_elements_as_json(JsonArraySerializer& children_array) const; + bool is_actually_disabled() const; + protected: Element(Document&, DOM::QualifiedName); virtual void initialize(JS::Realm&) override; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.cpp index 4090cb0c07..ece4176a8d 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.cpp @@ -5,6 +5,7 @@ */ #include +#include #include namespace Web::HTML { @@ -16,4 +17,25 @@ HTMLFieldSetElement::HTMLFieldSetElement(DOM::Document& document, DOM::Qualified } HTMLFieldSetElement::~HTMLFieldSetElement() = default; + +// https://html.spec.whatwg.org/multipage/form-elements.html#concept-fieldset-disabled +bool HTMLFieldSetElement::is_disabled() const +{ + // A fieldset element is a disabled fieldset if it matches any of the following conditions: + // - Its disabled attribute is specified + if (has_attribute(AttributeNames::disabled)) + return true; + + // - It is a descendant of another fieldset element whose disabled attribute is specified, and is not a descendant of that fieldset element's first legend element child, if any. + for (auto* fieldset_ancestor = first_ancestor_of_type(); fieldset_ancestor; fieldset_ancestor = fieldset_ancestor->first_ancestor_of_type()) { + if (fieldset_ancestor->has_attribute(HTML::AttributeNames::disabled)) { + auto* first_legend_element_child = fieldset_ancestor->first_child_of_type(); + if (!first_legend_element_child || !is_descendant_of(*first_legend_element_child)) + return true; + } + } + + return false; +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.h b/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.h index 39f971cd65..0619f9350e 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLFieldSetElement.h @@ -26,6 +26,8 @@ public: return fieldset; } + bool is_disabled() const; + // ^FormAssociatedElement // https://html.spec.whatwg.org/multipage/forms.html#category-listed virtual bool is_listed() const override { return true; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp index 2c9ffd9594..56555d0cdb 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -156,4 +157,12 @@ void HTMLOptionElement::ask_for_a_reset() // FIXME: Implement this operation. } +// https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-disabled +bool HTMLOptionElement::disabled() const +{ + // An option element is disabled if its disabled attribute is present or if it is a child of an optgroup element whose disabled attribute is present. + return has_attribute(AttributeNames::disabled) + || (parent() && is(parent()) && static_cast(*parent()).has_attribute(AttributeNames::disabled)); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.h b/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.h index 836ca42190..86eab9a942 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.h @@ -28,6 +28,8 @@ public: int index() const; + bool disabled() const; + private: friend class Bindings::OptionConstructor; friend class HTMLSelectElement;