mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-30 04:39:06 +00:00
LibWeb: Implement the :default pseudo-class
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This commit is contained in:
parent
7acc0f4a42
commit
3fe148f2d4
Notes:
github-actions[bot]
2025-05-24 09:32:32 +00:00
Author: https://github.com/Gingeh
Commit: 3fe148f2d4
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4838
Reviewed-by: https://github.com/AtkinsSJ ✅
9 changed files with 115 additions and 3 deletions
|
@ -11,6 +11,9 @@
|
||||||
"checked": {
|
"checked": {
|
||||||
"argument": ""
|
"argument": ""
|
||||||
},
|
},
|
||||||
|
"default": {
|
||||||
|
"argument": ""
|
||||||
|
},
|
||||||
"defined": {
|
"defined": {
|
||||||
"argument": ""
|
"argument": ""
|
||||||
},
|
},
|
||||||
|
|
|
@ -1037,6 +1037,29 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case CSS::PseudoClass::Default: {
|
||||||
|
// https://html.spec.whatwg.org/multipage/semantics-other.html#selector-default
|
||||||
|
|
||||||
|
// The :default pseudo-class must match any element falling into one of the following categories:
|
||||||
|
if (auto const* form_associated_element = as_if<Web::HTML::FormAssociatedElement>(element)) {
|
||||||
|
// - Submit buttons that are default buttons of their form owner.
|
||||||
|
if (form_associated_element->is_submit_button() && form_associated_element->form() && form_associated_element->form()->default_button() == form_associated_element)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// - input elements to which the checked attribute applies and that have a checked attribute
|
||||||
|
if (auto const* input_element = as_if<Web::HTML::HTMLInputElement>(form_associated_element)) {
|
||||||
|
if (input_element->checked_applies() && input_element->has_attribute(HTML::AttributeNames::checked))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// - option elements that have a selected attribute
|
||||||
|
else if (auto const* option_element = as_if<Web::HTML::HTMLOptionElement>(element)) {
|
||||||
|
if (option_element->has_attribute(HTML::AttributeNames::selected))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -75,6 +75,7 @@ static void collect_properties_used_in_has(Selector::SimpleSelector const& selec
|
||||||
case PseudoClass::Link:
|
case PseudoClass::Link:
|
||||||
case PseudoClass::AnyLink:
|
case PseudoClass::AnyLink:
|
||||||
case PseudoClass::LocalLink:
|
case PseudoClass::LocalLink:
|
||||||
|
case PseudoClass::Default:
|
||||||
if (in_has)
|
if (in_has)
|
||||||
style_invalidation_data.pseudo_classes_used_in_has_selectors.set(pseudo_class.type);
|
style_invalidation_data.pseudo_classes_used_in_has_selectors.set(pseudo_class.type);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1176,13 +1176,13 @@ JS::Value HTMLFormElement::named_item_value(FlyString const& name) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#default-button
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#default-button
|
||||||
FormAssociatedElement* HTMLFormElement::default_button()
|
FormAssociatedElement* HTMLFormElement::default_button() const
|
||||||
{
|
{
|
||||||
// A form element's default button is the first submit button in tree order whose form owner is that form element.
|
// A form element's default button is the first submit button in tree order whose form owner is that form element.
|
||||||
FormAssociatedElement* default_button = nullptr;
|
FormAssociatedElement* default_button = nullptr;
|
||||||
|
|
||||||
root().for_each_in_subtree([&](auto& node) {
|
root().for_each_in_subtree([&](auto& node) {
|
||||||
auto* form_associated_element = dynamic_cast<FormAssociatedElement*>(&node);
|
auto* form_associated_element = const_cast<FormAssociatedElement*>(dynamic_cast<FormAssociatedElement const*>(&node));
|
||||||
if (!form_associated_element)
|
if (!form_associated_element)
|
||||||
return TraversalDecision::Continue;
|
return TraversalDecision::Continue;
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,8 @@ public:
|
||||||
String action() const;
|
String action() const;
|
||||||
WebIDL::ExceptionOr<void> set_action(String const&);
|
WebIDL::ExceptionOr<void> set_action(String const&);
|
||||||
|
|
||||||
|
FormAssociatedElement* default_button() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HTMLFormElement(DOM::Document&, DOM::QualifiedName);
|
HTMLFormElement(DOM::Document&, DOM::QualifiedName);
|
||||||
|
|
||||||
|
@ -126,7 +128,6 @@ private:
|
||||||
ErrorOr<void> mail_as_body(URL::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, EncodingTypeAttributeState encoding_type, String encoding, GC::Ref<Navigable> target_navigable, Bindings::NavigationHistoryBehavior history_handling, UserNavigationInvolvement user_involvement);
|
ErrorOr<void> mail_as_body(URL::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, EncodingTypeAttributeState encoding_type, String encoding, GC::Ref<Navigable> target_navigable, Bindings::NavigationHistoryBehavior history_handling, UserNavigationInvolvement user_involvement);
|
||||||
void plan_to_navigate_to(URL::URL url, Variant<Empty, String, POSTResource> post_resource, Vector<XHR::FormDataEntry> entry_list, GC::Ref<Navigable> target_navigable, Bindings::NavigationHistoryBehavior history_handling, UserNavigationInvolvement user_involvement);
|
void plan_to_navigate_to(URL::URL url, Variant<Empty, String, POSTResource> post_resource, Vector<XHR::FormDataEntry> entry_list, GC::Ref<Navigable> target_navigable, Bindings::NavigationHistoryBehavior history_handling, UserNavigationInvolvement user_involvement);
|
||||||
|
|
||||||
FormAssociatedElement* default_button();
|
|
||||||
size_t number_of_fields_blocking_implicit_submission() const;
|
size_t number_of_fields_blocking_implicit_submission() const;
|
||||||
|
|
||||||
bool m_firing_submission_events { false };
|
bool m_firing_submission_events { false };
|
||||||
|
|
|
@ -3027,6 +3027,18 @@ bool HTMLInputElement::required_applies() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/input.html#do-not-apply
|
||||||
|
bool HTMLInputElement::checked_applies() const
|
||||||
|
{
|
||||||
|
switch (type_state()) {
|
||||||
|
case TypeAttributeState::Checkbox:
|
||||||
|
case TypeAttributeState::RadioButton:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool HTMLInputElement::has_selectable_text() const
|
bool HTMLInputElement::has_selectable_text() const
|
||||||
{
|
{
|
||||||
// Potential FIXME: Date, Month, Week, Time and LocalDateAndTime are rendered as a basic text input for now,
|
// Potential FIXME: Date, Month, Week, Time and LocalDateAndTime are rendered as a basic text input for now,
|
||||||
|
|
|
@ -220,6 +220,7 @@ public:
|
||||||
bool pattern_applies() const;
|
bool pattern_applies() const;
|
||||||
bool multiple_applies() const;
|
bool multiple_applies() const;
|
||||||
bool required_applies() const;
|
bool required_applies() const;
|
||||||
|
bool checked_applies() const;
|
||||||
bool has_selectable_text() const;
|
bool has_selectable_text() const;
|
||||||
|
|
||||||
bool supports_a_picker() const;
|
bool supports_a_picker() const;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 2 tests
|
||||||
|
|
||||||
|
2 Pass
|
||||||
|
Pass ':default' matches <button>s that are their form's default button, <input>s of type submit/image that are their form's default button, checked <input>s and selected <option>s
|
||||||
|
Pass ':default' matches dynamically changed form's default buttons
|
|
@ -0,0 +1,64 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>Selector: pseudo-classes (:default)</title>
|
||||||
|
<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org" id=link1>
|
||||||
|
<link rel=help href="https://html.spec.whatwg.org/multipage/#pseudo-classes" id=link2>
|
||||||
|
<script src="../../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="utils.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<form>
|
||||||
|
<button id=button1 type=button>button1</button>
|
||||||
|
<button id=button2 type=submit>button2</button>
|
||||||
|
</form>
|
||||||
|
<form>
|
||||||
|
<button id=button3 type=reset>button3</button>
|
||||||
|
<button id=button4>button4</button>
|
||||||
|
</form>
|
||||||
|
<button id=button5 type=submit>button5</button>
|
||||||
|
<form id=form1>
|
||||||
|
<input type=text id=input1>
|
||||||
|
</form>
|
||||||
|
<input type=text id=input2 form=form1>
|
||||||
|
<form>
|
||||||
|
<input type=submit id=input3>
|
||||||
|
<input type=submit id=input4>
|
||||||
|
</form>
|
||||||
|
<form>
|
||||||
|
<input type=image id=input5>
|
||||||
|
<input type=image id=input6>
|
||||||
|
</form>
|
||||||
|
<form>
|
||||||
|
<input type=submit id=input7>
|
||||||
|
</form>
|
||||||
|
<input type=checkbox id=checkbox1 checked>
|
||||||
|
<input type=checkbox id=checkbox2>
|
||||||
|
<input type=checkbox id=checkbox3 default>
|
||||||
|
<input type=radio name=radios id=radio1 checked>
|
||||||
|
<input type=radio name=radios id=radio2>
|
||||||
|
<input type=radio name=radios id=radio3 default>
|
||||||
|
<select id=select1>
|
||||||
|
<optgroup label="options" id=optgroup1>
|
||||||
|
<option value="option1" id=option1>option1
|
||||||
|
<option value="option2" id=option2 selected>option2
|
||||||
|
</select>
|
||||||
|
<dialog id="dialog">
|
||||||
|
<input type=submit id=input8>
|
||||||
|
</dialog>
|
||||||
|
<form>
|
||||||
|
<button id=button6 type='invalid'>button6</button>
|
||||||
|
<button id=button7>button7</button>
|
||||||
|
</form>
|
||||||
|
<form>
|
||||||
|
<button id=button8>button8</button>
|
||||||
|
<button id=button9>button9</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
testSelectorIdsMatch(":default", ["button2", "button4", "input3", "input5", "input7", "checkbox1", "radio1", "option2", "button6", "button8"], "':default' matches <button>s that are their form's default button, <input>s of type submit/image that are their form's default button, checked <input>s and selected <option>s");
|
||||||
|
|
||||||
|
document.getElementById("button1").type = "submit"; // change the form's default button
|
||||||
|
testSelectorIdsMatch(":default", ["button1", "button4", "input3", "input5", "input7", "checkbox1", "radio1", "option2", "button6", "button8"], "':default' matches dynamically changed form's default buttons");
|
||||||
|
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue