Changeset 346
- Timestamp:
- 03/08/08 09:55:39 (2 months ago)
- Files:
-
- trunk/src/ingy/pQuery/lib/pQuery/DOM.pm (modified) (11 diffs)
- trunk/src/ingy/pQuery/t/dom.t (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/ingy/pQuery/lib/pQuery/DOM.pm
r345 r346 40 40 $self->{'_ignore_text'} = 0; 41 41 $self->{'_warn'} = 0; 42 $self->{'_no_space_compacting'}= 0;42 $self->{'_no_space_compacting'}= 1; 43 43 $self->{'_store_comments'} = 0; 44 $self->{'_store_declarations'} = 1;44 $self->{'_store_declarations'} = 0; 45 45 $self->{'_store_pis'} = 0; 46 $self->{'_p_strict'} = 0;46 $self->{'_p_strict'} = 0; 47 47 48 48 # Parse attributes passed in as arguments … … 65 65 $self->{'_pos'} = undef; # pull it back up again 66 66 $self->ignore_ignorable_whitespace(0); 67 $self->store_comments(1); 67 68 $self->no_space_compacting(1); 68 69 … … 104 105 } 105 106 $_; 106 } @{$dom->{_body}{_content} };107 } @{$dom->{_body}{_content} || [$dom->{_content}[-1]]}; 107 108 return wantarray ? @dom : $dom[0]; 109 } 110 111 sub createElement { 112 my ($class, $tag) = @_; 113 return unless $tag =~ /^\w+$/; 114 return $class->fromHTML('<' . $tag . '>'); 115 } 116 117 sub createComment { 118 my ($class, $comment) = @_; 119 return $class->fromHTML('<!--' . $comment . '-->'); 108 120 } 109 121 … … 123 135 sub innerHTML { 124 136 my $self = shift; 137 138 return if $self->{_tag} eq '~comment'; 139 125 140 if (@_) { 126 my $dom = $self->html_to_dom(@_);127 die "XXX - need to insert dom here";141 $self->{_content} = [pQuery::DOM->fromHTML($_[0])]; 142 return $_[0]; 128 143 } 129 144 130 145 my $html = ''; 131 146 132 my @list = @{$self->{_content} };147 my @list = @{$self->{_content} || []}; 133 148 for (@list) { 134 149 _to_html($_, \$html); … … 139 154 140 155 sub getElementsByTagName { 141 die "Not yet implemented"; 156 my ($self, $tag) = @_; 157 my $found = []; 158 _find($self, $found, sub { $_->{_tag} eq $tag}); 159 return wantarray ? @$found : $found->[0]; 142 160 } 143 161 144 162 sub getElementById { 145 die "Not yet implemented"; 163 my ($self, $id) = @_; 164 my $found = []; 165 _find($self, $found, sub { $_->{id} and $_->{id} eq $id}); 166 return wantarray ? @$found : $found->[0]; 146 167 } 147 168 148 169 sub nodeType { 149 return 1;170 return $_[0]->{_tag} eq '~comment' ? 8 : 1; 150 171 } 151 172 152 173 sub nodeName { 174 return '#comment' if $_[0]->{_tag} eq '~comment'; 153 175 return uc($_[0]->{_tag}); 176 } 177 178 sub tagName { 179 return '' if $_[0]->{_tag} eq '~comment'; 180 return $_[0]->nodeName; 181 } 182 183 sub nodeValue { 184 my $self = shift; 185 return $self->{text} if $self->{_tag} eq '~comment'; 186 return; 154 187 } 155 188 … … 159 192 160 193 sub setAttribute { 161 die "Not yet implemented"; 194 $_[0]->{lc($_[1])} = $_[2]; 195 return; 196 } 197 198 sub removeAttribute { 199 delete $_[0]->{lc($_[1])}; 162 200 } 163 201 164 202 sub hasAttributes { 165 die "Not yet implemented"; 166 } 167 168 sub removeAttribute { 169 die "Not yet implemented"; 170 } 171 172 sub tagName { 173 die "Not yet implemented"; 203 my $self = shift; 204 return 0 if $self->{_tag} eq '~comment'; 205 return scalar(grep /^[a-z0-9]/, keys %$self) ? 1 : 0; 174 206 } 175 207 176 208 sub className { 209 if ($_[1]) { 210 return $_[0]->setAttribute(class => $_[1]); 211 } 177 212 $_[0]->getAttribute("class"); 178 213 } 179 214 180 sub nodeValue {181 die "Not yet implemented";182 }183 184 215 sub parentNode { 185 die "Not yet implemented";216 return $_[0]->{_parent}; 186 217 } 187 218 188 219 sub childNodes { 189 die "Not yet implemented";220 return @{$_[0]->{_content} || []}; 190 221 } 191 222 192 223 sub firstChild { 193 die "Not yet implemented"; 224 return unless $_[0]->{_content}; 225 return $_[0]->{_content}[0]; 194 226 } 195 227 196 228 sub lastChild { 197 die "Not yet implemented"; 229 return unless $_[0]->{_content}; 230 return $_[0]->{_content}[-1]; 231 } 232 233 sub appendChild { 234 my ($self, $elem) = @_; 235 return unless defined $elem; 236 my $content = $self->{_content} ||= []; 237 push @$content, $elem; 238 return $elem; 198 239 } 199 240 200 241 sub previousSibling { 201 die " Not yet implemented";242 die "pQuery::DOM does not support the previousSibling method"; 202 243 } 203 244 204 245 sub nextSibling { 205 die " Not yet implemented";246 die "pQuery::DOM does not support the nextSibling method"; 206 247 } 207 248 208 249 sub attributes { 209 die "Not yet implemented"; 210 } 211 250 die "pQuery::DOM::attributes not yet implemented"; 251 } 212 252 213 253 ################################################################################ … … 216 256 sub _to_html { 217 257 my ($elem, $html) = @_; 218 if (ref $elem) { 219 $$html .= '<' . $elem->{_tag}; 220 $$html .= qq{ id="$elem->{id}"} 221 if $elem->{id}; 222 $$html .= qq{ class="$elem->{class}"} 223 if $elem->{class}; 224 for (sort keys %$elem) { 225 next if /^(_|id$|class$)/i; 226 $$html .= qq{ $_="$elem->{$_}"}; 227 } 228 229 $$html .= '>'; 230 for my $child (@{$elem->{_content}}) { 231 _to_html($child, $html); 232 } 233 $$html .= '</' . $elem->{_tag} . '>'; 234 } 235 else { 258 if (not ref $elem) { 236 259 $$html .= $elem; 237 } 260 return; 261 } 262 if ($elem->{_tag} eq '~comment') { 263 $$html .= '<!--' . $elem->{text} . '-->'; 264 return; 265 } 266 $$html .= '<' . $elem->{_tag}; 267 $$html .= qq{ id="$elem->{id}"} 268 if $elem->{id}; 269 $$html .= qq{ class="$elem->{class}"} 270 if $elem->{class}; 271 for (sort keys %$elem) { 272 next if /^(_|id$|class$)/i; 273 $$html .= qq{ $_="$elem->{$_}"}; 274 } 275 276 $$html .= '>'; 277 for my $child (@{$elem->{_content} || []}) { 278 _to_html($child, $html); 279 } 280 $$html .= '</' . $elem->{_tag} . '>'; 281 } 282 283 sub _find { 284 my ($elem, $found, $test) = @_; 285 $_ = $elem; 286 if (&$test()) { 287 push @$found, $_; 288 } 289 290 map _find($_, $found, $test), grep ref($_), @{$elem->{_content} || []}; 238 291 } 239 292 … … 255 308 pQuery needs a DOM to represent its content. Since there is no standard 256 309 DOM class in Perl, pQuery implements its own. 310 311 =head1 DOM MODEL 312 313 It is important to note that pQuery::DOM is essentially a subclass of 314 HTML::TreeBuilder and HTML::Element. As such, text nodes are just 315 strings and therefore cannot have methods called on them. 316 317 This implies that the DOM methods previousSibling and nextSibling 318 wouldn't really work correctly. Therefore they are not implemented. 319 320 To deal with children, use the childNodes method which returns a list 321 of all the child nodes. Then you can you standard Perl idioms to 322 process them. 323 324 Note that all pQuery::DOM objects are either HTML Element nodes or HTML 325 Comment nodes. 257 326 258 327 =head1 METHODS … … 268 337 =item fromHTML($html) 269 338 270 This is the main constructor method. It takes any HTML string and returns the 271 DOM object tree that represents that HTML. 339 This is the main constructor method. It takes any HTML string and 340 returns the DOM object tree that represents that HTML. 341 342 =item createElement($tag) 343 344 Create a new HTML Element node with the specified tag. This node will be empty 345 and have no attributes. 346 347 =item createComment($text) 348 349 Create a new HTML Comment node with the given text value. 272 350 273 351 =back … … 290 368 with the tree created from the HTML. 291 369 370 =item getElementById($id) 371 372 Returns a list of all the elements with the given id. Normally this 373 should be one or zero elements, since two nodes should not have the same 374 id in the same DOM. 375 376 =item getElementsByTagName($tag) 377 378 Returns a list of all elements in the tree that have the given tag name. 379 380 =item nodeType 381 382 Returns 1 if the node is an HTML Element and 8 if it is a comment node. 383 Never returns 3 (the type value of a text node) since text nodes in the 384 DOM are just strings. 385 292 386 =item nodeName 293 387 … … 295 389 HTML tag name. 296 390 391 Returns '#comment' if the node is a comment node. 392 393 =item tagName 394 395 Returns the nodeName of the element if it is an HTML Element. (Returns 396 '' for comment nodes.) 397 398 =item nodeValue 399 400 This method returns undef unless the node is a comment. In most DOMs 401 this attribute contains the value for Text nodes (which are just 402 strings here). 403 404 =item getAttribute($attr) 405 406 Returns the value of the specified attribute. 407 408 =item setAttribute($attr, $value) 409 410 Sets the specified attribute to the given value. 411 412 =item removeAttribute($attr) 413 414 Removes the specified attribute. 415 416 =item hasAttributes 417 418 Returns 1 if the node has attributes. Otherwise returns 0. 419 420 =item id id($value) 421 422 Same as C<getAttribute('id')> or C<setAttribute('id', $value)>. 423 424 =item className className($value) 425 426 Same as C<getAttribute('class')> or C<setAttribute('class', $value)>. 427 428 =item parentNode 429 430 Returns the node's parent node. 431 432 =item childNodes 433 434 Returns a list of the node's child nodes. 435 436 =item firstChild 437 438 Returns the node's first child node. May be a string (aka a text node). 439 440 =item lastChild 441 442 Returns the node's last child node. May be a string (aka a text node). 443 444 =item appendChild($node) 445 446 Adds a node (or a string) to the end of the current node's children. 447 297 448 =back 298 449 trunk/src/ingy/pQuery/t/dom.t
r344 r346 1 use Test::More tests => 8; 1 use Test::More tests => 33; 2 use strict; 3 use warnings; 2 4 3 5 use pQuery::DOM; … … 17 19 is $dom->innerHTML, 'I <b>Like</b> <ul>Pie</ul>!', 18 20 'innerHTML works'; 21 22 $dom = pQuery::DOM->fromHTML(<<'...'); 23 <div id="div1"> 24 <div id="div2"> 25 <span id="span1">Foo</span> 26 <span id="span2">Bar</span> 27 <span id="span3">Baz</span> 28 </div> 29 </div> 30 ... 31 my $span = $dom->getElementById('span1'); 32 is $span->innerHTML, "Foo", 'getElementById works'; 33 is $span->nodeValue, undef, 'nodeValue is undefined for Element'; 34 is $span->tagName, "SPAN", 'tagName works'; 35 36 my @spans = $dom->getElementsByTagName('span'); 37 is scalar(@spans), 3, "Found 3 spans"; 38 is $spans[0]->innerHTML, "Foo", '1st value is correct'; 39 is $spans[1]->innerHTML, "Bar", '2nd value is correct'; 40 41 $span->setAttribute('Foo', 'Bar'); 42 is $span->toHTML, '<span id="span1" foo="Bar">Foo</span>', 43 'setAttribute works'; 44 45 is (pQuery::DOM->fromHTML('<div>')->hasAttributes, 0, 'hasAttributes works'); 46 is (pQuery::DOM->fromHTML('<div XXX="yyy">')->hasAttributes, 1, 'hasAttributes works'); 47 48 $span->removeAttribute('Id'); 49 is $span->toHTML, '<span foo="Bar">Foo</span>', 50 'removeAttribute works'; 51 52 is $span->parentNode->id, 'div2', 53 'parentNode works'; 54 55 my $div2 = $dom->getElementById('div2'); 56 my @children = $div2->childNodes; 57 is scalar(@children), 7, 'div2 has 7 children'; 58 is ref($children[0]), '', 'child 1 is text node'; 59 60 is $div2->firstChild, "\n ", "firstChild works"; 61 is $div2->lastChild, "\n ", "lastChild works"; 62 63 $dom = pQuery::DOM->fromHTML('<div>xxx<!-- yyy -->zzz</div>'); 64 my @elems = pQuery::DOM->fromHTML('<div>xxx<!-- yyy -->zzz</div>')->childNodes; 65 my $comment = $elems[1]; 66 is $comment->nodeType, 8, 'Handle comment nodes'; 67 is $comment->nodeValue, ' yyy ', 'Handle comment node value'; 68 is $comment->hasAttributes, 0, "Comments don't have attributes"; 69 is $comment->nodeName, '#comment', 'Comment has proper nodeName'; 70 is $comment->tagName, '', 'Comment has no tagName'; 71 is $comment->parentNode->tagName, 'DIV', 'Comment has parentNode'; 72 is $dom->toHTML, '<div>xxx<!-- yyy -->zzz</div>', 'Comments work in toHTML'; 73 is $comment->innerHTML, undef, 'Comments have no innerHTML'; 74 75 $dom->innerHTML('I <b>Like</b> Pie'); 76 77 is $dom->toHTML, '<div>I <b>Like</b> Pie</div>', 'Setting innerHTML works'; 78 79 my $div = pQuery::DOM->createElement('div'); 80 $div->id('new-div'); 81 $div->className('classy'); 82 $comment = pQuery::DOM->createComment('I am remarkable'); 83 $div->appendChild('Foo'); 84 $div->appendChild($comment); 85 is $div->toHTML, '<div id="new-div" class="classy">Foo<!--I am remarkable--></div>', 86 'createElement, createComment and appendChild work';
