2020-11-21 18:32:39 +00:00
/*
* Copyright ( c ) 2020 , the SerenityOS developers .
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-11-21 18:32:39 +00:00
*/
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/ShadowRootPrototype.h>
2024-03-08 19:27:24 +01:00
# include <LibWeb/DOM/AdoptedStyleSheets.h>
2021-09-13 22:42:57 +01:00
# include <LibWeb/DOM/Document.h>
2025-02-02 22:04:01 -08:00
# include <LibWeb/DOM/DocumentOrShadowRoot.h>
2020-11-21 18:32:39 +00:00
# include <LibWeb/DOM/Event.h>
# include <LibWeb/DOM/ShadowRoot.h>
2024-06-25 19:51:18 +01:00
# include <LibWeb/HTML/HTMLTemplateElement.h>
2024-06-25 14:52:06 +02:00
# include <LibWeb/HTML/Parser/HTMLParser.h>
2021-10-06 20:02:41 +02:00
# include <LibWeb/Layout/BlockContainer.h>
2020-11-21 18:32:39 +00:00
namespace Web : : DOM {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( ShadowRoot ) ;
2023-11-19 19:47:52 +01:00
2023-01-28 20:36:58 +01:00
ShadowRoot : : ShadowRoot ( Document & document , Element & host , Bindings : : ShadowRootMode mode )
2020-11-21 18:32:39 +00:00
: DocumentFragment ( document )
2023-01-28 20:36:58 +01:00
, m_mode ( mode )
2020-11-21 18:32:39 +00:00
{
2024-03-09 00:19:05 +01:00
document . register_shadow_root ( { } , * this ) ;
2022-03-16 00:26:40 +01:00
set_host ( & host ) ;
2020-11-21 18:32:39 +00:00
}
2024-03-09 00:19:05 +01:00
void ShadowRoot : : finalize ( )
{
Base : : finalize ( ) ;
document ( ) . unregister_shadow_root ( { } , * this ) ;
}
2023-08-07 08:41:28 +02:00
void ShadowRoot : : initialize ( JS : : Realm & realm )
2023-01-28 20:26:01 +01:00
{
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( ShadowRoot ) ;
2025-04-20 16:22:57 +02:00
Base : : initialize ( realm ) ;
2023-01-28 20:26:01 +01:00
}
2024-05-02 00:01:22 +01:00
// https://dom.spec.whatwg.org/#dom-shadowroot-onslotchange
void ShadowRoot : : set_onslotchange ( WebIDL : : CallbackType * event_handler )
{
set_event_handler_attribute ( HTML : : EventNames : : slotchange , event_handler ) ;
}
// https://dom.spec.whatwg.org/#dom-shadowroot-onslotchange
WebIDL : : CallbackType * ShadowRoot : : onslotchange ( )
{
return event_handler_attribute ( HTML : : EventNames : : slotchange ) ;
}
2021-09-02 19:27:42 +01:00
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
2022-04-01 20:58:27 +03:00
EventTarget * ShadowRoot : : get_parent ( Event const & event )
2020-11-21 18:32:39 +00:00
{
if ( ! event . composed ( ) ) {
2025-01-21 09:12:05 -05:00
auto & events_first_invocation_target = as < Node > ( * event . path ( ) . first ( ) . invocation_target ) ;
2021-09-02 19:27:42 +01:00
if ( & events_first_invocation_target . root ( ) = = this )
2020-11-21 18:32:39 +00:00
return nullptr ;
}
return host ( ) ;
}
2024-06-25 19:51:18 +01:00
// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-innerhtml
2023-11-20 21:32:29 +13:00
WebIDL : : ExceptionOr < String > ShadowRoot : : inner_html ( ) const
2021-09-13 22:42:57 +01:00
{
2025-03-03 13:04:14 +00:00
return serialize_fragment ( HTML : : RequireWellFormed : : Yes ) ;
2021-09-13 22:42:57 +01:00
}
2024-06-25 19:51:18 +01:00
// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-innerhtml
WebIDL : : ExceptionOr < void > ShadowRoot : : set_inner_html ( StringView value )
2021-09-13 22:42:57 +01:00
{
2024-06-25 19:51:18 +01:00
// FIXME: 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, the given value, "ShadowRoot innerHTML", and "script".
// 2. Let context be this's host.
auto context = this - > host ( ) ;
2024-08-08 14:19:14 +01:00
VERIFY ( context ) ;
2024-06-25 19:51:18 +01:00
// 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. FIXME: Use compliantString instead of markup.
2024-08-08 14:19:14 +01:00
auto fragment = TRY ( context - > parse_fragment ( value ) ) ;
2024-06-25 19:51:18 +01:00
// 4. Replace all with fragment within this.
this - > replace_all ( fragment ) ;
// NOTE: We don't invalidate style & layout for <template> elements since they don't affect rendering.
if ( ! is < HTML : : HTMLTemplateElement > ( * this ) ) {
this - > set_needs_style_update ( true ) ;
if ( this - > is_connected ( ) ) {
// NOTE: Since the DOM has changed, we have to rebuild the layout tree.
2025-03-05 21:04:20 +01:00
this - > document ( ) . invalidate_layout_tree ( InvalidateLayoutTreeReason : : ShadowRootSetInnerHTML ) ;
2024-06-25 19:51:18 +01:00
}
}
2021-09-13 22:42:57 +01:00
set_needs_style_update ( true ) ;
return { } ;
}
2025-02-04 13:01:46 +01:00
// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-gethtml
2024-06-25 14:52:06 +02:00
WebIDL : : ExceptionOr < String > ShadowRoot : : get_html ( GetHTMLOptions const & options ) const
{
// ShadowRoot's getHTML(options) method steps are to return the result
// of HTML fragment serialization algorithm with this,
// options["serializableShadowRoots"], and options["shadowRoots"].
return HTML : : HTMLParser : : serialize_html_fragment (
* this ,
options . serializable_shadow_roots ? HTML : : HTMLParser : : SerializableShadowRoots : : Yes : HTML : : HTMLParser : : SerializableShadowRoots : : No ,
options . shadow_roots ) ;
}
2025-02-04 13:01:46 +01:00
// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-sethtmlunsafe
2024-06-25 20:55:58 +01:00
WebIDL : : ExceptionOr < void > ShadowRoot : : set_html_unsafe ( StringView html )
{
// FIXME: 1. Let compliantHTML be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, html, "ShadowRoot setHTMLUnsafe", and "script".
// 3. Unsafe set HTML given this, this's shadow host, and compliantHTML. FIXME: Use compliantHTML.
TRY ( unsafely_set_html ( * this - > host ( ) , html ) ) ;
return { } ;
}
2025-02-02 22:04:01 -08:00
GC : : Ptr < Element > ShadowRoot : : active_element ( )
{
return calculate_active_element ( * this ) ;
}
2024-03-08 19:27:24 +01:00
CSS : : StyleSheetList & ShadowRoot : : style_sheets ( )
{
if ( ! m_style_sheets )
2024-08-20 14:55:28 +02:00
m_style_sheets = CSS : : StyleSheetList : : create ( * this ) ;
2024-03-08 19:27:24 +01:00
return * m_style_sheets ;
}
CSS : : StyleSheetList const & ShadowRoot : : style_sheets ( ) const
{
return const_cast < ShadowRoot * > ( this ) - > style_sheets ( ) ;
}
void ShadowRoot : : visit_edges ( Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_style_sheets ) ;
visitor . visit ( m_adopted_style_sheets ) ;
}
2024-11-15 04:01:23 +13:00
GC : : Ref < WebIDL : : ObservableArray > ShadowRoot : : adopted_style_sheets ( ) const
2024-03-08 19:27:24 +01:00
{
if ( ! m_adopted_style_sheets )
2025-01-10 20:00:43 +03:00
m_adopted_style_sheets = create_adopted_style_sheets_list ( const_cast < ShadowRoot & > ( * this ) ) ;
2024-03-08 19:27:24 +01:00
return * m_adopted_style_sheets ;
}
WebIDL : : ExceptionOr < void > ShadowRoot : : set_adopted_style_sheets ( JS : : Value new_value )
{
if ( ! m_adopted_style_sheets )
2025-01-10 20:00:43 +03:00
m_adopted_style_sheets = create_adopted_style_sheets_list ( * this ) ;
2024-03-08 19:27:24 +01:00
m_adopted_style_sheets - > clear ( ) ;
auto iterator_record = TRY ( get_iterator ( vm ( ) , new_value , JS : : IteratorHint : : Sync ) ) ;
while ( true ) {
auto next = TRY ( iterator_step_value ( vm ( ) , iterator_record ) ) ;
if ( ! next . has_value ( ) )
break ;
TRY ( m_adopted_style_sheets - > append ( * next ) ) ;
}
return { } ;
}
2023-03-19 17:01:26 +01:00
void ShadowRoot : : for_each_css_style_sheet ( Function < void ( CSS : : CSSStyleSheet & ) > & & callback ) const
{
for ( auto & style_sheet : style_sheets ( ) . sheets ( ) )
callback ( * style_sheet ) ;
if ( m_adopted_style_sheets ) {
m_adopted_style_sheets - > for_each < CSS : : CSSStyleSheet > ( [ & ] ( auto & style_sheet ) {
callback ( style_sheet ) ;
} ) ;
}
}
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < Vector < GC : : Ref < Animations : : Animation > > > ShadowRoot : : get_animations ( )
2024-06-02 07:26:36 -07:00
{
2024-11-15 04:01:23 +13:00
Vector < GC : : Ref < Animations : : Animation > > relevant_animations ;
2024-11-08 15:41:49 +00:00
TRY ( for_each_child_of_type_fallible < Element > ( [ & ] ( auto & child ) - > WebIDL : : ExceptionOr < IterationDecision > {
relevant_animations . extend ( TRY ( child . get_animations ( Animations : : GetAnimationsOptions { . subtree = true } ) ) ) ;
2024-06-02 07:26:36 -07:00
return IterationDecision : : Continue ;
2024-11-08 15:41:49 +00:00
} ) ) ;
2024-06-02 07:26:36 -07:00
return relevant_animations ;
}
2025-03-25 17:30:52 +00:00
ElementByIdMap & ShadowRoot : : element_by_id ( ) const
{
if ( ! m_element_by_id )
m_element_by_id = make < ElementByIdMap > ( ) ;
return * m_element_by_id ;
}
2020-11-21 18:32:39 +00:00
}