2021-04-22 22:11:20 +03:00
/*
2022-09-01 21:50:16 +03:00
* Copyright ( c ) 2021 - 2022 , Andreas Kling < kling @ serenityos . org >
2021-09-26 17:14:37 +03:00
* Copyright ( c ) 2021 , Luke Wilde < lukew @ serenityos . org >
2021-04-22 22:11:20 +03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-09-26 01:15:49 +03:00
# include <LibWeb/Bindings/Intrinsics.h>
2021-04-22 22:11:20 +03:00
# include <LibWeb/DOM/Element.h>
# include <LibWeb/DOM/HTMLCollection.h>
# include <LibWeb/DOM/ParentNode.h>
2021-09-26 17:14:37 +03:00
# include <LibWeb/Namespace.h>
2021-04-22 22:11:20 +03:00
namespace Web : : DOM {
2023-05-23 12:25:07 +03:00
WebIDL : : ExceptionOr < JS : : NonnullGCPtr < HTMLCollection > > HTMLCollection : : create ( ParentNode & root , Scope scope , Function < bool ( Element const & ) > filter )
2022-09-01 21:50:16 +03:00
{
2023-05-23 12:25:07 +03:00
return MUST_OR_THROW_OOM ( root . heap ( ) . allocate < HTMLCollection > ( root . realm ( ) , root , scope , move ( filter ) ) ) ;
2022-09-01 21:50:16 +03:00
}
2023-05-23 12:25:07 +03:00
HTMLCollection : : HTMLCollection ( ParentNode & root , Scope scope , Function < bool ( Element const & ) > filter )
2023-01-10 14:56:59 +03:00
: LegacyPlatformObject ( root . realm ( ) )
2022-09-01 21:50:16 +03:00
, m_root ( root )
2021-04-22 22:11:20 +03:00
, m_filter ( move ( filter ) )
2023-05-23 12:25:07 +03:00
, m_scope ( scope )
2021-04-22 22:11:20 +03:00
{
}
2022-03-14 22:21:51 +03:00
HTMLCollection : : ~ HTMLCollection ( ) = default ;
2021-04-22 22:11:20 +03:00
2023-01-28 20:33:35 +03:00
JS : : ThrowCompletionOr < void > HTMLCollection : : initialize ( JS : : Realm & realm )
2023-01-10 14:56:59 +03:00
{
2023-01-28 20:33:35 +03:00
MUST_OR_THROW_OOM ( Base : : initialize ( realm ) ) ;
2023-01-10 14:56:59 +03:00
set_prototype ( & Bindings : : ensure_web_prototype < Bindings : : HTMLCollectionPrototype > ( realm , " HTMLCollection " ) ) ;
2023-01-28 20:33:35 +03:00
return { } ;
2023-01-10 14:56:59 +03:00
}
2022-09-01 21:50:16 +03:00
void HTMLCollection : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_root . ptr ( ) ) ;
}
2022-08-28 14:42:07 +03:00
JS : : MarkedVector < Element * > HTMLCollection : : collect_matching_elements ( ) const
2021-04-22 22:11:20 +03:00
{
2022-08-28 14:42:07 +03:00
JS : : MarkedVector < Element * > elements ( m_root - > heap ( ) ) ;
2023-05-23 12:25:07 +03:00
if ( m_scope = = Scope : : Descendants ) {
m_root - > for_each_in_subtree_of_type < Element > ( [ & ] ( auto & element ) {
if ( m_filter ( element ) )
elements . append ( const_cast < Element * > ( & element ) ) ;
return IterationDecision : : Continue ;
} ) ;
} else {
m_root - > for_each_child_of_type < Element > ( [ & ] ( auto & element ) {
if ( m_filter ( element ) )
elements . append ( const_cast < Element * > ( & element ) ) ;
return IterationDecision : : Continue ;
} ) ;
}
2021-04-22 22:11:20 +03:00
return elements ;
}
2021-09-26 17:14:37 +03:00
// https://dom.spec.whatwg.org/#dom-htmlcollection-length
2021-04-22 22:11:20 +03:00
size_t HTMLCollection : : length ( )
{
2021-09-26 17:14:37 +03:00
// The length getter steps are to return the number of nodes represented by the collection.
2021-04-22 22:11:20 +03:00
return collect_matching_elements ( ) . size ( ) ;
}
2021-09-26 17:14:37 +03:00
// https://dom.spec.whatwg.org/#dom-htmlcollection-item
Element * HTMLCollection : : item ( size_t index ) const
2021-04-22 22:11:20 +03:00
{
2021-09-26 17:14:37 +03: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 22:11:20 +03:00
auto elements = collect_matching_elements ( ) ;
if ( index > = elements . size ( ) )
return nullptr ;
return elements [ index ] ;
}
2021-09-26 17:14:37 +03:00
// https://dom.spec.whatwg.org/#dom-htmlcollection-nameditem-key
2023-01-09 03:23:00 +03:00
Element * HTMLCollection : : named_item ( DeprecatedFlyString const & name ) const
2021-04-22 22:11:20 +03:00
{
2021-09-26 17:14:37 +03:00
// 1. If key is the empty string, return null.
if ( name . is_empty ( ) )
2021-04-22 22:11:20 +03:00
return nullptr ;
auto elements = collect_matching_elements ( ) ;
2021-09-26 17:14:37 +03: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 22:11:20 +03:00
if ( auto it = elements . find_if ( [ & ] ( auto & entry ) { return entry - > attribute ( HTML : : AttributeNames : : id ) = = name ; } ) ; it ! = elements . end ( ) )
return * it ;
2021-09-26 17:14:37 +03: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 22:11:20 +03:00
return * it ;
2021-09-26 17:14:37 +03:00
// or null if there is no such element.
2021-04-22 22:11:20 +03:00
return nullptr ;
}
2021-09-26 17:14:37 +03:00
// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-names
2022-12-04 21:02:33 +03:00
Vector < DeprecatedString > HTMLCollection : : supported_property_names ( ) const
2021-09-26 17:14:37 +03:00
{
// 1. Let result be an empty list.
2022-12-04 21:02:33 +03:00
Vector < DeprecatedString > result ;
2021-09-26 17:14:37 +03: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 ( ) ;
}
2023-02-28 03:05:39 +03:00
WebIDL : : ExceptionOr < JS : : Value > HTMLCollection : : item_value ( size_t index ) const
2022-09-01 21:50:16 +03:00
{
auto * element = item ( index ) ;
if ( ! element )
return JS : : js_undefined ( ) ;
return const_cast < Element * > ( element ) ;
}
2023-02-28 03:05:39 +03:00
WebIDL : : ExceptionOr < JS : : Value > HTMLCollection : : named_item_value ( DeprecatedFlyString const & index ) const
2022-09-01 21:50:16 +03:00
{
auto * element = named_item ( index ) ;
if ( ! element )
return JS : : js_undefined ( ) ;
return const_cast < Element * > ( element ) ;
}
2021-04-22 22:11:20 +03:00
}