LibWeb: Add select and option collection set length

This commit is contained in:
Bastiaan van der Plaat 2024-04-08 21:50:35 +02:00 committed by Andreas Kling
parent 4e5ce7b63e
commit 5c277144d8
8 changed files with 95 additions and 5 deletions

View file

@ -7,3 +7,7 @@
7. 45
8. 0
9. 0
10. 3
11. 999
12. 10
13. 10

View file

@ -95,5 +95,45 @@
const select = document.createElement('select');
return select.size;
});
// 10. Use select set length to remove options
testPart(() => {
const select = document.createElement('select');
for (let i = 0; i < 10; i++) {
select.appendChild(document.createElement('option'));
}
select.length = 3;
return select.length;
});
// 11. Use select set length to add options
testPart(() => {
const select = document.createElement('select');
for (let i = 0; i < 10; i++) {
select.appendChild(document.createElement('option'));
}
select.length = 999;
return select.length;
});
// 12. Use select set length to add options with invalid large size
testPart(() => {
const select = document.createElement('select');
for (let i = 0; i < 10; i++) {
select.appendChild(document.createElement('option'));
}
select.length = 100_001;
return select.length;
});
// 13. Use select set length to add options with invalid small size
testPart(() => {
const select = document.createElement('select');
for (let i = 0; i < 10; i++) {
select.appendChild(document.createElement('option'));
}
select.length = -10;
return select.length;
});
});
</script>

View file

@ -5,10 +5,12 @@
*/
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/DOM/ElementFactory.h>
#include <LibWeb/HTML/HTMLOptGroupElement.h>
#include <LibWeb/HTML/HTMLOptionElement.h>
#include <LibWeb/HTML/HTMLOptionsCollection.h>
#include <LibWeb/HTML/HTMLSelectElement.h>
#include <LibWeb/Namespace.h>
#include <LibWeb/WebIDL/DOMException.h>
namespace Web::HTML {
@ -33,6 +35,41 @@ void HTMLOptionsCollection::initialize(JS::Realm& realm)
WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLOptionsCollection);
}
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-length
WebIDL::ExceptionOr<void> HTMLOptionsCollection::set_length(WebIDL::UnsignedLong value)
{
// 1. Let current be the number of nodes represented by the collection.
auto current = static_cast<WebIDL::UnsignedLong>(length());
// 2. If the given value is greater than current, then:
if (value > current) {
// 2.1. If the given value is greater than 100,000, then return.
if (value > 100'000)
return {};
// 2.2. Let n be value current.
auto n = value - current;
// 2.3. Append n new option elements with no attributes and no child nodes to the select element on which this is rooted.
// Mutation events must be fired as if a DocumentFragment containing the new option elements had been inserted.
auto root_element = root();
for (WebIDL::UnsignedLong i = 0; i < n; i++)
TRY(root_element->append_child(TRY(DOM::create_element(root_element->document(), HTML::TagNames::option, Namespace::HTML))));
}
// 3. If the given value is less than current, then:
if (value < current) {
// 3.1. Let n be current value.
auto n = current - value;
// 3.2. Remove the last n nodes in the collection from their parent nodes.
for (WebIDL::UnsignedLong i = current - 1; i >= current - n; i--)
this->item(i)->remove();
}
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

@ -9,6 +9,7 @@
#include <AK/Variant.h>
#include <LibWeb/DOM/HTMLCollection.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
#include <LibWeb/WebIDL/Types.h>
namespace Web::HTML {
@ -23,6 +24,8 @@ public:
[[nodiscard]] static JS::NonnullGCPtr<HTMLOptionsCollection> create(DOM::ParentNode& root, Function<bool(DOM::Element const&)> filter);
virtual ~HTMLOptionsCollection() override;
WebIDL::ExceptionOr<void> set_length(WebIDL::UnsignedLong);
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before = {});
private:

View file

@ -5,7 +5,7 @@
// https://html.spec.whatwg.org/#htmloptionscollection
[Exposed=Window]
interface HTMLOptionsCollection : HTMLCollection {
// [CEReactions] attribute unsigned long length; // shadows inherited length
[CEReactions] attribute unsigned long length; // shadows inherited length
// [CEReactions] setter undefined (unsigned long index, HTMLOptionElement? option);
[CEReactions] undefined add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
// [CEReactions] undefined remove(long index);

View file

@ -100,12 +100,18 @@ JS::GCPtr<HTMLOptionsCollection> const& HTMLSelectElement::options()
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-select-length
size_t HTMLSelectElement::length()
WebIDL::UnsignedLong HTMLSelectElement::length()
{
// The length IDL attribute must return the number of nodes represented by the options collection. On setting, it must act like the attribute of the same name on the options collection.
return const_cast<HTMLOptionsCollection&>(*options()).length();
}
WebIDL::ExceptionOr<void> HTMLSelectElement::set_length(WebIDL::UnsignedLong length)
{
// On setting, it must act like the attribute of the same name on the options collection.
return const_cast<HTMLOptionsCollection&>(*options()).set_length(length);
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-select-item
DOM::Element* HTMLSelectElement::item(size_t index)
{

View file

@ -34,7 +34,8 @@ public:
JS::GCPtr<HTMLOptionsCollection> const& options();
size_t length();
WebIDL::UnsignedLong length();
WebIDL::ExceptionOr<void> set_length(WebIDL::UnsignedLong);
DOM::Element* item(size_t index);
DOM::Element* named_item(FlyString const& name);
WebIDL::ExceptionOr<void> add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before = {});

View file

@ -18,8 +18,7 @@ interface HTMLSelectElement : HTMLElement {
readonly attribute DOMString type;
[SameObject] readonly attribute HTMLOptionsCollection options;
// FIXME: This isn't readonly
[CEReactions] readonly attribute unsigned long length;
[CEReactions] attribute unsigned long length;
// FIXME: Element is really HTMLOptionElement
getter Element? item(unsigned long index);
// FIXME: Element is really HTMLOptionElement