blib/lib/jQuery.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 7 | 9 | 77.7 |
branch | n/a | ||
condition | n/a | ||
subroutine | 3 | 3 | 100.0 |
pod | n/a | ||
total | 10 | 12 | 83.3 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package jQuery; | ||||||
2 | |||||||
3 | 25 | 25 | 58716 | use warnings; | |||
25 | 42 | ||||||
25 | 821 | ||||||
4 | 25 | 25 | 129 | use strict; | |||
25 | 36 | ||||||
25 | 919 | ||||||
5 | 25 | 25 | 49278 | use XML::LibXML 1.70; | |||
0 | |||||||
0 | |||||||
6 | use HTML::Entities; | ||||||
7 | use Encode; | ||||||
8 | use Carp; | ||||||
9 | |||||||
10 | use base qw/jQuery::Functions Exporter/; | ||||||
11 | our @EXPORT = qw(jquery jQuery this); | ||||||
12 | |||||||
13 | use vars qw/$DOC $PARSER $VERSION/; | ||||||
14 | $VERSION = "0.004"; | ||||||
15 | |||||||
16 | my $obj_class = 'jQuery::Obj'; | ||||||
17 | sub this { 'jQuery::Functions'->this(@_) } | ||||||
18 | |||||||
19 | sub new { | ||||||
20 | my $class = shift; | ||||||
21 | my $string = shift; | ||||||
22 | my $parser; | ||||||
23 | my $doc; | ||||||
24 | if (!$PARSER){ | ||||||
25 | $parser = XML::LibXML->new(); | ||||||
26 | $parser->recover(1); | ||||||
27 | $parser->recover_silently(1); | ||||||
28 | $parser->keep_blanks(1); | ||||||
29 | $parser->expand_entities(1); | ||||||
30 | $parser->no_network(1); | ||||||
31 | local $XML::LibXML::skipXMLDeclaration = 1; | ||||||
32 | local $XML::LibXML::skipDTD = 1; | ||||||
33 | local $XML::LibXML::setTagCompression = 1; | ||||||
34 | $PARSER = $parser; | ||||||
35 | } else { | ||||||
36 | $parser = $PARSER; | ||||||
37 | } | ||||||
38 | |||||||
39 | if ($string){ | ||||||
40 | if ($string =~ /^http/){ | ||||||
41 | $string = $class->get($string); | ||||||
42 | } elsif ($string =~ /^<\?xml/) { | ||||||
43 | $doc = $parser->parse_string($string); | ||||||
44 | } else { | ||||||
45 | $doc = $parser->parse_html_string($string); | ||||||
46 | } | ||||||
47 | $DOC = $doc; | ||||||
48 | } | ||||||
49 | |||||||
50 | return bless({ | ||||||
51 | document => $doc | ||||||
52 | }, __PACKAGE__); | ||||||
53 | } | ||||||
54 | |||||||
55 | *jQuery = \&jquery; | ||||||
56 | sub jquery { | ||||||
57 | my ($selector, $context) = (shift,shift); | ||||||
58 | my $this; | ||||||
59 | my $c; | ||||||
60 | |||||||
61 | if ( ref ($selector) eq __PACKAGE__ ){ | ||||||
62 | $this->{document} = $selector->{document}; | ||||||
63 | $selector = $context; | ||||||
64 | $context = shift; | ||||||
65 | } else { | ||||||
66 | $this->{document} = $DOC; | ||||||
67 | } | ||||||
68 | |||||||
69 | if ($context){ | ||||||
70 | if (@_){ | ||||||
71 | $context = bless([$context,@_], ref $context); | ||||||
72 | } | ||||||
73 | return jQuery($context)->find($selector); | ||||||
74 | } | ||||||
75 | |||||||
76 | if ( ref($selector) eq $obj_class ){ | ||||||
77 | return $selector; | ||||||
78 | } | ||||||
79 | |||||||
80 | bless($this, $obj_class); | ||||||
81 | $this->{nodes} = []; | ||||||
82 | return $this if !$selector; | ||||||
83 | |||||||
84 | my $nodes; | ||||||
85 | if ( ref($selector) =~ /XML::/i ){ | ||||||
86 | if ($selector->isa('ARRAY')){ | ||||||
87 | $nodes = $selector; | ||||||
88 | } else { | ||||||
89 | $nodes = [$selector]; | ||||||
90 | } | ||||||
91 | } elsif ( ref ($selector) eq 'ARRAY' ){ | ||||||
92 | $nodes = $selector; | ||||||
93 | } elsif ($this->is_HTML($selector)) { | ||||||
94 | $nodes = $this->createNode($selector); | ||||||
95 | } else { | ||||||
96 | $nodes = $this->_find($selector); | ||||||
97 | ##another try to create html fragment | ||||||
98 | if (!$nodes->[0]){ | ||||||
99 | $nodes = $this->createNode($selector); | ||||||
100 | } | ||||||
101 | } | ||||||
102 | |||||||
103 | return $this->pushStack(@$nodes); | ||||||
104 | } | ||||||
105 | |||||||
106 | ##something like pushStack in jquery | ||||||
107 | sub pushStack { | ||||||
108 | my $self = shift; | ||||||
109 | my @elements; | ||||||
110 | |||||||
111 | return jQuery($self,@_) unless $self->isa('HASH') and | ||||||
112 | ref $self eq $obj_class; | ||||||
113 | @elements = ref $_[0] eq 'ARRAY' | ||||||
114 | ? @{$_[0]} | ||||||
115 | : @_; | ||||||
116 | |||||||
117 | #save old object | ||||||
118 | $self->{prevObject} = $self->{nodes}; | ||||||
119 | |||||||
120 | #$self = bless ([@elements], $obj_class); | ||||||
121 | $self->{nodes} = \@elements; | ||||||
122 | return $self; | ||||||
123 | } | ||||||
124 | |||||||
125 | sub toArray { | ||||||
126 | my $self = shift; | ||||||
127 | my @nodes; | ||||||
128 | if ($self->isa('ARRAY')) { | ||||||
129 | @nodes = @{$self}; | ||||||
130 | } elsif ($self->isa('HASH')) { | ||||||
131 | @nodes = @{$self->{nodes}}; | ||||||
132 | } else { | ||||||
133 | @nodes = ($self); | ||||||
134 | } | ||||||
135 | |||||||
136 | return wantarray ? | ||||||
137 | @nodes | ||||||
138 | : \@nodes; | ||||||
139 | } | ||||||
140 | |||||||
141 | sub getNodes { | ||||||
142 | my $self = shift; | ||||||
143 | my @nodes; | ||||||
144 | if ($self->isa('ARRAY')) { | ||||||
145 | @nodes = @{$self}; | ||||||
146 | } elsif ($self->isa('HASH')) { | ||||||
147 | @nodes = @{$self->{nodes}}; | ||||||
148 | } else { | ||||||
149 | @nodes = ($self); | ||||||
150 | } | ||||||
151 | return wantarray ? @nodes : bless(\@nodes, $obj_class); | ||||||
152 | } | ||||||
153 | |||||||
154 | |||||||
155 | sub _find { | ||||||
156 | my ($this, $selector, $context ) = @_; | ||||||
157 | $context ||= $this->document; | ||||||
158 | my @nodes; | ||||||
159 | eval { | ||||||
160 | if ($selector !~ m/\//){ | ||||||
161 | $selector = $this->_translate_css_to_xpath($selector,$context->nodePath); | ||||||
162 | } | ||||||
163 | @nodes = $context->findnodes($selector) if $selector; | ||||||
164 | }; | ||||||
165 | |||||||
166 | if ($@){ | ||||||
167 | croak $@; | ||||||
168 | } | ||||||
169 | return wantarray | ||||||
170 | ? @nodes | ||||||
171 | : \@nodes; | ||||||
172 | } | ||||||
173 | |||||||
174 | #Should I use HTML::Selector::XPath and port some jquery selectors by hand ?? | ||||||
175 | #it's well maintained | ||||||
176 | #this is faster but not easy to maintain and not quiet mature | ||||||
177 | sub _translate_css_to_xpath { | ||||||
178 | my $self = shift; | ||||||
179 | my $start_query = shift; | ||||||
180 | my $old_query = shift; | ||||||
181 | my $custompath = shift || ''; | ||||||
182 | my @args; | ||||||
183 | $start_query =~ s/\((.*?),(.*?)\)/\($1 |
||||||
184 | my @queries = split(/\,/,$start_query); | ||||||
185 | my $this_query = 0; | ||||||
186 | |||||||
187 | foreach my $query (@queries){ | ||||||
188 | $query =~ s/ |
||||||
189 | #remove all leading and ending whitespaces | ||||||
190 | $query =~ s/^\s+|\s+$//g; | ||||||
191 | $query =~ s/\s+/ | ||||||
192 | ##add one whitespace at the beginning | ||||||
193 | $query = " ".$query; | ||||||
194 | |||||||
195 | my $selector; | ||||||
196 | $selector = $old_query if $old_query; | ||||||
197 | |||||||
198 | my $pos = 0; | ||||||
199 | my $directpath = 0; | ||||||
200 | my $empty_path =0; | ||||||
201 | my $single = 0; | ||||||
202 | |||||||
203 | ##setting starting search path custom path is // which search down all elements | ||||||
204 | my $path = '//'; | ||||||
205 | $path = $custompath if $custompath; | ||||||
206 | |||||||
207 | ##I wrote this some while ago, I feel dizzy when I try to read it again | ||||||
208 | while ($query =~ /([\s|\.|\:|\#]?)((\[.*?\])|(~)|(\+)|(\>)|(\<)|(\*)|([\w\-]+(\(.*?\))?))/g){ | ||||||
209 | |||||||
210 | my $type = $1; | ||||||
211 | my $value = $2; | ||||||
212 | my $pos2 = 0; | ||||||
213 | |||||||
214 | ##set empty starting path | ||||||
215 | if ($custompath eq 'empty' && $pos2 eq '0'){ | ||||||
216 | $path = ''; | ||||||
217 | ###if we want to search direct childrens | ||||||
218 | } elsif ($directpath || $empty_path){ | ||||||
219 | $path = '/'; | ||||||
220 | $path = '//' if $directpath eq '2'; | ||||||
221 | $path = '' if $empty_path; | ||||||
222 | if (($type =~ /(\:|\.|\#)/ || $value =~ /\[.*?\]/)){ | ||||||
223 | $selector .= $path.'*'; | ||||||
224 | } | ||||||
225 | |||||||
226 | #reset direct path | ||||||
227 | $directpath = 0; | ||||||
228 | ##reset empty path | ||||||
229 | $empty_path = 0; | ||||||
230 | } else { | ||||||
231 | $path = '//'; | ||||||
232 | } | ||||||
233 | |||||||
234 | $type =~ s/\s+//; | ||||||
235 | $value =~ s/\s+//; | ||||||
236 | if ($pos == 0){ | ||||||
237 | $path = $custompath if $custompath && $custompath ne 'empty'; | ||||||
238 | if (($type =~ /(\:|\.|\#)/ || $value =~ /\[.*?\]/)){ | ||||||
239 | $selector .= $path.'*'; | ||||||
240 | } | ||||||
241 | } | ||||||
242 | |||||||
243 | if ($value eq '*'){ | ||||||
244 | $selector .= $path.'*'; | ||||||
245 | } elsif ($value eq '>'){ | ||||||
246 | $directpath = 1; | ||||||
247 | } elsif ($value eq '<'){ | ||||||
248 | $directpath = 2; | ||||||
249 | } elsif ($value eq '+'){ | ||||||
250 | $selector .= '/following-sibling::'; | ||||||
251 | $empty_path = 1; | ||||||
252 | $single = 1; | ||||||
253 | } elsif ($value eq '~'){ | ||||||
254 | $selector .= '/following-sibling::'; | ||||||
255 | $empty_path = 1; | ||||||
256 | } elsif ($value =~ /\[(.*?)\]/){ | ||||||
257 | |||||||
258 | my ($name, $value) = split(/\s*=\s*/, $1, 2); | ||||||
259 | if (defined $value) { | ||||||
260 | for ($value) { | ||||||
261 | s/^['"]//; | ||||||
262 | s/['"]$//; | ||||||
263 | } | ||||||
264 | |||||||
265 | if ($name =~ s/\^$//){ | ||||||
266 | $selector .= "[starts-with (\@$name,'$value')]"; | ||||||
267 | } elsif ($name =~ s/\$$//){ | ||||||
268 | #$selector .= "[ends-with (\@$name,'$value')]"; | ||||||
269 | $selector .= "[substring(\@$name, string-length(\@$name) - string-length('$value')+ 1, string-length(\@$name))= '$value']"; | ||||||
270 | } elsif ($name =~ s/\*$//){ | ||||||
271 | $selector .= "[contains (\@$name,'$value')]"; | ||||||
272 | } elsif ($name =~ s/\|$//){ | ||||||
273 | $selector .= "[\@$name ='$value'"." or "."starts-with(\@$name,'$value".'-'."')]"; | ||||||
274 | } else { | ||||||
275 | $selector .= "[\@$name='$value']"; | ||||||
276 | } | ||||||
277 | |||||||
278 | } else { | ||||||
279 | $selector .= "[\@$name]"; | ||||||
280 | } | ||||||
281 | |||||||
282 | ##this is tag | ||||||
283 | } elsif (!$type){ | ||||||
284 | $selector .= $path.$value; | ||||||
285 | ##this is class | ||||||
286 | } elsif ($type eq "."){ | ||||||
287 | ##finally found a good solution from | ||||||
288 | ##http://plasmasturm.org/log/444/ | ||||||
289 | $selector .= '[ contains(concat( " ", @class, " " ),concat( " ", "'.$value.'", " " )) ]'; | ||||||
290 | |||||||
291 | ##id selector | ||||||
292 | } elsif ($type eq '#'){ | ||||||
293 | $selector .= '[@id="'.$value.'"]'; | ||||||
294 | } | ||||||
295 | |||||||
296 | ###pseduo-class | ||||||
297 | elsif ($type eq ':'){ | ||||||
298 | |||||||
299 | if ($value eq "first-child"){ | ||||||
300 | $selector .= '[1]'; | ||||||
301 | } elsif ($value eq "first"){ | ||||||
302 | #$selector = "getIndex($selector,'eq','0')"; | ||||||
303 | $selector .= '[position() = 1]'; ##this doesn't really do the job exactly as jQuery | ||||||
304 | } elsif ($value eq "odd"){ | ||||||
305 | #$selector = 'getOdd('.$selector.')'; | ||||||
306 | $selector .= '[position() mod 2 != 1]'; ##this doesn't do the job exactly as jQuery | ||||||
307 | } elsif ($value eq "even"){ | ||||||
308 | #$selector = 'getEven('.$selector.')'; | ||||||
309 | $selector .= '[position() mod 2 != 0]'; ##this doesn't do the job exactly as jQuery | ||||||
310 | } elsif ($value =~ /(gt|lt|eq)\((.*?)\)/){ | ||||||
311 | $selector = "getIndex($selector,'$1','$2')"; | ||||||
312 | } elsif ($value =~ /nth-child\((.*?)\)/){ | ||||||
313 | $selector .= "[position() = $1]"; | ||||||
314 | } elsif ($value =~ /has\((.*?)\)/){ | ||||||
315 | $selector = "getHas($selector,'$1')"; | ||||||
316 | } elsif ($value =~ /not\((.*?)\)/){ | ||||||
317 | $selector = "getNot($selector,'$1')"; | ||||||
318 | } elsif ($value eq "button"){ | ||||||
319 | #$selector .= '[@type="button"]'; | ||||||
320 | $selector = "getButton($selector)"; | ||||||
321 | } elsif ($value =~ /(checkbox|file|hidden|image|text|submit|radio|password|reset)/){ | ||||||
322 | $selector .= "[\@type='$value']"; | ||||||
323 | } elsif ($value eq "checked"){ | ||||||
324 | $selector .= '[@checked="checked"]'; | ||||||
325 | } elsif ($value eq "selected"){ | ||||||
326 | $selector .= '[@selected="selected"]'; | ||||||
327 | } elsif ($value eq "disabled"){ | ||||||
328 | $selector .= '[@disabled]'; | ||||||
329 | } elsif ($value eq "enabled"){ | ||||||
330 | $selector .= '[not(@disabled)]'; | ||||||
331 | } elsif ($value =~ /contains\((.*?)\)/){ | ||||||
332 | my $str = $1; | ||||||
333 | for ($str) { | ||||||
334 | s/^['"]//; | ||||||
335 | s/['"]$//; | ||||||
336 | } | ||||||
337 | $selector .= "[contains(.,'$str')]"; | ||||||
338 | } elsif ($value eq "empty"){ | ||||||
339 | $selector .= '[not(node())]'; | ||||||
340 | } elsif ($value eq "only-child"){ | ||||||
341 | |||||||
342 | my ($str1, $str2) = $selector =~ /(.*)\/(.*)/; | ||||||
343 | if ($str1 =~ s/\/$//){ | ||||||
344 | $str2 = '/'.$str2; | ||||||
345 | $selector = $str1.'//child::*/parent::*[count(*)=1]'.'/'.$str2; | ||||||
346 | } else{ | ||||||
347 | $selector = $str1.'/child::*/parent::*[count(*)=1]'.'/'.$str2; | ||||||
348 | } | ||||||
349 | |||||||
350 | } elsif ($value eq "header"){ | ||||||
351 | $selector = "getHeaders($selector)"; | ||||||
352 | } elsif ($value eq "parent"){ | ||||||
353 | $selector .= '[(node())]'; | ||||||
354 | } elsif ($value eq "last"){ | ||||||
355 | #$selector = "getLast($selector)"; | ||||||
356 | $selector .= '[position()=last()]'; | ||||||
357 | } elsif ($value eq "last-child"){ | ||||||
358 | $selector .= "[last()]"; | ||||||
359 | } | ||||||
360 | } | ||||||
361 | $pos++; $pos2++; | ||||||
362 | } | ||||||
363 | if ($single){ | ||||||
364 | $selector .= '[1]'; | ||||||
365 | $single = 0; | ||||||
366 | } | ||||||
367 | $this_query++; | ||||||
368 | push (@args,$selector); | ||||||
369 | } | ||||||
370 | return join(' | ',@args); | ||||||
371 | } | ||||||
372 | |||||||
373 | sub as_HTML { | ||||||
374 | my $self = shift; | ||||||
375 | my $doc = $self->document; | ||||||
376 | if (ref($doc) eq 'XML::LibXML::Document' ){ | ||||||
377 | my $html = $doc->serialize_html(); | ||||||
378 | if ($html =~ m/ /g){ |
||||||
379 | $html =~ s/(?:.*?) (.*)<\/div>(?:.*)/$1/s; |
||||||
380 | } | ||||||
381 | return $html; | ||||||
382 | } | ||||||
383 | return $doc->getDocumentElement->html(); | ||||||
384 | } | ||||||
385 | |||||||
386 | sub as_XML { | ||||||
387 | my $doc = $_[0]->document; | ||||||
388 | if ($$DOC ne $$doc){ | ||||||
389 | if (ref($doc) eq 'XML::LibXML::Document' ){ | ||||||
390 | my $xml = $doc->serialize(); | ||||||
391 | if ($xml =~ m/ /g){ |
||||||
392 | $xml =~ s/(?:.*?) (.*)<\/div>(?:.*)/$1/s; |
||||||
393 | } | ||||||
394 | return $xml; | ||||||
395 | } | ||||||
396 | return $doc->getDocumentElement->html(); | ||||||
397 | } | ||||||
398 | |||||||
399 | return $doc->serialize(); | ||||||
400 | } | ||||||
401 | |||||||
402 | |||||||
403 | sub is_HTML { | ||||||
404 | my ($self,$html) = @_; | ||||||
405 | ### very permative solution but it seems | ||||||
406 | ### to work with all tests so far | ||||||
407 | if ($html =~ /<.*>/g){ | ||||||
408 | return 1; | ||||||
409 | } | ||||||
410 | return 0; | ||||||
411 | } | ||||||
412 | |||||||
413 | sub createNode { | ||||||
414 | my ($self,$html) = @_; | ||||||
415 | my $node; | ||||||
416 | if (!$PARSER){ $self->new(); } | ||||||
417 | $html = " ".$html." "; |
||||||
418 | if ($html =~ /^ <\?xml/) { |
||||||
419 | $node = $PARSER->parse_string($html); | ||||||
420 | } else{ | ||||||
421 | $node = $PARSER->parse_html_string($html); | ||||||
422 | } | ||||||
423 | |||||||
424 | $DOC = $node if !$DOC; | ||||||
425 | $node->removeInternalSubset; | ||||||
426 | my $nodes = $node->getDocumentElement->findnodes("//*[\@class='REMOVE_THIS_ELEMENT']")->[0]->childNodes; | ||||||
427 | return $nodes; | ||||||
428 | } | ||||||
429 | |||||||
430 | sub createNode2 { | ||||||
431 | my ($self,$html) = @_; | ||||||
432 | $html = " ".$html." "; |
||||||
433 | my $new = $self->new($html); | ||||||
434 | return $new->jQuery('.REMOVE_THIS_ELEMENT *'); | ||||||
435 | } | ||||||
436 | |||||||
437 | ##detect node parent document | ||||||
438 | sub document { | ||||||
439 | my $self = shift; | ||||||
440 | my $doc; | ||||||
441 | if ($self->isa('ARRAY') && $self->[0]){ | ||||||
442 | $doc = $self->[0]->ownerDocument; | ||||||
443 | } elsif ($self->isa('HASH') && $self->{document}){ | ||||||
444 | $doc = $self->{document}; | ||||||
445 | } | ||||||
446 | return $doc ? $doc : $DOC; | ||||||
447 | } | ||||||
448 | |||||||
449 | sub cloneDOC { | ||||||
450 | my $self = shift; | ||||||
451 | my $clone = $self->document->cloneNode(1); | ||||||
452 | return bless([$clone], __PACKAGE__); | ||||||
453 | } | ||||||
454 | |||||||
455 | sub decode_html { return decode_entities($_[1]); } | ||||||
456 | sub parser { return shift->{parser}; } | ||||||
457 | |||||||
458 | ###custom internal functions | ||||||
459 | ###copied from jQuery.js | ||||||
460 | sub body { return shift->getElementsByTagName('body'); } | ||||||
461 | |||||||
462 | sub makeArray { | ||||||
463 | my ( $array, $results ) = @_; | ||||||
464 | my $ret = $results || []; | ||||||
465 | if ( ref $array eq 'ARRAY' ) { | ||||||
466 | push @{$ret}, @{$array}; | ||||||
467 | } | ||||||
468 | else { $ret = \@_; } | ||||||
469 | return wantarray | ||||||
470 | ? @$ret | ||||||
471 | : $ret; | ||||||
472 | } | ||||||
473 | |||||||
474 | sub merge { | ||||||
475 | my ( $first, $second ) = @_; | ||||||
476 | my $i = _length($first); | ||||||
477 | my $j = 0; | ||||||
478 | if ( _length($second) ) { | ||||||
479 | for ( my $l = _length($second); $j < $l; $j++ ) { | ||||||
480 | $first->[ $i++ ] = $second->[ $j ]; | ||||||
481 | } | ||||||
482 | } else { | ||||||
483 | while ( $second->[$j] ) { | ||||||
484 | $first->[ $i++ ] = $second->[ $j++ ]; | ||||||
485 | } | ||||||
486 | } | ||||||
487 | $i = _length($first); | ||||||
488 | return wantarray | ||||||
489 | ? @$first | ||||||
490 | : $first ; | ||||||
491 | } | ||||||
492 | |||||||
493 | sub _length { | ||||||
494 | if (ref $_[0] eq 'ARRAY'){ | ||||||
495 | @_ = @{$_[0]}; | ||||||
496 | } | ||||||
497 | return $#_ + 1; | ||||||
498 | } | ||||||
499 | |||||||
500 | sub isDisconnected { | ||||||
501 | my $node = shift; | ||||||
502 | return !$node || !$node->parentNode || $node->parentNode->nodeType == 11; | ||||||
503 | } | ||||||
504 | |||||||
505 | sub unique { | ||||||
506 | my %hash; | ||||||
507 | my @ele = grep{!$hash{$$_}++} @_; | ||||||
508 | return @ele; | ||||||
509 | } | ||||||
510 | |||||||
511 | sub nodeName { | ||||||
512 | my ( $elem, $name ) = @_; | ||||||
513 | return $elem->nodeName && uc $elem->nodeName eq uc $name; | ||||||
514 | } | ||||||
515 | |||||||
516 | package jQuery::Obj; | ||||||
517 | use base 'jQuery'; | ||||||
518 | |||||||
519 | ##hack Libxml modules to use jQuery as base module | ||||||
520 | ##is this a bad practice? | ||||||
521 | package XML::LibXML::NodeList; | ||||||
522 | use base 'jQuery::Obj'; | ||||||
523 | |||||||
524 | package XML::LibXML::Node; | ||||||
525 | use base 'jQuery::Obj'; | ||||||
526 | |||||||
527 | package XML::LibXML::Element; | ||||||
528 | use base 'jQuery::Obj'; | ||||||
529 | |||||||
530 | package XML::LibXML::Text; | ||||||
531 | use base 'jQuery::Obj'; | ||||||
532 | use base 'XML::LibXML::Element'; | ||||||
533 | |||||||
534 | 1; | ||||||
535 | |||||||
536 | __END__ |