From 99824eae142b02c7bce84b9e98d10fc6428f31fe Mon Sep 17 00:00:00 2001 From: Colin Reeder Date: Sun, 14 Jul 2024 15:24:02 -0600 Subject: [PATCH] LibWeb: Add support for indexed setter of HTMLOptionsCollection --- Tests/LibWeb/Ref/options-set-index.html | 7 +++ .../Ref/reference/options-set-index.html | 1 + .../Text/expected/select-options-limit.txt | 1 + .../Text/input/select-options-limit.html | 11 +++++ .../LibWeb/HTML/HTMLOptionsCollection.cpp | 48 +++++++++++++++++++ .../LibWeb/HTML/HTMLOptionsCollection.h | 2 + 6 files changed, 70 insertions(+) create mode 100644 Tests/LibWeb/Ref/options-set-index.html create mode 100644 Tests/LibWeb/Ref/reference/options-set-index.html create mode 100644 Tests/LibWeb/Text/expected/select-options-limit.txt create mode 100644 Tests/LibWeb/Text/input/select-options-limit.html diff --git a/Tests/LibWeb/Ref/options-set-index.html b/Tests/LibWeb/Ref/options-set-index.html new file mode 100644 index 00000000000..7c1efb233f9 --- /dev/null +++ b/Tests/LibWeb/Ref/options-set-index.html @@ -0,0 +1,7 @@ + + + diff --git a/Tests/LibWeb/Ref/reference/options-set-index.html b/Tests/LibWeb/Ref/reference/options-set-index.html new file mode 100644 index 00000000000..f2530448d2d --- /dev/null +++ b/Tests/LibWeb/Ref/reference/options-set-index.html @@ -0,0 +1 @@ + diff --git a/Tests/LibWeb/Text/expected/select-options-limit.txt b/Tests/LibWeb/Text/expected/select-options-limit.txt new file mode 100644 index 00000000000..f01f4b30e1f --- /dev/null +++ b/Tests/LibWeb/Text/expected/select-options-limit.txt @@ -0,0 +1 @@ + 0 diff --git a/Tests/LibWeb/Text/input/select-options-limit.html b/Tests/LibWeb/Text/input/select-options-limit.html new file mode 100644 index 00000000000..61d131d737b --- /dev/null +++ b/Tests/LibWeb/Text/input/select-options-limit.html @@ -0,0 +1,11 @@ + + + + diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp index 48b2eff472d..2009332cbcf 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp @@ -26,6 +26,8 @@ JS::NonnullGCPtr HTMLOptionsCollection::create(DOM::Paren HTMLOptionsCollection::HTMLOptionsCollection(DOM::ParentNode& root, Function filter) : DOM::HTMLCollection(root, Scope::Descendants, move(filter)) { + m_legacy_platform_object_flags->has_indexed_property_setter = true; + m_legacy_platform_object_flags->indexed_property_setter_has_identifier = true; } HTMLOptionsCollection::~HTMLOptionsCollection() = default; @@ -71,6 +73,52 @@ WebIDL::ExceptionOr HTMLOptionsCollection::set_length(WebIDL::UnsignedLong return {}; } +// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-setter +WebIDL::ExceptionOr HTMLOptionsCollection::set_value_of_indexed_property(u32 index, JS::Value unconverted_option) +{ + // The spec doesn't seem to require this, but it's consistent with length handling and other browsers + if (index >= 100'000) { + return {}; + } + + // 1. If value is null, invoke the steps for the remove method with index as the argument, and return. + if (unconverted_option.is_null()) { + remove(static_cast(index)); + return {}; + } + + if (!unconverted_option.is_object() || !is(unconverted_option.as_object())) { + return WebIDL::TypeMismatchError::create(realm(), "The value provided is not an HTMLOptionElement"_fly_string); + } + + auto& option = static_cast(unconverted_option.as_object()); + + // 2. Let length be the number of nodes represented by the collection. + auto length = this->length(); + + auto root_element = root(); + + if (index >= length) { + // 3. Let n be index minus length. + auto n = index - length; + + // 4. If n is greater than zero, then append a DocumentFragment consisting of n-1 new option elements with no attributes and no child nodes to the select element on which the HTMLOptionsCollection is rooted. + if (n > 0) { + for (WebIDL::UnsignedLong i = 0; i < n - 1; i++) { + TRY(root_element->append_child(TRY(DOM::create_element(root_element->document(), HTML::TagNames::option, Namespace::HTML)))); + } + } + + // 5. If n is greater than or equal to zero, append value to the select element. + TRY(root_element->append_child(option)); + } else { + // 5 (cont). Otherwise, replace the indexth element in the collection by value. + TRY(root_element->replace_child(option, *item(index))); + } + + return {}; +} + // https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-add WebIDL::ExceptionOr HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, Optional before) { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h index 68b97dde8e4..6d95d5f744b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h @@ -24,6 +24,8 @@ public: [[nodiscard]] static JS::NonnullGCPtr create(DOM::ParentNode& root, ESCAPING Function filter); virtual ~HTMLOptionsCollection() override; + WebIDL::ExceptionOr set_value_of_indexed_property(u32, JS::Value) override; + WebIDL::ExceptionOr set_length(WebIDL::UnsignedLong); WebIDL::ExceptionOr add(HTMLOptionOrOptGroupElement element, Optional before = {});