2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2021-04-22 22:51:19 +02:00
* Copyright ( c ) 2021 , Linus Groh < linusg @ serenityos . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2019-09-29 16:22:15 +02:00
# include <AK/StringBuilder.h>
2020-03-18 15:22:31 +01:00
# include <LibJS/AST.h>
# include <LibJS/Runtime/Function.h>
2020-03-21 18:17:18 +01:00
# include <LibWeb/Bindings/EventWrapper.h>
2020-03-18 15:22:31 +01:00
# include <LibWeb/Bindings/NodeWrapper.h>
2020-06-20 22:09:38 +02:00
# include <LibWeb/Bindings/NodeWrapperFactory.h>
2021-04-06 19:34:49 +01:00
# include <LibWeb/DOM/Comment.h>
# include <LibWeb/DOM/DocumentType.h>
2020-03-07 10:32:51 +01:00
# include <LibWeb/DOM/Element.h>
2020-03-21 18:17:18 +01:00
# include <LibWeb/DOM/Event.h>
2020-09-06 14:28:41 +02:00
# include <LibWeb/DOM/EventDispatcher.h>
2020-03-18 15:22:31 +01:00
# include <LibWeb/DOM/EventListener.h>
2020-03-07 10:32:51 +01:00
# include <LibWeb/DOM/Node.h>
2021-04-06 19:34:49 +01:00
# include <LibWeb/DOM/ProcessingInstruction.h>
2020-11-21 18:32:39 +00:00
# include <LibWeb/DOM/ShadowRoot.h>
2020-08-25 22:18:32 +04:30
# include <LibWeb/HTML/HTMLAnchorElement.h>
2020-11-22 15:53:01 +01:00
# include <LibWeb/Layout/InitialContainingBlockBox.h>
# include <LibWeb/Layout/Node.h>
# include <LibWeb/Layout/TextNode.h>
2021-04-14 01:25:10 +02:00
# include <LibWeb/Origin.h>
2019-06-15 18:55:47 +02:00
2020-07-26 19:37:56 +02:00
namespace Web : : DOM {
2020-03-07 10:27:02 +01:00
2019-09-29 11:43:07 +02:00
Node : : Node ( Document & document , NodeType type )
2020-09-20 19:22:44 +02:00
: EventTarget ( static_cast < Bindings : : ScriptExecutionContext & > ( document ) )
, m_document ( & document )
2019-09-29 11:43:07 +02:00
, m_type ( type )
2019-06-15 18:55:47 +02:00
{
2020-10-22 23:38:14 +02:00
if ( ! is_document ( ) )
m_document - > ref_from_node ( { } ) ;
2019-06-15 18:55:47 +02:00
}
Node : : ~ Node ( )
{
2021-02-23 20:42:32 +01:00
VERIFY ( m_deletion_has_begun ) ;
2020-03-25 18:48:32 +01:00
if ( layout_node ( ) & & layout_node ( ) - > parent ( ) )
layout_node ( ) - > parent ( ) - > remove_child ( * layout_node ( ) ) ;
2020-10-22 23:38:14 +02:00
if ( ! is_document ( ) )
m_document - > unref_from_node ( { } ) ;
2019-06-15 18:55:47 +02:00
}
2019-09-25 12:17:29 +03:00
2020-07-28 18:20:36 +02:00
const HTML : : HTMLAnchorElement * Node : : enclosing_link_element ( ) const
2019-09-29 11:59:38 +02:00
{
2019-10-19 21:21:29 +02:00
for ( auto * node = this ; node ; node = node - > parent ( ) ) {
2020-07-28 18:20:36 +02:00
if ( is < HTML : : HTMLAnchorElement > ( * node ) & & downcast < HTML : : HTMLAnchorElement > ( * node ) . has_attribute ( HTML : : AttributeNames : : href ) )
return downcast < HTML : : HTMLAnchorElement > ( node ) ;
2019-10-19 21:21:29 +02:00
}
return nullptr ;
2019-09-29 11:59:38 +02:00
}
2019-09-29 12:24:36 +02:00
2020-07-28 18:20:36 +02:00
const HTML : : HTMLElement * Node : : enclosing_html_element ( ) const
2019-09-29 12:24:36 +02:00
{
2020-07-28 18:20:36 +02:00
return first_ancestor_of_type < HTML : : HTMLElement > ( ) ;
2019-09-29 12:24:36 +02:00
}
2019-09-29 16:22:15 +02:00
2021-03-30 12:06:06 -04:00
const HTML : : HTMLElement * Node : : enclosing_html_element_with_attribute ( const FlyString & attribute ) const
{
for ( auto * node = this ; node ; node = node - > parent ( ) ) {
if ( is < HTML : : HTMLElement > ( * node ) & & downcast < HTML : : HTMLElement > ( * node ) . has_attribute ( attribute ) )
return downcast < HTML : : HTMLElement > ( node ) ;
}
return nullptr ;
}
2019-09-29 16:22:15 +02:00
String Node : : text_content ( ) const
{
StringBuilder builder ;
for ( auto * child = first_child ( ) ; child ; child = child - > next_sibling ( ) ) {
2020-08-17 21:19:10 -04:00
builder . append ( child - > text_content ( ) ) ;
2019-09-29 16:22:15 +02:00
}
return builder . to_string ( ) ;
}
2019-10-06 19:54:50 +02:00
2020-08-17 12:36:00 -04:00
void Node : : set_text_content ( const String & content )
{
if ( is_text ( ) ) {
downcast < Text > ( this ) - > set_data ( content ) ;
} else {
remove_all_children ( ) ;
append_child ( document ( ) . create_text_node ( content ) ) ;
}
set_needs_style_update ( true ) ;
document ( ) . invalidate_layout ( ) ;
}
2021-01-06 14:27:40 +01:00
RefPtr < Layout : : Node > Node : : create_layout_node ( )
2019-10-09 20:17:01 +02:00
{
return nullptr ;
}
2019-10-14 18:32:02 +02:00
void Node : : invalidate_style ( )
{
2021-04-06 18:38:10 +01:00
for_each_in_inclusive_subtree_of_type < Element > ( [ & ] ( auto & element ) {
2019-12-18 21:34:03 +01:00
element . set_needs_style_update ( true ) ;
2019-10-21 12:01:30 +02:00
return IterationDecision : : Continue ;
2019-10-19 18:57:02 +02:00
} ) ;
document ( ) . schedule_style_update ( ) ;
2019-10-14 18:32:02 +02:00
}
2019-10-19 21:21:29 +02:00
bool Node : : is_link ( ) const
{
2020-06-13 00:22:41 +02:00
return enclosing_link_element ( ) ;
2019-10-19 21:21:29 +02:00
}
2020-03-07 10:27:02 +01:00
2020-11-21 18:32:39 +00:00
bool Node : : dispatch_event ( NonnullRefPtr < Event > event )
2020-03-18 15:22:31 +01:00
{
2020-11-21 18:32:39 +00:00
return EventDispatcher : : dispatch ( * this , event ) ;
2020-03-18 15:22:31 +01:00
}
2020-05-24 21:59:24 +02:00
String Node : : child_text_content ( ) const
{
if ( ! is < ParentNode > ( * this ) )
return String : : empty ( ) ;
StringBuilder builder ;
2020-07-26 17:16:18 +02:00
downcast < ParentNode > ( * this ) . for_each_child ( [ & ] ( auto & child ) {
2020-05-24 21:59:24 +02:00
if ( is < Text > ( child ) )
2020-07-26 17:16:18 +02:00
builder . append ( downcast < Text > ( child ) . text_content ( ) ) ;
2020-05-24 21:59:24 +02:00
} ) ;
return builder . build ( ) ;
}
2020-11-21 18:32:39 +00:00
Node * Node : : root ( )
2020-05-24 21:59:24 +02:00
{
2020-11-21 18:32:39 +00:00
Node * root = this ;
2020-05-24 21:59:24 +02:00
while ( root - > parent ( ) )
root = root - > parent ( ) ;
return root ;
}
2020-11-21 18:32:39 +00:00
Node * Node : : shadow_including_root ( )
{
auto node_root = root ( ) ;
if ( is < ShadowRoot > ( node_root ) )
return downcast < ShadowRoot > ( node_root ) - > host ( ) - > shadow_including_root ( ) ;
return node_root ;
}
2020-05-24 21:59:24 +02:00
bool Node : : is_connected ( ) const
{
2020-11-21 18:32:39 +00:00
return shadow_including_root ( ) & & shadow_including_root ( ) - > is_document ( ) ;
2020-05-24 21:59:24 +02:00
}
2020-06-20 22:26:54 +02:00
Element * Node : : parent_element ( )
{
if ( ! parent ( ) | | ! is < Element > ( parent ( ) ) )
return nullptr ;
2020-07-26 17:16:18 +02:00
return downcast < Element > ( parent ( ) ) ;
2020-06-20 22:26:54 +02:00
}
const Element * Node : : parent_element ( ) const
{
if ( ! parent ( ) | | ! is < Element > ( parent ( ) ) )
return nullptr ;
2020-07-26 17:16:18 +02:00
return downcast < Element > ( parent ( ) ) ;
2020-06-20 22:26:54 +02:00
}
2021-04-06 19:34:49 +01:00
// https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
ExceptionOr < void > Node : : ensure_pre_insertion_validity ( NonnullRefPtr < Node > node , RefPtr < Node > child ) const
2020-06-21 01:00:58 +02:00
{
2021-04-06 19:34:49 +01:00
if ( ! is < Document > ( this ) & & ! is < DocumentFragment > ( this ) & & ! is < Element > ( this ) )
return DOM : : HierarchyRequestError : : create ( " Can only insert into a document, document fragment or element " ) ;
if ( node - > is_host_including_inclusive_ancestor_of ( * this ) )
return DOM : : HierarchyRequestError : : create ( " New node is an ancestor of this node " ) ;
if ( child & & child - > parent ( ) ! = this )
return DOM : : NotFoundError : : create ( " This node is not the parent of the given child " ) ;
// FIXME: All the following "Invalid node type for insertion" messages could be more descriptive.
if ( ! is < DocumentFragment > ( * node ) & & ! is < DocumentType > ( * node ) & & ! is < Element > ( * node ) & & ! is < Text > ( * node ) & & ! is < Comment > ( * node ) & & ! is < ProcessingInstruction > ( * node ) )
return DOM : : HierarchyRequestError : : create ( " Invalid node type for insertion " ) ;
if ( ( is < Text > ( * node ) & & is < Document > ( this ) ) | | ( is < DocumentType > ( * node ) & & ! is < Document > ( this ) ) )
return DOM : : HierarchyRequestError : : create ( " Invalid node type for insertion " ) ;
if ( is < Document > ( this ) ) {
if ( is < DocumentFragment > ( * node ) ) {
2021-04-11 17:13:10 +01:00
auto node_element_child_count = downcast < DocumentFragment > ( * node ) . child_element_count ( ) ;
2021-04-06 19:34:49 +01:00
if ( ( node_element_child_count > 1 | | node - > has_child_of_type < Text > ( ) )
| | ( node_element_child_count = = 1 & & ( has_child_of_type < Element > ( ) | | is < DocumentType > ( child . ptr ( ) ) /* FIXME: or child is non-null and a doctype is following child. */ ) ) ) {
return DOM : : HierarchyRequestError : : create ( " Invalid node type for insertion " ) ;
}
} else if ( is < Element > ( * node ) ) {
if ( has_child_of_type < Element > ( ) | | is < DocumentType > ( child . ptr ( ) ) /* FIXME: or child is non-null and a doctype is following child. */ )
return DOM : : HierarchyRequestError : : create ( " Invalid node type for insertion " ) ;
} else if ( is < DocumentType > ( * node ) ) {
if ( has_child_of_type < DocumentType > ( ) /* FIXME: or child is non-null and an element is preceding child */ | | ( ! child & & has_child_of_type < Element > ( ) ) )
return DOM : : HierarchyRequestError : : create ( " Invalid node type for insertion " ) ;
}
}
return { } ;
2020-06-21 01:00:58 +02:00
}
2021-04-06 19:34:49 +01:00
// https://dom.spec.whatwg.org/#concept-node-insert
void Node : : insert_before ( NonnullRefPtr < Node > node , RefPtr < Node > child , bool suppress_observers )
2021-01-28 08:57:37 +01:00
{
2021-04-06 19:34:49 +01:00
NonnullRefPtrVector < Node > nodes ;
if ( is < DocumentFragment > ( * node ) )
nodes = downcast < DocumentFragment > ( * node ) . child_nodes ( ) ;
else
nodes . append ( node ) ;
auto count = nodes . size ( ) ;
if ( count = = 0 )
return ;
if ( is < DocumentFragment > ( * node ) ) {
node - > remove_all_children ( true ) ;
// FIXME: Queue a tree mutation record for node with « », nodes, null, and null.
}
if ( child ) {
// FIXME: For each live range whose start node is parent and start offset is greater than child’ s index, increase its start offset by count.
// FIXME: For each live range whose end node is parent and end offset is greater than child’ s index, increase its end offset by count.
}
// FIXME: Let previousSibling be child’ s previous sibling or parent’ s last child if child is null. (Currently unused so not included)
for ( auto & node_to_insert : nodes ) { // FIXME: In tree order
document ( ) . adopt_node ( node_to_insert ) ;
if ( ! child )
TreeNode < Node > : : append_child ( node ) ;
else
TreeNode < Node > : : insert_before ( node , child ) ;
// FIXME: If parent is a shadow host and node is a slottable, then assign a slot for node.
// FIXME: If parent’ s root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run signal a slot change for parent.
// FIXME: Run assign slottables for a tree with node’ s root.
// FIXME: This should be shadow-including.
node_to_insert . for_each_in_inclusive_subtree ( [ & ] ( Node & inclusive_descendant ) {
inclusive_descendant . inserted ( ) ;
if ( inclusive_descendant . is_connected ( ) ) {
// FIXME: If inclusiveDescendant is custom, then enqueue a custom element callback reaction with inclusiveDescendant,
// callback name "connectedCallback", and an empty argument list.
// FIXME: Otherwise, try to upgrade inclusiveDescendant.
}
return IterationDecision : : Continue ;
} ) ;
}
if ( ! suppress_observers ) {
// FIXME: queue a tree mutation record for parent with nodes, « », previousSibling, and child.
}
children_changed ( ) ;
2021-01-28 08:57:37 +01:00
}
2021-04-06 19:34:49 +01:00
// https://dom.spec.whatwg.org/#concept-node-pre-insert
2021-04-13 23:03:48 +04:30
ExceptionOr < NonnullRefPtr < Node > > Node : : pre_insert ( NonnullRefPtr < Node > node , RefPtr < Node > child )
2020-06-21 16:45:21 +02:00
{
2021-04-06 19:34:49 +01:00
auto validity_result = ensure_pre_insertion_validity ( node , child ) ;
2021-04-13 23:03:48 +04:30
if ( validity_result . is_exception ( ) )
return NonnullRefPtr < DOMException > ( validity_result . exception ( ) ) ;
2021-04-06 19:34:49 +01:00
auto reference_child = child ;
if ( reference_child = = node )
reference_child = node - > next_sibling ( ) ;
insert_before ( node , reference_child ) ;
2020-06-21 16:45:21 +02:00
return node ;
}
2021-04-06 19:34:49 +01:00
// https://dom.spec.whatwg.org/#concept-node-pre-remove
2021-04-13 23:03:48 +04:30
ExceptionOr < NonnullRefPtr < Node > > Node : : pre_remove ( NonnullRefPtr < Node > child )
2021-04-06 19:34:49 +01:00
{
2021-04-13 23:03:48 +04:30
if ( child - > parent ( ) ! = this )
return DOM : : NotFoundError : : create ( " Child does not belong to this node " ) ;
2021-04-06 19:34:49 +01:00
child - > remove ( ) ;
return child ;
}
// https://dom.spec.whatwg.org/#concept-node-append
2021-04-13 23:03:48 +04:30
ExceptionOr < NonnullRefPtr < Node > > Node : : append_child ( NonnullRefPtr < Node > node )
2021-04-06 19:34:49 +01:00
{
return pre_insert ( node , nullptr ) ;
}
// https://dom.spec.whatwg.org/#concept-node-remove
void Node : : remove ( bool suppress_observers )
{
auto * parent = TreeNode < Node > : : parent ( ) ;
VERIFY ( parent ) ;
// FIXME: Let index be node’ s index. (Currently unused so not included)
// FIXME: For each live range whose start node is an inclusive descendant of node, set its start to (parent, index).
// FIXME: For each live range whose end node is an inclusive descendant of node, set its end to (parent, index).
// FIXME: For each live range whose start node is parent and start offset is greater than index, decrease its start offset by 1.
// FIXME: For each live range whose end node is parent and end offset is greater than index, decrease its end offset by 1.
// FIXME: For each NodeIterator object iterator whose root’ s node document is node’ s node document, run the NodeIterator pre-removing steps given node and iterator.
// FIXME: Let oldPreviousSibling be node’ s previous sibling. (Currently unused so not included)
// FIXME: Let oldNextSibling be node’ s next sibling. (Currently unused so not included)
parent - > remove_child ( * this ) ;
// FIXME: If node is assigned, then run assign slottables for node’ s assigned slot.
// FIXME: If parent’ s root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run signal a slot change for parent.
// FIXME: If node has an inclusive descendant that is a slot, then:
// Run assign slottables for a tree with parent’ s root.
// Run assign slottables for a tree with node.
removed_from ( parent ) ;
// FIXME: Let isParentConnected be parent’ s connected. (Currently unused so not included)
// FIXME: If node is custom and isParentConnected is true, then enqueue a custom element callback reaction with node,
// callback name "disconnectedCallback", and an empty argument list.
// FIXME: This should be shadow-including.
for_each_in_subtree ( [ & ] ( Node & descendant ) {
descendant . removed_from ( nullptr ) ;
// FIXME: If descendant is custom and isParentConnected is true, then enqueue a custom element callback reaction with descendant,
// callback name "disconnectedCallback", and an empty argument list.
return IterationDecision : : Continue ;
} ) ;
if ( ! suppress_observers ) {
// FIXME: queue a tree mutation record for parent with « », « node », oldPreviousSibling, and oldNextSibling.
}
parent - > children_changed ( ) ;
}
2021-04-14 01:25:10 +02:00
// https://dom.spec.whatwg.org/#concept-node-clone
NonnullRefPtr < Node > Node : : clone_node ( Document * document , bool clone_children ) const
{
if ( ! document )
document = m_document ;
RefPtr < Node > copy ;
if ( is < Element > ( this ) ) {
auto & element = * downcast < Element > ( this ) ;
auto qualified_name = QualifiedName ( element . local_name ( ) , element . prefix ( ) , element . namespace_ ( ) ) ;
2021-04-23 16:46:57 +02:00
auto element_copy = adopt_ref ( * new Element ( * document , move ( qualified_name ) ) ) ;
2021-04-14 01:25:10 +02:00
element . for_each_attribute ( [ & ] ( auto & name , auto & value ) {
element_copy - > set_attribute ( name , value ) ;
} ) ;
copy = move ( element_copy ) ;
} else if ( is < Document > ( this ) ) {
auto document_ = downcast < Document > ( this ) ;
auto document_copy = Document : : create ( document_ - > url ( ) ) ;
document_copy - > set_encoding ( document_ - > encoding ( ) ) ;
document_copy - > set_content_type ( document_ - > content_type ( ) ) ;
document_copy - > set_origin ( document_ - > origin ( ) ) ;
document_copy - > set_quirks_mode ( document_ - > mode ( ) ) ;
// FIXME: Set type ("xml" or "html")
copy = move ( document_copy ) ;
} else if ( is < DocumentType > ( this ) ) {
auto document_type = downcast < DocumentType > ( this ) ;
2021-04-23 16:46:57 +02:00
auto document_type_copy = adopt_ref ( * new DocumentType ( * document ) ) ;
2021-04-14 01:25:10 +02:00
document_type_copy - > set_name ( document_type - > name ( ) ) ;
document_type_copy - > set_public_id ( document_type - > public_id ( ) ) ;
document_type_copy - > set_system_id ( document_type - > system_id ( ) ) ;
copy = move ( document_type_copy ) ;
} else if ( is < Text > ( this ) ) {
auto text = downcast < Text > ( this ) ;
2021-04-23 16:46:57 +02:00
auto text_copy = adopt_ref ( * new Text ( * document , text - > data ( ) ) ) ;
2021-04-14 01:25:10 +02:00
copy = move ( text_copy ) ;
} else if ( is < Comment > ( this ) ) {
auto comment = downcast < Comment > ( this ) ;
2021-04-23 16:46:57 +02:00
auto comment_copy = adopt_ref ( * new Comment ( * document , comment - > data ( ) ) ) ;
2021-04-14 01:25:10 +02:00
copy = move ( comment_copy ) ;
} else if ( is < ProcessingInstruction > ( this ) ) {
auto processing_instruction = downcast < ProcessingInstruction > ( this ) ;
2021-04-23 16:46:57 +02:00
auto processing_instruction_copy = adopt_ref ( * new ProcessingInstruction ( * document , processing_instruction - > data ( ) , processing_instruction - > target ( ) ) ) ;
2021-04-14 01:25:10 +02:00
copy = move ( processing_instruction_copy ) ;
} else {
dbgln ( " clone_node() not implemented for NodeType {} " , ( u16 ) m_type ) ;
TODO ( ) ;
}
// FIXME: 4. Set copy’ s node document and document to copy, if copy is a document, and set copy’ s node document to document otherwise.
// FIXME: 5. Run any cloning steps defined for node in other applicable specifications and pass copy, node, document and the clone children flag if set, as parameters.
if ( clone_children ) {
for_each_child ( [ & ] ( auto & child ) {
copy - > append_child ( child . clone_node ( document , true ) ) ;
} ) ;
}
return copy . release_nonnull ( ) ;
}
// https://dom.spec.whatwg.org/#dom-node-clonenode
ExceptionOr < NonnullRefPtr < Node > > Node : : clone_node_binding ( bool deep ) const
{
if ( is < ShadowRoot > ( * this ) )
return NotSupportedError : : create ( " Cannot clone shadow root " ) ;
return clone_node ( nullptr , deep ) ;
}
2020-06-25 23:42:08 +02:00
void Node : : set_document ( Badge < Document > , Document & document )
{
2020-10-22 23:37:17 +02:00
if ( m_document = = & document )
return ;
document . ref_from_node ( { } ) ;
m_document - > unref_from_node ( { } ) ;
2020-06-25 23:42:08 +02:00
m_document = & document ;
}
2020-08-02 16:05:59 +02:00
bool Node : : is_editable ( ) const
{
return parent ( ) & & parent ( ) - > is_editable ( ) ;
}
2021-01-18 12:15:02 +01:00
JS : : Object * Node : : create_wrapper ( JS : : GlobalObject & global_object )
2020-09-06 14:28:41 +02:00
{
return wrap ( global_object , * this ) ;
}
2020-10-11 21:52:59 +02:00
void Node : : removed_last_ref ( )
{
if ( is < Document > ( * this ) ) {
downcast < Document > ( * this ) . removed_last_ref ( ) ;
return ;
}
2020-10-22 23:38:14 +02:00
m_deletion_has_begun = true ;
2020-10-11 21:52:59 +02:00
delete this ;
}
2020-11-22 15:53:01 +01:00
void Node : : set_layout_node ( Badge < Layout : : Node > , Layout : : Node * layout_node ) const
2020-10-22 20:26:32 +02:00
{
if ( layout_node )
m_layout_node = layout_node - > make_weak_ptr ( ) ;
else
m_layout_node = nullptr ;
}
2020-11-21 18:32:39 +00:00
EventTarget * Node : : get_parent ( const Event & )
{
// FIXME: returns the node’ s assigned slot, if node is assigned, and node’ s parent otherwise.
return parent ( ) ;
}
2020-12-13 15:19:42 +01:00
void Node : : set_needs_style_update ( bool value )
{
if ( m_needs_style_update = = value )
return ;
m_needs_style_update = value ;
2020-12-14 12:04:30 +01:00
if ( m_needs_style_update ) {
2021-04-06 19:34:49 +01:00
for ( auto * ancestor = parent ( ) ; ancestor ; ancestor = ancestor - > parent ( ) ) {
//dbgln("{}", ancestor->node_name());
2020-12-14 12:04:30 +01:00
ancestor - > m_child_needs_style_update = true ;
2021-04-06 19:34:49 +01:00
}
2020-12-13 15:19:42 +01:00
document ( ) . schedule_style_update ( ) ;
2020-12-14 12:04:30 +01:00
}
}
2021-04-06 19:34:49 +01:00
void Node : : inserted ( )
2020-12-14 12:04:30 +01:00
{
set_needs_style_update ( true ) ;
2020-12-13 15:19:42 +01:00
}
2021-02-10 18:22:20 +01:00
ParentNode * Node : : parent_or_shadow_host ( )
{
if ( is < ShadowRoot > ( * this ) )
return downcast < ShadowRoot > ( * this ) . host ( ) ;
return downcast < ParentNode > ( parent ( ) ) ;
}
2021-03-06 17:06:25 +00:00
NonnullRefPtrVector < Node > Node : : child_nodes ( ) const
{
NonnullRefPtrVector < Node > nodes ;
for_each_child ( [ & ] ( auto & child ) {
nodes . append ( child ) ;
} ) ;
return nodes ;
}
2021-04-06 19:34:49 +01:00
void Node : : remove_all_children ( bool suppress_observers )
{
while ( RefPtr < Node > child = first_child ( ) )
child - > remove ( suppress_observers ) ;
}
2021-04-10 17:21:22 -07:00
// https://dom.spec.whatwg.org/#dom-node-comparedocumentposition
u16 Node : : compare_document_position ( RefPtr < Node > other )
{
enum Position : u16 {
DOCUMENT_POSITION_EQUAL = 0 ,
DOCUMENT_POSITION_DISCONNECTED = 1 ,
DOCUMENT_POSITION_PRECEDING = 2 ,
DOCUMENT_POSITION_FOLLOWING = 4 ,
DOCUMENT_POSITION_CONTAINS = 8 ,
DOCUMENT_POSITION_CONTAINED_BY = 16 ,
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 32 ,
} ;
if ( this = = other )
return DOCUMENT_POSITION_EQUAL ;
Node * node1 = other . ptr ( ) ;
Node * node2 = this ;
// FIXME: Once LibWeb supports attribute nodes fix to follow the specification.
VERIFY ( node1 - > type ( ) ! = NodeType : : ATTRIBUTE_NODE & & node2 - > type ( ) ! = NodeType : : ATTRIBUTE_NODE ) ;
if ( ( node1 = = nullptr | | node2 = = nullptr ) | | ( node1 - > root ( ) ! = node2 - > root ( ) ) )
return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | ( node1 > node2 ? DOCUMENT_POSITION_PRECEDING : DOCUMENT_POSITION_FOLLOWING ) ;
if ( node1 - > is_ancestor_of ( * node2 ) )
return DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING ;
if ( node2 - > is_ancestor_of ( * node1 ) )
return DOCUMENT_POSITION_CONTAINED_BY | DOCUMENT_POSITION_FOLLOWING ;
if ( node1 - > is_before ( * node2 ) )
return DOCUMENT_POSITION_PRECEDING ;
else
return DOCUMENT_POSITION_FOLLOWING ;
}
2021-04-06 19:34:49 +01:00
// https://dom.spec.whatwg.org/#concept-tree-host-including-inclusive-ancestor
bool Node : : is_host_including_inclusive_ancestor_of ( const Node & other ) const
{
return is_inclusive_ancestor_of ( other ) | | ( is < DocumentFragment > ( other . root ( ) ) & & downcast < DocumentFragment > ( other . root ( ) ) - > host ( ) & & is_inclusive_ancestor_of ( * downcast < DocumentFragment > ( other . root ( ) ) - > host ( ) . ptr ( ) ) ) ;
}
2020-03-07 10:27:02 +01:00
}