From 6f84f69677c923b765e49346775a274b1a9a6da0 Mon Sep 17 00:00:00 2001 From: Bastiaan van der Plaat Date: Mon, 8 Apr 2024 21:58:39 +0200 Subject: [PATCH] LibWeb: Add select selected options collection getter --- Tests/LibWeb/Text/expected/select.txt | 1 + Tests/LibWeb/Text/input/select.html | 13 ++++++++++ .../LibWeb/HTML/HTMLSelectElement.cpp | 24 ++++++++++++++++--- .../Libraries/LibWeb/HTML/HTMLSelectElement.h | 7 ++++-- .../LibWeb/HTML/HTMLSelectElement.idl | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Tests/LibWeb/Text/expected/select.txt b/Tests/LibWeb/Text/expected/select.txt index 93409b847f5..d381c1eec5a 100644 --- a/Tests/LibWeb/Text/expected/select.txt +++ b/Tests/LibWeb/Text/expected/select.txt @@ -14,3 +14,4 @@ 14. "5 5" 15. 8 16. 10 +17. "2" diff --git a/Tests/LibWeb/Text/input/select.html b/Tests/LibWeb/Text/input/select.html index a6a24bd786f..b9ddf9edaa7 100644 --- a/Tests/LibWeb/Text/input/select.html +++ b/Tests/LibWeb/Text/input/select.html @@ -168,5 +168,18 @@ select.options.remove(11); return select.length; }); + + // 17. Get selected selected options + testPart(() => { + const select = document.createElement('select'); + for (let i = 0; i < 10; i++) { + const option = document.createElement('option'); + option.textContent = i; + if (i == 5) option.selected = true; + select.appendChild(option); + } + select.options[2].selected = true; + return select.selectedOptions[0].textContent; + }); }); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index b1a16e40338..8d423dfef07 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -45,6 +45,7 @@ void HTMLSelectElement::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_options); + visitor.visit(m_selected_options); visitor.visit(m_inner_text_element); visitor.visit(m_chevron_icon_element); @@ -146,6 +147,23 @@ void HTMLSelectElement::remove(WebIDL::Long index) const_cast(*options()).remove(index); } +// https://html.spec.whatwg.org/multipage/form-elements.html#dom-select-selectedoptions +JS::NonnullGCPtr HTMLSelectElement::selected_options() +{ + // The selectedOptions IDL attribute must return an HTMLCollection rooted at the select node, + // whose filter matches the elements in the list of options that have their selectedness set to true. + if (!m_selected_options) { + m_selected_options = DOM::HTMLCollection::create(*this, DOM::HTMLCollection::Scope::Descendants, [](Element const& element) { + if (is(element)) { + auto const& option_element = verify_cast(element); + return option_element.selected(); + } + return false; + }); + } + return *m_selected_options; +} + // https://html.spec.whatwg.org/multipage/form-elements.html#concept-select-option-list Vector> HTMLSelectElement::list_of_options() const { @@ -181,12 +199,12 @@ void HTMLSelectElement::reset_algorithm() } // https://html.spec.whatwg.org/multipage/form-elements.html#dom-select-selectedindex -int HTMLSelectElement::selected_index() const +WebIDL::Long HTMLSelectElement::selected_index() const { // The selectedIndex IDL attribute, on getting, must return the index of the first option element in the list of options // in tree order that has its selectedness set to true, if any. If there isn't one, then it must return −1. - int index = 0; + WebIDL::Long index = 0; for (auto const& option_element : list_of_options()) { if (option_element->selected()) return index; @@ -195,7 +213,7 @@ int HTMLSelectElement::selected_index() const return -1; } -void HTMLSelectElement::set_selected_index(int index) +void HTMLSelectElement::set_selected_index(WebIDL::Long index) { // On setting, the selectedIndex attribute must set the selectedness of all the option elements in the list of options to false, // and then the option element in the list of options whose index is the given new value, diff --git a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h index 95ffe5ad7f7..819e174c2d2 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h @@ -42,8 +42,10 @@ public: void remove(); void remove(WebIDL::Long); - int selected_index() const; - void set_selected_index(int); + JS::NonnullGCPtr selected_options(); + + WebIDL::Long selected_index() const; + void set_selected_index(WebIDL::Long); virtual String value() const override; WebIDL::ExceptionOr set_value(String const&); @@ -104,6 +106,7 @@ private: void queue_input_and_change_events(); JS::GCPtr m_options; + JS::GCPtr m_selected_options; bool m_is_open { false }; Vector m_select_items; JS::GCPtr m_inner_text_element; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.idl index 52bbb71192f..d512e769fcf 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.idl +++ b/Userland/Libraries/LibWeb/HTML/HTMLSelectElement.idl @@ -28,7 +28,7 @@ interface HTMLSelectElement : HTMLElement { [CEReactions] undefined remove(long index); // FIXME: [CEReactions] setter undefined (unsigned long index, HTMLOptionElement? option); - // FIXME: [SameObject] readonly attribute HTMLCollection selectedOptions; + [SameObject] readonly attribute HTMLCollection selectedOptions; attribute long selectedIndex; attribute DOMString value;