2022-03-16 12:58:28 +01:00
/*
* Copyright ( c ) 2022 , the SerenityOS developers .
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-09-25 16:38:21 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2024-04-08 21:50:35 +02:00
# include <LibWeb/DOM/ElementFactory.h>
2022-03-21 20:02:40 -04:00
# include <LibWeb/HTML/HTMLOptGroupElement.h>
# include <LibWeb/HTML/HTMLOptionElement.h>
2022-03-16 12:58:28 +01:00
# include <LibWeb/HTML/HTMLOptionsCollection.h>
2022-03-21 20:02:40 -04:00
# include <LibWeb/HTML/HTMLSelectElement.h>
2024-04-08 21:50:35 +02:00
# include <LibWeb/Namespace.h>
2022-09-25 17:28:46 +01:00
# include <LibWeb/WebIDL/DOMException.h>
2022-03-16 12:58:28 +01:00
namespace Web : : HTML {
2023-11-19 19:47:52 +01:00
JS_DEFINE_ALLOCATOR ( HTMLOptionsCollection ) ;
2023-08-13 13:05:26 +02:00
JS : : NonnullGCPtr < HTMLOptionsCollection > HTMLOptionsCollection : : create ( DOM : : ParentNode & root , Function < bool ( DOM : : Element const & ) > filter )
2022-09-01 20:50:16 +02:00
{
2023-08-13 13:05:26 +02:00
return root . heap ( ) . allocate < HTMLOptionsCollection > ( root . realm ( ) , root , move ( filter ) ) ;
2022-09-01 20:50:16 +02:00
}
2022-03-16 12:58:28 +01:00
HTMLOptionsCollection : : HTMLOptionsCollection ( DOM : : ParentNode & root , Function < bool ( DOM : : Element const & ) > filter )
2023-05-23 11:25:07 +02:00
: DOM : : HTMLCollection ( root , Scope : : Descendants , move ( filter ) )
2022-03-16 12:58:28 +01:00
{
}
2022-09-01 20:50:16 +02:00
HTMLOptionsCollection : : ~ HTMLOptionsCollection ( ) = default ;
2023-08-07 08:41:28 +02:00
void HTMLOptionsCollection : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( HTMLOptionsCollection ) ;
2023-01-10 06:28:20 -05:00
}
2024-04-08 21:50:35 +02:00
// 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 { } ;
}
2022-03-21 20:02:40 -04:00
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-add
2022-09-25 17:03:42 +01:00
WebIDL : : ExceptionOr < void > HTMLOptionsCollection : : add ( HTMLOptionOrOptGroupElement element , Optional < HTMLElementOrElementIndex > before )
2022-03-21 20:02:40 -04:00
{
2022-08-28 13:42:07 +02:00
auto resolved_element = element . visit (
[ ] ( auto & e ) - > JS : : Handle < HTMLElement > {
return JS : : make_handle ( static_cast < HTML : : HTMLElement & > ( * e ) ) ;
} ) ;
2022-03-21 20:02:40 -04:00
2022-08-28 13:42:07 +02:00
JS : : GCPtr < DOM : : Node > before_element ;
if ( before . has_value ( ) & & before - > has < JS : : Handle < HTMLElement > > ( ) )
before_element = before - > get < JS : : Handle < HTMLElement > > ( ) . ptr ( ) ;
2022-03-21 20:02:40 -04:00
// 1. If element is an ancestor of the select element on which the HTMLOptionsCollection is rooted, then throw a "HierarchyRequestError" DOMException.
if ( resolved_element - > is_ancestor_of ( root ( ) ) )
2023-09-06 16:03:01 +12:00
return WebIDL : : HierarchyRequestError : : create ( realm ( ) , " The provided element is an ancestor of the root select element. " _fly_string ) ;
2022-03-21 20:02:40 -04:00
// 2. If before is an element, but that element isn't a descendant of the select element on which the HTMLOptionsCollection is rooted, then throw a "NotFoundError" DOMException.
if ( before_element & & ! before_element - > is_descendant_of ( root ( ) ) )
2023-09-06 16:03:01 +12:00
return WebIDL : : NotFoundError : : create ( realm ( ) , " The 'before' element is not a descendant of the root select element. " _fly_string ) ;
2022-03-21 20:02:40 -04:00
// 3. If element and before are the same element, then return.
if ( before_element & & ( resolved_element . ptr ( ) = = before_element . ptr ( ) ) )
return { } ;
// 4. If before is a node, then let reference be that node. Otherwise, if before is an integer, and there is a beforeth node in the collection, let reference be that node. Otherwise, let reference be null.
2022-08-28 13:42:07 +02:00
JS : : GCPtr < DOM : : Node > reference ;
2022-03-21 20:02:40 -04:00
if ( before_element )
reference = move ( before_element ) ;
else if ( before . has_value ( ) & & before - > has < i32 > ( ) )
reference = item ( before - > get < i32 > ( ) ) ;
// 5. If reference is not null, let parent be the parent node of reference. Otherwise, let parent be the select element on which the HTMLOptionsCollection is rooted.
DOM : : Node * parent = reference ? reference - > parent ( ) : root ( ) . ptr ( ) ;
// 6. Pre-insert element into parent node before reference.
2022-08-28 13:42:07 +02:00
( void ) TRY ( parent - > pre_insert ( * resolved_element , reference ) ) ;
2022-03-21 20:02:40 -04:00
return { } ;
}
2024-04-08 21:56:33 +02:00
// https://html.spec.whatwg.org/#dom-htmloptionscollection-remove
void HTMLOptionsCollection : : remove ( WebIDL : : Long index )
{
// 1. If the number of nodes represented by the collection is zero, return.
if ( length ( ) = = 0 )
return ;
// 2. If index is not a number greater than or equal to 0 and less than the number of nodes represented by the collection, return.
if ( index < 0 | | static_cast < WebIDL : : UnsignedLong > ( index ) > = length ( ) )
return ;
// 3. Let element be the indexth element in the collection.
auto * element = this - > item ( index ) ;
// 4. Remove element from its parent node.
element - > remove ( ) ;
}
2024-04-08 21:53:22 +02:00
// https://html.spec.whatwg.org/#dom-htmloptionscollection-selectedindex
WebIDL : : Long HTMLOptionsCollection : : selected_index ( ) const
{
// The selectedIndex IDL attribute must act like the identically named attribute
// on the select element on which the HTMLOptionsCollection is rooted.
return verify_cast < HTMLSelectElement > ( * root ( ) ) . selected_index ( ) ;
}
void HTMLOptionsCollection : : set_selected_index ( WebIDL : : Long index )
{
verify_cast < HTMLSelectElement > ( * root ( ) ) . set_selected_index ( index ) ;
}
2022-03-16 12:58:28 +01:00
}