line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## HTML Object - ~/lib/HTML/Object/DOM/Node.pm |
3
|
|
|
|
|
|
|
## Version v0.2.1 |
4
|
|
|
|
|
|
|
## Copyright(c) 2022 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2021/12/13 |
7
|
|
|
|
|
|
|
## Modified 2022/09/20 |
8
|
|
|
|
|
|
|
## All rights reserved |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
## |
11
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
12
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
13
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
package HTML::Object::DOM::Node; |
15
|
|
|
|
|
|
|
BEGIN |
16
|
|
|
|
|
|
|
{ |
17
|
29
|
|
|
29
|
|
20032
|
use strict; |
|
29
|
|
|
|
|
106
|
|
|
29
|
|
|
|
|
1017
|
|
18
|
29
|
|
|
29
|
|
243
|
use warnings; |
|
29
|
|
|
|
|
94
|
|
|
29
|
|
|
|
|
1098
|
|
19
|
29
|
|
|
29
|
|
668
|
use parent qw( HTML::Object::EventTarget ); |
|
29
|
|
|
|
|
379
|
|
|
29
|
|
|
|
|
416
|
|
20
|
29
|
|
|
29
|
|
2219
|
use vars qw( @EXPORT $XP $VERSION ); |
|
29
|
|
|
|
|
105
|
|
|
29
|
|
|
|
|
2239
|
|
21
|
29
|
|
|
29
|
|
326
|
use Nice::Try; |
|
29
|
|
|
|
|
109
|
|
|
29
|
|
|
|
|
862
|
|
22
|
29
|
|
|
29
|
|
68893866
|
use Want; |
|
29
|
|
|
|
|
81
|
|
|
29
|
|
|
|
|
4471
|
|
23
|
|
|
|
|
|
|
use constant { |
24
|
29
|
|
|
|
|
12051
|
DOCUMENT_POSITION_IDENTICAL => 0, |
25
|
|
|
|
|
|
|
DOCUMENT_POSITION_DISCONNECTED => 1, |
26
|
|
|
|
|
|
|
DOCUMENT_POSITION_PRECEDING => 2, |
27
|
|
|
|
|
|
|
DOCUMENT_POSITION_FOLLOWING => 4, |
28
|
|
|
|
|
|
|
DOCUMENT_POSITION_CONTAINS => 8, |
29
|
|
|
|
|
|
|
DOCUMENT_POSITION_CONTAINED_BY => 16, |
30
|
|
|
|
|
|
|
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC => 32, |
31
|
|
|
|
|
|
|
XML_DEFAULT_NAMESPACE => 'http://www.w3.org/XML/1998/namespace', |
32
|
|
|
|
|
|
|
ELEMENT_NODE => 1, |
33
|
|
|
|
|
|
|
ATTRIBUTE_NODE => 2, |
34
|
|
|
|
|
|
|
TEXT_NODE => 3, |
35
|
|
|
|
|
|
|
CDATA_SECTION_NODE => 4, |
36
|
|
|
|
|
|
|
# Deprecated |
37
|
|
|
|
|
|
|
ENTITY_REFERENCE_NODE => 5, |
38
|
|
|
|
|
|
|
# Deprecated |
39
|
|
|
|
|
|
|
ENTITY_NODE => 6, |
40
|
|
|
|
|
|
|
PROCESSING_INSTRUCTION_NODE => 7, |
41
|
|
|
|
|
|
|
COMMENT_NODE => 8, |
42
|
|
|
|
|
|
|
DOCUMENT_NODE => 9, |
43
|
|
|
|
|
|
|
DOCUMENT_TYPE_NODE => 10, |
44
|
|
|
|
|
|
|
DOCUMENT_FRAGMENT_NODE => 11, |
45
|
|
|
|
|
|
|
NOTATION_NODE => 12, |
46
|
|
|
|
|
|
|
SPACE_NODE => 13, |
47
|
29
|
|
|
29
|
|
368
|
}; |
|
29
|
|
|
|
|
93
|
|
48
|
29
|
|
|
29
|
|
4825
|
our @EXPORT = qw( |
49
|
|
|
|
|
|
|
DOCUMENT_POSITION_IDENTICAL |
50
|
|
|
|
|
|
|
DOCUMENT_POSITION_DISCONNECTED |
51
|
|
|
|
|
|
|
DOCUMENT_POSITION_PRECEDING |
52
|
|
|
|
|
|
|
DOCUMENT_POSITION_FOLLOWING |
53
|
|
|
|
|
|
|
DOCUMENT_POSITION_CONTAINS |
54
|
|
|
|
|
|
|
DOCUMENT_POSITION_CONTAINED_BY |
55
|
|
|
|
|
|
|
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
ELEMENT_NODE |
58
|
|
|
|
|
|
|
ATTRIBUTE_NODE |
59
|
|
|
|
|
|
|
TEXT_NODE |
60
|
|
|
|
|
|
|
CDATA_SECTION_NODE |
61
|
|
|
|
|
|
|
ENTITY_REFERENCE_NODE |
62
|
|
|
|
|
|
|
ENTITY_NODE |
63
|
|
|
|
|
|
|
PROCESSING_INSTRUCTION_NODE |
64
|
|
|
|
|
|
|
COMMENT_NODE |
65
|
|
|
|
|
|
|
DOCUMENT_NODE |
66
|
|
|
|
|
|
|
DOCUMENT_TYPE_NODE |
67
|
|
|
|
|
|
|
DOCUMENT_FRAGMENT_NODE |
68
|
|
|
|
|
|
|
NOTATION_NODE |
69
|
|
|
|
|
|
|
SPACE_NODE |
70
|
|
|
|
|
|
|
); |
71
|
|
|
|
|
|
|
use overload ( |
72
|
29
|
|
|
|
|
787
|
'==' => \&isSameNode, |
73
|
|
|
|
|
|
|
'eq' => \&isSameNode, |
74
|
29
|
|
|
29
|
|
276
|
); |
|
29
|
|
|
|
|
83
|
|
75
|
29
|
|
|
|
|
72
|
our $XP; |
76
|
29
|
|
|
|
|
654
|
our $VERSION = 'v0.2.1'; |
77
|
|
|
|
|
|
|
}; |
78
|
|
|
|
|
|
|
|
79
|
29
|
|
|
29
|
|
224
|
use strict; |
|
29
|
|
|
|
|
78
|
|
|
29
|
|
|
|
|
867
|
|
80
|
29
|
|
|
29
|
|
180
|
use warnings; |
|
29
|
|
|
|
|
73
|
|
|
29
|
|
|
|
|
94989
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub init |
83
|
|
|
|
|
|
|
{ |
84
|
347
|
|
|
347
|
1
|
1093
|
my $self = shift( @_ ); |
85
|
347
|
|
|
|
|
1213
|
$self->{_init_strict_use_sub} = 1; |
86
|
347
|
50
|
|
|
|
1978
|
$self->HTML::Object::Element::init( @_ ) || return( $self->pass_error ); |
87
|
347
|
|
|
|
|
2533
|
return( $self ); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub appendChild |
91
|
|
|
|
|
|
|
{ |
92
|
7
|
|
|
7
|
1
|
71
|
my $self = shift( @_ ); |
93
|
7
|
50
|
|
|
|
30
|
return( $self->error({ |
94
|
|
|
|
|
|
|
message => sprintf( "At least 1 arguments is required, but only %d provided.", scalar( @_ ) ), |
95
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
96
|
|
|
|
|
|
|
}) ) if( scalar( @_ ) < 1 ); |
97
|
7
|
|
|
|
|
14
|
my $new = shift( @_ ); |
98
|
7
|
|
|
|
|
23
|
my $new_parent = $new->parent; |
99
|
7
|
|
|
|
|
163
|
my $parent = $self->parent; |
100
|
|
|
|
|
|
|
# We use 'nodes' rather than 'children' so this works well with HTML::Object::DOM::Document |
101
|
7
|
|
|
|
|
156
|
my $nodes = $self->nodes; |
102
|
7
|
50
|
33
|
|
|
1393
|
if( $new_parent && |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
103
|
|
|
|
|
|
|
!$self->_is_a( $new_parent => 'HTML::Object::DOM::Document' ) && |
104
|
|
|
|
|
|
|
!$self->_is_a( $new_parent => 'HTML::Object::DOM::DocumentFragment' ) && |
105
|
|
|
|
|
|
|
!$self->_is_a( $new_parent => 'HTML::Object::DOM::Element' ) ) |
106
|
|
|
|
|
|
|
{ |
107
|
0
|
|
|
|
|
0
|
return( $self->error({ |
108
|
|
|
|
|
|
|
message => "Node's parent is not an HTML::Object::DOM::Document, HTML::Object::DOM::DocumentFragment or HTML::Object::DOM::Element object.", |
109
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
110
|
|
|
|
|
|
|
}) ); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
# All other conditions below are strictly similar to replaceChild() |
113
|
|
|
|
|
|
|
elsif( !$self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) && |
114
|
|
|
|
|
|
|
!$self->_is_a( $new => 'HTML::Object::DOM::Declaration' ) && |
115
|
|
|
|
|
|
|
!$self->_is_a( $new => 'HTML::Object::DOM::Element' ) && |
116
|
|
|
|
|
|
|
!$self->_is_a( $new => 'HTML::Object::DOM::CharacterData' ) ) |
117
|
|
|
|
|
|
|
{ |
118
|
0
|
|
|
|
|
0
|
return( $self->error({ |
119
|
|
|
|
|
|
|
message => "New node is not an HTML::Object::DOM::DocumentFragment, HTML::Object::DOM::Declaration, HTML::Object::DOM::Element or HTML::Object::DOM::CharacterData object.", |
120
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
121
|
|
|
|
|
|
|
}) ); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
elsif( $self->lineage->has( $new ) ) |
124
|
|
|
|
|
|
|
{ |
125
|
0
|
|
|
|
|
0
|
return( $self->error({ |
126
|
|
|
|
|
|
|
message => "New node provided is an ancestor of the current node.", |
127
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
128
|
|
|
|
|
|
|
}) ); |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
elsif( ( $self->_is_a( $new => 'HTML::Object::DOM::Text' ) || $self->_is_a( $new => 'HTML::Object::DOM::Space' ) ) && |
131
|
|
|
|
|
|
|
$self->_is_a( $new_parent => 'HTML::Object::DOM::Document' ) ) |
132
|
|
|
|
|
|
|
{ |
133
|
0
|
|
|
|
|
0
|
return( $self->error({ |
134
|
|
|
|
|
|
|
message => "New node is a HTML::Object::DOM::Text or HTML::Object::DOM::Space node and its parent is a HTML::Object::DOM::Document node.", |
135
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
136
|
|
|
|
|
|
|
}) ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
elsif( $self->isa( 'HTML::Object::DOM::Declaration' ) && !$self->_is_a( $parent => 'HTML::Object::DOM::Document' ) ) |
139
|
|
|
|
|
|
|
{ |
140
|
0
|
|
|
|
|
0
|
return( $self->error({ |
141
|
|
|
|
|
|
|
message => "Current node is a DocumentType, but its parent is not an HTML::Object::DOM::Document object.", |
142
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
143
|
|
|
|
|
|
|
}) ); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
elsif( $self->_is_a( $parent => 'HTML::Object::DOM::Document' ) && |
146
|
|
|
|
|
|
|
$self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) && |
147
|
0
|
|
|
0
|
|
0
|
( $new->childElementCount > 1 || $new->children->grep(sub{ $self->_is_a( $_ => 'HTML::Object::DOM::Text' ) })->length ) ) |
148
|
|
|
|
|
|
|
{ |
149
|
0
|
|
|
|
|
0
|
return( $self->error({ |
150
|
|
|
|
|
|
|
message => "Current node parent is a HTML::Object::DOM::Document object and new node is a HTML::Object::DOM::DocumentFragment object that has either more than 1 element or has a HTML::Object::DOM::Text node.", |
151
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
152
|
|
|
|
|
|
|
}) ); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
# This is different from replaceChild() |
155
|
|
|
|
|
|
|
elsif( $self->_is_a( $parent => 'HTML::Object::DOM::Document' ) && |
156
|
|
|
|
|
|
|
$parent->childElementCount > 0 && |
157
|
|
|
|
|
|
|
$self->_is_a( $new => 'HTML::Object::DOM::Element' ) ) |
158
|
|
|
|
|
|
|
{ |
159
|
0
|
|
|
|
|
0
|
return( $self->error({ |
160
|
|
|
|
|
|
|
message => "Attempting to replace a child element in a Document with another non HTML-tag element. Document can have only one Element: the HTML-tag element.", |
161
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
162
|
|
|
|
|
|
|
}) ); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
# If the node to append is a doctype and the curent last node is an element, this would put a doctype after an element, which is forbidden |
165
|
|
|
|
|
|
|
elsif( $self->_is_a( $new => 'HTML::Object::DOM::Declaration' ) && |
166
|
|
|
|
|
|
|
$self->_is_a( $nodes->last, 'HTML::Object::DOM::Element' ) ) |
167
|
|
|
|
|
|
|
{ |
168
|
0
|
|
|
|
|
0
|
return( $self->error({ |
169
|
|
|
|
|
|
|
message => "The last node is an element. Appending the DocumentType would place it after.", |
170
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
171
|
|
|
|
|
|
|
}) ); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
7
|
|
|
|
|
1113
|
$new->detach; |
175
|
7
|
50
|
|
|
|
34
|
my $new_array = $self->new_array( $self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) ? $new->children : $new ); |
176
|
|
|
|
|
|
|
$new_array->foreach(sub |
177
|
|
|
|
|
|
|
{ |
178
|
7
|
50
|
|
7
|
|
98
|
next if( !$self->_is_a( $_ => 'HTML::Object::DOM::Node' ) ); |
179
|
7
|
|
|
|
|
280
|
$_->parent( $self ); |
180
|
7
|
|
|
|
|
473
|
}); |
181
|
7
|
|
|
|
|
222
|
$nodes->push( $new_array->list ); |
182
|
7
|
|
|
|
|
98
|
$self->reset(1); |
183
|
7
|
50
|
|
|
|
29
|
if( $self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) ) |
184
|
|
|
|
|
|
|
{ |
185
|
0
|
|
|
|
|
0
|
$new->children->reset; |
186
|
|
|
|
|
|
|
} |
187
|
7
|
|
|
|
|
239
|
return( $new ); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub appendNodes |
191
|
|
|
|
|
|
|
{ |
192
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
193
|
0
|
|
|
|
|
0
|
my $children = $self->children; |
194
|
0
|
|
|
|
|
0
|
foreach my $this ( @_ ) |
195
|
|
|
|
|
|
|
{ |
196
|
0
|
0
|
|
|
|
0
|
if( $self->_is_a( $this => 'HTML::Object::DOM::Node' ) ) |
197
|
|
|
|
|
|
|
{ |
198
|
0
|
|
|
|
|
0
|
$this->parent( $self ); |
199
|
0
|
|
|
|
|
0
|
$children->push( $this ); |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
0
|
|
|
|
|
0
|
return( $self ); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Note: Property |
206
|
|
|
|
|
|
|
# Example: <base href="https://www.example.com/"> |
207
|
|
|
|
|
|
|
sub baseURI : lvalue { return( shift->_set_get_callback({ |
208
|
|
|
|
|
|
|
get => sub |
209
|
|
|
|
|
|
|
{ |
210
|
1
|
|
|
1
|
|
531
|
my $self = shift( @_ ); |
211
|
1
|
|
|
|
|
11
|
my $root = $self->root; |
212
|
1
|
50
|
|
|
|
11
|
return( $self->new_null ) if( !$root ); |
213
|
1
|
50
|
|
|
|
10
|
return( $self->new_null ) if( !$root->can( 'uri' ) ); |
214
|
1
|
50
|
|
|
|
6
|
return( $root->uri ) if( $root->uri ); |
215
|
1
|
|
|
|
|
797
|
my $nodes = $self->find( 'base' ); |
216
|
1
|
50
|
|
|
|
4
|
return( $self->new_null ) if( $nodes->is_empty ); |
217
|
1
|
|
|
|
|
36
|
my $node = $nodes->first; |
218
|
1
|
50
|
|
|
|
106
|
return( $self->new_null ) if( !$node ); |
219
|
1
|
50
|
|
|
|
16
|
return( $self->new_null ) if( !$node->attributes->has( 'href' ) ); |
220
|
1
|
|
|
|
|
588
|
my $uri = $node->attributes->get( 'href' ); |
221
|
1
|
50
|
33
|
|
|
547
|
return( $self->new_null ) if( !defined( $uri ) || !CORE::length( "$uri" ) ); |
222
|
1
|
|
|
|
|
10
|
return( $self->_set_get_uri( 'uri', $uri ) ); |
223
|
|
|
|
|
|
|
}, |
224
|
|
|
|
|
|
|
set => sub |
225
|
|
|
|
|
|
|
{ |
226
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
227
|
0
|
|
|
|
|
0
|
my $uri = shift( @_ ); |
228
|
0
|
|
|
|
|
0
|
my $root = $self->root; |
229
|
0
|
0
|
|
|
|
0
|
return( $self->new_null ) if( !$root ); |
230
|
0
|
|
|
|
|
0
|
my $nodes = $root->find( 'base' ); |
231
|
0
|
|
|
|
|
0
|
my $base; |
232
|
0
|
0
|
|
|
|
0
|
if( $nodes->is_empty ) |
233
|
|
|
|
|
|
|
{ |
234
|
0
|
|
0
|
|
|
0
|
$base = $root->createElement( 'base' ) || return( $self->error( $root->pass_error ) ); |
235
|
0
|
|
0
|
|
|
0
|
my $head = $root->find( 'head' )->first || |
236
|
|
|
|
|
|
|
return( $self->error( "No base uri can be set, because there is no head element in this document." ) ); |
237
|
0
|
|
|
|
|
0
|
$head->appendChild( $base ); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
else |
240
|
|
|
|
|
|
|
{ |
241
|
0
|
|
|
|
|
0
|
$base = $nodes->first; |
242
|
|
|
|
|
|
|
} |
243
|
0
|
0
|
|
|
|
0
|
$base->href( $uri ) || return( $self->error( $base->pass_error ) ); |
244
|
0
|
|
|
|
|
0
|
return( $uri ); |
245
|
|
|
|
|
|
|
}, |
246
|
1
|
|
|
1
|
1
|
5263
|
}, @_ ) ); } |
247
|
|
|
|
|
|
|
|
248
|
5
|
|
|
5
|
1
|
1606
|
sub childNodes { return( shift->children ); } |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub cloneNode |
251
|
|
|
|
|
|
|
{ |
252
|
1
|
|
|
1
|
1
|
470
|
my $self = shift( @_ ); |
253
|
1
|
|
|
|
|
9
|
my $clone = $self->clone; |
254
|
1
|
|
|
|
|
20
|
$clone->parent( undef ); |
255
|
1
|
|
|
|
|
27
|
return( $clone ); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub compareDocumentPosition |
259
|
|
|
|
|
|
|
{ |
260
|
10
|
|
|
10
|
1
|
8075
|
my $self = shift( @_ ); |
261
|
10
|
|
50
|
|
|
52
|
my $elem = shift( @_ ) || return( $self->error( "No element was provided to append." ) ); |
262
|
10
|
50
|
|
|
|
45
|
return( $self->error( "Element provided (", overload::StrVal( $elem ), ") is actually not an HTML element." ) ) if( !$self->_is_a( $elem => 'HTML::Object::Element' ) ); |
263
|
|
|
|
|
|
|
# 0 - Elements are identical. |
264
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_IDENTICAL |
265
|
|
|
|
|
|
|
# 1 - No relationship, both nodes are in different documents or different trees in the same document. |
266
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_DISCONNECTED |
267
|
|
|
|
|
|
|
# 2 - The specified node precedes the current node. |
268
|
|
|
|
|
|
|
# otherNode precedes the node in either a pre-order depth-first traversal of a tree containing both (e.g., as an ancestor or previous sibling or a descendant of a previous sibling or previous sibling of an ancestor) or (if they are disconnected) in an arbitrary but consistent ordering. |
269
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_PRECEDING |
270
|
|
|
|
|
|
|
# 4 - The specified node follows the current node. |
271
|
|
|
|
|
|
|
# The otherNode follows the node in either a pre-order depth-first traversal of a tree containing both (e.g., as a descendant or following sibling or a descendant of a following sibling or following sibling of an ancestor) or (if they are disconnected) in an arbitrary but consistent ordering. |
272
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_FOLLOWING |
273
|
|
|
|
|
|
|
# 8 - The otherNode is an ancestor of / contains the current node. |
274
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_CONTAINS |
275
|
|
|
|
|
|
|
# 16 - The otherNode is a descendant of / contained by the node. |
276
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_CONTAINED_BY |
277
|
|
|
|
|
|
|
# 32 - The specified node and the current node have no common container node or the two nodes are different attributes of the same node. |
278
|
|
|
|
|
|
|
# -> DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# "If the two nodes being compared are the same node, then no flags are set on the return." |
281
|
|
|
|
|
|
|
# <https://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
282
|
10
|
100
|
|
|
|
497
|
return(0) if( Scalar::Util::refaddr( $self ) eq Scalar::Util::refaddr( $elem ) ); |
283
|
|
|
|
|
|
|
# Current object and other element are both attributes of the same element (ownerElement) |
284
|
|
|
|
|
|
|
# "If neither of the two determining node is a child node and nodeType is the same for both determining nodes, then an implementation-dependent order between the determining nodes is returned." |
285
|
|
|
|
|
|
|
# <https://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
286
|
9
|
100
|
66
|
|
|
76
|
if( $self->nodeType == ATTRIBUTE_NODE && $elem->nodeType == ATTRIBUTE_NODE ) |
287
|
|
|
|
|
|
|
{ |
288
|
|
|
|
|
|
|
# 2 attributes of the same node |
289
|
1
|
50
|
33
|
|
|
12
|
return(32) if( $self->ownerElement && $self->ownerElement eq $elem->ownerElement ); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
8
|
|
|
|
|
25
|
my $parent = $self->parent; |
293
|
8
|
|
|
|
|
261
|
my $parent2 = $elem->parent; |
294
|
|
|
|
|
|
|
# "If neither of the two determining node is a child node and one determining node has a greater value of nodeType than the other, then the corresponding node precedes the other." |
295
|
|
|
|
|
|
|
# <https://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
296
|
8
|
0
|
33
|
|
|
294
|
if( !$parent && !$parent2 ) |
297
|
|
|
|
|
|
|
{ |
298
|
0
|
0
|
|
|
|
0
|
return( $self->nodeType < $elem->nodeType ? DOCUMENT_POSITION_FOLLOWING : DOCUMENT_POSITION_PRECEDING ); |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
8
|
|
|
|
|
43
|
my $root = $self->root; |
302
|
8
|
|
|
|
|
45
|
my $root2 = $elem->root; |
303
|
|
|
|
|
|
|
# Both elements are in different documents |
304
|
8
|
100
|
|
|
|
56
|
if( $root ne $root2 ) |
305
|
|
|
|
|
|
|
{ |
306
|
1
|
|
|
|
|
4
|
return( DOCUMENT_POSITION_DISCONNECTED ); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
7
|
|
|
|
|
20
|
my $bit = 0; |
310
|
7
|
|
|
|
|
43
|
my $lineage = $self->lineage; |
311
|
7
|
|
|
|
|
54
|
my $lineage2 = $elem->lineage; |
312
|
7
|
|
|
|
|
72
|
my $prev_siblings = $self->left; |
313
|
7
|
|
|
|
|
1255
|
my $next_siblings = $self->right; |
314
|
7
|
|
|
|
|
5162
|
my $seen = {}; |
315
|
7
|
|
|
|
|
844
|
my $crawl; |
316
|
|
|
|
|
|
|
$crawl = sub |
317
|
|
|
|
|
|
|
{ |
318
|
99
|
|
|
99
|
|
423
|
my $kid = shift( @_ ); |
319
|
99
|
|
|
|
|
189
|
my $addr = Scalar::Util::refaddr( $kid ); |
320
|
99
|
50
|
|
|
|
342
|
return if( ++$seen->{ $addr } > 1 ); |
321
|
99
|
|
|
|
|
375
|
my $children = $kid->children; |
322
|
99
|
|
|
|
|
8649
|
foreach( @$children ) |
323
|
|
|
|
|
|
|
{ |
324
|
58
|
100
|
33
|
|
|
623
|
if( $_->can( 'eid' ) && |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
325
|
|
|
|
|
|
|
defined( $_->eid ) && |
326
|
|
|
|
|
|
|
defined( $elem->eid ) && |
327
|
|
|
|
|
|
|
$_->eid eq $elem->eid ) |
328
|
|
|
|
|
|
|
{ |
329
|
2
|
|
|
|
|
9
|
return( $_ ); |
330
|
|
|
|
|
|
|
} |
331
|
56
|
50
|
|
|
|
163
|
if( my $e = $crawl->( $_ ) ) |
332
|
|
|
|
|
|
|
{ |
333
|
0
|
|
|
|
|
0
|
return( $e ); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
97
|
|
|
|
|
357
|
return; |
337
|
7
|
|
|
|
|
66
|
}; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# Check if our parent is among the other element's parents |
340
|
7
|
|
|
|
|
40
|
my $parent_pos = $lineage2->pos( $parent ); |
341
|
|
|
|
|
|
|
# Check if the other element's parent is among our parents |
342
|
7
|
|
|
|
|
194
|
my $parent2_pos = $lineage->pos( $parent2 ); |
343
|
|
|
|
|
|
|
# Then check their position, if found |
344
|
7
|
100
|
100
|
|
|
196
|
if( defined( $parent_pos ) && defined( $parent2_pos ) ) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
345
|
|
|
|
|
|
|
{ |
346
|
2
|
50
|
|
|
|
10
|
if( $parent_pos > $parent2_pos ) |
|
|
50
|
|
|
|
|
|
347
|
|
|
|
|
|
|
{ |
348
|
0
|
|
|
|
|
0
|
$bit |= DOCUMENT_POSITION_FOLLOWING; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
elsif( $parent2_pos > $parent_pos ) |
351
|
|
|
|
|
|
|
{ |
352
|
0
|
|
|
|
|
0
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
else |
355
|
|
|
|
|
|
|
{ |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
elsif( defined( $parent_pos ) ) |
359
|
|
|
|
|
|
|
{ |
360
|
4
|
|
|
|
|
17
|
$bit |= DOCUMENT_POSITION_FOLLOWING; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
elsif( defined( $parent2_pos ) ) |
363
|
|
|
|
|
|
|
{ |
364
|
1
|
|
|
|
|
4
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
# Otherwise neither our parent or the other's parent is in either lineage |
367
|
|
|
|
|
|
|
else |
368
|
|
|
|
|
|
|
{ |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
7
|
50
|
33
|
|
|
63
|
if( $lineage->intersection( $lineage2 )->is_empty && |
372
|
|
|
|
|
|
|
$lineage2->intersection( $lineage )->is_empty ) |
373
|
|
|
|
|
|
|
{ |
374
|
0
|
|
|
|
|
0
|
$bit |= DOCUMENT_POSITION_DISCONNECTED; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
else |
377
|
|
|
|
|
|
|
{ |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
# Check for the other node in: |
380
|
|
|
|
|
|
|
# 1) ancestor |
381
|
|
|
|
|
|
|
# 2) previous sibling |
382
|
|
|
|
|
|
|
# 3) descendant of previous sibling |
383
|
|
|
|
|
|
|
# 4) previous sibling of an ancestor |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
# "If one of the nodes being compared contains the other node, then the container precedes the contained node, and reversely the contained node follows the container." |
386
|
|
|
|
|
|
|
# <https://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
387
|
7
|
100
|
|
|
|
6082
|
if( $lineage->has( $elem ) ) |
|
|
100
|
|
|
|
|
|
388
|
|
|
|
|
|
|
{ |
389
|
1
|
|
|
|
|
87
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
390
|
1
|
|
|
|
|
3
|
$bit |= DOCUMENT_POSITION_CONTAINS; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
# check previous sibling |
393
|
|
|
|
|
|
|
elsif( $prev_siblings->has( $elem ) ) |
394
|
|
|
|
|
|
|
{ |
395
|
1
|
|
|
|
|
79
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
else |
398
|
|
|
|
|
|
|
{ |
399
|
|
|
|
|
|
|
# check for descendant of previous sibling |
400
|
5
|
|
|
|
|
561
|
$seen = {}; |
401
|
5
|
|
|
|
|
27
|
foreach( @$prev_siblings ) |
402
|
|
|
|
|
|
|
{ |
403
|
12
|
100
|
|
|
|
30
|
if( my $e = $crawl->( $_ ) ) |
404
|
|
|
|
|
|
|
{ |
405
|
1
|
|
|
|
|
3
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
406
|
1
|
|
|
|
|
2
|
last; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# no luck so far. Checking previous sibling of an ancestor |
411
|
5
|
100
|
|
|
|
38
|
if( !( $bit & DOCUMENT_POSITION_PRECEDING ) ) |
412
|
|
|
|
|
|
|
{ |
413
|
|
|
|
|
|
|
# Go through each ancestor |
414
|
4
|
|
|
|
|
14
|
foreach( @$lineage ) |
415
|
|
|
|
|
|
|
{ |
416
|
|
|
|
|
|
|
# then get its previous siblings |
417
|
10
|
|
|
|
|
404
|
my $ancestor_siblings = $_->left; |
418
|
|
|
|
|
|
|
# and check if the other element is one of them |
419
|
10
|
50
|
33
|
|
|
1205
|
if( $ancestor_siblings && $ancestor_siblings->has( $elem ) ) |
420
|
|
|
|
|
|
|
{ |
421
|
0
|
|
|
|
|
0
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
422
|
0
|
|
|
|
|
0
|
last; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# still no luck, check |
429
|
|
|
|
|
|
|
# 1) descendants |
430
|
|
|
|
|
|
|
# 2) following sibling |
431
|
|
|
|
|
|
|
# 3) a descendant of a following sibling |
432
|
|
|
|
|
|
|
# 4) following sibling of an ancestor |
433
|
7
|
|
|
|
|
214
|
$seen = {}; |
434
|
|
|
|
|
|
|
# e.g. a child or an attribute of our element: |
435
|
|
|
|
|
|
|
# "when comparing an element against its own attribute or child, the element node precedes its attribute node and its child node, which both follow it." |
436
|
|
|
|
|
|
|
# <https://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
437
|
7
|
100
|
|
|
|
26
|
if( $lineage2->has( $self ) ) |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
438
|
|
|
|
|
|
|
{ |
439
|
2
|
|
|
|
|
72
|
$bit |= ( DOCUMENT_POSITION_CONTAINED_BY | DOCUMENT_POSITION_FOLLOWING ) |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
# Now check for following siblings |
442
|
|
|
|
|
|
|
elsif( $next_siblings->has( $elem ) ) |
443
|
|
|
|
|
|
|
{ |
444
|
1
|
|
|
|
|
75
|
$bit |= DOCUMENT_POSITION_FOLLOWING; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
# "If one of the nodes being compared contains the other node, then the container precedes the contained node, and reversely the contained node follows the container." |
447
|
|
|
|
|
|
|
# <https://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
448
|
|
|
|
|
|
|
# We look deeper than our direct child |
449
|
|
|
|
|
|
|
elsif( my $e = $crawl->( $self ) ) |
450
|
|
|
|
|
|
|
{ |
451
|
0
|
|
|
|
|
0
|
$bit |= ( DOCUMENT_POSITION_CONTAINED_BY | DOCUMENT_POSITION_FOLLOWING ) |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
# check for a descendant of a following sibling |
454
|
|
|
|
|
|
|
else |
455
|
|
|
|
|
|
|
{ |
456
|
4
|
|
|
|
|
16
|
$seen = {}; |
457
|
4
|
|
|
|
|
65
|
foreach( @$next_siblings ) |
458
|
|
|
|
|
|
|
{ |
459
|
27
|
100
|
|
|
|
53
|
if( my $e = $crawl->( $_ ) ) |
460
|
|
|
|
|
|
|
{ |
461
|
1
|
|
|
|
|
7
|
$bit |= DOCUMENT_POSITION_FOLLOWING; |
462
|
1
|
|
|
|
|
5
|
last; |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# no luck so far. Checking previous sibling of an ancestor |
467
|
4
|
100
|
|
|
|
30
|
if( !( $bit & DOCUMENT_POSITION_FOLLOWING ) ) |
468
|
|
|
|
|
|
|
{ |
469
|
|
|
|
|
|
|
# Go through each ancestor |
470
|
2
|
|
|
|
|
16
|
foreach( @$lineage ) |
471
|
|
|
|
|
|
|
{ |
472
|
|
|
|
|
|
|
# then get its following siblings |
473
|
5
|
|
|
|
|
577
|
my $ancestor_siblings = $_->right; |
474
|
|
|
|
|
|
|
# and check if the other element is one of them |
475
|
5
|
50
|
66
|
|
|
3086
|
if( $ancestor_siblings && $ancestor_siblings->has( $elem ) ) |
476
|
|
|
|
|
|
|
{ |
477
|
0
|
|
|
|
|
0
|
$bit |= DOCUMENT_POSITION_PRECEDING; |
478
|
0
|
|
|
|
|
0
|
last; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
} |
483
|
7
|
|
|
|
|
47
|
return( $bit ); |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
sub contains |
487
|
|
|
|
|
|
|
{ |
488
|
2
|
|
|
2
|
1
|
4973
|
my $self = shift( @_ ); |
489
|
2
|
|
50
|
|
|
11
|
my $elem = shift( @_ ) || return( $self->error( "No element was provided to append." ) ); |
490
|
2
|
50
|
|
|
|
9
|
return( $self->error( "Element provided (", overload::StrVal( $elem ), ") is actually not an HTML element." ) ) if( !$self->_is_a( $elem => 'HTML::Object::Element' ) ); |
491
|
|
|
|
|
|
|
# Object and comparison object are the same |
492
|
2
|
50
|
|
|
|
86
|
return(1) if( Scalar::Util::refaddr( $self ) eq Scalar::Util::refaddr( $elem ) ); |
493
|
2
|
|
|
|
|
6
|
my $found = 0; |
494
|
2
|
|
|
|
|
3
|
my $seen = {}; |
495
|
2
|
|
|
|
|
5
|
my $traverse; |
496
|
|
|
|
|
|
|
$traverse = sub |
497
|
|
|
|
|
|
|
{ |
498
|
40
|
|
|
40
|
|
62
|
my $e = shift( @_ ); |
499
|
40
|
50
|
33
|
|
|
529
|
return if( !defined( $e ) || !CORE::length( $e ) ); |
500
|
40
|
|
|
|
|
84
|
my $addr = Scalar::Util::refaddr( $e ); |
501
|
40
|
50
|
|
|
|
107
|
return if( CORE::exists( $seen->{ $addr } ) ); |
502
|
40
|
|
|
|
|
77
|
$seen->{ $addr }++; |
503
|
|
|
|
|
|
|
$e->children->foreach(sub |
504
|
|
|
|
|
|
|
{ |
505
|
40
|
100
|
|
|
|
7939
|
if( $_->eid eq $elem->eid ) |
506
|
|
|
|
|
|
|
{ |
507
|
2
|
|
|
|
|
9
|
$found++; |
508
|
2
|
|
|
|
|
6
|
return; |
509
|
|
|
|
|
|
|
} |
510
|
38
|
|
|
|
|
85
|
return( $traverse->( $_ ) ); |
511
|
40
|
|
|
|
|
102
|
}); |
512
|
2
|
|
|
|
|
13
|
}; |
513
|
2
|
|
|
|
|
6
|
$traverse->( $self ); |
514
|
2
|
|
|
|
|
460
|
return( $found ); |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
# Takes a selector; or |
518
|
|
|
|
|
|
|
# Element object |
519
|
|
|
|
|
|
|
sub find |
520
|
|
|
|
|
|
|
{ |
521
|
19
|
|
|
19
|
1
|
37952
|
my $self = shift( @_ ); |
522
|
19
|
|
|
|
|
55
|
my $this = shift( @_ ); |
523
|
19
|
|
|
|
|
96
|
my $opts = $self->_get_args_as_hash( @_ ); |
524
|
19
|
|
|
|
|
346
|
my $results = $self->new_array; |
525
|
|
|
|
|
|
|
|
526
|
19
|
50
|
33
|
|
|
496
|
if( ref( $this ) && $self->_is_object( $this ) && $this->isa( 'HTML::Object::DOM::Element' ) ) |
|
|
|
33
|
|
|
|
|
527
|
|
|
|
|
|
|
{ |
528
|
0
|
|
|
|
|
0
|
my $a = $self->new_array( [ $this ] ); |
529
|
0
|
|
|
|
|
0
|
my $lookup; |
530
|
|
|
|
|
|
|
$lookup = sub |
531
|
|
|
|
|
|
|
{ |
532
|
0
|
|
|
0
|
|
0
|
my $kids = shift( @_ ); |
533
|
|
|
|
|
|
|
$kids->foreach(sub |
534
|
|
|
|
|
|
|
{ |
535
|
0
|
|
|
|
|
0
|
my $child = shift( @_ ); |
536
|
|
|
|
|
|
|
$a->foreach(sub |
537
|
|
|
|
|
|
|
{ |
538
|
0
|
|
|
|
|
0
|
my $candidate = shift( @_ ); |
539
|
0
|
0
|
|
|
|
0
|
if( $child->eid eq $candidate->eid ) |
540
|
|
|
|
|
|
|
{ |
541
|
0
|
|
|
|
|
0
|
$results->push( $child ); |
542
|
|
|
|
|
|
|
# We've added this child. Move to next child. |
543
|
0
|
|
|
|
|
0
|
return( 1 ); |
544
|
|
|
|
|
|
|
} |
545
|
0
|
|
|
|
|
0
|
}); |
546
|
0
|
0
|
|
|
|
0
|
if( $child->children->length > 0 ) |
547
|
|
|
|
|
|
|
{ |
548
|
0
|
|
|
|
|
0
|
$lookup->( $child->children ); |
549
|
|
|
|
|
|
|
} |
550
|
0
|
|
|
|
|
0
|
}); |
551
|
0
|
|
|
|
|
0
|
}; |
552
|
|
|
|
|
|
|
# Wether this is a collection or just an element object, we check our children |
553
|
0
|
|
|
|
|
0
|
$lookup->( $self->children ); |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
# I am expecting an xpath value |
556
|
|
|
|
|
|
|
else |
557
|
|
|
|
|
|
|
{ |
558
|
19
|
0
|
0
|
|
|
62
|
if( ref( $this ) && |
|
|
|
33
|
|
|
|
|
559
|
|
|
|
|
|
|
( |
560
|
|
|
|
|
|
|
!overload::Overloaded( $this ) || |
561
|
|
|
|
|
|
|
( overload::Overloaded( $this ) && !overload::Method( $this, '""' ) ) |
562
|
|
|
|
|
|
|
) ) |
563
|
|
|
|
|
|
|
{ |
564
|
0
|
|
|
|
|
0
|
return( $self->error( "I was expecting an xpath string, but instead I got '$this'." ) ); |
565
|
|
|
|
|
|
|
} |
566
|
19
|
|
50
|
|
|
125
|
my $xpath = $self->_xpath_value( $this, $opts ) || return( $self->pass_error ); |
567
|
|
|
|
|
|
|
# $self->children->foreach(sub |
568
|
|
|
|
|
|
|
# { |
569
|
|
|
|
|
|
|
# my $child = shift( @_ ); |
570
|
|
|
|
|
|
|
# return(1) if( !$child->isElementNode ); |
571
|
|
|
|
|
|
|
# # Propagate debug value |
572
|
|
|
|
|
|
|
# $child->debug( $self->debug ); |
573
|
|
|
|
|
|
|
# try |
574
|
|
|
|
|
|
|
# { |
575
|
|
|
|
|
|
|
# my @nodes = $child->findnodes( $xpath ); |
576
|
|
|
|
|
|
|
# # $self->messagef( 4, "%d nodes found under child element '$child' whose tag is '%s' -> '%s'", scalar( @nodes ), $child->tag, join( "', '", map( overload::StrVal( $_ ), @nodes ) ) ); |
577
|
|
|
|
|
|
|
# $results->push( @nodes ); |
578
|
|
|
|
|
|
|
# } |
579
|
|
|
|
|
|
|
# catch( $e ) |
580
|
|
|
|
|
|
|
# { |
581
|
|
|
|
|
|
|
# warn( "Error while calling findnodes on element id \"", $_->id, "\" and tag \"", $_->tag, "\": $e\n" ); |
582
|
|
|
|
|
|
|
# } |
583
|
|
|
|
|
|
|
# }); |
584
|
19
|
50
|
33
|
|
|
57
|
try |
|
19
|
|
|
|
|
34
|
|
|
19
|
|
|
|
|
31
|
|
|
19
|
|
|
|
|
118
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
38
|
|
|
19
|
|
|
|
|
54
|
|
|
19
|
|
|
|
|
42
|
|
585
|
19
|
|
|
19
|
|
29
|
{ |
586
|
19
|
|
|
|
|
145
|
my @nodes = $self->findnodes( $xpath ); |
587
|
19
|
|
|
|
|
602
|
$results->push( @nodes ); |
588
|
|
|
|
|
|
|
} |
589
|
19
|
0
|
50
|
|
|
121
|
catch( $e ) |
|
19
|
0
|
33
|
|
|
223
|
|
|
19
|
0
|
|
|
|
85
|
|
|
19
|
0
|
|
|
|
43
|
|
|
19
|
0
|
|
|
|
36
|
|
|
19
|
0
|
|
|
|
26
|
|
|
19
|
0
|
|
|
|
34
|
|
|
19
|
0
|
|
|
|
103
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
78
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
47
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
71
|
|
|
19
|
|
|
|
|
97
|
|
|
19
|
|
|
|
|
62
|
|
|
19
|
|
|
|
|
66
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
590
|
0
|
|
|
0
|
|
0
|
{ |
591
|
|
|
|
|
|
|
# warn( "Error while calling findnodes on element id \"", ( $self->id // '' ), "\" and tag \"", ( $self->tag // '' ), "\": $e\n" ); |
592
|
0
|
|
0
|
|
|
0
|
warn( "Error while calling findnodes on element with tag \"", ( $self->tag // '' ), "\": $e\n" ); |
593
|
29
|
0
|
0
|
29
|
|
267
|
} |
|
29
|
0
|
0
|
|
|
106
|
|
|
29
|
0
|
33
|
|
|
136897
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
19
|
0
|
|
|
|
62
|
|
|
0
|
0
|
|
|
|
0
|
|
|
19
|
0
|
|
|
|
697
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
88
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
74
|
|
594
|
|
|
|
|
|
|
} |
595
|
19
|
|
|
|
|
139
|
return( $results ); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
sub find_xpath |
599
|
|
|
|
|
|
|
{ |
600
|
0
|
|
|
0
|
1
|
0
|
my( $self, $path ) = @_; |
601
|
0
|
|
|
|
|
0
|
return( $self->xp->find( $path, $self ) ); |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
sub findnodes |
605
|
|
|
|
|
|
|
{ |
606
|
19
|
|
|
19
|
1
|
66
|
my( $self, $path ) = @_; |
607
|
19
|
|
|
|
|
113
|
return( $self->xp->findnodes( $path, $self ) ); |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub findnodes_as_string |
611
|
|
|
|
|
|
|
{ |
612
|
0
|
|
|
0
|
1
|
0
|
my( $self, $path ) = @_; |
613
|
0
|
|
|
|
|
0
|
return( $self->xp->findnodes_as_string( $path, $self ) ); |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
sub findnodes_as_strings |
617
|
|
|
|
|
|
|
{ |
618
|
0
|
|
|
0
|
1
|
0
|
my( $self, $path ) = @_; |
619
|
0
|
|
|
|
|
0
|
return( $self->xp->findnodes_as_strings( $path, $self ) ); |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub findvalue |
623
|
|
|
|
|
|
|
{ |
624
|
0
|
|
|
0
|
1
|
0
|
my( $self, $path ) = @_; |
625
|
0
|
|
|
|
|
0
|
return( $self->xp->findvalue( $path, $self ) ); |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub findvalues |
629
|
|
|
|
|
|
|
{ |
630
|
0
|
|
|
0
|
1
|
0
|
my( $self, $path ) = @_; |
631
|
0
|
|
|
|
|
0
|
return( $self->xp->findvalues( $path, $self ) ); |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
# Note: Property |
635
|
6
|
|
|
6
|
1
|
2070
|
sub firstChild { return( shift->nodes->first ); } |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
sub getAttributes |
638
|
|
|
|
|
|
|
{ |
639
|
36
|
|
|
36
|
1
|
72
|
my $self = shift( @_ ); |
640
|
36
|
|
|
|
|
66
|
my $rank = 0; |
641
|
|
|
|
|
|
|
my $a = $self->attributes_sequence->map(sub |
642
|
|
|
|
|
|
|
{ |
643
|
32
|
|
|
32
|
|
10884
|
return( $self->new_attribute( |
644
|
|
|
|
|
|
|
name => $_, |
645
|
|
|
|
|
|
|
element => $self, |
646
|
|
|
|
|
|
|
rank => $rank++, |
647
|
|
|
|
|
|
|
value => $self->attributes->get( $_ ), |
648
|
|
|
|
|
|
|
) ); |
649
|
36
|
|
|
|
|
212
|
}); |
650
|
36
|
50
|
|
|
|
12335
|
return( wantarray() ? $a->list : $a ); |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
sub getChildNodes |
654
|
|
|
|
|
|
|
{ |
655
|
553
|
|
|
553
|
1
|
904
|
my $self = shift( @_ ); |
656
|
553
|
|
|
|
|
1629
|
my $nodes = $self->nodes; |
657
|
553
|
100
|
|
|
|
39415
|
return( wantarray() ? $nodes->list : $nodes ); |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
|
660
|
0
|
|
|
0
|
1
|
0
|
sub getElementById { return; } |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# sub getFirstChild { return; } |
663
|
1
|
|
|
1
|
1
|
5
|
sub getFirstChild { return( shift->nodes->first ); } |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
# sub getLastChild { return; } |
666
|
0
|
|
|
0
|
1
|
0
|
sub getLastChild { return( shift->nodes->last ); } |
667
|
|
|
|
|
|
|
|
668
|
0
|
|
|
0
|
1
|
0
|
sub getName { return; } |
669
|
|
|
|
|
|
|
|
670
|
75
|
|
|
75
|
1
|
316
|
sub getNextSibling { return( shift->nextSibling ); } |
671
|
|
|
|
|
|
|
|
672
|
0
|
|
|
0
|
1
|
0
|
sub getParentNode { return( shift->parent ); } |
673
|
|
|
|
|
|
|
|
674
|
98
|
|
|
98
|
1
|
477
|
sub getPreviousSibling { return( shift->previousSibling ); } |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub getRootNode |
677
|
|
|
|
|
|
|
{ |
678
|
8
|
|
|
8
|
1
|
1920
|
my $self = shift( @_ ); |
679
|
|
|
|
|
|
|
# The parent of root is a HTML::Object::Root |
680
|
|
|
|
|
|
|
# that helps getting the tree to mimic a DOM tree |
681
|
|
|
|
|
|
|
# return( $self->root->getParentNode ); |
682
|
8
|
|
|
|
|
60
|
return( $self->root ); |
683
|
|
|
|
|
|
|
} |
684
|
|
|
|
|
|
|
|
685
|
1
|
|
|
1
|
1
|
5
|
sub hasChildNodes { return( !shift->nodes->is_empty ); } |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub insertAfter |
688
|
|
|
|
|
|
|
{ |
689
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
690
|
0
|
|
0
|
|
|
0
|
my $e = shift( @_ ) || return( $self->error( "No node was provided to insert." ) ); |
691
|
0
|
0
|
|
|
|
0
|
return( $self->error({ |
692
|
|
|
|
|
|
|
message => "Node provided (" . overload::StrVal( $e ) . ") is not an HTML::Object::DOM::Node.", |
693
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
694
|
|
|
|
|
|
|
}) ) if( !$self->_is_a( $e => 'HTML::Object::DOM::Node' ) ); |
695
|
0
|
|
|
|
|
0
|
my $refNode = shift( @_ ); |
696
|
0
|
|
|
|
|
0
|
my $nodes = $self->nodes; |
697
|
0
|
|
|
|
|
0
|
my $pos; |
698
|
0
|
0
|
|
|
|
0
|
if( !defined( $refNode ) ) |
699
|
|
|
|
|
|
|
{ |
700
|
0
|
|
|
|
|
0
|
$pos = $nodes->size; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
else |
703
|
|
|
|
|
|
|
{ |
704
|
0
|
0
|
|
|
|
0
|
return( $self->error({ |
705
|
|
|
|
|
|
|
message => "Reference node provided (" . overload::StrVal( $refNode ) . ") is not an HTML::Object::DOM::Node.", |
706
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
707
|
|
|
|
|
|
|
}) ) if( !$self->_is_a( $refNode => 'HTML::Object::DOM::Node' ) ); |
708
|
0
|
|
|
|
|
0
|
$pos = $nodes->pos( $refNode ); |
709
|
0
|
0
|
|
|
|
0
|
return( $self->error({ |
710
|
|
|
|
|
|
|
message => "Reference node provided (" . overload::StrVal( $refNode ) . ") is not among the document nodes.", |
711
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
712
|
|
|
|
|
|
|
}) ) if( !defined( $pos ) ); |
713
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Somehow, position for the reference node returned $pos, but I expected an integer equal or above 0" ) ) if( $pos < 0 ); |
714
|
|
|
|
|
|
|
} |
715
|
0
|
0
|
|
|
|
0
|
my $list = $self->new_array( $self->_is_a( $e => 'HTML::Object::DOM::DocumentFragment' ) ? $e->children : $e ); |
716
|
0
|
|
|
|
|
0
|
$nodes->splice( $pos + 1, 0, $list->list ); |
717
|
|
|
|
|
|
|
$list->foreach(sub |
718
|
|
|
|
|
|
|
{ |
719
|
0
|
|
|
0
|
|
0
|
$_->detach; |
720
|
0
|
|
|
|
|
0
|
$_->parent( $self ); |
721
|
0
|
|
|
|
|
0
|
}); |
722
|
0
|
|
|
|
|
0
|
$self->reset(1); |
723
|
0
|
0
|
|
|
|
0
|
if( $self->_is_a( $e => 'HTML::Object::DOM::DocumentFragment' ) ) |
724
|
|
|
|
|
|
|
{ |
725
|
0
|
|
|
|
|
0
|
$e->children->reset; |
726
|
|
|
|
|
|
|
} |
727
|
0
|
|
|
|
|
0
|
return( $e ); |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
sub insertBefore |
731
|
|
|
|
|
|
|
{ |
732
|
2
|
|
|
2
|
1
|
33
|
my $self = shift( @_ ); |
733
|
2
|
|
50
|
|
|
14
|
my $e = shift( @_ ) || return( $self->error( "No node was provided to insert." ) ); |
734
|
2
|
50
|
|
|
|
9
|
return( $self->error({ |
735
|
|
|
|
|
|
|
message => "Node provided (" . overload::StrVal( $e ) . ") is not an HTML::Object::DOM::Node.", |
736
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
737
|
|
|
|
|
|
|
}) ) if( !$self->_is_a( $e => 'HTML::Object::DOM::Node' ) ); |
738
|
2
|
|
|
|
|
96
|
my $refNode = shift( @_ ); |
739
|
2
|
|
|
|
|
7
|
my $nodes = $self->nodes; |
740
|
2
|
|
|
|
|
134
|
my $pos; |
741
|
2
|
50
|
|
|
|
11
|
if( !defined( $refNode ) ) |
742
|
|
|
|
|
|
|
{ |
743
|
0
|
|
|
|
|
0
|
$pos = $nodes->length; # set the position to size + 1 to make it equivalent to a push() |
744
|
|
|
|
|
|
|
} |
745
|
|
|
|
|
|
|
else |
746
|
|
|
|
|
|
|
{ |
747
|
2
|
50
|
|
|
|
10
|
return( $self->error({ |
748
|
|
|
|
|
|
|
message => "Reference node provided (" . overload::StrVal( $refNode ) . ") is not an HTML::Object::DOM::Node.", |
749
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
750
|
|
|
|
|
|
|
}) ) if( !$self->_is_a( $refNode => 'HTML::Object::DOM::Node' ) ); |
751
|
2
|
|
|
|
|
70
|
$pos = $nodes->pos( $refNode ); |
752
|
2
|
50
|
|
|
|
60
|
return( $self->error({ |
753
|
|
|
|
|
|
|
message => "Reference node provided (" . overload::StrVal( $refNode ) . ") is not among the document nodes.", |
754
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
755
|
|
|
|
|
|
|
}) ) if( !defined( $pos ) ); |
756
|
2
|
50
|
|
|
|
12
|
return( $self->error( "Somehow, position for the reference node returned $pos, but I expected an integer equal or above 0" ) ) if( $pos < 0 ); |
757
|
|
|
|
|
|
|
} |
758
|
2
|
50
|
|
|
|
9
|
my $list = $self->new_array( $self->_is_a( $e => 'HTML::Object::DOM::DocumentFragment' ) ? $e->children : $e ); |
759
|
2
|
|
|
|
|
141
|
$nodes->splice( $pos, 0, $list->list ); |
760
|
|
|
|
|
|
|
$list->foreach(sub |
761
|
|
|
|
|
|
|
{ |
762
|
2
|
|
|
2
|
|
40
|
$_->detach; |
763
|
2
|
|
|
|
|
12
|
$_->parent( $self ); |
764
|
2
|
|
|
|
|
80
|
}); |
765
|
2
|
|
|
|
|
50
|
$self->reset(1); |
766
|
2
|
50
|
|
|
|
18
|
if( $self->_is_a( $e => 'HTML::Object::DOM::DocumentFragment' ) ) |
767
|
|
|
|
|
|
|
{ |
768
|
0
|
|
|
|
|
0
|
$e->children->reset; |
769
|
|
|
|
|
|
|
} |
770
|
2
|
|
|
|
|
79
|
return( $e ); |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
0
|
|
|
0
|
1
|
0
|
sub isAttributeNode { return(0); } |
774
|
|
|
|
|
|
|
|
775
|
0
|
|
|
0
|
1
|
0
|
sub isCommentNode { return(0); } |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
# Note: Property |
778
|
|
|
|
|
|
|
sub isConnected |
779
|
|
|
|
|
|
|
{ |
780
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
781
|
1
|
|
|
|
|
4
|
my $root = $self->root; |
782
|
1
|
50
|
|
|
|
9
|
return( $self->false ) if( !$root ); |
783
|
1
|
50
|
|
|
|
16
|
return( $root->isa( 'HTML::Object::Document' ) ? $self->true : $self->false ); |
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
sub isDefaultNamespace |
787
|
|
|
|
|
|
|
{ |
788
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
789
|
0
|
|
|
|
|
0
|
my $uri = shift( @_ ); |
790
|
0
|
0
|
|
|
|
0
|
return( $self->error( "No namespace URI was provided to check." ) ) if( !defined( $uri ) ); |
791
|
0
|
0
|
|
|
|
0
|
if( $self->tag eq 'svg' ) |
792
|
|
|
|
|
|
|
{ |
793
|
0
|
|
|
|
|
0
|
return( $self->attributes->get( 'xmlns' ) eq $uri ); |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
else |
796
|
|
|
|
|
|
|
{ |
797
|
0
|
|
|
|
|
0
|
return( $uri eq "" ); |
798
|
|
|
|
|
|
|
} |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub isEqualNode |
802
|
|
|
|
|
|
|
{ |
803
|
1
|
|
|
1
|
1
|
33
|
my $self = shift( @_ ); |
804
|
1
|
|
50
|
|
|
6
|
my $e = shift( @_ ) || return( $self->error( "No html element was provided to check for equality." ) ); |
805
|
1
|
50
|
|
|
|
4
|
return( $self->error( "Element provided (", overload::StrVal( $e ), ") is not an HTML::Object::Element." ) ) if( !$self->_is_a( $e => 'HTML::Object::Element' ) ); |
806
|
1
|
50
|
|
|
|
116
|
return(0) if( $self->nodeType != $e->nodeType ); |
807
|
1
|
50
|
|
|
|
15
|
return(0) if( $self->children->length != $e->children->length ); |
808
|
1
|
50
|
|
|
|
36548
|
return(0) if( $self->attributes_sequence->join( ',' ) ne $e->attributes_sequence->join( ',' ) ); |
809
|
1
|
|
|
|
|
548
|
my $failed = 0; |
810
|
|
|
|
|
|
|
$self->attributes_sequence->foreach(sub |
811
|
|
|
|
|
|
|
{ |
812
|
3
|
|
|
3
|
|
550
|
my $v1 = $self->attributes->get( $_ ); |
813
|
3
|
|
|
|
|
1627
|
my $v2 = $e->attributes->get( $_ ); |
814
|
3
|
50
|
|
|
|
1547
|
if( $v1 ne $v2 ) |
815
|
|
|
|
|
|
|
{ |
816
|
0
|
|
|
|
|
0
|
$failed++; |
817
|
0
|
|
|
|
|
0
|
return; |
818
|
|
|
|
|
|
|
} |
819
|
1
|
|
|
|
|
32
|
}); |
820
|
1
|
50
|
|
|
|
43
|
return(0) if( $failed ); |
821
|
1
|
|
|
|
|
9
|
return(1); |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
|
824
|
26
|
|
|
26
|
1
|
191
|
sub isElementNode { return(0); } |
825
|
|
|
|
|
|
|
|
826
|
0
|
|
|
0
|
1
|
0
|
sub isNamespaceNode { return(0); } |
827
|
|
|
|
|
|
|
|
828
|
0
|
|
|
0
|
1
|
0
|
sub isPINode { return(0); } |
829
|
|
|
|
|
|
|
|
830
|
0
|
|
|
0
|
1
|
0
|
sub isProcessingInstructionNode { return(0); } |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
sub isSameNode |
833
|
|
|
|
|
|
|
{ |
834
|
107
|
50
|
|
107
|
1
|
20424
|
return(0) if( !defined( $_[1] ) ); |
835
|
107
|
100
|
|
|
|
485
|
if( !$_[0]->_is_a( $_[1] => 'HTML::Object::DOM::Node' ) ) |
836
|
|
|
|
|
|
|
{ |
837
|
44
|
50
|
|
|
|
911
|
warn( "Value provided ($_[1]) is not a reference.\n" ) if( $_[0]->_warnings_is_enabled ); |
838
|
44
|
|
|
|
|
1151
|
return(0); |
839
|
|
|
|
|
|
|
} |
840
|
63
|
|
|
|
|
2906
|
return( Scalar::Util::refaddr( $_[0] ) eq Scalar::Util::refaddr( $_[1] ) ); |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
|
843
|
0
|
|
|
0
|
1
|
0
|
sub isTextNode { return(0); } |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
# Node: Property |
846
|
1
|
|
|
1
|
1
|
6
|
sub lastChild { return( shift->nodes->last ); } |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
sub lookupNamespaceURI |
849
|
|
|
|
|
|
|
{ |
850
|
1
|
|
|
1
|
1
|
440
|
my $self = shift( @_ ); |
851
|
1
|
|
50
|
|
|
8
|
my $prefix = shift( @_ ) || return( '' ); |
852
|
0
|
0
|
|
|
|
0
|
return( XML_DEFAULT_NAMESPACE ) if( lc( $prefix ) eq 'xml' ); |
853
|
0
|
|
|
|
|
0
|
return( '' ); |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
|
856
|
1
|
|
|
1
|
1
|
8
|
sub lookupPrefix { return; } |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
sub new_closing |
859
|
|
|
|
|
|
|
{ |
860
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
861
|
0
|
0
|
|
|
|
0
|
$self->_load_class( 'HTML::Object::DOM::Closing' ) || return( $self->pass_error ); |
862
|
0
|
|
0
|
|
|
0
|
my $e = HTML::Object::DOM::Closing->new( @_ ) || |
863
|
|
|
|
|
|
|
return( $self->pass_error( HTML::Object::DOM::Closing->error ) ); |
864
|
0
|
|
|
|
|
0
|
return( $e ); |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
sub new_comment |
868
|
|
|
|
|
|
|
{ |
869
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
870
|
0
|
0
|
|
|
|
0
|
$self->_load_class( 'HTML::Object::DOM::Comment' ) || return( $self->pass_error ); |
871
|
0
|
|
0
|
|
|
0
|
my $e = HTML::Object::DOM::Comment->new( @_ ) || |
872
|
|
|
|
|
|
|
return( $self->pass_error( HTML::Object::DOM::Comment->error ) ); |
873
|
0
|
|
|
|
|
0
|
return( $e ); |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
sub new_element |
877
|
|
|
|
|
|
|
{ |
878
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
879
|
0
|
0
|
|
|
|
0
|
$self->_load_class( 'HTML::Object::DOM::Element' ) || return( $self->pass_error ); |
880
|
0
|
|
0
|
|
|
0
|
my $e = HTML::Object::DOM::Element->new( @_ ) || |
881
|
|
|
|
|
|
|
return( $self->pass_error( HTML::Object::DOM::Element->error ) ); |
882
|
0
|
|
|
|
|
0
|
return( $e ); |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
sub new_parser |
886
|
|
|
|
|
|
|
{ |
887
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
888
|
0
|
0
|
|
|
|
0
|
$self->_load_class( 'HTML::Object::DOM' ) || return( $self->pass_error ); |
889
|
0
|
|
0
|
|
|
0
|
my $p = HTML::Object::DOM->new( debug => $self->debug ) || |
890
|
|
|
|
|
|
|
return( $self->pass_error( HTML::Object::DOM->error ) ); |
891
|
0
|
|
|
|
|
0
|
return( $p ); |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
sub new_text |
895
|
|
|
|
|
|
|
{ |
896
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
897
|
0
|
0
|
|
|
|
0
|
$self->_load_class( 'HTML::Object::DOM::Text' ) || return( $self->pass_error ); |
898
|
0
|
|
0
|
|
|
0
|
my $e = HTML::Object::DOM::Text->new( @_ ) || |
899
|
|
|
|
|
|
|
return( $self->pass_error( HTML::Object::DOM::Text->error ) ); |
900
|
0
|
|
|
|
|
0
|
return( $e ); |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
# Note: Property |
904
|
93
|
|
|
93
|
1
|
7990
|
sub nextSibling { return( shift->right->first ); } |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
# Note: Property |
907
|
|
|
|
|
|
|
sub nodeName |
908
|
|
|
|
|
|
|
{ |
909
|
64
|
|
|
64
|
1
|
17987
|
my $self = shift( @_ ); |
910
|
64
|
|
33
|
|
|
229
|
my $class = ref( $self ) || $self; |
911
|
64
|
|
|
|
|
460
|
my $map = |
912
|
|
|
|
|
|
|
{ |
913
|
|
|
|
|
|
|
Comment => '#comment', |
914
|
|
|
|
|
|
|
Document => '#document', |
915
|
|
|
|
|
|
|
DocumentFragment => '#documentFragment', |
916
|
|
|
|
|
|
|
Space => '#space', |
917
|
|
|
|
|
|
|
Text => '#text', |
918
|
|
|
|
|
|
|
}; |
919
|
64
|
|
|
|
|
361
|
my $type = [split( /::/, $class )]->[-1]; |
920
|
64
|
100
|
|
|
|
452
|
return( CORE::exists( $map->{ $type } ) ? $map->{ $type } : $self->tag ); |
921
|
|
|
|
|
|
|
} |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
# For any nodes except for Document, nodes are the same as children |
924
|
540
|
|
|
540
|
1
|
2123
|
sub nodes { return( shift->children( @_ ) ); } |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
# ELEMENT_NODE 1 |
927
|
|
|
|
|
|
|
# ATTRIBUTE_NODE 2 |
928
|
|
|
|
|
|
|
# TEXT_NODE 3 |
929
|
|
|
|
|
|
|
# CDATA_SECTION_NODE 4 |
930
|
|
|
|
|
|
|
# PROCESSING_INSTRUCTION_NODE 7 |
931
|
|
|
|
|
|
|
# COMMENT_NODE 8 |
932
|
|
|
|
|
|
|
# DOCUMENT_NODE 9 |
933
|
|
|
|
|
|
|
# DOCUMENT_TYPE_NODE 10 |
934
|
|
|
|
|
|
|
# DOCUMENT_FRAGMENT_NODE 11 |
935
|
|
|
|
|
|
|
# <https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType> |
936
|
|
|
|
|
|
|
# Note: Property |
937
|
|
|
|
|
|
|
sub nodeType |
938
|
|
|
|
|
|
|
{ |
939
|
495
|
|
|
495
|
1
|
4019
|
my $self = shift( @_ ); |
940
|
495
|
|
|
|
|
1532
|
my $map = |
941
|
|
|
|
|
|
|
[ |
942
|
|
|
|
|
|
|
# Document also inherits from Element, so we test it first |
943
|
|
|
|
|
|
|
'HTML::Object::DOM::Document' => DOCUMENT_NODE, |
944
|
|
|
|
|
|
|
'HTML::Object::DOM::Element' => ELEMENT_NODE, |
945
|
|
|
|
|
|
|
'HTML::Object::DOM::Attribute' => ATTRIBUTE_NODE, |
946
|
|
|
|
|
|
|
'HTML::Object::DOM::Text' => TEXT_NODE, |
947
|
|
|
|
|
|
|
# Nothing for CData (4) or Processing Instruction (7) |
948
|
|
|
|
|
|
|
'HTML::Object::DOM::Comment' => COMMENT_NODE, |
949
|
|
|
|
|
|
|
'HTML::Object::DOM::Declaration' => DOCUMENT_TYPE_NODE, |
950
|
|
|
|
|
|
|
'HTML::Object::DOM::DocumentFragment' => DOCUMENT_FRAGMENT_NODE, |
951
|
|
|
|
|
|
|
# We treat space separately, but the DOM normally treats it as text |
952
|
|
|
|
|
|
|
'HTML::Object::DOM::Space' => SPACE_NODE, |
953
|
|
|
|
|
|
|
]; |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
# return( $map->{ [split( /::/, ( ref( $self ) || $self ) )]->[-1] } ); |
956
|
495
|
|
|
|
|
1166
|
for( my $i = 0; $i < scalar( @$map ); $i += 2 ) |
957
|
|
|
|
|
|
|
{ |
958
|
2466
|
|
|
|
|
2906
|
my $class = $map->[$i]; |
959
|
2466
|
|
|
|
|
2740
|
my $const = $map->[$i + 1]; |
960
|
2466
|
100
|
|
|
|
7841
|
if( $self->isa( $class ) ) |
961
|
|
|
|
|
|
|
{ |
962
|
495
|
|
|
|
|
1476
|
return( $const ); |
963
|
|
|
|
|
|
|
} |
964
|
|
|
|
|
|
|
} |
965
|
0
|
|
|
|
|
0
|
return; |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
# Note: Property |
969
|
3
|
|
|
3
|
1
|
49
|
sub nodeValue { return; } |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub normalize |
972
|
|
|
|
|
|
|
{ |
973
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
974
|
1
|
|
|
|
|
3
|
my $process; |
975
|
|
|
|
|
|
|
$process = sub |
976
|
|
|
|
|
|
|
{ |
977
|
1
|
|
|
1
|
|
3
|
my $e = shift( @_ ); |
978
|
1
|
|
|
|
|
6
|
my $new = $self->new_array; |
979
|
1
|
|
|
|
|
20
|
my $found = ''; |
980
|
|
|
|
|
|
|
$e->children->foreach(sub |
981
|
|
|
|
|
|
|
{ |
982
|
4
|
|
|
|
|
430
|
my $kid = shift( @_ ); |
983
|
|
|
|
|
|
|
# text |
984
|
4
|
100
|
|
|
|
64
|
if( $kid->nodeType == 3 ) |
985
|
|
|
|
|
|
|
{ |
986
|
3
|
100
|
|
|
|
10
|
if( $found ) |
987
|
|
|
|
|
|
|
{ |
988
|
|
|
|
|
|
|
# merge it with previous text element and skip it |
989
|
1
|
|
|
|
|
5
|
$found->value->append( $kid->value->scalar ); |
990
|
|
|
|
|
|
|
# next |
991
|
1
|
|
|
|
|
629
|
return(1); |
992
|
|
|
|
|
|
|
} |
993
|
|
|
|
|
|
|
# We found a text element. Save it and merge it with siblings, if any |
994
|
|
|
|
|
|
|
else |
995
|
|
|
|
|
|
|
{ |
996
|
2
|
|
|
|
|
4
|
$found = $kid; |
997
|
|
|
|
|
|
|
} |
998
|
|
|
|
|
|
|
} |
999
|
|
|
|
|
|
|
else |
1000
|
|
|
|
|
|
|
{ |
1001
|
1
|
|
|
|
|
5
|
$found = ''; |
1002
|
|
|
|
|
|
|
} |
1003
|
3
|
|
|
|
|
10
|
$new->push( $kid ); |
1004
|
1
|
|
|
|
|
5
|
}); |
1005
|
|
|
|
|
|
|
# Set the new children elements array object |
1006
|
1
|
|
|
|
|
163
|
$e->children( $new ); |
1007
|
1
|
|
|
|
|
7
|
}; |
1008
|
1
|
|
|
|
|
4
|
$process->( $self ); |
1009
|
1
|
|
|
|
|
308
|
return( $self ); |
1010
|
|
|
|
|
|
|
} |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
# Note: Property |
1013
|
|
|
|
|
|
|
sub ownerDocument |
1014
|
|
|
|
|
|
|
{ |
1015
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
1016
|
1
|
|
|
|
|
7
|
my $root = $self->root; |
1017
|
1
|
|
|
|
|
5
|
return( $root ); |
1018
|
|
|
|
|
|
|
} |
1019
|
|
|
|
|
|
|
|
1020
|
2324
|
|
|
2324
|
1
|
3073125
|
sub parent { return( shift->_set_get_object_without_init( 'parent', 'HTML::Object::DOM::Node', @_ ) ); } |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
# Note: Property |
1023
|
10
|
|
|
10
|
1
|
473
|
sub parentNode { return( shift->parent ); } |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
# Note: Property |
1026
|
|
|
|
|
|
|
# "Returns an Element that is the parent of this node. If the node has no parent, or if that parent is not an Element, this property returns null." |
1027
|
|
|
|
|
|
|
sub parentElement |
1028
|
|
|
|
|
|
|
{ |
1029
|
5
|
|
|
5
|
1
|
689
|
my $self = shift( @_ ); |
1030
|
5
|
|
|
|
|
23
|
my $parent = $self->parent; |
1031
|
5
|
100
|
66
|
|
|
194
|
return( $parent ) if( defined( $parent ) && $self->_is_a( $parent => 'HTML::Object::DOM::Element' ) ); |
1032
|
1
|
|
|
|
|
6
|
return; |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
# Note: Property |
1036
|
|
|
|
|
|
|
# The last element of our siblings, is our first element on our left |
1037
|
103
|
|
|
103
|
1
|
1477
|
sub previousSibling { return( shift->left->last ); } |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
sub removeChild |
1040
|
|
|
|
|
|
|
{ |
1041
|
2
|
|
|
2
|
1
|
1594
|
my $self = shift( @_ ); |
1042
|
2
|
|
50
|
|
|
14
|
my $elem = shift( @_ ) || return( $self->error({ |
1043
|
|
|
|
|
|
|
message => "No element was provided to remove.", |
1044
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError' |
1045
|
|
|
|
|
|
|
}) ); |
1046
|
2
|
50
|
|
|
|
13
|
return( $self->error({ |
1047
|
|
|
|
|
|
|
message => "Element provided (" . overload::StrVal( $elem ) . ") is actually not an HTML element.", |
1048
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError' |
1049
|
|
|
|
|
|
|
}) ) if( !$self->_is_a( $elem => 'HTML::Object::Element' ) ); |
1050
|
2
|
|
|
|
|
81
|
my $nodes = $self->nodes; |
1051
|
2
|
|
|
|
|
155
|
my $pos = $nodes->pos( $elem ); |
1052
|
2
|
100
|
|
|
|
89
|
return( $self->error({ |
1053
|
|
|
|
|
|
|
message => "Node to remove was not found among the current object's children.", |
1054
|
|
|
|
|
|
|
class => 'HTML::Object::NotFoundError', |
1055
|
|
|
|
|
|
|
}) ) if( !defined( $pos ) ); |
1056
|
1
|
|
|
|
|
6
|
$nodes->splice( $pos, 1 ); |
1057
|
1
|
|
|
|
|
116
|
$elem->parent( undef ); |
1058
|
|
|
|
|
|
|
# Remove the closing tag also, if there are any. |
1059
|
1
|
50
|
|
|
|
35
|
if( my $close = $elem->close_tag ) |
1060
|
|
|
|
|
|
|
{ |
1061
|
1
|
50
|
|
|
|
31
|
if( defined( $pos = $nodes->pos( $close ) ) ) |
1062
|
|
|
|
|
|
|
{ |
1063
|
0
|
|
|
|
|
0
|
$nodes->splice( $pos, 1 ); |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
} |
1066
|
1
|
|
|
|
|
27
|
$self->reset(1); |
1067
|
1
|
|
|
|
|
2
|
return( $elem ); |
1068
|
|
|
|
|
|
|
} |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
sub replaceChild |
1071
|
|
|
|
|
|
|
{ |
1072
|
1
|
|
|
1
|
1
|
46
|
my $self = shift( @_ ); |
1073
|
1
|
50
|
|
|
|
7
|
return( $self->error({ |
1074
|
|
|
|
|
|
|
message => sprintf( "At least 2 arguments are required, but only %d provided.", scalar( @_ ) ), |
1075
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
1076
|
|
|
|
|
|
|
}) ) if( scalar( @_ ) < 2 ); |
1077
|
1
|
|
|
|
|
4
|
my( $new, $old ) = @_; |
1078
|
1
|
|
|
|
|
4
|
my $new_parent = $new->parent; |
1079
|
1
|
|
|
|
|
51
|
my $old_parent = $old->parent; |
1080
|
1
|
|
|
|
|
38
|
my $parent = $self->parent; |
1081
|
1
|
50
|
33
|
|
|
44
|
if( !$parent ) |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1082
|
|
|
|
|
|
|
{ |
1083
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1084
|
|
|
|
|
|
|
message => "Current node does not have any parent.", |
1085
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1086
|
|
|
|
|
|
|
}) ); |
1087
|
|
|
|
|
|
|
} |
1088
|
|
|
|
|
|
|
elsif( !$old_parent ) |
1089
|
|
|
|
|
|
|
{ |
1090
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1091
|
|
|
|
|
|
|
message => "Old node provided does not have any parent", |
1092
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1093
|
|
|
|
|
|
|
}) ); |
1094
|
|
|
|
|
|
|
} |
1095
|
|
|
|
|
|
|
elsif( $old_parent ne $self ) |
1096
|
|
|
|
|
|
|
{ |
1097
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1098
|
|
|
|
|
|
|
message => "Old node parent is not the current node.", |
1099
|
|
|
|
|
|
|
class => 'HTML::Object::NotFoundError', |
1100
|
|
|
|
|
|
|
}) ); |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
elsif( !$self->_is_a( $old_parent => 'HTML::Object::DOM::Document' ) && |
1103
|
|
|
|
|
|
|
!$self->_is_a( $old_parent => 'HTML::Object::DOM::DocumentFragment' ) && |
1104
|
|
|
|
|
|
|
!$self->_is_a( $old_parent => 'HTML::Object::DOM::Element' ) ) |
1105
|
|
|
|
|
|
|
{ |
1106
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1107
|
|
|
|
|
|
|
message => "Old node's parent is not an HTML::Object::DOM::Document, HTML::Object::DOM::DocumentFragment or HTML::Object::DOM::Element object.", |
1108
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1109
|
|
|
|
|
|
|
}) ); |
1110
|
|
|
|
|
|
|
} |
1111
|
|
|
|
|
|
|
elsif( !$self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) && |
1112
|
|
|
|
|
|
|
!$self->_is_a( $new => 'HTML::Object::DOM::Declaration' ) && |
1113
|
|
|
|
|
|
|
!$self->_is_a( $new => 'HTML::Object::DOM::Element' ) && |
1114
|
|
|
|
|
|
|
!$self->_is_a( $new => 'HTML::Object::DOM::CharacterData' ) ) |
1115
|
|
|
|
|
|
|
{ |
1116
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1117
|
|
|
|
|
|
|
message => "New node is not an HTML::Object::DOM::DocumentFragment, HTML::Object::DOM::Declaration, HTML::Object::DOM::Element or HTML::Object::DOM::CharacterData object.", |
1118
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1119
|
|
|
|
|
|
|
}) ); |
1120
|
|
|
|
|
|
|
} |
1121
|
|
|
|
|
|
|
elsif( $self->lineage->has( $new ) ) |
1122
|
|
|
|
|
|
|
{ |
1123
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1124
|
|
|
|
|
|
|
message => "New node provided is an ancestor of the current node.", |
1125
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1126
|
|
|
|
|
|
|
}) ); |
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
elsif( ( $self->_is_a( $new => 'HTML::Object::DOM::Text' ) || $self->_is_a( $new => 'HTML::Object::DOM::Space' ) ) && |
1129
|
|
|
|
|
|
|
$self->_is_a( $new_parent => 'HTML::Object::DOM::Document' ) ) |
1130
|
|
|
|
|
|
|
{ |
1131
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1132
|
|
|
|
|
|
|
message => "New node is a HTML::Object::DOM::Text or HTML::Object::DOM::Space node and its parent is a HTML::Object::DOM::Document node.", |
1133
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1134
|
|
|
|
|
|
|
}) ); |
1135
|
|
|
|
|
|
|
} |
1136
|
|
|
|
|
|
|
elsif( $self->isa( 'HTML::Object::DOM::Declaration' ) && !$self->_is_a( $parent => 'HTML::Object::DOM::Document' ) ) |
1137
|
|
|
|
|
|
|
{ |
1138
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1139
|
|
|
|
|
|
|
message => "Current node is a DocumentType, but its parent is not an HTML::Object::DOM::Document object.", |
1140
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1141
|
|
|
|
|
|
|
}) ); |
1142
|
|
|
|
|
|
|
} |
1143
|
|
|
|
|
|
|
elsif( $self->_is_a( $parent => 'HTML::Object::DOM::Document' ) && |
1144
|
|
|
|
|
|
|
$self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) && |
1145
|
0
|
|
|
0
|
|
0
|
( $new->childElementCount > 1 || $new->children->grep(sub{ $self->_is_a( $_ => 'HTML::Object::DOM::Text' ) })->length ) ) |
1146
|
|
|
|
|
|
|
{ |
1147
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1148
|
|
|
|
|
|
|
message => "Current node parent is a HTML::Object::DOM::Document object and new node is a HTML::Object::DOM::DocumentFragment object that has either more than 1 element or has a HTML::Object::DOM::Text node.", |
1149
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1150
|
|
|
|
|
|
|
}) ); |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
elsif( $self->_is_a( $parent => 'HTML::Object::DOM::Document' ) && |
1153
|
|
|
|
|
|
|
$parent->childElementCount > 0 && |
1154
|
|
|
|
|
|
|
$self->_is_a( $new => 'HTML::Object::DOM::Element' ) && |
1155
|
|
|
|
|
|
|
# Non-standard addition: |
1156
|
|
|
|
|
|
|
# replacement is not forbidden if the user replace an element that is not an HTML element by an HTML element and there is no HTML element yet or |
1157
|
|
|
|
|
|
|
# the user replace an HTML element by another HTML element |
1158
|
|
|
|
|
|
|
!( |
1159
|
|
|
|
|
|
|
( $self->_is_a( $old => 'HTML::Object::DOM::Element' ) && |
1160
|
|
|
|
|
|
|
!$self->_is_a( $old => 'HTML::Object::DOM::Element::HTML' ) && |
1161
|
0
|
|
|
0
|
|
0
|
$parent->children->grep(sub{ $self->_is_a( $_ => 'HTML::Object::DOM::Element::HTML' ) })->is_empty && |
1162
|
|
|
|
|
|
|
$self->_is_a( $new => 'HTML::Object::DOM::Element::HTML' ) ) || |
1163
|
|
|
|
|
|
|
( $self->_is_a( $old => 'HTML::Object::DOM::Element::HTML' ) && |
1164
|
|
|
|
|
|
|
$self->_is_a( $new => 'HTML::Object::DOM::Element::HTML' ) ) |
1165
|
|
|
|
|
|
|
) ) |
1166
|
|
|
|
|
|
|
{ |
1167
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1168
|
|
|
|
|
|
|
message => "Attempting to replace a child element in a Document with another non HTML-tag element. Document can have only one Element: the HTML-tag element.", |
1169
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1170
|
|
|
|
|
|
|
}) ); |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
elsif( $self->_is_a( $new => 'HTML::Object::DOM::Element' ) && |
1173
|
|
|
|
|
|
|
$self->_is_a( $old->previousSibling => 'HTML::Object::DOM::Declaration' ) ) |
1174
|
|
|
|
|
|
|
{ |
1175
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1176
|
|
|
|
|
|
|
message => "Attempting to add an Element object before a DocumentType object", |
1177
|
|
|
|
|
|
|
class => 'HTML::Object::HierarchyRequestError', |
1178
|
|
|
|
|
|
|
}) ); |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
# We use 'nodes' rather than 'children' so this works well with HTML::Object::DOM::Document |
1181
|
1
|
|
|
|
|
343
|
my $nodes = $self->nodes; |
1182
|
1
|
|
|
|
|
71
|
my $newPos = $nodes->pos( $new ); |
1183
|
1
|
|
|
|
|
27
|
my $oldPos = $nodes->pos( $old ); |
1184
|
1
|
50
|
33
|
|
|
47
|
if( defined( $newPos ) && !defined( $oldPos ) ) |
|
|
50
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
{ |
1186
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1187
|
|
|
|
|
|
|
message => "New child already has this parent and old child does not. Please check the order of replaceChild's arguments.", |
1188
|
|
|
|
|
|
|
class => 'HTML::Object::NotFoundError', |
1189
|
|
|
|
|
|
|
}) ); |
1190
|
|
|
|
|
|
|
} |
1191
|
|
|
|
|
|
|
elsif( !defined( $oldPos ) ) |
1192
|
|
|
|
|
|
|
{ |
1193
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1194
|
|
|
|
|
|
|
message => "Child to be replaced is not a child of this node", |
1195
|
|
|
|
|
|
|
class => 'HTML::Object::NotFoundError', |
1196
|
|
|
|
|
|
|
}) ); |
1197
|
|
|
|
|
|
|
} |
1198
|
1
|
|
|
|
|
13
|
$new->detach; |
1199
|
1
|
50
|
|
|
|
4
|
my $new_array = $self->new_array( $self->_is_a( $new => 'HTML::Object::DOM::DocumentFragment' ) ? $new->children : $new ); |
1200
|
|
|
|
|
|
|
$new_array->foreach(sub |
1201
|
|
|
|
|
|
|
{ |
1202
|
1
|
50
|
|
1
|
|
12
|
next if( !$self->_is_a( $_ => 'HTML::Object::DOM::Node' ) ); |
1203
|
1
|
|
|
|
|
30
|
$_->parent( $self ); |
1204
|
1
|
|
|
|
|
72
|
}); |
1205
|
1
|
|
|
|
|
28
|
$nodes->splice( $oldPos, 1, $new_array->list ); |
1206
|
1
|
|
|
|
|
33
|
$old->parent( undef ); |
1207
|
1
|
|
|
|
|
31
|
$self->reset(1); |
1208
|
1
|
|
|
|
|
3
|
return( $old ); |
1209
|
|
|
|
|
|
|
} |
1210
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
sub textContent : lvalue { return( shift->_set_get_callback({ |
1212
|
|
|
|
|
|
|
get => sub |
1213
|
|
|
|
|
|
|
{ |
1214
|
7
|
|
|
7
|
|
4405
|
my $self = shift( @_ ); |
1215
|
7
|
50
|
|
|
|
80
|
return if( $self->isa( 'HTML::Object::DOM::Document' ) ); |
1216
|
7
|
50
|
33
|
|
|
162
|
unless( $self->isa( 'HTML::Object::DOM::Comment' ) || |
|
|
|
33
|
|
|
|
|
1217
|
|
|
|
|
|
|
$self->isa( 'HTML::Object::DOM::Text' ) || |
1218
|
|
|
|
|
|
|
$self->isa( 'HTML::Object::DOM::Element' ) ) |
1219
|
|
|
|
|
|
|
{ |
1220
|
0
|
|
|
|
|
0
|
return; |
1221
|
|
|
|
|
|
|
} |
1222
|
7
|
|
|
|
|
68
|
my $str = $self->as_text; |
1223
|
7
|
|
|
|
|
42
|
return( $str ); |
1224
|
|
|
|
|
|
|
}, |
1225
|
|
|
|
|
|
|
set => sub |
1226
|
|
|
|
|
|
|
{ |
1227
|
9
|
|
|
9
|
|
3294
|
my $self = shift( @_ ); |
1228
|
9
|
|
|
|
|
24
|
my $ctx = $_; |
1229
|
9
|
|
|
|
|
27
|
my $arg = shift( @_ ); |
1230
|
9
|
50
|
|
|
|
110
|
return if( $self->isa( 'HTML::Object::DOM::Document' ) ); |
1231
|
9
|
|
|
|
|
20
|
my $dummy; |
1232
|
9
|
50
|
100
|
|
|
173
|
if( $self->isa( 'HTML::Object::DOM::Comment' ) || |
|
|
|
66
|
|
|
|
|
1233
|
|
|
|
|
|
|
$self->isa( 'HTML::Object::DOM::Text' ) || |
1234
|
|
|
|
|
|
|
$self->isa( 'HTML::Object::DOM::Element' ) ) |
1235
|
|
|
|
|
|
|
{ |
1236
|
9
|
100
|
100
|
|
|
86
|
if( $self->isa( 'HTML::Object::DOM::Comment' ) || |
1237
|
|
|
|
|
|
|
$self->isa( 'HTML::Object::DOM::Text' ) ) |
1238
|
|
|
|
|
|
|
{ |
1239
|
2
|
|
|
|
|
18
|
$self->value( $arg ); |
1240
|
|
|
|
|
|
|
} |
1241
|
|
|
|
|
|
|
else |
1242
|
|
|
|
|
|
|
{ |
1243
|
7
|
|
|
|
|
71
|
my $e = $self->new_text( value => $arg, parent => $self ); |
1244
|
7
|
|
|
|
|
37
|
$self->children->set( $e ); |
1245
|
|
|
|
|
|
|
} |
1246
|
9
|
|
|
|
|
3683
|
$self->reset(1); |
1247
|
9
|
|
|
|
|
28
|
$dummy = 1; |
1248
|
9
|
|
|
|
|
39
|
return( $dummy ); |
1249
|
|
|
|
|
|
|
} |
1250
|
0
|
|
|
|
|
0
|
return( $dummy ); |
1251
|
|
|
|
|
|
|
}, |
1252
|
16
|
|
|
16
|
1
|
6104
|
}, @_ ) ); } |
1253
|
|
|
|
|
|
|
|
1254
|
|
|
|
|
|
|
sub trigger |
1255
|
|
|
|
|
|
|
{ |
1256
|
2
|
|
|
2
|
1
|
1396
|
my $self = shift( @_ ); |
1257
|
2
|
|
|
|
|
8
|
my $type = shift( @_ ); |
1258
|
2
|
50
|
33
|
|
|
19
|
return( $self->error({ |
1259
|
|
|
|
|
|
|
message => "No event type was provided to trigger.", |
1260
|
|
|
|
|
|
|
class => 'HTML::Object::SyntaxError', |
1261
|
|
|
|
|
|
|
}) ) if( !defined( $type ) || !CORE::length( "$type" ) ); |
1262
|
2
|
50
|
|
|
|
22
|
return( $self->error({ |
1263
|
|
|
|
|
|
|
message => "Event type provided \"$type\" contains illegal characters. Only alphanuneric, underscore (\"_\") and dash (\"-\") are allowed", |
1264
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
1265
|
|
|
|
|
|
|
}) ) if( $type !~ /^\w[\w\-]*$/ ); |
1266
|
2
|
|
|
|
|
24
|
require HTML::Object::Event; |
1267
|
2
|
|
50
|
|
|
14
|
my $evt = HTML::Object::Event->new( $type, @_ ) || |
1268
|
|
|
|
|
|
|
return( $self->pass_error( HTML::Object::Event->error ) ); |
1269
|
2
|
|
|
|
|
30
|
return( $self->dispatchEvent( $evt ) ); |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
sub xp |
1273
|
|
|
|
|
|
|
{ |
1274
|
19
|
|
|
19
|
1
|
54
|
my $self = shift( @_ ); |
1275
|
19
|
100
|
|
|
|
106
|
unless( $XP ) |
1276
|
|
|
|
|
|
|
{ |
1277
|
4
|
50
|
|
|
|
24
|
$self->_load_class( 'HTML::Object::XPath' ) || return( $self->pass_error ); |
1278
|
4
|
|
|
|
|
1064
|
$XP = HTML::Object::XPath->new; |
1279
|
|
|
|
|
|
|
} |
1280
|
|
|
|
|
|
|
# $XP->debug( $self->debug ); |
1281
|
19
|
|
|
|
|
114
|
return( $XP ); |
1282
|
|
|
|
|
|
|
} |
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
sub _list_to_nodes |
1285
|
|
|
|
|
|
|
{ |
1286
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1287
|
0
|
|
|
|
|
0
|
my $list = $self->new_array; |
1288
|
0
|
|
|
|
|
0
|
my $p = $self->new_parser; |
1289
|
0
|
|
|
|
|
0
|
my $prev; |
1290
|
0
|
|
|
|
|
0
|
foreach( @_ ) |
1291
|
|
|
|
|
|
|
{ |
1292
|
0
|
0
|
0
|
|
|
0
|
if( $self->_is_a( $_ => 'HTML::Object::DOM::Node' ) ) |
|
|
0
|
0
|
|
|
|
|
1293
|
|
|
|
|
|
|
{ |
1294
|
0
|
0
|
|
|
|
0
|
if( $self->_is_a( $_ => 'HTML::Object::DOM::DocumentFragment' ) ) |
1295
|
|
|
|
|
|
|
{ |
1296
|
0
|
|
|
|
|
0
|
my $kids = $_->children->clone; |
1297
|
0
|
|
|
|
|
0
|
$_->children->reset; |
1298
|
0
|
|
|
|
|
0
|
foreach my $kid ( @$kids ) |
1299
|
|
|
|
|
|
|
{ |
1300
|
0
|
|
|
|
|
0
|
$kid->detach; |
1301
|
|
|
|
|
|
|
} |
1302
|
0
|
|
|
|
|
0
|
$list->push( $kids->list ); |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
else |
1305
|
|
|
|
|
|
|
{ |
1306
|
0
|
|
|
|
|
0
|
$list->push( $_ ); |
1307
|
0
|
|
|
|
|
0
|
$_->detach; |
1308
|
|
|
|
|
|
|
} |
1309
|
0
|
|
|
|
|
0
|
undef( $prev ); |
1310
|
|
|
|
|
|
|
} |
1311
|
|
|
|
|
|
|
# HTML string |
1312
|
|
|
|
|
|
|
elsif( !ref( $_ ) || ( ref( $_ ) && overload::Method( $_, '""' ) ) ) |
1313
|
|
|
|
|
|
|
{ |
1314
|
0
|
0
|
|
|
|
0
|
if( $self->looks_like_html( $_ ) ) |
1315
|
|
|
|
|
|
|
{ |
1316
|
0
|
|
0
|
|
|
0
|
my $doc = $p->parse_data( $_ ) || |
1317
|
|
|
|
|
|
|
return( $self->pass_error({ class => 'HTML::Object::TypeError' }) ); |
1318
|
0
|
0
|
|
|
|
0
|
$list->push( $doc->children->list ) if( !$doc->children->is_empty ); |
1319
|
0
|
|
|
|
|
0
|
undef( $prev ); |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
else |
1322
|
|
|
|
|
|
|
{ |
1323
|
0
|
0
|
0
|
|
|
0
|
if( defined( $prev ) && $self->_is_a( $prev => 'HTML::Object::DOM::Text' ) ) |
1324
|
|
|
|
|
|
|
{ |
1325
|
0
|
|
|
|
|
0
|
$prev->value->append( $_ ); |
1326
|
|
|
|
|
|
|
} |
1327
|
|
|
|
|
|
|
else |
1328
|
|
|
|
|
|
|
{ |
1329
|
0
|
|
|
|
|
0
|
my $e = $self->new_text( value => $_ ); |
1330
|
0
|
|
|
|
|
0
|
$list->push( $e ); |
1331
|
0
|
|
|
|
|
0
|
$prev = $e; |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
} |
1335
|
|
|
|
|
|
|
else |
1336
|
|
|
|
|
|
|
{ |
1337
|
0
|
|
|
|
|
0
|
return( $self->error({ |
1338
|
|
|
|
|
|
|
message => "Unsupported data provided (" . overload::StrVal( $_ ) . ").", |
1339
|
|
|
|
|
|
|
class => 'HTML::Object::TypeError', |
1340
|
|
|
|
|
|
|
}) ); |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
} |
1343
|
0
|
|
|
|
|
0
|
return( $list ); |
1344
|
|
|
|
|
|
|
} |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
sub _xpath_value |
1347
|
|
|
|
|
|
|
{ |
1348
|
19
|
|
|
19
|
|
47
|
my $self = shift( @_ ); |
1349
|
19
|
|
|
|
|
47
|
my $this = shift( @_ ); |
1350
|
19
|
|
|
|
|
55
|
my $opts = $self->_get_args_as_hash( @_ ); |
1351
|
19
|
50
|
|
|
|
2836
|
if( ref( $this ) ) |
1352
|
|
|
|
|
|
|
{ |
1353
|
0
|
|
|
|
|
0
|
return( $$this ); |
1354
|
|
|
|
|
|
|
} |
1355
|
|
|
|
|
|
|
else |
1356
|
|
|
|
|
|
|
{ |
1357
|
19
|
50
|
|
|
|
109
|
$self->_load_class( 'HTML::Selector::XPath' ) || |
1358
|
|
|
|
|
|
|
return( $self->pass_error ); |
1359
|
19
|
50
|
33
|
|
|
13871
|
try |
|
19
|
|
|
|
|
53
|
|
|
19
|
|
|
|
|
43
|
|
|
19
|
|
|
|
|
124
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
46
|
|
|
19
|
|
|
|
|
73
|
|
|
19
|
|
|
|
|
46
|
|
1360
|
19
|
|
|
19
|
|
60
|
{ |
1361
|
19
|
|
|
|
|
132
|
return( HTML::Selector::XPath::selector_to_xpath( $this, %$opts ) ); |
1362
|
|
|
|
|
|
|
} |
1363
|
19
|
0
|
0
|
|
|
99
|
catch( $e ) |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
19
|
0
|
|
|
|
46
|
|
|
19
|
0
|
|
|
|
40
|
|
|
19
|
0
|
|
|
|
36
|
|
|
19
|
0
|
|
|
|
45
|
|
|
19
|
0
|
|
|
|
127
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
130
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
79
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
2627
|
|
|
19
|
|
|
|
|
110
|
|
|
19
|
|
|
|
|
64
|
|
|
19
|
|
|
|
|
74
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1364
|
0
|
|
|
0
|
|
0
|
{ |
1365
|
0
|
|
|
|
|
0
|
return( $self->error( "Bad selector \"$this\": $e" ) ); |
1366
|
29
|
0
|
0
|
29
|
|
281
|
} |
|
29
|
0
|
0
|
|
|
87
|
|
|
29
|
0
|
33
|
|
|
5751
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
19
|
0
|
|
|
|
79
|
|
|
0
|
0
|
|
|
|
0
|
|
|
19
|
50
|
|
|
|
222
|
|
|
19
|
50
|
|
|
|
152
|
|
|
19
|
50
|
|
|
|
116
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
19
|
|
|
|
|
245
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
} |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
1; |
1371
|
|
|
|
|
|
|
# NOTE: POD |
1372
|
|
|
|
|
|
|
__END__ |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
=encoding utf-8 |
1375
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
=head1 NAME |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
HTML::Object::DOM::Node - HTML Object DOM Node Class |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
use HTML::Object::DOM::Node; |
1383
|
|
|
|
|
|
|
my $node = HTML::Object::DOM::Node->new || |
1384
|
|
|
|
|
|
|
die( HTML::Object::DOM::Node->error, "\n" ); |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
=head1 VERSION |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
v0.2.1 |
1389
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
This module implement the properties and methods for HTML DOM nodes. It inherits from L<HTML::Object::EventTarget> and is used by L<HTML::Object::DOM::Element> |
1393
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
=head1 INHERITANCE |
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
+-----------------------+ +---------------------------+ +-------------------------+ |
1397
|
|
|
|
|
|
|
| HTML::Object::Element | --> | HTML::Object::EventTarget | --> | HTML::Object::DOM::Node | |
1398
|
|
|
|
|
|
|
+-----------------------+ +---------------------------+ +-------------------------+ |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
=head1 PROPERTIES |
1401
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
All the following properties can be used as lvalue method as well as regular method. For example with L</baseURI> |
1403
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
# Get the base uri, if any |
1405
|
|
|
|
|
|
|
my $uri = $e->baseURI; |
1406
|
|
|
|
|
|
|
$e->baseURI = 'https://example.org/some/where'; |
1407
|
|
|
|
|
|
|
# or |
1408
|
|
|
|
|
|
|
$e->baseURI( 'https://example.org/some/where' ); |
1409
|
|
|
|
|
|
|
|
1410
|
|
|
|
|
|
|
=head2 baseURI |
1411
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
Normally this is read-only, but in this api, you can set an URI. |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
This returns an L<URI> object representing the base URL of the document containing the Node, if any. |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
The base URL is determined as follows: |
1417
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
=over 4 |
1419
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
=item 1. By default, the base URL is the location of the document (as set by L<HTML::Object/parse_url>). |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
=item 2. If it is an L<HTML Document|HTML::Object::DOM::Document> and there is a L<<base>|https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base> element in the L<document|HTML::Object::DOM::Document>, the hrefvalue of the first Base element with such an attribute is used instead. |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
=item 3. By specifying an uri with L<HTML::Object::DOM::Document/documentURI> or L<HTML::Object::DOM::Document/URL> |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
=back |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
=head2 childNodes |
1429
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
Read-only |
1431
|
|
|
|
|
|
|
|
1432
|
|
|
|
|
|
|
This returns an L<array object|Module::Generic::Array> containing all the children of this node (including elements, text and comments). This list being live means that if the children of the Node change, the L<list object|Module::Generic::Array> is automatically updated. |
1433
|
|
|
|
|
|
|
|
1434
|
|
|
|
|
|
|
=head2 firstChild |
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
Read-only |
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
This returns an element representing the first direct child element of the element, or C<undef> if the element has no child. |
1439
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
=head2 isConnected |
1441
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
Returns a boolean indicating whether or not the element is connected (directly or indirectly) to the context object, i.e. the L<Document object|HTML::Object::Document> in the case of the normal DOM. |
1443
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected> |
1445
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
=head2 lastChild |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
Read-only |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
This returns an element representing the last direct child element of the element, or C<undef> if the element has no child. |
1451
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/lastChild> |
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
=head2 nextSibling |
1455
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
Read-only |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
This returns an element representing the next element in the tree, or C<undef> if there is not such element. |
1459
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
The next node could also be a L<whitespace|HTML::Object::DOM::Space> or a L<text|HTML::Object::DOM::Text>. If you want to get the next element and not just any node, use L<nextElementSibling|HTML::Object::DOM/nextElementSibling> instead. |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/nextSibling> |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
=head2 nodeName |
1465
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
Read-only |
1467
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
This returns a string containing the name of the element. The structure of the name will differ with the element type. E.g. An L<HTML Element|HTML::Object::Element> will contain the name of the corresponding tag, like 'audio' for an HTML audio element, a L<Text|HTML::Object::Text> element will have the '#text' string, or a L<Document|HTML::Object::Document> element will have the '#document' string. |
1469
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
For L<HTML element|HTML::Object::DOM::Element>, contrary to the standard specifications, is not the uppercase value of the tag name, but the lowercase value. However, if you really wanted the uppercase value, you could get it quite easily like so: |
1471
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
$e->nodeName->uc; |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
This is because L<HTML::Object::Element/tag> returns a L<scalar object|Module::Generic::Scalar> |
1475
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
Example: |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
This is some html: |
1479
|
|
|
|
|
|
|
<div id="d1">Hello world</div> |
1480
|
|
|
|
|
|
|
<!-- Example of comment --> |
1481
|
|
|
|
|
|
|
Text <span>Text</span> |
1482
|
|
|
|
|
|
|
Text<br/> |
1483
|
|
|
|
|
|
|
<svg height="20" width="20"> |
1484
|
|
|
|
|
|
|
<circle cx="10" cy="10" r="5" stroke="black" stroke-width="1" fill="red" /> |
1485
|
|
|
|
|
|
|
<hr> |
1486
|
|
|
|
|
|
|
<output id="result">Not calculated yet.</output> |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
then, with the script: |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
let node = document.getElementsByTagName("body")[0].firstChild; |
1491
|
|
|
|
|
|
|
let result = "Node names are:<br/>"; |
1492
|
|
|
|
|
|
|
while (node) { |
1493
|
|
|
|
|
|
|
result += node.nodeName + "<br/>"; |
1494
|
|
|
|
|
|
|
node = node.nextSibling |
1495
|
|
|
|
|
|
|
} |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
const output = document.getElementById("result"); |
1498
|
|
|
|
|
|
|
output.innerHTML = result; |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
would produce: |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
Node names are: |
1503
|
|
|
|
|
|
|
#text |
1504
|
|
|
|
|
|
|
div |
1505
|
|
|
|
|
|
|
#text |
1506
|
|
|
|
|
|
|
#comment |
1507
|
|
|
|
|
|
|
#text |
1508
|
|
|
|
|
|
|
span |
1509
|
|
|
|
|
|
|
#text |
1510
|
|
|
|
|
|
|
br |
1511
|
|
|
|
|
|
|
#text |
1512
|
|
|
|
|
|
|
svg |
1513
|
|
|
|
|
|
|
hr |
1514
|
|
|
|
|
|
|
#text |
1515
|
|
|
|
|
|
|
output |
1516
|
|
|
|
|
|
|
#text |
1517
|
|
|
|
|
|
|
script |
1518
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName> |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
=head2 nodeType |
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
Read-only |
1524
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
This returns an integer representing the type of the element. Possible values are: |
1526
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
=over 4 |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
=item 1. element node |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
=item 2. attribute node |
1532
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
=item 3. text node |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
=item 4. CDATA section node |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
=item 5. unused (formerly entity reference node) |
1538
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
=item 6. unused (formerly entity node) |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
=item 7. processing instruction node |
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
=item 8. comment node |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
=item 9. document node |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
=item 10. document type node |
1548
|
|
|
|
|
|
|
|
1549
|
|
|
|
|
|
|
=item 11. document fragment node |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
=item 12. notation node |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
=item 13. space node |
1554
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
=back |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType> |
1558
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
=head2 nodeValue |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
This returns or sets the value of the current node. |
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
For document, element or collection, this returns C<undef> and for attribute, text or comment, this sets or returns the objct value. |
1564
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeValue> |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
=head2 ownerDocument |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
Read-only |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
This returns the L<Document|HTML::Object::Document> that this element belongs to. If the element is itself a document, returns C<undef>. |
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/ownerDocument> |
1574
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
=head2 parentNode |
1576
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
Read-only |
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
This returns an element that is the parent of this element. If there is no such element, like if this element is the top of the tree or if does not participate in a tree, this property returns C<undef>. |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/parentNode> |
1582
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
=head2 parentElement |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
Read-only |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
This returns an element that is the parent of this element. If the element has no parent, or if that parent is not an Element, this property returns C<undef>. |
1588
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement> |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
=head2 previousSibling |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
Read-only |
1594
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
This returns a element representing the previous element in the tree, or C<undef> if there is not such element. |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
The previous node could also be a L<whitespace|HTML::Object::DOM::Space> or a L<text|HTML::Object::DOM::Text>. If you want to get the previous element and not just any node, use L<previousElementSibling|HTML::Object::DOM/previousElementSibling> instead. |
1598
|
|
|
|
|
|
|
|
1599
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/previousSibling> |
1600
|
|
|
|
|
|
|
|
1601
|
|
|
|
|
|
|
=head2 textContent |
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
Returns / Sets the textual content of an element and all its descendants. |
1604
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
If this is called on a L<text node|HTML::Object::DOM::Text> or a L<comment node|HTML::Object::DOM::Comment>, it will, instead, set the object value to the textual content provided. |
1606
|
|
|
|
|
|
|
|
1607
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent> |
1608
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
=head1 METHODS |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
=head2 addEventListener |
1612
|
|
|
|
|
|
|
|
1613
|
|
|
|
|
|
|
Registers an event handler to a specific event type on the node. This is inherited from L<HTML::Object::EventTarget> |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
See L<HTML::Object::EventTarget/addEventListener> for more information. |
1616
|
|
|
|
|
|
|
|
1617
|
|
|
|
|
|
|
=head2 appendChild |
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
Adds the specified C<child> L<element|HTML::Object::Element> argument as the last child to the current L<element|HTML::Object::Element>. If the argument referenced an existing L<element|HTML::Object::Element> on the DOM tree, the element will be detached from its current position and attached at the new position. |
1620
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
If the given C<child> is a L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, the entire contents of the L<DocumentFragment|HTML::Object::DOM::DocumentFragment> are moved into the child list of the specified parent node. |
1622
|
|
|
|
|
|
|
|
1623
|
|
|
|
|
|
|
It returns the element added, except when the C<child> is a L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, in which case the empty L<DocumentFragment|HTML::Object::DOM::DocumentFragment> is returned. |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
It returns C<undef> and sets an C<HTML::Object::HierarchyRequestError> error |
1626
|
|
|
|
|
|
|
|
1627
|
|
|
|
|
|
|
=over 4 |
1628
|
|
|
|
|
|
|
|
1629
|
|
|
|
|
|
|
=item * the parent of C<child> is not a L<Document|HTML::Object::DOM::Document>, L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, or an L<Element|HTML::Object::DOM::Element>. |
1630
|
|
|
|
|
|
|
|
1631
|
|
|
|
|
|
|
=item * the insertion of C<child> would lead to a cycle, that is If C<child> is an ancestor of the node. |
1632
|
|
|
|
|
|
|
|
1633
|
|
|
|
|
|
|
=item * C<child> is not a L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, a L<DocumentType|HTML::Object::DOM::Declaration>, an L<Element|HTML::Object::DOM::Element>, or a L<CharacterData|HTML::Object::DOM::CharacterData>. |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
=item * the current node is a L<Text|HTML::Object::DOM::Text>, and its parent is a L<Document|HTML::Object::DOM::Document>. |
1636
|
|
|
|
|
|
|
|
1637
|
|
|
|
|
|
|
=item * the current node is a L<DocumentType|HTML::Object::DOM::Declaration> and its parent is not a L<Document|HTML::Object::DOM::Document>, as a doctype should always be a direct descendant of a document. |
1638
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
=item * the parent of the node is a L<Document|HTML::Object::DOM::Document> and C<child> is a L<DocumentFragment|HTML::Object::DOM::DocumentFragment> with more than one L<Element|HTML::Object::DOM::Element> child, or that has a L<Text|HTML::Object::DOM::Text> child. |
1640
|
|
|
|
|
|
|
|
1641
|
|
|
|
|
|
|
=item * the insertion of C<child> would lead to L<Document|HTML::Object::DOM::Document> with more than one L<Element|HTML::Object::DOM::Element> as child. |
1642
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
=item * the insertion of C<child> would lead to the presence of an L<Element|HTML::Object::DOM::Element> node before a L<DocumentType|HTML::Object::DOM::Declaration> node. |
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
=back |
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild> |
1648
|
|
|
|
|
|
|
|
1649
|
|
|
|
|
|
|
=head2 appendNodes |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
Provided with some nodes, and this will add them to the list of nodes for the current node. |
1652
|
|
|
|
|
|
|
|
1653
|
|
|
|
|
|
|
Returns the current node object. |
1654
|
|
|
|
|
|
|
|
1655
|
|
|
|
|
|
|
=head2 cloneNode |
1656
|
|
|
|
|
|
|
|
1657
|
|
|
|
|
|
|
Clone an element, and optionally, all of its contents. By default, it clones the content of the element. |
1658
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
To clone a node to insert into a different document, use L<HTML::Object::DOM::Document/importNode> instead. |
1660
|
|
|
|
|
|
|
|
1661
|
|
|
|
|
|
|
Returns the element cloned. The cloned node has no parent and is not part of the document, until it is added to another node that is part of the document, using L</appendChild> or a similar method. |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode> |
1664
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
=head2 compareDocumentPosition |
1666
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
Compares the position of the current element against another element in any other document and returns a bitwise value comprised of one or more of the following constants (that are automatically exported): |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
=over 4 |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_IDENTICAL (0 or in bits: 000000) |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
Elements are identical. |
1674
|
|
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_DISCONNECTED (1 or in bits: 000001) |
1676
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
No relationship, both nodes are in different documents or different trees in the same document. |
1678
|
|
|
|
|
|
|
|
1679
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_PRECEDING (2 or in bits: 000010) |
1680
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
The specified node precedes the current node. |
1682
|
|
|
|
|
|
|
|
1683
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_FOLLOWING (4 or in bits: 000100) |
1684
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
The specified node follows the current node. |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_CONTAINS (8 or in bits: 001000) |
1688
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
The otherNode is an ancestor of / contains the current node. |
1690
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_CONTAINED_BY (16 or in bits: 010000) |
1692
|
|
|
|
|
|
|
|
1693
|
|
|
|
|
|
|
The otherNode is a descendant of / contained by the node. |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC (32 or in bits: 100000) |
1696
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
The specified node and the current node have no common container node or the two nodes are different attributes of the same node. |
1698
|
|
|
|
|
|
|
|
1699
|
|
|
|
|
|
|
=back |
1700
|
|
|
|
|
|
|
|
1701
|
|
|
|
|
|
|
use HTML::Object::DOM::Node; |
1702
|
|
|
|
|
|
|
my $head = $doc->head; |
1703
|
|
|
|
|
|
|
my $body = $doc->body; |
1704
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
if( $head->compareDocumentPosition( $body ) & DOCUMENT_POSITION_FOLLOWING ) |
1706
|
|
|
|
|
|
|
{ |
1707
|
|
|
|
|
|
|
say( 'Well-formed document' ); |
1708
|
|
|
|
|
|
|
} |
1709
|
|
|
|
|
|
|
else |
1710
|
|
|
|
|
|
|
{ |
1711
|
|
|
|
|
|
|
say( '<head> is not before <body>' ); |
1712
|
|
|
|
|
|
|
} |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
For example: |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
<div id="writeroot"> |
1717
|
|
|
|
|
|
|
<form> |
1718
|
|
|
|
|
|
|
<input id="test" /> |
1719
|
|
|
|
|
|
|
</form> |
1720
|
|
|
|
|
|
|
</div> |
1721
|
|
|
|
|
|
|
|
1722
|
|
|
|
|
|
|
my $x = $doc->getElementById('writeroot'); |
1723
|
|
|
|
|
|
|
my $y = $doc->getElementById('test'); |
1724
|
|
|
|
|
|
|
say( $x->compareDocumentPosition( $y ) ); # 20, i.e. 16 | 4 |
1725
|
|
|
|
|
|
|
say( $y->compareDocumentPosition( $x ) ); # 10, i.e. 8 | 2 |
1726
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
Be careful that, since this method does quite a bit of searching among various hierarchies, this method is a bit expensive, especially on large documents. |
1728
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition> and also this L<blog post from John Resig|https://johnresig.com/blog/comparing-document-position/> or L<this one from Peter-Paul Koch|https://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html> |
1730
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
Also the L<W3C specifications|http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-compareDocumentPosition> and L<here|http://www.w3.org/TR/DOM-Level-3-Core/core.html#DocumentPosition> |
1732
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
=head2 contains |
1734
|
|
|
|
|
|
|
|
1735
|
|
|
|
|
|
|
Returns true or false value indicating whether or not an element is a descendant of the calling element. |
1736
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/contains> |
1738
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
=head2 dispatchEvent |
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
Dispatches an event to this node in the DOM and returns a boolean value that indicates whether no handler canceled the event. This is inherited from L<HTML::Object::EventTarget> |
1742
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
See L<HTML::Object::EventTarget/dispatchEvent> for more information. |
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
=head2 find |
1746
|
|
|
|
|
|
|
|
1747
|
|
|
|
|
|
|
Provided with an node object or a selector and this will search throughout the current node hierarchy using the XPath expression provided. |
1748
|
|
|
|
|
|
|
|
1749
|
|
|
|
|
|
|
It returns an L<array object|Module::Generic::Array> of the nodes found. |
1750
|
|
|
|
|
|
|
|
1751
|
|
|
|
|
|
|
=head2 find_xpath |
1752
|
|
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
Provided with an XPath expression and this will perform a search using the current node as the context. |
1754
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
=head2 findnodes |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
Provided with an XPath expression and this will perform a search using the current node as the context. |
1758
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
=head2 findnodes_as_string |
1760
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
Provided with an XPath expression and this will perform a search using the current node as the context and return the result as string. |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
=head2 findnodes_as_strings |
1764
|
|
|
|
|
|
|
|
1765
|
|
|
|
|
|
|
Provided with an XPath expression and this will perform a search using the current node as the context and return the result as a list of strings. |
1766
|
|
|
|
|
|
|
|
1767
|
|
|
|
|
|
|
=head2 findvalue |
1768
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
Provided with an XPath expression and this will perform a search using the current node as the context and return the result as the node value. |
1770
|
|
|
|
|
|
|
|
1771
|
|
|
|
|
|
|
=head2 findvalues |
1772
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
Provided with an XPath expression and this will perform a search using the current node as the context and return the result as a list of node values. |
1774
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
=head2 getAttributes |
1776
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
Returns a list of attribute objects for this node in list context or an L<array object|Module::Generic::Array> in scalar context. |
1778
|
|
|
|
|
|
|
|
1779
|
|
|
|
|
|
|
=head2 getChildNodes |
1780
|
|
|
|
|
|
|
|
1781
|
|
|
|
|
|
|
Returns a list of the current child nodes in list context or an L<array object|Module::Generic::Array> in scalar context. |
1782
|
|
|
|
|
|
|
|
1783
|
|
|
|
|
|
|
=head2 getElementById |
1784
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
Returns an empty list in list context and an empty array reference in scalar context. |
1786
|
|
|
|
|
|
|
|
1787
|
|
|
|
|
|
|
=head2 getFirstChild |
1788
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
Returns the first child node of this node, if any, or C<undef> if there are none. |
1790
|
|
|
|
|
|
|
|
1791
|
|
|
|
|
|
|
=head2 getLastChild |
1792
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
Returns the last child node of this node, if any, or C<undef> if there are none. |
1794
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
=head2 getName |
1796
|
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
Returns an C<undef> and this method is superseded in L<HTML::Object::DOM::Element> |
1798
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
=head2 getNextSibling |
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
This non-standard method is an alias for the property L</nextSibling> |
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
=head2 getParentNode |
1804
|
|
|
|
|
|
|
|
1805
|
|
|
|
|
|
|
Returns the current node's parent node, if any. |
1806
|
|
|
|
|
|
|
|
1807
|
|
|
|
|
|
|
=head2 getPreviousSibling |
1808
|
|
|
|
|
|
|
|
1809
|
|
|
|
|
|
|
This non-standard method is an alias for the property L</previousSibling> |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
=head2 getRootNode |
1812
|
|
|
|
|
|
|
|
1813
|
|
|
|
|
|
|
Returns the context object's root. |
1814
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
Under JavaScript, this optionally includes the shadow root if it is available. However a shadow root has no meaning under this perl interface. |
1816
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode> |
1818
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
=head2 hasChildNodes |
1820
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
Returns a boolean value indicating whether or not the element has any child elements. |
1822
|
|
|
|
|
|
|
|
1823
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/hasChildNodes> |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
=head2 insertAfter |
1826
|
|
|
|
|
|
|
|
1827
|
|
|
|
|
|
|
This is a non-standard method since it does not exist in the web API, surprisingly enough. |
1828
|
|
|
|
|
|
|
|
1829
|
|
|
|
|
|
|
This is exactly the same as L</insertBefore> below except it inserts the C<node> after. |
1830
|
|
|
|
|
|
|
|
1831
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/insertAfter> |
1832
|
|
|
|
|
|
|
|
1833
|
|
|
|
|
|
|
=head2 insertBefore |
1834
|
|
|
|
|
|
|
|
1835
|
|
|
|
|
|
|
Provided with a C<new> node and an optional C<reference> node and this inserts an element before the reference element as a child of a specified parent element. If the C<reference> node is C<undef>, then C<new> node is inserted at the end of current node's child nodes. |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
If the given node already exists in the document, C<insertBefore> moves it from its current position to the new position. This means it will automatically be removed from its existing parent before appending it to the specified new parent. |
1838
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
This means that a node cannot be in two locations of the document simultaneously. |
1840
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
If the given child is a L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, the entire contents of the L<DocumentFragment|HTML::Object::DOM::DocumentFragment> are moved into the child list of the specified parent node. |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
Returns the added child (unless C<new> is a L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, in which case the empty L<DocumentFragment|HTML::Object::DOM::DocumentFragment> is returned). |
1844
|
|
|
|
|
|
|
|
1845
|
|
|
|
|
|
|
Example: |
1846
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
<div id="parentElement"> |
1848
|
|
|
|
|
|
|
<span id="childElement">foo bar</span> |
1849
|
|
|
|
|
|
|
</div> |
1850
|
|
|
|
|
|
|
|
1851
|
|
|
|
|
|
|
# Create a new, plain <span> element |
1852
|
|
|
|
|
|
|
my $sp1 = $doc->createElement( 'span' ); |
1853
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
# Get the reference element |
1855
|
|
|
|
|
|
|
my $sp2 = $doc->getElementById( 'childElement' ); |
1856
|
|
|
|
|
|
|
# Get the parent element |
1857
|
|
|
|
|
|
|
my $parentDiv = $sp2->parentNode |
1858
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
# Insert the new element into before sp2 |
1860
|
|
|
|
|
|
|
$parentDiv->insertBefore( $sp1, $sp2 ); |
1861
|
|
|
|
|
|
|
|
1862
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore> |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
=head2 isAttributeNode |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
Returns false by default. |
1867
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
=head2 isCommentNode |
1869
|
|
|
|
|
|
|
|
1870
|
|
|
|
|
|
|
Returns false by default. |
1871
|
|
|
|
|
|
|
|
1872
|
|
|
|
|
|
|
=head2 isDefaultNamespace |
1873
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
Accepts a namespace URI as an argument and returns a boolean value with a value of true if the namespace is the default namespace on the given element or false if not. |
1875
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/isDefaultNamespace> |
1877
|
|
|
|
|
|
|
|
1878
|
|
|
|
|
|
|
=head2 isElementNode |
1879
|
|
|
|
|
|
|
|
1880
|
|
|
|
|
|
|
Returns false by default. |
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
=head2 isEqualNode |
1883
|
|
|
|
|
|
|
|
1884
|
|
|
|
|
|
|
Returns a boolean value which indicates whether or not two elements are of the same type and all their defining data points match. |
1885
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
Two elements are equal when they have the same type, defining characteristics (this would be their ID, number of children, and so forth), its attributes match, and so on. The specific set of data points that must match varies depending on the types of the elements. |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/isEqualNode> |
1889
|
|
|
|
|
|
|
|
1890
|
|
|
|
|
|
|
=head2 isNamespaceNode |
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
Returns false by default. |
1893
|
|
|
|
|
|
|
|
1894
|
|
|
|
|
|
|
=head2 isPINode |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
Returns false by default. |
1897
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
=head2 isProcessingInstructionNode |
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
Returns false by default. |
1901
|
|
|
|
|
|
|
|
1902
|
|
|
|
|
|
|
=head2 isSameNode |
1903
|
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
Returns a boolean value indicating whether or not the two elements are the same (that is, they reference the same object). |
1905
|
|
|
|
|
|
|
|
1906
|
|
|
|
|
|
|
Example: |
1907
|
|
|
|
|
|
|
|
1908
|
|
|
|
|
|
|
my $div1 = $doc->createElement('div'); |
1909
|
|
|
|
|
|
|
$div1->appendChild( $doc->createTextNode('This is an element.') ); |
1910
|
|
|
|
|
|
|
my $div2 = $div1->cloneNode; |
1911
|
|
|
|
|
|
|
say $div1->isSameNode( $div2 ); # false |
1912
|
|
|
|
|
|
|
say $div1->isSameNode( $div1 ); # true |
1913
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
We can also use with the equality operator: |
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
say $div1 == $div2; # false |
1917
|
|
|
|
|
|
|
say $div1 eq $div2; # same; false |
1918
|
|
|
|
|
|
|
say $div1 == $div1; # true |
1919
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/isSameNode> |
1921
|
|
|
|
|
|
|
|
1922
|
|
|
|
|
|
|
=head2 isTextNode |
1923
|
|
|
|
|
|
|
|
1924
|
|
|
|
|
|
|
Returns false by default. |
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
=head2 lookupNamespaceURI |
1927
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
Accepts a prefix and returns the namespace URI associated with it on the given element if found (and C<undef> if not). Supplying C<undef> for the prefix will return the default namespace. |
1929
|
|
|
|
|
|
|
|
1930
|
|
|
|
|
|
|
This always return an empty string and C<http://www.w3.org/XML/1998/namespace> if the prefix is C<xml> |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/lookupNamespaceURI> |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
=head2 lookupPrefix |
1935
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
This always returns C<undef>, because this is for XML, which is not supported. |
1937
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
Returns a string containing the prefix for a given namespace URI, if present, and C<undef> if not. |
1939
|
|
|
|
|
|
|
|
1940
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/lookupPrefix> |
1941
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
=head2 new_closing |
1943
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
Returns a new L<HTML::Object::DOM::Closing> object, passing it whatever arguments were provided and return the newly instantiated object. |
1945
|
|
|
|
|
|
|
|
1946
|
|
|
|
|
|
|
If an error occurred, this returns C<undef> and sets an L<error|Module::Generic/error> |
1947
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
=head2 new_comment |
1949
|
|
|
|
|
|
|
|
1950
|
|
|
|
|
|
|
Returns a new L<HTML::Object::DOM::Comment> object, passing it whatever arguments were provided and return the newly instantiated object. |
1951
|
|
|
|
|
|
|
|
1952
|
|
|
|
|
|
|
If an error occurred, this returns C<undef> and sets an L<error|Module::Generic/error> |
1953
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
=head2 new_element |
1955
|
|
|
|
|
|
|
|
1956
|
|
|
|
|
|
|
Returns a new L<HTML::Object::DOM::Element> object, passing it whatever arguments were provided and return the newly instantiated object. |
1957
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
If an error occurred, this returns C<undef> and sets an L<error|Module::Generic/error> |
1959
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
=head2 new_parser |
1961
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
Returns a new L<HTML::Object::DOM> object, passing it whatever arguments were provided and return the newly instantiated object. |
1963
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
If an error occurred, this returns C<undef> and sets an L<error|Module::Generic/error> |
1965
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
=head2 new_text |
1967
|
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
Returns a new L<HTML::Object::DOM::Text> object, passing it whatever arguments were provided and return the newly instantiated object. |
1969
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
If an error occurred, this returns C<undef> and sets an L<error|Module::Generic/error> |
1971
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
=head2 nodes |
1973
|
|
|
|
|
|
|
|
1974
|
|
|
|
|
|
|
Returns the L<array object|Module::Generic::Array> containing the current node's sub nodes. |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
=head2 normalize |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
Clean up all the text elements under this element (merge adjacent, remove empty). |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/normalize> |
1981
|
|
|
|
|
|
|
|
1982
|
|
|
|
|
|
|
=head2 removeChild |
1983
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
Provided with a child node and this removes the child node from the current element, which must be a child of the current element and returns the removed node. |
1985
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
A C<HTML::Object::NotFoundError> error is returned if the child is not a child of the node. |
1987
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
Example: |
1989
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
<div id="top"> |
1991
|
|
|
|
|
|
|
<div id="nested"></div> |
1992
|
|
|
|
|
|
|
</div> |
1993
|
|
|
|
|
|
|
|
1994
|
|
|
|
|
|
|
To remove a specified element when knowing its parent node: |
1995
|
|
|
|
|
|
|
|
1996
|
|
|
|
|
|
|
my $d = $doc->getElementById('top'); |
1997
|
|
|
|
|
|
|
my $d_nested = $doc->getElementById('nested'); |
1998
|
|
|
|
|
|
|
my $throwawayNode = $d->removeChild( $d_nested ); |
1999
|
|
|
|
|
|
|
|
2000
|
|
|
|
|
|
|
To remove a specified element without having to specify its parent node: |
2001
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
my $node = $doc->getElementById('nested'); |
2003
|
|
|
|
|
|
|
if( $node->parentNode ) |
2004
|
|
|
|
|
|
|
{ |
2005
|
|
|
|
|
|
|
$node->parentNode->removeChild( $node ); |
2006
|
|
|
|
|
|
|
} |
2007
|
|
|
|
|
|
|
|
2008
|
|
|
|
|
|
|
See L<for more information|https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild> |
2009
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
=head2 removeEventListener |
2011
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
Removes an event listener from the node. This is inherited from L<HTML::Object::EventTarget> |
2013
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
See L<HTML::Object::EventTarget/removeEventListener> for more information. |
2015
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
=head2 replaceChild |
2017
|
|
|
|
|
|
|
|
2018
|
|
|
|
|
|
|
Provided with a C<new> node and and an C<old> node and this will replace the C<old> one by the C<new> one. Note that if the C<new> node is already present somewhere else in the C<DOM>, it is first removed from that position. |
2019
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
This returns the C<old> node removed. |
2021
|
|
|
|
|
|
|
|
2022
|
|
|
|
|
|
|
For L<nodes|HTML::Object::DOM::Node> that are L<elements|HTML::Object::DOM::Element>, it might be easier to read and use L<HTML::Object::DOM::Element/replaceWith> |
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
It returns C<undef> and sets an L<HTML::Object::HierarchyRequestError|Module::Generic/error> if: |
2025
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
=over 4 |
2027
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
=item * the parent of C<old> node is not a L<Document|HTML::Object::DOM::Document>, L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, or an L<Element|HTML::Object::DOM::Element>. |
2029
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
=item * the replacement of C<old> node by C<new> node would lead to a cycle, that is if C<new> node is an ancestor of the node. |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
=item * C<new> is not a L<DocumentFragment|HTML::Object::DOM::DocumentFragment>, a L<DocumentType|HTML::Object::DOM::Declaration>, an L<Element|HTML::Object::DOM::Element>, or a L<CharacterData|HTML::Object::DOM::CharacterData>. |
2033
|
|
|
|
|
|
|
|
2034
|
|
|
|
|
|
|
=item * the current node is a L<Text|HTML::Object::DOM::Text>, and its parent is a L<Document|HTML::Object::DOM::Document>. |
2035
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
=item * the current node is a L<DocumentType|HTML::Object::DOM::Declaration> and its parent is not a L<Document|HTML::Object::DOM::Document>, as a doctype should always be a direct descendant of a document. |
2037
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
=item * the parent of the node is a L<Document|HTML::Object::DOM::Document> and C<new> node is a L<DocumentFragment|HTML::Object::DOM::DocumentFragment> with more than one L<Element|HTML::Object::DOM::Element> child, or that has a L<Text|HTML::Object::DOM::Text> child. |
2039
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
=item * the replacement of C<old> node by C<new> node would lead to L<Document|HTML::Object::DOM::Document> with more than one L<Element|HTML::Object::DOM::Element> as child. |
2041
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
=item * the replacement of C<old> node by C<new> node would lead to the presence of an L<Element|HTML::Object::DOM::Element> node before a L<DocumentType|HTML::Object::DOM::Declaration> node. |
2043
|
|
|
|
|
|
|
|
2044
|
|
|
|
|
|
|
=back |
2045
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
It returns an L<HTML::Object::NotFoundError|Module::Generic/error> if the parent of C<old> is not the current node. |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
Example: |
2049
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
<div> |
2051
|
|
|
|
|
|
|
<span id="childSpan">foo bar</span> |
2052
|
|
|
|
|
|
|
</div> |
2053
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
// Build a reference to the existing node to be replaced |
2055
|
|
|
|
|
|
|
let sp1 = document.getElementById('childSpan'); |
2056
|
|
|
|
|
|
|
let parentDiv = sp2.parentNode; |
2057
|
|
|
|
|
|
|
// Create an empty element node without an ID, any attributes, or any content |
2058
|
|
|
|
|
|
|
let sp2 = document.createElement('span'); |
2059
|
|
|
|
|
|
|
// Give it an id attribute called 'newSpan' |
2060
|
|
|
|
|
|
|
sp2.id = "newSpan"; |
2061
|
|
|
|
|
|
|
// Create some content for the new element. |
2062
|
|
|
|
|
|
|
sp2.appendChild( document.createTextNode('new replacement span element.') ); |
2063
|
|
|
|
|
|
|
// Replace existing node sp1 with the new span element sp2 |
2064
|
|
|
|
|
|
|
parentDiv.replaceChild(sp2, sp1); |
2065
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
Result: |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
<div> |
2069
|
|
|
|
|
|
|
<span id="newSpan">new replacement span element.</span> |
2070
|
|
|
|
|
|
|
</div> |
2071
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/Node/replaceChild> |
2073
|
|
|
|
|
|
|
|
2074
|
|
|
|
|
|
|
=head2 trigger |
2075
|
|
|
|
|
|
|
|
2076
|
|
|
|
|
|
|
Provided with an even C<type> and this will instantiate a new L<HTML::Object::Event> object, passing it the C<type> argument, and any other arguments provided. it returns the value returned by L<HTML::Object::EventTarget/dispatchEvent> |
2077
|
|
|
|
|
|
|
|
2078
|
|
|
|
|
|
|
If no event type is provided, it returns a C<HTML::Object::SyntaxError> error. |
2079
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
If the event type contains illegal characters, it returns a C<HTML::Object::TypeError> error. Accepted characters are alpha-numeric, underscore, and dash ("-"). |
2081
|
|
|
|
|
|
|
|
2082
|
|
|
|
|
|
|
=head2 xp |
2083
|
|
|
|
|
|
|
|
2084
|
|
|
|
|
|
|
Returns a L<HTML::Object::XPath> object. |
2085
|
|
|
|
|
|
|
|
2086
|
|
|
|
|
|
|
=head1 CONSTANTS |
2087
|
|
|
|
|
|
|
|
2088
|
|
|
|
|
|
|
=over 4 |
2089
|
|
|
|
|
|
|
|
2090
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_IDENTICAL (0 or in bits: 000000) |
2091
|
|
|
|
|
|
|
|
2092
|
|
|
|
|
|
|
Elements are identical. |
2093
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_DISCONNECTED (1 or in bits: 000001) |
2095
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
No relationship, both nodes are in different documents or different trees in the same document. |
2097
|
|
|
|
|
|
|
|
2098
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_PRECEDING (2 or in bits: 000010) |
2099
|
|
|
|
|
|
|
|
2100
|
|
|
|
|
|
|
The specified node precedes the current node. |
2101
|
|
|
|
|
|
|
|
2102
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_FOLLOWING (4 or in bits: 000100) |
2103
|
|
|
|
|
|
|
|
2104
|
|
|
|
|
|
|
The specified node follows the current node. |
2105
|
|
|
|
|
|
|
|
2106
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_CONTAINS (8 or in bits: 001000) |
2107
|
|
|
|
|
|
|
|
2108
|
|
|
|
|
|
|
The otherNode is an ancestor of / contains the current node. |
2109
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_CONTAINED_BY (16 or in bits: 010000) |
2111
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
The otherNode is a descendant of / contained by the node. |
2113
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
=item * DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC (32 or in bits: 100000) |
2115
|
|
|
|
|
|
|
|
2116
|
|
|
|
|
|
|
The specified node and the current node have no common container node or the two nodes are different attributes of the same node. |
2117
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
=back |
2119
|
|
|
|
|
|
|
|
2120
|
|
|
|
|
|
|
And also the following constants: |
2121
|
|
|
|
|
|
|
|
2122
|
|
|
|
|
|
|
=over 4 |
2123
|
|
|
|
|
|
|
|
2124
|
|
|
|
|
|
|
=item * ELEMENT_NODE (1) |
2125
|
|
|
|
|
|
|
|
2126
|
|
|
|
|
|
|
=item * ATTRIBUTE_NODE (2) |
2127
|
|
|
|
|
|
|
|
2128
|
|
|
|
|
|
|
=item * TEXT_NODE (3) |
2129
|
|
|
|
|
|
|
|
2130
|
|
|
|
|
|
|
=item * CDATA_SECTION_NODE (4) |
2131
|
|
|
|
|
|
|
|
2132
|
|
|
|
|
|
|
=item * ENTITY_REFERENCE_NODE (5) |
2133
|
|
|
|
|
|
|
|
2134
|
|
|
|
|
|
|
=item * ENTITY_NODE (6) |
2135
|
|
|
|
|
|
|
|
2136
|
|
|
|
|
|
|
=item * PROCESSING_INSTRUCTION_NODE (7) |
2137
|
|
|
|
|
|
|
|
2138
|
|
|
|
|
|
|
=item * COMMENT_NODE (8) |
2139
|
|
|
|
|
|
|
|
2140
|
|
|
|
|
|
|
=item * DOCUMENT_NODE (9) |
2141
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
=item * DOCUMENT_TYPE_NODE (10) |
2143
|
|
|
|
|
|
|
|
2144
|
|
|
|
|
|
|
=item * DOCUMENT_FRAGMENT_NODE (11) |
2145
|
|
|
|
|
|
|
|
2146
|
|
|
|
|
|
|
=item * NOTATION_NODE (12) |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
=item * SPACE_NODE (13) |
2149
|
|
|
|
|
|
|
|
2150
|
|
|
|
|
|
|
=back |
2151
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
=head1 AUTHOR |
2153
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
2155
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
=head1 SEE ALSO |
2157
|
|
|
|
|
|
|
|
2158
|
|
|
|
|
|
|
See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/API/Node> |
2159
|
|
|
|
|
|
|
|
2160
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
2161
|
|
|
|
|
|
|
|
2162
|
|
|
|
|
|
|
Copyright(c) 2021 DEGUEST Pte. Ltd. |
2163
|
|
|
|
|
|
|
|
2164
|
|
|
|
|
|
|
All rights reserved |
2165
|
|
|
|
|
|
|
|
2166
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
2167
|
|
|
|
|
|
|
|
2168
|
|
|
|
|
|
|
=cut |