From f4102b1dc99c9bb1ec012106d28a35e03a6faea3 Mon Sep 17 00:00:00 2001 From: Timur Sultanov Date: Thu, 25 Jul 2024 21:13:22 +0400 Subject: [PATCH] LibWeb: Implement selectedness algorithm Implement selectedness setting algorithm in HTMLSelectElement --- .../LibWeb/HTML/HTMLOptionElement.cpp | 7 +- .../Libraries/LibWeb/HTML/HTMLOptionElement.h | 1 + .../LibWeb/HTML/HTMLSelectElement.cpp | 70 +++++++++++++++---- .../Libraries/LibWeb/HTML/HTMLSelectElement.h | 2 + 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp index b7e738c00e8..fc74b0b4383 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp @@ -57,11 +57,16 @@ void HTMLOptionElement::attribute_changed(FlyString const& name, Optional set_value(String const&); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index d7001e33f24..113607f8740 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -135,12 +135,7 @@ WebIDL::ExceptionOr HTMLSelectElement::add(HTMLOptionOrOptGroupElement ele // Similarly, the add(element, before) method must act like its namesake method on that same options collection. TRY(const_cast(*options()).add(move(element), move(before))); - // If the inserted element is the first and only element, mark it as selected - auto options = list_of_options(); - if (options.size() == 1) { - options.at(0)->set_selected(true); - update_inner_text_element(); - } + update_selectedness(); // Not in spec return {}; } @@ -481,14 +476,7 @@ void HTMLSelectElement::form_associated_element_was_inserted() // Wait until children are ready queue_an_element_task(HTML::Task::Source::Microtask, [this] { - // Select first option when no other option is selected - if (selected_index() == -1) { - auto options = list_of_options(); - if (options.size() > 0) { - options.at(0)->set_selected(true); - } - } - update_inner_text_element(); + update_selectedness(); }); } @@ -558,4 +546,58 @@ void HTMLSelectElement::update_inner_text_element() } } } + +// https://html.spec.whatwg.org/multipage/form-elements.html#selectedness-setting-algorithm +void HTMLSelectElement::update_selectedness() +{ + if (has_attribute(AttributeNames::multiple)) + return; + + // If element's multiple attribute is absent, and element's display size is 1, + if (size() == 1) { + bool has_selected_elements = false; + for (auto const& option_element : list_of_options()) { + if (option_element->selected()) { + has_selected_elements = true; + break; + } + } + + // and no option elements in the element's list of options have their selectedness set to true, + if (!has_selected_elements) { + // then set the selectedness of the first option element in the list of options in tree order + // that is not disabled, if any, to true, and return. + for (auto const& option_element : list_of_options()) { + if (!option_element->disabled()) { + option_element->set_selected_internal(true); + update_inner_text_element(); + return; + } + } + } + } + + // If element's multiple attribute is absent, + // and two or more option elements in element's list of options have their selectedness set to true, + // then set the selectedness of all but the last option element with its selectedness set to true + // in the list of options in tree order to false. + int number_of_selected = 0; + for (auto const& option_element : list_of_options()) { + if (option_element->selected()) + ++number_of_selected; + } + // and two or more option elements in element's list of options have their selectedness set to true, + if (number_of_selected >= 2) { + // then set the selectedness of all but the last option element with its selectedness set to true + // in the list of options in tree order to false. + for (auto const& option_element : list_of_options()) { + if (number_of_selected == 1) { + break; + } + option_element->set_selected_internal(false); + --number_of_selected; + } + } + update_inner_text_element(); +} } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h index dd12a73d243..9afd1ad86e8 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h @@ -92,6 +92,8 @@ public: void did_select_item(Optional const& id); + void update_selectedness(); + private: HTMLSelectElement(DOM::Document&, DOM::QualifiedName);