LibWeb: Add support for indexed setter of HTMLOptionsCollection

This commit is contained in:
Colin Reeder 2024-07-14 15:24:02 -06:00 committed by Tim Ledbetter
commit 99824eae14
Notes: sideshowbarker 2024-07-17 08:25:15 +09:00
6 changed files with 70 additions and 0 deletions

View file

@ -0,0 +1,7 @@
<link rel="match" href="reference/options-set-index.html" />
<select id="select"></select>
<script>
const select = document.getElementById("select");
select.options[0] = new Option("text");
select.value = "text";
</script>

View file

@ -0,0 +1 @@
<select><option>text</option></select>

View file

@ -0,0 +1 @@
0

View file

@ -0,0 +1,11 @@
<select id="select"></select>
<script src="include.js"></script>
<script>
test(() => {
const select = document.getElementById("select");
select.options[100000] = new Option("0");
println(select.options.length);
});
</script>

View file

@ -26,6 +26,8 @@ JS::NonnullGCPtr<HTMLOptionsCollection> HTMLOptionsCollection::create(DOM::Paren
HTMLOptionsCollection::HTMLOptionsCollection(DOM::ParentNode& root, Function<bool(DOM::Element const&)> 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<void> HTMLOptionsCollection::set_length(WebIDL::UnsignedLong
return {};
}
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-setter
WebIDL::ExceptionOr<void> 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<WebIDL::Long>(index));
return {};
}
if (!unconverted_option.is_object() || !is<HTMLOptionElement>(unconverted_option.as_object())) {
return WebIDL::TypeMismatchError::create(realm(), "The value provided is not an HTMLOptionElement"_fly_string);
}
auto& option = static_cast<HTMLOptionElement&>(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<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before)
{

View file

@ -24,6 +24,8 @@ public:
[[nodiscard]] static JS::NonnullGCPtr<HTMLOptionsCollection> create(DOM::ParentNode& root, ESCAPING Function<bool(DOM::Element const&)> filter);
virtual ~HTMLOptionsCollection() override;
WebIDL::ExceptionOr<void> set_value_of_indexed_property(u32, JS::Value) override;
WebIDL::ExceptionOr<void> set_length(WebIDL::UnsignedLong);
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before = {});