2021-04-22 21:11:20 +02:00
/*
2022-09-01 20:50:16 +02:00
* Copyright ( c ) 2021 - 2022 , Andreas Kling < kling @ serenityos . org >
2021-09-26 15:14:37 +01:00
* Copyright ( c ) 2021 , Luke Wilde < lukew @ serenityos . org >
2021-04-22 21:11:20 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-09-25 16:15:49 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2021-04-22 21:11:20 +02:00
# include <LibWeb/DOM/Element.h>
# include <LibWeb/DOM/HTMLCollection.h>
# include <LibWeb/DOM/ParentNode.h>
2021-09-26 15:14:37 +01:00
# include <LibWeb/Namespace.h>
2021-04-22 21:11:20 +02:00
namespace Web : : DOM {
2022-09-01 20:50:16 +02:00
JS : : NonnullGCPtr < HTMLCollection > HTMLCollection : : create ( ParentNode & root , Function < bool ( Element const & ) > filter )
{
2022-12-14 17:40:33 +00:00
return root . heap ( ) . allocate < HTMLCollection > ( root . realm ( ) , root , move ( filter ) ) ;
2022-09-01 20:50:16 +02:00
}
2021-04-22 21:11:20 +02:00
HTMLCollection : : HTMLCollection ( ParentNode & root , Function < bool ( Element const & ) > filter )
2023-01-10 06:56:59 -05:00
: LegacyPlatformObject ( root . realm ( ) )
2022-09-01 20:50:16 +02:00
, m_root ( root )
2021-04-22 21:11:20 +02:00
, m_filter ( move ( filter ) )
{
}
2022-03-14 13:21:51 -06:00
HTMLCollection : : ~ HTMLCollection ( ) = default ;
2021-04-22 21:11:20 +02:00
2023-01-28 12:33:35 -05:00
JS : : ThrowCompletionOr < void > HTMLCollection : : initialize ( JS : : Realm & realm )
2023-01-10 06:56:59 -05:00
{
2023-01-28 12:33:35 -05:00
MUST_OR_THROW_OOM ( Base : : initialize ( realm ) ) ;
2023-01-10 06:56:59 -05:00
set_prototype ( & Bindings : : ensure_web_prototype < Bindings : : HTMLCollectionPrototype > ( realm , " HTMLCollection " ) ) ;
2023-01-28 12:33:35 -05:00
return { } ;
2023-01-10 06:56:59 -05:00
}
2022-09-01 20:50:16 +02:00
void HTMLCollection : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_root . ptr ( ) ) ;
}
2022-08-28 13:42:07 +02:00
JS : : MarkedVector < Element * > HTMLCollection : : collect_matching_elements ( ) const
2021-04-22 21:11:20 +02:00
{
2022-08-28 13:42:07 +02:00
JS : : MarkedVector < Element * > elements ( m_root - > heap ( ) ) ;
2021-04-22 21:11:20 +02:00
m_root - > for_each_in_inclusive_subtree_of_type < Element > ( [ & ] ( auto & element ) {
if ( m_filter ( element ) )
2022-08-28 13:42:07 +02:00
elements . append ( const_cast < Element * > ( & element ) ) ;
2021-04-22 21:11:20 +02:00
return IterationDecision : : Continue ;
} ) ;
return elements ;
}
2021-09-26 15:14:37 +01:00
// https://dom.spec.whatwg.org/#dom-htmlcollection-length
2021-04-22 21:11:20 +02:00
size_t HTMLCollection : : length ( )
{
2021-09-26 15:14:37 +01:00
// The length getter steps are to return the number of nodes represented by the collection.
2021-04-22 21:11:20 +02:00
return collect_matching_elements ( ) . size ( ) ;
}
2021-09-26 15:14:37 +01:00
// https://dom.spec.whatwg.org/#dom-htmlcollection-item
Element * HTMLCollection : : item ( size_t index ) const
2021-04-22 21:11:20 +02:00
{
2021-09-26 15:14:37 +01:00
// The item(index) method steps are to return the indexth element in the collection. If there is no indexth element in the collection, then the method must return null.
2021-04-22 21:11:20 +02:00
auto elements = collect_matching_elements ( ) ;
if ( index > = elements . size ( ) )
return nullptr ;
return elements [ index ] ;
}
2021-09-26 15:14:37 +01:00
// https://dom.spec.whatwg.org/#dom-htmlcollection-nameditem-key
2023-01-08 19:23:00 -05:00
Element * HTMLCollection : : named_item ( DeprecatedFlyString const & name ) const
2021-04-22 21:11:20 +02:00
{
2021-09-26 15:14:37 +01:00
// 1. If key is the empty string, return null.
if ( name . is_empty ( ) )
2021-04-22 21:11:20 +02:00
return nullptr ;
auto elements = collect_matching_elements ( ) ;
2021-09-26 15:14:37 +01:00
// 2. Return the first element in the collection for which at least one of the following is true:
// - it has an ID which is key;
2021-04-22 21:11:20 +02:00
if ( auto it = elements . find_if ( [ & ] ( auto & entry ) { return entry - > attribute ( HTML : : AttributeNames : : id ) = = name ; } ) ; it ! = elements . end ( ) )
return * it ;
2021-09-26 15:14:37 +01:00
// - it is in the HTML namespace and has a name attribute whose value is key;
if ( auto it = elements . find_if ( [ & ] ( auto & entry ) { return entry - > namespace_ ( ) = = Namespace : : HTML & & entry - > name ( ) = = name ; } ) ; it ! = elements . end ( ) )
2021-04-22 21:11:20 +02:00
return * it ;
2021-09-26 15:14:37 +01:00
// or null if there is no such element.
2021-04-22 21:11:20 +02:00
return nullptr ;
}
2021-09-26 15:14:37 +01:00
// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-names
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > HTMLCollection : : supported_property_names ( ) const
2021-09-26 15:14:37 +01:00
{
// 1. Let result be an empty list.
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > result ;
2021-09-26 15:14:37 +01:00
// 2. For each element represented by the collection, in tree order:
auto elements = collect_matching_elements ( ) ;
for ( auto & element : elements ) {
// 1. If element has an ID which is not in result, append element’ s ID to result.
if ( element - > has_attribute ( HTML : : AttributeNames : : id ) ) {
auto id = element - > attribute ( HTML : : AttributeNames : : id ) ;
if ( ! result . contains_slow ( id ) )
result . append ( id ) ;
}
// 2. If element is in the HTML namespace and has a name attribute whose value is neither the empty string nor is in result, append element’ s name attribute value to result.
if ( element - > namespace_ ( ) = = Namespace : : HTML & & element - > has_attribute ( HTML : : AttributeNames : : name ) ) {
auto name = element - > attribute ( HTML : : AttributeNames : : name ) ;
if ( ! name . is_empty ( ) & & ! result . contains_slow ( name ) )
result . append ( name ) ;
}
}
// 3. Return result.
return result ;
}
// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-indices%E2%91%A1
bool HTMLCollection : : is_supported_property_index ( u32 index ) const
{
// The object’ s supported property indices are the numbers in the range zero to one less than the number of elements represented by the collection.
// If there are no such elements, then there are no supported property indices.
auto elements = collect_matching_elements ( ) ;
if ( elements . is_empty ( ) )
return false ;
return index < elements . size ( ) ;
}
2022-09-01 20:50:16 +02:00
JS : : Value HTMLCollection : : item_value ( size_t index ) const
{
auto * element = item ( index ) ;
if ( ! element )
return JS : : js_undefined ( ) ;
return const_cast < Element * > ( element ) ;
}
2023-01-08 19:23:00 -05:00
JS : : Value HTMLCollection : : named_item_value ( DeprecatedFlyString const & index ) const
2022-09-01 20:50:16 +02:00
{
auto * element = named_item ( index ) ;
if ( ! element )
return JS : : js_undefined ( ) ;
return const_cast < Element * > ( element ) ;
}
2021-04-22 21:11:20 +02:00
}