File Coverage

blib/lib/HTML/DOM/Element.pm
Criterion Covered Total %
statement 431 446 96.6
branch 193 224 86.1
condition 63 90 70.0
subroutine 150 153 98.0
pod 21 29 72.4
total 858 942 91.0


line stmt bran cond sub pod time code
1             package HTML::DOM::Element;
2              
3 25     25   495 use strict;
  25         23  
  25         501  
4 25     25   75 use warnings;
  25         24  
  25         533  
5              
6 25         1341 use HTML::DOM::Exception qw 'INVALID_CHARACTER_ERR
7 25     25   8227 INUSE_ATTRIBUTE_ERR NOT_FOUND_ERR SYNTAX_ERR';
  25         36  
8 25     25   9459 use HTML::DOM::Node 'ELEMENT_NODE';
  25         36  
  25         1345  
9 25     25   117 use HTML'Entities;
  25         26  
  25         1149  
10 25     25   91 use Scalar::Util qw'refaddr blessed weaken';
  25         23  
  25         17119  
11              
12             require HTML::DOM::Attr;
13             require HTML::DOM::Element::Form;
14             require HTML::DOM::Element::Table;
15             require HTML::DOM::NamedNodeMap;
16             require HTML::DOM::Node;
17             require HTML::DOM::NodeList::Magic;
18              
19             our @ISA = qw'HTML::DOM::Node';
20             our $VERSION = '0.056';
21              
22              
23             {
24             # ~~~ Perhaps I should make class_for into a class method, rather
25             # than a function, so Element.pm can be subclassed. Maybe I'll
26             # wait until someone tries to subclass it. (Applies to Event.pm
27             # as well.) If a potential subclasser is reading this, will he
28             # please give me a holler?
29              
30             my %class_for = (
31             '~text' => 'HTML::DOM::Text',
32             html => 'HTML::DOM::Element::HTML',
33             head => 'HTML::DOM::Element::Head',
34             link => 'HTML::DOM::Element::Link',
35             title => 'HTML::DOM::Element::Title',
36             meta => 'HTML::DOM::Element::Meta',
37             base => 'HTML::DOM::Element::Base',
38             isindex=> 'HTML::DOM::Element::IsIndex',
39             style => 'HTML::DOM::Element::Style',
40             body => 'HTML::DOM::Element::Body',
41             form => 'HTML::DOM::Element::Form',
42             select => 'HTML::DOM::Element::Select',
43             optgroup=> 'HTML::DOM::Element::OptGroup',
44             option => 'HTML::DOM::Element::Option',
45             input => 'HTML::DOM::Element::Input',
46             textarea=> 'HTML::DOM::Element::TextArea',
47             button => 'HTML::DOM::Element::Button',
48             label => 'HTML::DOM::Element::Label',
49             fieldset=> 'HTML::DOM::Element::FieldSet',
50             legend => 'HTML::DOM::Element::Legend',
51             ul => 'HTML::DOM::Element::UL',
52             ol => 'HTML::DOM::Element::OL',
53             dl => 'HTML::DOM::Element::DL',
54             dir => 'HTML::DOM::Element::Dir',
55             menu => 'HTML::DOM::Element::Menu',
56             li => 'HTML::DOM::Element::LI',
57             div => 'HTML::DOM::Element::Div',
58             p => 'HTML::DOM::Element::P',
59             map((
60             "h$_" => 'HTML::DOM::Element::Heading'
61             ), 1..6),
62             q => 'HTML::DOM::Element::Quote',
63             blockquote=> 'HTML::DOM::Element::Quote',
64             pre => 'HTML::DOM::Element::Pre',
65             br => 'HTML::DOM::Element::Br',
66             basefont => 'HTML::DOM::Element::BaseFont',
67             font => 'HTML::DOM::Element::Font',
68             hr => 'HTML::DOM::Element::HR',
69             ins => 'HTML::DOM::Element::Mod',
70             del => 'HTML::DOM::Element::Mod',
71             a => 'HTML::DOM::Element::A',
72             img => 'HTML::DOM::Element::Img',
73             object => 'HTML::DOM::Element::Object',
74             param => 'HTML::DOM::Element::Param',
75             applet => 'HTML::DOM::Element::Applet',
76             map => 'HTML::DOM::Element::Map',
77             area => 'HTML::DOM::Element::Area',
78             script => 'HTML::DOM::Element::Script',
79             table => 'HTML::DOM::Element::Table',
80             caption => 'HTML::DOM::Element::Caption',
81             col => 'HTML::DOM::Element::TableColumn',
82             colgroup=> 'HTML::DOM::Element::TableColumn',
83             thead => 'HTML::DOM::Element::TableSection',
84             tfoot => 'HTML::DOM::Element::TableSection',
85             tbody => 'HTML::DOM::Element::TableSection',
86             tr => 'HTML::DOM::Element::TR',
87             th => 'HTML::DOM::Element::TableCell',
88             td => 'HTML::DOM::Element::TableCell',
89             frameset=> 'HTML::DOM::Element::FrameSet',
90             frame => 'HTML::DOM::Element::Frame',
91             iframe => 'HTML::DOM::Element::IFrame',
92             );
93             sub class_for {
94 1402 100   1402 0 4386 $class_for{lc$_[0]} || __PACKAGE__
95             }
96             }
97              
98              
99             =head1 NAME
100              
101             HTML::DOM::Element - A Perl class for representing elements in an HTML DOM tree
102              
103             =head1 VERSION
104              
105             Version 0.056
106              
107             =head1 SYNOPSIS
108              
109             use HTML::DOM;
110             $doc = HTML::DOM->new;
111             $elem = $doc->createElement('a');
112              
113             $elem->setAttribute('href', 'http://www.perl.org/');
114             $elem->getAttribute('href');
115             $elem->tagName;
116             # etc
117              
118             =head1 DESCRIPTION
119              
120             This class represents elements in an HTML::DOM tree. It is the base class
121             for other element classes (see
122             L.) It implements the Element and
123             HTMLElement DOM interfaces.
124              
125             =head1 METHODS
126              
127             =head2 Constructor
128              
129             You should normally use HTML::DOM's C method. This is listed
130             here only for completeness:
131              
132             $elem = new HTML::DOM::Element $tag_name;
133              
134             C<$elem> will automatically be blessed into the appropriate class for
135             C<$tag_name>.
136              
137             =cut
138              
139             sub new {
140 1408     1408 0 1381 my $tagname = $_[1];
141              
142             # Hack to make parsing comments work
143 1408 100       2382 $tagname eq '~comment'
144             and require HTML'DOM'Comment, return new HTML'DOM'Comment;
145              
146             # ~~~ The DOM spec does not specify which characters are invaleid.
147             # I think I need to check the HTML spec. For now, I'm simply
148             # letting HTML::Element do the insanity checking, and I'm turn-
149             # ing its errors into HTML::DOM::Exceptions.
150 1401         988 my $ret;
151 1401         1287 eval {
152 1401         3395 $ret = bless shift->SUPER::new(@_), class_for $tagname;
153              
154             # require can sometimes fail if it’s part of a tainted
155             # statement. That’s why it’s in a do block.
156             $tagname =~ /^html\z/i
157 1401 100       3300 and do { require HTML'DOM }; # paranoia
  162         746  
158             };
159 1401 50       3225 $@ or return $ret;
160 0         0 die HTML::DOM::Exception->new( INVALID_CHARACTER_ERR, $@);
161             }
162              
163              
164             =head2 Attributes
165              
166             The following DOM attributes are supported:
167              
168             =over 4
169              
170             =item tagName
171              
172             Returns the tag name.
173              
174             =item id
175              
176             =item title
177              
178             =item lang
179              
180             =item dir
181              
182             =item className
183              
184             These five get (optionally set) the corresponding HTML attributes. Note
185             that C corresponds to the C attribute.
186              
187             =cut
188              
189             sub tagName {
190 458     458 1 24664 uc $_[0]->tag;
191             }
192              
193 2718     2718 1 8673 sub id { shift->_attr(id => @_) }
194              
195 5     5 1 964 sub title { shift->_attr(title => @_) }
196 5     5 1 960 sub lang { shift->_attr(lang => @_) }
197 5     5 1 907 sub dir { lc shift->_attr(dir => @_) }
198 5     5 1 905 sub className { shift->_attr(class => @_) }
199              
200             =item style
201              
202             This returns a L object, representing the contents
203             of the 'style' HTML attribute.
204              
205             =cut
206              
207             sub style {
208 38     38 1 2076 my $self = shift;
209 38   66     67 ($self->getAttributeNode('style') || do {
210             $self->setAttribute('style','');
211             $self->getAttributeNode('style');
212             }) -> style;
213             }
214              
215             =back
216              
217             And there is also the following non-DOM attribute:
218              
219             =over 4
220              
221             =item content_offset
222              
223             This contains the offset (in characters) within the HTML source of the
224             element's first child node, if it is a text node. This is set (indirectly)
225             by HTML::DOM's C method. You can also set it yourself.
226              
227             =back
228              
229             =cut
230              
231             sub content_offset {
232 549     549 1 627 my $old = (my $self = shift)->{_HTML_DOM_offset};
233 549 100       1021 @_ and $self->{_HTML_DOM_offset} = shift;
234 549         838 $old;
235             }
236              
237              
238             =head2 Other Methods
239              
240             =over 4
241              
242             =item getAttribute ( $name )
243              
244             Returns the attribute's value as a string.
245              
246             =item setAttribute ( $name, $value )
247              
248             Sets the attribute named C<$name> to C<$value>.
249              
250             =item removeAttribute ( $name )
251              
252             Deletes the C<$name>d attribute.
253              
254             =item getAttributeNode ( $name )
255              
256             Returns an attribute node (L).
257              
258             =item setAttributeNode ( $attr )
259              
260             Sets the attribute whose name is C<< $attr->nodeName >> to the attribute
261             object itself. If it replaces another attribute object, the latter is
262             returned.
263              
264             =item removeAttributeNode ( $attr )
265              
266             Removes and returns the C<$attr>.
267              
268             =item getElementsByTagName ( $tagname)
269              
270             This finds all elements with that tag name under the current element,
271             returning them as a list in list context or a node list object in scalar
272             context.
273              
274             =item getElementsByClassName ( $names )
275              
276             This finds all elements whose class attribute contains all the names in
277             C<$names>, which is a space-separated list; returning the elements as a
278             list in list context or a node list object in scalar
279             context.
280              
281             =item hasAttribute ( $name )
282              
283             Returns true or false, indicating whether this element has an attribute
284             named C<$name>, even one that is implied.
285              
286             =item click() (HTML 5)
287              
288             This triggers a click event on the element; nothing more.
289              
290             =item trigger_event
291              
292             This overrides L's method to trigger a DOMActivate event
293             after a click.
294              
295             =back
296              
297             =cut
298              
299             my %attr_defaults = (
300             br => { clear => 'none' },
301             td => { colspan => '1', rowspan=>1},
302             th => { colspan => 1, rowspan=>1},
303             form => {
304             enctype => 'application/x-www-form-urlencoded',
305             method => 'GET',
306             },
307             frame =>{frameborder => 1,scrolling=> 'auto'},
308             iframe=> {frameborder => 1,scrolling=>'auto'},
309             'area'=> {'shape' => 'rect',},
310             'a' =>{'shape' => 'rect',},
311             'col'=>{ 'span' => 1,},
312             'colgroup'=>{ 'span' => 1,},
313             'input',{ 'type' => 'TEXT',},
314             'button' =>{'type' => 'submit',},
315             'param' =>{'valuetype' => 'DATA'},
316             );
317             # Note: The _HTML_DOM_unspecified key used below points to a hash that
318             # stores Attr objects for implicit attributes in this list.
319              
320             sub getAttribute {
321 5018     5018 1 10544 my $ret = $_[0]->attr($_[1]);
322 5018 100       7236 defined $ret ? "$ret" : do{
323 1166         1858 my $tag = $_[0]->tag;
324 1166 50       1599 if(!$_[0]->tag){warn $_[0]->as_HTML; Carp::cluck}
  0         0  
  0         0  
325             return '' unless exists $attr_defaults{$tag}
326             and exists $attr_defaults{$tag}{$_[1]}
327             or $tag eq 'html' and $_[1] eq 'version'
328 1166 100 100     4798 and exists $_[0]->{_HTML_DOM_version};
      100        
      66        
      66        
329             $_[1] eq 'version'
330             ? $_[0]->{_HTML_DOM_version}
331 198 100       535 : $attr_defaults{$tag}{$_[1]}
332             };
333             }
334              
335             sub setAttribute {
336             # ~~~ INVALID_CHARACTER_ERR
337 802     802 1 1697 my $self = shift;
338              
339             # If the current value is an Attr object, we have to modify that
340             # instead of just assigning to the attribute.
341 802         1679 my $attr = $self->attr($_[0]);
342 802 100 100     2910 if(defined blessed $attr && $attr->isa('HTML::DOM::Attr')){
343 216         441 $attr->value($_[1]);
344             }else{
345 586         623 my($name,$val) = @_;
346 586         577 my $str_val = "$val";
347 586         903 my $old = $self->attr($name,$str_val);
348 25     25   120 no warnings 'uninitialized';
  25         43  
  25         23958  
349             $old ne $str_val
350             and $self->trigger_event('DOMAttrModified',
351             auto_viv => sub {
352 249     249   521 require HTML'DOM'Event'Mutation;
353 249 100       844 attr_name => $name,
354             attr_change_type =>
355             defined $old
356             ? &HTML'DOM'Event'Mutation'MODIFICATION
357             : &HTML'DOM'Event'Mutation'ADDITION,
358             prev_value => $old,
359             new_value => $val,
360             rel_node => $self->getAttributeNode($name),
361             }
362 586 100       3098 );
363             }
364              
365             # possible event handler
366 802 100 100     4816 if ($_[0] =~ /^on(.*)/is and my $listener_maker = $self->
367             ownerDocument->event_attr_handler) {
368 2         8 my $eavesdropper = &$listener_maker(
369             $self, my $name = lc $1, $_[1]
370             );
371 2 50       15 defined $eavesdropper and $self-> event_handler(
372             $name, $eavesdropper
373             );
374             }
375              
376             return # nothing;
377 802         809 }
378              
379             # This is just like attr, except that it triggers events.
380             sub _attr {
381 5165     5165   4813 my($self,$name) = (shift,shift);
382             # ~~~ Can we change getAttribute to attr, to make it faster, or will attr reject a reference? (Do we have to stringify it?)
383 5165 100       9375 my $old = $self->getAttribute($name) if defined wantarray;
384             @_
385 5165 100       8207 and defined $_[0]
    100          
386             ? $self->setAttribute($name, shift)
387             : $self->removeAttribute($name);
388 5165         11642 $old;
389             }
390              
391              
392             sub removeAttribute {
393 47     47 1 1516 my $old = (my $self = shift)->attr(my $name = shift);
394 47         89 $self->attr($name => undef);
395 47 100 66     190 if(defined blessed $old and $old->isa('HTML::DOM::Attr')) {
396             # So the attr node can be reused:
397 7         16 $old->_element(undef);
398              
399 7         20 $self->trigger_event('DOMAttrModified',
400             attr_name => $name,
401             attr_change_type => 3,
402             prev_value =>
403             (new_value => ($old->value) x 2)[-1..1],
404             rel_node => $old,
405             );
406             }
407             else {
408 40 100       73 return unless defined $old;
409             $self->trigger_event('DOMAttrModified',
410             auto_viv => sub {
411 2     2   7 (my $attr =
412             $self->ownerDocument
413             ->createAttribute($name)
414             )->value($old);
415 2         8 attr_name => $name,
416             attr_change_type => 3,
417             prev_value => $old,
418             new_value => $old,
419             rel_node => $attr,
420             }
421 39         170 );
422             }
423              
424             return # nothing;
425 46         261 }
426              
427             sub getAttributeNode {
428 387     387 1 959 my $elem = shift;
429 387         362 my $name = lc shift;
430              
431 387         710 my $attr = $elem->attr($name);
432 387 100       601 unless(defined $attr
433             ) { # check to see whether it has a default value
434 45         99 my $tag = $elem->tag;
435 45   100     150 return $elem->{_HTML_DOM_unspecified}{$name} ||= do{
436             return unless exists $attr_defaults{$tag}
437             and exists $attr_defaults{$tag}{$name}
438             or $tag eq 'html' and $name eq 'version'
439 44 100 66     234 and exists $elem->{_HTML_DOM_version};
      66        
      66        
      66        
440 21         49 my $attr = HTML::DOM::Attr->new($name);
441 21         58 $attr->_set_ownerDocument($elem->ownerDocument);
442 21         32 $attr->_element($elem);
443             $attr->value($name eq 'version'
444             ? $elem->{_HTML_DOM_version}
445 21 100       60 : $attr_defaults{$tag}{$name});
446 21         49 $attr;
447             };
448             }
449              
450 342 100       473 if(!ref $attr) {
451 304         734 $elem->attr($name, my $new_attr =
452             HTML::DOM::Attr->new($name, $attr));
453 304         568 $new_attr->_set_ownerDocument($elem->ownerDocument);
454 304         547 $new_attr->_element($elem);
455 304         1166 return $new_attr;
456             }
457 38         115 $attr;
458             }
459              
460             sub setAttributeNode {
461 19     19 1 413 my $doc = $_[0]->ownerDocument;
462              
463             # Even if it’s already the same document, it’s actually
464             # quicker just to set it than to check first.
465 19         44 $_[1]->_set_ownerDocument($doc);
466              
467 19         14 my $e;
468 19 100 66     33 die HTML::DOM::Exception->new(INUSE_ATTRIBUTE_ERR,
469             'The attribute passed to setAttributeNode is in use')
470             if defined($e = $_[1]->_element) && $e != $_[0];
471              
472 18         40 my $old = $_[0]->attr(my $name = $_[1]->nodeName, $_[1]);
473 18         39 $_[1]->_element($_[0]);
474              
475             # possible event handler
476 18 50 33     65 if ($name =~ /^on(.*)/is and my $listener_maker = $_[0]->
477             ownerDocument->event_attr_handler) {
478             # ~~~ Is there a possibility that the listener-maker
479             # will have a reference to the old attr node, and
480             # that calling it when that attr still has an
481             # 'owner' element when it shouldn't will cause any
482             # problems? Yet I don't want to intertwine this
483             # section of code with the one below.
484 0         0 my $eavesdropper = &$listener_maker(
485             $_[0], $name = lc $1, $_[1]->nodeValue
486             );
487 0 0       0 defined $eavesdropper and $_[0]-> event_handler(
488             $name, $eavesdropper
489             );
490             }
491              
492 18         12 my $ret;
493 18 100       35 if(defined $old) {
494 10 100 66     87 if(defined blessed $old and $old->isa("HTML::DOM::Attr")) {
495 9         21 $old->_element(undef);
496 9         12 $ret = $old;
497             } else {
498 1         2 $ret =
499             HTML::DOM::Attr->new($name);
500 1         2 $ret->_set_ownerDocument($doc);
501 1         3 $ret->_element($_[0]);
502 1         2 $ret->value($old);
503             }
504             }
505              
506 18 100       52 defined $ret and $_[0]->trigger_event('DOMAttrModified',
507             attr_name => $name,
508             attr_change_type => 3,
509             prev_value =>
510             (new_value => ($ret->value) x 2)[-1..1],
511             rel_node => $ret,
512             );
513 18         91 $_[0]->trigger_event('DOMAttrModified',
514             attr_name => $_[1]->name,
515             attr_change_type => 2,
516             prev_value =>
517             (new_value => ($_[1]->value) x 2)[-1..1],
518             rel_node => $_[1],
519             );
520              
521 18 100       116 return $ret if defined $ret;
522              
523             return # nothing;
524 8         20 }
525              
526             sub removeAttributeNode {
527 11     11 1 605 my($elem,$attr) = @_;
528              
529 11         40 my $old_val = $elem->attr(my $name = $attr->nodeName);
530             defined($old_val)
531             ? ref$old_val && refaddr $attr == refaddr $old_val
532 11 100 100     82 : exists $elem->{_HTML_DOM_unspecified}{$name}
    100          
533             or die HTML::DOM::Exception->new(NOT_FOUND_ERR,
534             "The node passed to removeAttributeNode is not an " .
535             "attribute of this element.");
536              
537 8         18 $elem->attr($name, undef);
538 8         12 delete $elem->{_HTML_DOM_unspecified}{$name};
539 8         17 $attr->_element(undef);
540              
541 8         44 $elem->trigger_event('DOMAttrModified',
542             attr_name => $name,
543             attr_change_type => 3,
544             prev_value =>
545             (new_value => ($attr->value) x 2)[-1..1],
546             rel_node => $attr,
547             );
548              
549              
550 8         46 return $attr
551             }
552              
553              
554             sub getElementsByTagName {
555 10     10 1 21 my($self,$tagname) = @_;
556 10 100       17 if (wantarray) {
557 4 100       18 return $tagname eq '*'
558             ? grep tag $_ !~ /^~/, $self->descendants
559             : (
560             ($tagname = lc $tagname)[()],
561             grep tag $_ eq $tagname, $self->descendants
562             );
563             }
564             else {
565             my $list = HTML::DOM::NodeList::Magic->new(
566             $tagname eq '*'
567 2     2   5 ? sub { grep tag $_ !~ /^~/, $self->descendants }
568             : (
569             $tagname = lc $tagname,
570             sub {
571 9     9   23 grep tag $_ eq $tagname, $self->descendants
572             }
573 6 100       48 )[1]
574             );
575 6         12 $self->ownerDocument-> _register_magic_node_list($list);
576 6         32 $list;
577             }
578             }
579              
580             sub getElementsByClassName {
581 9     9 1 289 splice @_, 2; # Remove extra elements
582 9         20 goto &_getElementsByClassName;
583             }
584             sub _getElementsByClassName {
585 18     18   25 my($self,$names,$is_doc) = @_;
586              
587 18         10 my $cref;
588 18 50       30 if(defined $names) {
589 25     25   115 no warnings 'uninitialized';
  25         25  
  25         7929  
590             # The DOM spec says to skip *ASCII* whitespace, and defines it as:
591             # U+0009, U+000A, U+000C, U+000D, and U+0020
592             # \t \n \f \r
593 18         92 $names
594             = join ".*", map " $_ ", sort split /[ \t\n\f\r]+/, $names;
595             $cref = sub {
596 177     177   265 (" ".join(" ", sort split /[ \t\n\f\r]+/, $_[0]->attr('class'))
597             ." ")
598             =~ $names
599 18         78 };
600             }
601 0     0   0 else { $cref = sub {} }
602              
603 18 100       30 if (wantarray) {
604 14         35 return $self->look_down($cref);
605             }
606             else {
607             my $list = HTML::DOM::NodeList::Magic->new(
608 4     4   12 sub { $self->look_down($cref); }
609 4         16 );
610 4 100       14 ($is_doc ? $self : $self-> ownerDocument)
611             ->_register_magic_node_list($list);
612 4         13 $list;
613             }
614             }
615              
616             sub hasAttribute {
617 497     497 1 590 my ($self,$attrname)= (shift, lc shift);
618 497         317 my $tag;
619             defined $self->attr($attrname)
620             or exists $attr_defaults{$tag = $self->tag}
621             and exists $attr_defaults{$tag}{$attrname}
622             or $tag eq 'html' and $attrname eq 'version'
623             and exists $self->{_HTML_DOM_version}
624 497 100 66     822 }
      66        
      66        
      66        
625              
626 21     21   35 sub _attr_specified { defined shift->attr(shift) }
627              
628 2     2 1 5 sub click { shift->trigger_event('click') }
629              
630             # used by innerHTML and insertAdjacentHTML
631             sub _html_fragment_parser {
632 31     31   126 require HTML'DOM; # paranoia
633 31         85 (my $tb = new HTML::DOM::Element::HTML:: no_magic_forms=>1)
634             ->_set_ownerDocument(shift->ownerDocument);
635 31         204 $tb->parse(shift);
636 31         77 $tb->eof();
637 31         66 $_->implicit(1) for $tb, $tb->content_list; # more paranoia
638 31         40 $tb;
639             }
640              
641 25         88 use constant _html_element_adds_newline =>
642 25     25   556 new HTML::DOM::_Element 'foo' =>->as_HTML =~ /\n/;
  25         30  
643              
644             sub innerHTML {
645 44     44 0 567 my $self = shift;
646 44 50       120 my $old = join '', map $_->nodeType==ELEMENT_NODE
    100          
    100          
647             ? _html_element_adds_newline
648             ? substr(
649             $_->as_HTML((undef)x2,{}),0,-1
650             )
651             : $_->as_HTML((undef)x2,{})
652             : encode_entities($_->data),$self->content_list
653             if defined wantarray;
654 44 100       168 if(@_) {
655 26         47 my $tb = _html_fragment_parser($self,shift);
656 26         85 $self->delete_content;
657 26         89 $self->push_content($tb->guts);
658 26   50     22 {($self->ownerDocument||last)->_modified}
  26         58  
659             }
660 44         113 $old;
661             }
662              
663             {
664             my %mm # method map
665             = qw(
666             beforebegin preinsert
667             afterend postinsert
668             afterbegin unshift_content
669             beforeend push_content
670             );
671              
672             sub insertAdjacentHTML {
673 5     5 0 8 my $elem = shift;
674            
675             die new HTML::DOM::Exception:: SYNTAX_ERR,
676             "$_[0]: invalid first argument to insertAdjacentHTML"
677 5 50       14 unless exists $mm{ my $where = lc $_[0] };
678            
679 5         9 my $tb = _html_fragment_parser($elem,$_[1]);
680 5         16 $elem->${\$mm{$where}}(guts $tb);
  5         30  
681              
682 5   50     3 {($elem->ownerDocument||last)->_modified}
  5         10  
683              
684             ()
685 5         66 }
686            
687             sub insertAdjacentElement {
688 5     5 0 5 my $elem = shift;
689            
690             die new HTML::DOM::Exception:: SYNTAX_ERR,
691             "$_[0]: invalid first argument to insertAdjacentElement"
692 5 50       13 unless exists $mm{ my $where = lc $_[0] };
693            
694 5         5 $elem->${\$mm{$where}}($_[1]);
  5         14  
695              
696 5   50     2 {($elem->ownerDocument||last)->_modified}
  5         12  
697              
698             ()
699 5         9 }
700             }
701              
702             sub innerText {
703 3     3 0 3 my $self = shift;
704 3 50       13 my $old = $self->as_text
705             if defined wantarray;
706 3 100       6 if(@_) {
707             # The slow way (with removeChild instead of delete_content)
708             # in order to trigger mutation events. (This may change if
709             # there is a spec one day for innerText.)
710 1         3 $self->removeChild($_) for $self->childNodes;
711 1         9 $self->appendChild(
712             $self->ownerDocument->createTextNode(shift)
713             );
714             }
715 3         9 $old;
716             }
717              
718             sub starttag {
719 147     147 0 118 my $self = shift;
720 147         245 my $tag = $self->SUPER::starttag(@ _);
721 147         201 $tag =~ s/ \/>\z/>/;
722 147         251 $tag
723             }
724              
725             # ------- OVERRIDDEN NODE METHDOS ---------- #
726              
727             *nodeName = \&tagName;
728             *nodeType = \& ELEMENT_NODE;
729              
730             sub attributes {
731 30     30 1 251 my $self = shift;
732             $self->{_HTML_DOM_Element_map} ||=
733 30   66     103 HTML::DOM::NamedNodeMap->new($self);
734             }
735              
736              
737             sub cloneNode { # override of HTML::DOM::Node’s method
738 7     7 1 37 my $clown = shift->SUPER::cloneNode(@_);
739              
740 7 100       11 unless(shift) { # if it’s shallow
741             # Flatten attr nodes, effectively cloning them:
742 3         20 $$clown{$_} = "$$clown{$_}" for grep !/^_/, keys %$clown;
743 3         5 delete $clown->{_HTML_DOM_Element_map};
744             } # otherwise clone takes care of this, so we don’t need to here
745 7         15 $clown;
746             }
747              
748             sub clone { # override of HTML::Element’s method; this is called
749             # recursively during a deep clone
750 201     201 0 338 my $clown = shift->SUPER::clone;
751 201         786 $$clown{$_} = "$$clown{$_}" for grep !/^_/, keys %$clown;
752 201         195 delete $clown->{_HTML_DOM_Element_map};
753 201         448 $clown;
754             }
755              
756             sub trigger_event {
757 1571     1571 1 5427 my ($a,$evnt) = (shift,shift);
758             $a->SUPER::trigger_event(
759             $evnt,
760             click_default =>sub {
761             $_[0]->target->trigger_event(DOMActivate =>
762 16     16   31 detail => eval{$_[0]->detail}
  16         40  
763             );;
764             },
765             # We check magic_forms before adding this for efficiency’s
766             # sake: so as not to burden well-formed documents with
767             # the extra overhead of auto-vivving an event object
768             # unnecessarily.
769             $a->ownerDocument->magic_forms ? (
770             DOMNodeRemoved_default => sub {
771 61     61   111 my $targy = $_[0]->target;
772 61         199 for($targy, $targy->descendants) {
773 282         221 eval { $_->form(undef) };
  282         880  
774             }
775 61         109 return; # give the eval void context
776             },
777 1571 50       5084 ) : (),
778             @_,
779             );
780             }
781              
782              
783             =head1 SEE ALSO
784              
785             L
786              
787             L
788              
789             L
790              
791             All the HTML::DOM::Element subclasses listed under
792             L
793              
794             =cut
795              
796              
797             # ------- HTMLHtmlElement interface ---------- #
798             # This has been moved to DOM.pm.
799              
800             # ------- HTMLHeadElement interface ---------- #
801              
802             package HTML::DOM::Element::Head;
803             our $VERSION = '0.056';
804             our @ISA = 'HTML::DOM::Element';
805 5     5   351 sub profile { shift->_attr('profile' => @_) }
806              
807             # ------- HTMLLinkElement interface ---------- #
808              
809             package HTML::DOM::Element::Link;
810             our $VERSION = '0.056';
811             our @ISA = 'HTML::DOM::Element';
812 25     25   114 use Scalar::Util 'blessed';
  25         26  
  25         4746  
813             sub disabled {
814 6 100   6   10 if(@_ > 1) {
815 2         3 my $old = $_[0]->{_HTML_DOM_disabled};
816 2         3 $_[0]->{_HTML_DOM_disabled} = $_[1];
817 2         5 return $old;
818             }
819 4         12 else { $_[0]->{_HTML_DOM_disabled};}
820             }
821 15     15   1837 sub charset { shift->_attr('charset' => @_) }
822 43     43   2467 sub href { shift->_attr('href' => @_) }
823 10     10   1395 sub hreflang { shift->_attr( hreflang => @_) }
824 10     10   1105 sub media { shift->_attr('media' => @_) }
825 10     10   1317 sub rel { shift->_attr('rel' => @_) }
826 10     10   1397 sub rev { shift->_attr('rev' => @_) }
827 20     20   2684 sub target { shift->_attr('target' => @_) }
828 40     40   5146 sub type { shift->_attr('type' => @_) }
829              
830             sub sheet {
831 40     40   27461 my $self = shift;
832 25     25   107 no warnings 'uninitialized';
  25         27  
  25         1643  
833 40 100       70 $self->attr('rel') =~
834 25     25   9144 /(?:^|\p{IsSpacePerl})stylesheet(?:\z|\p{IsSpacePerl})/i
  25         154  
  25         300  
835             or return;
836              
837 16         21 my $old = $$self{_HTML_DOM_sheet};
838 16 100       29 @_ and $self->{_HTML_DOM_sheet} = shift;
839 16 100       109 $old||(); }
840              
841             # I need to override these four to update the document’s style sheet list.
842             # ~~~ These could be made more efficient if they checked the attribute
843             # name first, to avoid unnecessary method calls.
844             sub setAttribute {
845 29     29   305 for(shift) {
846 29         55 $_->SUPER::setAttribute(@_);
847 29         59 $_->ownerDocument->_populate_sheet_list;
848             }
849             return # nothing;
850 29         35 }
851             sub removeAttribute {
852 1     1   77 for(shift) {
853 1         6 $_->SUPER::removeAttribute(@_);
854 1         3 $_->ownerDocument->_populate_sheet_list
855             }
856             return # nothing;
857 1         3 }
858             sub setAttributeNode {
859 3     3   11 (my $self = shift)->SUPER::setAttributeNode(@_);
860 3         6 $self->ownerDocument->_populate_sheet_list;
861             return # nothing;
862 3         5 }
863             sub removeAttributeNode {
864 1     1   1 my $self = shift;
865 1         8 my $attr = $self->SUPER::removeAttributeNode(@_);
866 1         3 $self->ownerDocument->_populate_sheet_list;
867 1         2 $attr
868             }
869              
870             sub trigger_event {
871             # ~~~ This defeats the purpose of having an auto-viv sub. I need to do
872             # some rethinking....
873 38     38   34 my $elem = shift;
874 38 50 33     214 if(defined blessed $_[0] and $_[0]->isa("HTML::DOM::Event")) {
    50          
875 0 0       0 return $elem->SUPER::trigger_event(@_)
876             unless $_[0]->type =~ /^domattrmodified\z/i;
877 0         0 my $attr_name = $_[0]->attrName;
878 0 0       0 if($attr_name eq 'href') { _reset_style_sheet($elem) }
  0         0  
879             }
880             elsif($_[0] !~ /^domattrmodified\z/i) {
881 0         0 return $elem->SUPER::trigger_event(@_);
882             }
883             else {
884 38         89 my($event,%args) = @_;
885 38 100       69 $args{auto_viv} and %args = &{$args{auto_viv}}, @_ = ($event, %args);
  19         29  
886 38 100       119 $args{attr_name} eq 'href' and _reset_style_sheet($elem);
887             }
888 38         262 SUPER'trigger_event $elem @_;
889             }
890              
891             sub _reset_style_sheet {
892 21     21   21 my $elem = shift;
893             return
894 21 100 100     52 unless ($elem->attr('rel')||'')
895             =~ /(?:^|\p{IsSpacePerl})stylesheet(?:\z|\p{IsSpacePerl})/i;
896 7         20 my $doc = $elem->ownerDocument;
897 7 100       17 return unless my $fetcher = $doc->css_url_fetcher;
898 5         11 my $base = $doc->base;
899 5 50       17 my $url = defined $base
900             ? new_abs URI
901             $elem->href, $doc->base
902             : $elem->href;
903 5         10 my ($css_code, %args)
904             = $fetcher->($url);
905 5 100       19 return unless defined $css_code;
906 4         15 require CSS'DOM;
907 4         48 VERSION CSS'DOM 0.03;
908 4   50     16 my $hint
909             = $doc->charset || 'iso-8859-1';
910             # default HTML charset
911             $elem->sheet(
912             # ’Tis true we create a new clo-
913             # sure for each style sheet, but
914             # what if the charset changes?
915             # ~~~ Is that even possible?
916             CSS'DOM'parse(
917             $css_code,
918             url_fetcher => sub {
919 0     0   0 my @ret = $fetcher->(shift);
920             @ret
921 0 0       0 ? (
922             $ret[0],
923             encoding_hint => $hint,
924             @ret[1..$#ret]
925             ) : ()
926             },
927 4         22 encoding_hint => $hint,
928             %args
929             )
930             );
931             }
932              
933             # ------- HTMLTitleElement interface ---------- #
934              
935             package HTML::DOM::Element::Title;
936             our $VERSION = '0.056';
937             our @ISA = 'HTML::DOM::Element';
938             # This is what I call FWP (no lexical vars):
939             sub text {
940 19   66 19   58 ($_[0]->firstChild or
941             @_ > 1 && $_[0]->appendChild(
942             shift->ownerDocument->createTextNode(shift)
943             ),
944             return '',
945             )->data(@_[1..$#_]);
946             }
947              
948             # ------- HTMLMetaElement interface ---------- #
949              
950             package HTML::DOM::Element::Meta;
951             our $VERSION = '0.056';
952             our @ISA = 'HTML::DOM::Element';
953 5     5   352 sub content { shift->_attr('content' => @_) }
954 5     5   680 sub httpEquiv { shift->_attr('http-equiv' => @_) }
955 45     45   5174 sub name { shift->_attr('name' => @_) }
956 5     5   713 sub scheme { shift->_attr('scheme' => @_) }
957              
958             # ------- HTMLBaseElement interface ---------- #
959              
960             package HTML::DOM::Element::Base;
961             our $VERSION = '0.056';
962             our @ISA = 'HTML::DOM::Element';
963             *href =\& HTML::DOM::Element::Link::href;
964             *target =\& HTML::DOM::Element::Link::target;
965              
966             # ------- HTMLIsIndexElement interface ---------- #
967              
968             package HTML::DOM::Element::IsIndex;
969             our $VERSION = '0.056';
970             our @ISA = 'HTML::DOM::Element';
971 2 100   2   10 sub form { (shift->look_up(_tag => 'form'))[0] || () }
972             # ~~~ Should this be the same as Select::form? I.e., should isindex ele-
973             # ments get magic form associations?
974 5     5   372 sub prompt { shift->_attr('prompt' => @_) }
975              
976             # ------- HTMLStyleElement interface ---------- #
977              
978             package HTML::DOM::Element::Style;
979             our $VERSION = '0.056';
980             our @ISA = 'HTML::DOM::Element';
981             *disabled = \&HTML::DOM::Element::Link::disabled;
982             *media =\& HTML::DOM::Element::Link::media;
983             *type =\& HTML::DOM::Element::Link::type;
984              
985             sub sheet {
986 15     15   789 my $self = shift;
987 15   66     53 $self->{_HTML_DOM_sheet} ||= do{
988 4         13 my $first_child = $self->firstChild;
989 4         10 local *@;
990 4         15 require CSS::DOM;
991 4         51 VERSION CSS::DOM .03;
992 4 50       23 CSS::DOM::parse($first_child?$first_child->data:'');
993             };
994             }
995              
996             # ------- HTMLBodyElement interface ---------- #
997              
998             package HTML::DOM::Element::Body;
999             our $VERSION = '0.056';
1000             our @ISA = 'HTML::DOM::Element';
1001 7     7   343 sub aLink { shift->_attr( aLink => @_) }
1002 7     7   670 sub background { shift->_attr( background => @_) }
1003 7     7   663 sub bgColor { shift->_attr('bgcolor' => @_) }
1004 7     7   681 sub link { shift->_attr('link' => @_) }
1005 7     7   1037 sub text { shift->_attr('text' => @_) }
1006 7     7   674 sub vLink { shift->_attr('vlink' => @_) }
1007             sub event_handler {
1008 4     4   8 my $self = shift;
1009 4         8 my $target = $self->ownerDocument->event_parent;
1010 4 100       24 $target
1011             ? $target->event_handler(@_)
1012             : $self->SUPER::event_handler(@_);
1013             }
1014              
1015             # ------- HTMLFormElement interface ---------- #
1016              
1017             # See Element/Form.pm
1018              
1019             # ~~~ list other form things here for reference
1020              
1021             # ------- HTMLUListElement interface ---------- #
1022              
1023             package HTML::DOM::Element::UL;
1024             our $VERSION = '0.056';
1025             our @ISA = 'HTML::DOM::Element';
1026 30 100   30   154 sub compact { shift->_attr( compact => @_ ? $_[0]?'compact': undef : () ) }
    100          
1027 5     5   354 sub type { lc shift->_attr( type => @_) }
1028              
1029             # ------- HTMLOListElement interface ---------- #
1030              
1031             package HTML::DOM::Element::OL;
1032             our $VERSION = '0.056';
1033             our @ISA = 'HTML::DOM::Element';
1034 5     5   341 sub start { shift->_attr( start => @_) }
1035             *compact=\&HTML::DOM::Element::UL::compact;
1036             * type = \ & HTML::DOM::Element::Link::type ;
1037              
1038             # ------- HTMLDListElement interface ---------- #
1039              
1040             package HTML::DOM::Element::DL;
1041             our $VERSION = '0.056';
1042             our @ISA = 'HTML::DOM::Element';
1043             *compact=\&HTML::DOM::Element::UL::compact;
1044              
1045             # ------- HTMLDirectoryElement interface ---------- #
1046              
1047             package HTML::DOM::Element::Dir;
1048             our $VERSION = '0.056';
1049             our @ISA = 'HTML::DOM::Element';
1050             *compact=\&HTML::DOM::Element::UL::compact;
1051              
1052             # ------- HTMLMenuElement interface ---------- #
1053              
1054             package HTML::DOM::Element::Menu;
1055             our $VERSION = '0.056';
1056             our @ISA = 'HTML::DOM::Element';
1057             *compact=\&HTML::DOM::Element::UL::compact;
1058              
1059             # ------- HTMLLIElement interface ---------- #
1060              
1061             package HTML::DOM::Element::LI;
1062             our $VERSION = '0.056';
1063             our @ISA = 'HTML::DOM::Element';
1064             *type =\& HTML::DOM::Element::Link::type;
1065 10     10   1360 sub value { shift->_attr( value => @_) }
1066              
1067             # ------- HTMLDivElement interface ---------- #
1068              
1069             package HTML::DOM::Element::Div;
1070             our $VERSION = '0.056';
1071             our @ISA = 'HTML::DOM::Element';
1072 40     40   3460 sub align { lc shift->_attr( align => @_) }
1073              
1074             # ------- HTMLParagraphElement interface ---------- #
1075              
1076             package HTML::DOM::Element::P;
1077             our $VERSION = '0.056';
1078             our @ISA = 'HTML::DOM::Element';
1079             *align =\& HTML::DOM::Element::Div::align;
1080              
1081             # ------- HTMLHeadingElement interface ---------- #
1082              
1083             package HTML::DOM::Element::Heading;
1084             our $VERSION = '0.056';
1085             our @ISA = 'HTML::DOM::Element';
1086             *align =\& HTML::DOM::Element::Div::align;
1087              
1088             # ------- HTMLQuoteElement interface ---------- #
1089              
1090             package HTML::DOM::Element::Quote;
1091             our $VERSION = '0.056';
1092             our @ISA = 'HTML::DOM::Element';
1093 10     10   728 sub cite { shift->_attr( cite => @_) }
1094              
1095             # ------- HTMLPreElement interface ---------- #
1096              
1097             package HTML::DOM::Element::Pre;
1098             our $VERSION = '0.056';
1099             our @ISA = 'HTML::DOM::Element';
1100 30     30   3816 sub width { shift->_attr( width => @_) }
1101              
1102             # ------- HTMLBRElement interface ---------- #
1103              
1104             package HTML::DOM::Element::Br;
1105             our $VERSION = '0.056';
1106             our @ISA = 'HTML::DOM::Element';
1107 5     5   354 sub clear { lc shift->_attr( clear => @_) }
1108              
1109             # ------- HTMLBaseFontElement interface ---------- #
1110              
1111             package HTML::DOM::Element::BaseFont;
1112             our $VERSION = '0.056';
1113             our @ISA = 'HTML::DOM::Element';
1114 10     10   708 sub color { shift->_attr( color => @_) }
1115 10     10   1332 sub face { shift->_attr( face => @_) }
1116 15     15   1994 sub size { shift->_attr( size => @_) }
1117              
1118             # ------- HTMLBaseFontElement interface ---------- #
1119              
1120             package HTML::DOM::Element::Font;
1121             our $VERSION = '0.056';
1122             our @ISA = 'HTML::DOM::Element';
1123             *color =\& HTML::DOM::Element::BaseFont::color;
1124             *face =\& HTML::DOM::Element::BaseFont::face;
1125             *size =\& HTML::DOM::Element::BaseFont::size;
1126              
1127             # ------- HTMLHRElement interface ---------- #
1128              
1129             package HTML::DOM::Element::HR;
1130             our $VERSION = '0.056';
1131             our @ISA = 'HTML::DOM::Element';
1132             *align =\& HTML::DOM::Element::Div::align;
1133 6 100   6   31 sub noShade { shift->_attr( noshade => @_ ? $_[0]?'noshade':undef : () ) }
    100          
1134              
1135             *size =\& HTML::DOM::Element::BaseFont::size;
1136             *width =\& HTML::DOM::Element::Pre::width;
1137              
1138             # ------- HTMLModElement interface ---------- #
1139              
1140             package HTML::DOM::Element::Mod;
1141             our $VERSION = '0.056';
1142             our @ISA = 'HTML::DOM::Element';
1143             *cite =\& HTML::DOM::Element::Quote::cite;
1144 5     5   978 sub dateTime { shift->_attr( datetime => @_) }
1145              
1146             # ------- HTMLAnchorElement interface ---------- #
1147              
1148             package HTML::DOM::Element::A;
1149             our $VERSION = '0.056';
1150             our @ISA = 'HTML::DOM::Element';
1151 10     10   696 sub accessKey { shift->_attr( accesskey => @_) }
1152             * charset =\&HTML::DOM::Element::Link::charset ;
1153             * coords =\&HTML::DOM::Element::Area::coords ;
1154             * href =\&HTML::DOM::Element::Link::href ;
1155             * hreflang =\&HTML::DOM::Element::Link::hreflang ;
1156             * name =\&HTML::DOM::Element::Meta::name ;
1157             * rel =\&HTML::DOM::Element::Link::rel ;
1158             * rev =\&HTML::DOM::Element::Link::rev ;
1159 10     10   1319 sub shape { shift->_attr( shape => @_) }
1160             * tabIndex =\&HTML::DOM::Element::Object::tabIndex ;
1161             * target =\&HTML::DOM::Element::Link::target ;
1162             * type =\&HTML::DOM::Element::Link::type ;
1163              
1164 1     1   3 sub blur { shift->trigger_event('blur') }
1165 1     1   3 sub focus { shift->trigger_event('focus') }
1166              
1167             sub trigger_event {
1168 119     119   233 my ($a,$evnt) = (shift,shift);
1169 119         290 $a->SUPER::trigger_event(
1170             $evnt,
1171             DOMActivate_default =>
1172             $a->ownerDocument->
1173             default_event_handler_for('link')
1174             ,
1175             @_,
1176             );
1177             }
1178              
1179             sub _get_abs_href {
1180 128     128   100 my $elem = shift;
1181 128         283 my $uri = new URI $elem->attr('href');
1182 128 100       9479 if(!$uri->scheme) {
1183 90         694 my $base = $elem->ownerDocument->base;
1184 90 100       452 return unless $base;
1185 6         14 $uri = $uri->abs($base);
1186 6 50       1011 return unless $uri->scheme;
1187             }
1188             $uri
1189 44         460 }
1190              
1191             sub hash {
1192 18     18   40 my $elem = shift;
1193 18 100       23 defined(my $uri = _get_abs_href $elem) or return '';
1194 6         6 my $old;
1195 6 50       9 if(defined wantarray) {
1196 6         17 $old = $uri->fragment;
1197 6 100       36 $old = "#$old" if defined $old;
1198             }
1199 6 100       12 if (@_){
1200 2         6 shift() =~ /#?(.*)/s;
1201 2         5 $uri->fragment($1);
1202 2         44 $elem->_attr(href => $uri);
1203             }
1204 6 100       35 $old||''
1205             }
1206              
1207             sub host {
1208 18     18   1035 my $elem = shift;
1209 18 100       23 defined(my $uri = _get_abs_href $elem) or return '';
1210 6 50       24 my $old = $uri->host_port if defined wantarray;
1211 6 100       116 if (@_) {
1212 2         7 $uri->port("");
1213 2         67 $uri->host_port(shift);
1214 2         119 $elem->attr(href => $uri);
1215             }
1216             $old
1217 6         19 }
1218              
1219             sub hostname {
1220 18     18   1063 my $elem = shift;
1221 18 100       26 defined(my $uri = _get_abs_href $elem) or return '';
1222 6 50       19 my $old = $uri->host if defined wantarray;
1223 6 100       110 if (@_) {
1224 2         6 $uri->host(shift);
1225 2         90 $elem->attr(href => $uri);
1226             }
1227             $old
1228 6         18 }
1229              
1230             sub pathname {
1231 18     18   1083 my $elem = shift;
1232 18 100       29 defined(my $uri = _get_abs_href $elem) or return '';
1233 6 50       25 my $old = $uri->path if defined wantarray;
1234 6 100       49 if (@_) {
1235 2         4 $uri->path(shift);
1236 2         33 $elem->attr(href => $uri);
1237             }
1238             $old
1239 6         20 }
1240              
1241             sub port {
1242 18     18   1045 my $elem = shift;
1243 18 100       27 defined(my $uri = _get_abs_href $elem) or return '';
1244 6 50       24 my $old = $uri->port if defined wantarray;
1245 6 100       98 if (@_) {
1246 2         6 $uri->port(shift);
1247 2         61 $elem->attr(href => $uri);
1248             }
1249             $old
1250 6         18 }
1251              
1252             sub protocol {
1253 18     18   992 my $elem = shift;
1254 18 100       40 defined(my $uri = _get_abs_href $elem) or return '';
1255 6 50       17 my $old = $uri->scheme . ':' if defined wantarray;
1256 6 100       46 if (@_) {
1257 2         5 shift() =~ /(.*):?/s;
1258 2         6 $uri->scheme("$1");
1259 2         1468 $elem->attr(href => $uri);
1260             }
1261             $old
1262              
1263 6         22 }
1264              
1265             sub search {
1266 20     20   1068 my $elem = shift;
1267 20 100       29 defined(my $uri = _get_abs_href $elem) or return '';
1268 8         5 my $old;
1269 8 100       16 if(defined wantarray) {
1270 6         19 my $q = $uri->query;
1271 6 100       53 $old = defined $q ? "?$q" : "";
1272             }
1273 8 100       13 if (@_){
1274 4         9 shift() =~ /(\??)(.*)/s;
1275 4 50 33     20 $uri->query(
1276             $1||length$2 ? "$2" : undef
1277             );
1278 4         70 $elem->attr(href => $uri);
1279             }
1280             $old
1281 8         39 }
1282              
1283              
1284             # ------- HTMLImageElement interface ---------- #
1285              
1286             package HTML::DOM::Element::Img;
1287             our $VERSION = '0.056';
1288             our @ISA = 'HTML::DOM::Element';
1289 0     0   0 sub lowSrc { shift->attr( lowsrc => @_) }
1290             * name = \&HTML::DOM::Element::Meta::name ;
1291             * align = \&HTML::DOM::Element::Div::align ;
1292 15     15   2070 sub alt { shift->_attr( alt => @_) }
1293 5     5   684 sub border { shift->_attr( border => @_) }
1294 20     20   2732 sub height { shift->_attr( height => @_) }
1295 15     15   1996 sub hspace { shift->_attr( hspace => @_) }
1296 6 100   6   344 sub isMap { shift->_attr( ismap => @_ ? $_[0] ? 'ismap' : undef : () ) }
    100          
1297 5     5   657 sub longDesc { shift->_attr( longdesc => @_) }
1298 22     22   2646 sub src { shift->_attr( src => @_) }
1299 10     10   1313 sub useMap { shift->_attr( usemap => @_) }
1300 15     15   2005 sub vspace { shift->_attr( vspace => @_) }
1301             * width = \&HTML::DOM::Element::Pre::width ;
1302              
1303             # ------- HTMLObjectElement interface ---------- #
1304              
1305             package HTML::DOM::Element::Object;
1306             our $VERSION = '0.056';
1307             our @ISA = 'HTML::DOM::Element';
1308             *form=\&HTML::DOM::Element::Select::form;
1309 10     10   1009 sub code { shift->_attr( code => @_) }
1310             * align = \&HTML::DOM::Element::Div::align ;
1311 10     10   1347 sub archive { shift->_attr( archive => @_) }
1312 5     5   681 sub border { shift->_attr( border => @_) }
1313 10     10   1386 sub codeBase { shift->_attr( codebase => @_) }
1314 5     5   678 sub codeType { shift->_attr( codetype => @_) }
1315 5     5   679 sub data { shift->_attr( data => @_) }
1316 6 100   6   34 sub declare { shift->_attr( declare => @_ ? $_[0]?'declare':undef : () ) }
    100          
1317             * height = \&HTML::DOM::Element::Img::height ;
1318             * hspace = \&HTML::DOM::Element::Img::hspace ;
1319             * name = \&HTML::DOM::Element::Meta::name ;
1320 5     5   721 sub standby { shift->_attr( standby => @_) }
1321 15     15   2021 sub tabIndex { shift->_attr( tabindex => @_) }
1322             *type =\& HTML::DOM::Element::Link::type;
1323             *useMap =\& HTML::DOM::Element::Img::useMap;
1324             *vspace =\& HTML::DOM::Element::Img::vspace;
1325             * width = \&HTML::DOM::Element::Pre::width ;
1326       1     sub contentDocument{}
1327              
1328             # ------- HTMLParamElement interface ---------- #
1329              
1330             package HTML::DOM::Element::Param;
1331             our $VERSION = '0.056';
1332             our @ISA = 'HTML::DOM::Element';
1333             *name=\&HTML::DOM::Element::Meta::name;
1334             *type=\&HTML::DOM::Element::Link::type;
1335             *value=\&HTML::DOM::Element::LI::value;
1336 5     5   674 sub valueType{lc shift->_attr(valuetype=>@_)}
1337              
1338             # ------- HTMLAppletElement interface ---------- #
1339              
1340             package HTML::DOM::Element::Applet;
1341             our $VERSION = '0.056';
1342             our @ISA = 'HTML::DOM::Element';
1343             * align = \ & HTML::DOM::Element::Div::align ;
1344             * alt = \ & HTML::DOM::Element::Img::alt ;
1345             * archive = \ & HTML::DOM::Element::Object::archive ;
1346             * code = \ & HTML::DOM::Element::Object::code ;
1347             * codeBase = \ & HTML::DOM::Element::Object::codeBase ;
1348             * height = \ & HTML::DOM::Element::Img::height ;
1349             * hspace = \ & HTML::DOM::Element::Img::hspace ;
1350             * name = \ & HTML::DOM::Element::Meta::name ;
1351 5     5   679 sub object { shift -> _attr ( object => @_ ) }
1352             * vspace = \ & HTML::DOM::Element::Img::vspace ;
1353             * width = \ & HTML::DOM::Element::Pre::width ;
1354              
1355             # ------- HTMLMapElement interface ---------- #
1356              
1357             package HTML::DOM::Element::Map;
1358             our $VERSION = '0.056';
1359             our @ISA = 'HTML::DOM::Element';
1360             sub areas { # ~~~ I need to make this cache the resulting collection obj
1361 1     1   2 my $self = shift;
1362 1 50       3 if (wantarray) {
1363 0         0 return grep tag $_ eq 'area', $self->descendants;
1364             }
1365             else {
1366             my $collection = HTML::DOM::Collection->new(
1367             my $list = HTML::DOM::NodeList::Magic->new(
1368 1     1   39 sub { grep tag $_ eq 'area', $self->descendants }
1369 1         12 ));
1370 1         4 $self->ownerDocument-> _register_magic_node_list($list);
1371 1         2 $collection;
1372             }
1373             }
1374             * name = \ & HTML::DOM::Element::Meta::name ;
1375              
1376             # ------- HTMLAreaElement interface ---------- #
1377              
1378             package HTML::DOM::Element::Area;
1379             our $VERSION = '0.056';
1380             our @ISA = 'HTML::DOM::Element';
1381             * alt = \ & HTML::DOM::Element::Img::alt ;
1382 10     10   1351 sub coords { shift -> _attr ( coords => @_ ) }
1383             * href = \ & HTML::DOM::Element::Link::href ;
1384 5 100   5   20 sub noHref { shift->attr ( nohref => @_ ? $_[0] ? 'nohref' : undef : () ) }
    100          
1385             * tabIndex = \ & HTML::DOM::Element::Object::tabIndex ;
1386             * target = \ & HTML::DOM::Element::Link::target ;
1387             {
1388 25     25   397796 no strict 'refs';
  25         27  
  25         13222  
1389             *$_ = \&{"HTML::DOM::Element::A::$_"}
1390             for qw(accessKey shape hash host hostname pathname port protocol search
1391             trigger_event);
1392             }
1393              
1394             # ------- HTMLScriptElement interface ---------- #
1395              
1396             package HTML::DOM::Element::Script;
1397             our $VERSION = '0.056';
1398             our @ISA = 'HTML::DOM::Element';
1399             * text = \ &HTML::DOM::Element::Title::text ;
1400 5     5   666 sub htmlFor { shift -> _attr ( for => @_ ) }
1401 5     5   352 sub event { shift -> _attr ( event => @_ ) }
1402             * charset = \ &HTML::DOM::Element::Link::charset ;
1403 6 100   6   30 sub defer { shift -> _attr ( defer => @_ ? $_[0] ? 'defer' : undef : () ) }
    100          
1404             * src = \ &HTML::DOM::Element::Img::src ;
1405             * type = \ &HTML::DOM::Element::Link::type ;
1406              
1407             # ------- HTMLFrameSetElement interface ---------- #
1408              
1409             package HTML::DOM::Element::FrameSet;
1410             our $VERSION = '0.056';
1411             our @ISA = 'HTML::DOM::Element';
1412 5     5   672 sub rows { shift -> _attr ( rows => @_ ) }
1413 5     5   352 sub cols { shift -> _attr ( cols => @_ ) }
1414              
1415             # ------- HTMLFrameElement interface ---------- #
1416              
1417             package HTML::DOM::Element::Frame;
1418             our $VERSION = '0.056';
1419             our @ISA = 'HTML::DOM::Element';
1420 12     12   1050 sub frameBorder { lc shift -> _attr ( frameBorder => @_ ) }
1421 10     10   1343 sub longDesc { shift -> _attr ( longdesc => @_ ) }
1422 10     10   1356 sub marginHeight{ shift -> _attr ( marginheight => @_ ) }
1423 10     10   1395 sub marginWidth { shift -> _attr ( marginwidth => @_ ) }
1424             * name = \ &HTML::DOM::Element::Meta::name ;
1425 6 100   6   30 sub noResize { shift->_attr(noresize => @_ ? $_[0]?'noresize':undef : ()) }
    100          
1426 10     10   1368 sub scrolling { lc shift -> _attr ( scrolling => @_ ) }
1427             * src = \ &HTML::DOM::Element::Img::src ;
1428 6   100 6   23 sub contentDocument{ (shift->{_HTML_DOM_view} || return)->document }
1429             sub contentWindow {
1430 8     8   17 my $old = (my $self = shift)->{_HTML_DOM_view};
1431 8 100       17 @_ and $self->{_HTML_DOM_view} = shift;
1432 8 100       31 defined $old ? $old : ()
1433             };
1434              
1435             # ------- HTMLIFrameElement interface ---------- #
1436              
1437             package HTML::DOM::Element::IFrame;
1438             our $VERSION = '0.056';
1439             our @ISA = 'HTML::DOM::Element';
1440             *align = \&HTML::DOM::Element::Div::align;
1441             *frameBorder = \&HTML::DOM::Element::Frame::frameBorder;
1442             *height = \&HTML::DOM::Element::Img::height;
1443             *longDesc = \&HTML::DOM::Element::Frame::longDesc;
1444             * marginHeight = \&HTML::DOM::Element::Frame::marginHeight;
1445             *marginWidth = \&HTML::DOM::Element::Frame::marginWidth;
1446             *name = \&HTML::DOM::Element::Meta::name;
1447             *scrolling = \&HTML::DOM::Element::Frame::scrolling;
1448             *src = \&HTML::DOM::Element::Img::src;
1449             *width = \&HTML::DOM::Element::Pre::width;
1450             *contentDocument = \&HTML::DOM::Element::Frame::contentDocument;
1451             *contentWindow = \&HTML::DOM::Element::Frame::contentWindow;
1452              
1453             1