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   532 use strict;
  25         28  
  25         510  
4 25     25   79 use warnings;
  25         23  
  25         540  
5              
6 25         1369 use HTML::DOM::Exception qw 'INVALID_CHARACTER_ERR
7 25     25   8471 INUSE_ATTRIBUTE_ERR NOT_FOUND_ERR SYNTAX_ERR';
  25         36  
8 25     25   9272 use HTML::DOM::Node 'ELEMENT_NODE';
  25         49  
  25         1686  
9 25     25   127 use HTML'Entities;
  25         29  
  25         1270  
10 25     25   111 use Scalar::Util qw'refaddr blessed weaken';
  25         26  
  25         17506  
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.057';
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 4892 $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.057
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 1459 my $tagname = $_[1];
141              
142             # Hack to make parsing comments work
143 1408 100       2728 $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         1167 my $ret;
151 1401         1350 eval {
152 1401         3696 $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       3581 and do { require HTML'DOM }; # paranoia
  162         771  
158             };
159 1401 50       3529 $@ 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 25563 uc $_[0]->tag;
191             }
192              
193 2718     2718 1 9078 sub id { shift->_attr(id => @_) }
194              
195 5     5 1 1072 sub title { shift->_attr(title => @_) }
196 5     5 1 1030 sub lang { shift->_attr(lang => @_) }
197 5     5 1 1025 sub dir { lc shift->_attr(dir => @_) }
198 5     5 1 1064 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 2360 my $self = shift;
209 38   66     77 ($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 665 my $old = (my $self = shift)->{_HTML_DOM_offset};
233 549 100       1079 @_ and $self->{_HTML_DOM_offset} = shift;
234 549         897 $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 11072 my $ret = $_[0]->attr($_[1]);
322 5018 100       7950 defined $ret ? "$ret" : do{
323 1166         1930 my $tag = $_[0]->tag;
324 1166 50       1676 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     5213 and exists $_[0]->{_HTML_DOM_version};
      100        
      66        
      66        
329             $_[1] eq 'version'
330             ? $_[0]->{_HTML_DOM_version}
331 198 100       569 : $attr_defaults{$tag}{$_[1]}
332             };
333             }
334              
335             sub setAttribute {
336             # ~~~ INVALID_CHARACTER_ERR
337 802     802 1 2126 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         1848 my $attr = $self->attr($_[0]);
342 802 100 100     3218 if(defined blessed $attr && $attr->isa('HTML::DOM::Attr')){
343 216         483 $attr->value($_[1]);
344             }else{
345 586         633 my($name,$val) = @_;
346 586         653 my $str_val = "$val";
347 586         1271 my $old = $self->attr($name,$str_val);
348 25     25   125 no warnings 'uninitialized';
  25         30  
  25         24547  
349             $old ne $str_val
350             and $self->trigger_event('DOMAttrModified',
351             auto_viv => sub {
352 249     249   580 require HTML'DOM'Event'Mutation;
353 249 100       983 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       3447 );
363             }
364              
365             # possible event handler
366 802 100 100     5155 if ($_[0] =~ /^on(.*)/is and my $listener_maker = $self->
367             ownerDocument->event_attr_handler) {
368 2         7 my $eavesdropper = &$listener_maker(
369             $self, my $name = lc $1, $_[1]
370             );
371 2 50       19 defined $eavesdropper and $self-> event_handler(
372             $name, $eavesdropper
373             );
374             }
375              
376             return # nothing;
377 802         917 }
378              
379             # This is just like attr, except that it triggers events.
380             sub _attr {
381 5165     5165   5190 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       10066 my $old = $self->getAttribute($name) if defined wantarray;
384             @_
385 5165 100       8937 and defined $_[0]
    100          
386             ? $self->setAttribute($name, shift)
387             : $self->removeAttribute($name);
388 5165         13184 $old;
389             }
390              
391              
392             sub removeAttribute {
393 47     47 1 1971 my $old = (my $self = shift)->attr(my $name = shift);
394 47         97 $self->attr($name => undef);
395 47 100 66     213 if(defined blessed $old and $old->isa('HTML::DOM::Attr')) {
396             # So the attr node can be reused:
397 7         22 $old->_element(undef);
398              
399 7         27 $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       80 return unless defined $old;
409             $self->trigger_event('DOMAttrModified',
410             auto_viv => sub {
411 2     2   8 (my $attr =
412             $self->ownerDocument
413             ->createAttribute($name)
414             )->value($old);
415 2         10 attr_name => $name,
416             attr_change_type => 3,
417             prev_value => $old,
418             new_value => $old,
419             rel_node => $attr,
420             }
421 39         183 );
422             }
423              
424             return # nothing;
425 46         269 }
426              
427             sub getAttributeNode {
428 387     387 1 1228 my $elem = shift;
429 387         444 my $name = lc shift;
430              
431 387         792 my $attr = $elem->attr($name);
432 387 100       655 unless(defined $attr
433             ) { # check to see whether it has a default value
434 45         117 my $tag = $elem->tag;
435 45   100     161 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     238 and exists $elem->{_HTML_DOM_version};
      66        
      66        
      66        
440 21         52 my $attr = HTML::DOM::Attr->new($name);
441 21         72 $attr->_set_ownerDocument($elem->ownerDocument);
442 21         35 $attr->_element($elem);
443             $attr->value($name eq 'version'
444             ? $elem->{_HTML_DOM_version}
445 21 100       70 : $attr_defaults{$tag}{$name});
446 21         59 $attr;
447             };
448             }
449              
450 342 100       561 if(!ref $attr) {
451 304         825 $elem->attr($name, my $new_attr =
452             HTML::DOM::Attr->new($name, $attr));
453 304         681 $new_attr->_set_ownerDocument($elem->ownerDocument);
454 304         552 $new_attr->_element($elem);
455 304         1170 return $new_attr;
456             }
457 38         127 $attr;
458             }
459              
460             sub setAttributeNode {
461 19     19 1 471 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         41 $_[1]->_set_ownerDocument($doc);
466              
467 19         15 my $e;
468 19 100 66     46 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         48 my $old = $_[0]->attr(my $name = $_[1]->nodeName, $_[1]);
473 18         42 $_[1]->_element($_[0]);
474              
475             # possible event handler
476 18 50 33     66 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         18 my $ret;
493 18 100       35 if(defined $old) {
494 10 100 66     74 if(defined blessed $old and $old->isa("HTML::DOM::Attr")) {
495 9         33 $old->_element(undef);
496 9         11 $ret = $old;
497             } else {
498 1         4 $ret =
499             HTML::DOM::Attr->new($name);
500 1         3 $ret->_set_ownerDocument($doc);
501 1         3 $ret->_element($_[0]);
502 1         2 $ret->value($old);
503             }
504             }
505              
506 18 100       64 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         84 $_[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       124 return $ret if defined $ret;
522              
523             return # nothing;
524 8         25 }
525              
526             sub removeAttributeNode {
527 11     11 1 810 my($elem,$attr) = @_;
528              
529 11         30 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     87 : 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         24 $elem->attr($name, undef);
538 8         17 delete $elem->{_HTML_DOM_unspecified}{$name};
539 8         17 $attr->_element(undef);
540              
541 8         26 $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         49 return $attr
551             }
552              
553              
554             sub getElementsByTagName {
555 10     10 1 27 my($self,$tagname) = @_;
556 10 100       23 if (wantarray) {
557 4 100       25 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   7 ? sub { grep tag $_ !~ /^~/, $self->descendants }
568             : (
569             $tagname = lc $tagname,
570             sub {
571 9     9   22 grep tag $_ eq $tagname, $self->descendants
572             }
573 6 100       63 )[1]
574             );
575 6         16 $self->ownerDocument-> _register_magic_node_list($list);
576 6         37 $list;
577             }
578             }
579              
580             sub getElementsByClassName {
581 9     9 1 325 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         14 my $cref;
588 18 50       31 if(defined $names) {
589 25     25   127 no warnings 'uninitialized';
  25         35  
  25         8055  
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         106 $names
594             = join ".*", map " $_ ", sort split /[ \t\n\f\r]+/, $names;
595             $cref = sub {
596 177     177   302 (" ".join(" ", sort split /[ \t\n\f\r]+/, $_[0]->attr('class'))
597             ." ")
598             =~ $names
599 18         89 };
600             }
601 0     0   0 else { $cref = sub {} }
602              
603 18 100       28 if (wantarray) {
604 14         42 return $self->look_down($cref);
605             }
606             else {
607             my $list = HTML::DOM::NodeList::Magic->new(
608 4     4   10 sub { $self->look_down($cref); }
609 4         22 );
610 4 100       16 ($is_doc ? $self : $self-> ownerDocument)
611             ->_register_magic_node_list($list);
612 4         16 $list;
613             }
614             }
615              
616             sub hasAttribute {
617 497     497 1 699 my ($self,$attrname)= (shift, lc shift);
618 497         423 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     976 }
      66        
      66        
      66        
625              
626 21     21   41 sub _attr_specified { defined shift->attr(shift) }
627              
628 2     2 1 7 sub click { shift->trigger_event('click') }
629              
630             # used by innerHTML and insertAdjacentHTML
631             sub _html_fragment_parser {
632 31     31   141 require HTML'DOM; # paranoia
633 31         97 (my $tb = new HTML::DOM::Element::HTML:: no_magic_forms=>1)
634             ->_set_ownerDocument(shift->ownerDocument);
635 31         224 $tb->parse(shift);
636 31         87 $tb->eof();
637 31         67 $_->implicit(1) for $tb, $tb->content_list; # more paranoia
638 31         52 $tb;
639             }
640              
641 25         95 use constant _html_element_adds_newline =>
642 25     25   652 new HTML::DOM::_Element 'foo' =>->as_HTML =~ /\n/;
  25         32  
643              
644             sub innerHTML {
645 44     44 0 651 my $self = shift;
646 44 50       118 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       190 if(@_) {
655 26         62 my $tb = _html_fragment_parser($self,shift);
656 26         96 $self->delete_content;
657 26         100 $self->push_content($tb->guts);
658 26   50     26 {($self->ownerDocument||last)->_modified}
  26         56  
659             }
660 44         128 $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       17 unless exists $mm{ my $where = lc $_[0] };
678            
679 5         11 my $tb = _html_fragment_parser($elem,$_[1]);
680 5         12 $elem->${\$mm{$where}}(guts $tb);
  5         32  
681              
682 5   50     6 {($elem->ownerDocument||last)->_modified}
  5         9  
683              
684             ()
685 5         73 }
686            
687             sub insertAdjacentElement {
688 5     5 0 7 my $elem = shift;
689            
690             die new HTML::DOM::Exception:: SYNTAX_ERR,
691             "$_[0]: invalid first argument to insertAdjacentElement"
692 5 50       14 unless exists $mm{ my $where = lc $_[0] };
693            
694 5         6 $elem->${\$mm{$where}}($_[1]);
  5         18  
695              
696 5   50     5 {($elem->ownerDocument||last)->_modified}
  5         9  
697              
698             ()
699 5         9 }
700             }
701              
702             sub innerText {
703 3     3 0 5 my $self = shift;
704 3 50       14 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         4 $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 121 my $self = shift;
720 147         279 my $tag = $self->SUPER::starttag(@ _);
721 147         220 $tag =~ s/ \/>\z/>/;
722 147         288 $tag
723             }
724              
725             # ------- OVERRIDDEN NODE METHDOS ---------- #
726              
727             *nodeName = \&tagName;
728             *nodeType = \& ELEMENT_NODE;
729              
730             sub attributes {
731 30     30 1 418 my $self = shift;
732             $self->{_HTML_DOM_Element_map} ||=
733 30   66     119 HTML::DOM::NamedNodeMap->new($self);
734             }
735              
736              
737             sub cloneNode { # override of HTML::DOM::Node’s method
738 7     7 1 44 my $clown = shift->SUPER::cloneNode(@_);
739              
740 7 100       22 unless(shift) { # if it’s shallow
741             # Flatten attr nodes, effectively cloning them:
742 3         23 $$clown{$_} = "$$clown{$_}" for grep !/^_/, keys %$clown;
743 3         6 delete $clown->{_HTML_DOM_Element_map};
744             } # otherwise clone takes care of this, so we don’t need to here
745 7         16 $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 361 my $clown = shift->SUPER::clone;
751 201         876 $$clown{$_} = "$$clown{$_}" for grep !/^_/, keys %$clown;
752 201         209 delete $clown->{_HTML_DOM_Element_map};
753 201         522 $clown;
754             }
755              
756             sub trigger_event {
757 1571     1571 1 6161 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   36 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   127 my $targy = $_[0]->target;
772 61         212 for($targy, $targy->descendants) {
773 282         244 eval { $_->form(undef) };
  282         1026  
774             }
775 61         103 return; # give the eval void context
776             },
777 1571 50       5696 ) : (),
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.057';
804             our @ISA = 'HTML::DOM::Element';
805 5     5   465 sub profile { shift->_attr('profile' => @_) }
806              
807             # ------- HTMLLinkElement interface ---------- #
808              
809             package HTML::DOM::Element::Link;
810             our $VERSION = '0.057';
811             our @ISA = 'HTML::DOM::Element';
812 25     25   126 use Scalar::Util 'blessed';
  25         28  
  25         4847  
813             sub disabled {
814 6 100   6   14 if(@_ > 1) {
815 2         4 my $old = $_[0]->{_HTML_DOM_disabled};
816 2         4 $_[0]->{_HTML_DOM_disabled} = $_[1];
817 2         7 return $old;
818             }
819 4         30 else { $_[0]->{_HTML_DOM_disabled};}
820             }
821 15     15   1955 sub charset { shift->_attr('charset' => @_) }
822 43     43   2846 sub href { shift->_attr('href' => @_) }
823 10     10   1583 sub hreflang { shift->_attr( hreflang => @_) }
824 10     10   1205 sub media { shift->_attr('media' => @_) }
825 10     10   1544 sub rel { shift->_attr('rel' => @_) }
826 10     10   1604 sub rev { shift->_attr('rev' => @_) }
827 20     20   3090 sub target { shift->_attr('target' => @_) }
828 40     40   5928 sub type { shift->_attr('type' => @_) }
829              
830             sub sheet {
831 40     40   26756 my $self = shift;
832 25     25   107 no warnings 'uninitialized';
  25         28  
  25         1764  
833 40 100       79 $self->attr('rel') =~
834 25     25   10037 /(?:^|\p{IsSpacePerl})stylesheet(?:\z|\p{IsSpacePerl})/i
  25         164  
  25         292  
835             or return;
836              
837 16         23 my $old = $$self{_HTML_DOM_sheet};
838 16 100       29 @_ and $self->{_HTML_DOM_sheet} = shift;
839 16 100       117 $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   433 for(shift) {
846 29         70 $_->SUPER::setAttribute(@_);
847 29         65 $_->ownerDocument->_populate_sheet_list;
848             }
849             return # nothing;
850 29         35 }
851             sub removeAttribute {
852 1     1   226 for(shift) {
853 1         7 $_->SUPER::removeAttribute(@_);
854 1         3 $_->ownerDocument->_populate_sheet_list
855             }
856             return # nothing;
857 1         2 }
858             sub setAttributeNode {
859 3     3   12 (my $self = shift)->SUPER::setAttributeNode(@_);
860 3         7 $self->ownerDocument->_populate_sheet_list;
861             return # nothing;
862 3         5 }
863             sub removeAttributeNode {
864 1     1   2 my $self = shift;
865 1         7 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   38 my $elem = shift;
874 38 50 33     217 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         104 my($event,%args) = @_;
885 38 100       74 $args{auto_viv} and %args = &{$args{auto_viv}}, @_ = ($event, %args);
  19         42  
886 38 100       126 $args{attr_name} eq 'href' and _reset_style_sheet($elem);
887             }
888 38         307 SUPER'trigger_event $elem @_;
889             }
890              
891             sub _reset_style_sheet {
892 21     21   23 my $elem = shift;
893             return
894 21 100 100     47 unless ($elem->attr('rel')||'')
895             =~ /(?:^|\p{IsSpacePerl})stylesheet(?:\z|\p{IsSpacePerl})/i;
896 7         19 my $doc = $elem->ownerDocument;
897 7 100       19 return unless my $fetcher = $doc->css_url_fetcher;
898 5         11 my $base = $doc->base;
899 5 50       16 my $url = defined $base
900             ? new_abs URI
901             $elem->href, $doc->base
902             : $elem->href;
903 5         12 my ($css_code, %args)
904             = $fetcher->($url);
905 5 100       24 return unless defined $css_code;
906 4         18 require CSS'DOM;
907 4         61 VERSION CSS'DOM 0.03;
908 4   50     17 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         24 encoding_hint => $hint,
928             %args
929             )
930             );
931             }
932              
933             # ------- HTMLTitleElement interface ---------- #
934              
935             package HTML::DOM::Element::Title;
936             our $VERSION = '0.057';
937             our @ISA = 'HTML::DOM::Element';
938             # This is what I call FWP (no lexical vars):
939             sub text {
940 19   66 19   64 ($_[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.057';
952             our @ISA = 'HTML::DOM::Element';
953 5     5   429 sub content { shift->_attr('content' => @_) }
954 5     5   814 sub httpEquiv { shift->_attr('http-equiv' => @_) }
955 45     45   6399 sub name { shift->_attr('name' => @_) }
956 5     5   828 sub scheme { shift->_attr('scheme' => @_) }
957              
958             # ------- HTMLBaseElement interface ---------- #
959              
960             package HTML::DOM::Element::Base;
961             our $VERSION = '0.057';
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.057';
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   442 sub prompt { shift->_attr('prompt' => @_) }
975              
976             # ------- HTMLStyleElement interface ---------- #
977              
978             package HTML::DOM::Element::Style;
979             our $VERSION = '0.057';
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   888 my $self = shift;
987 15   66     54 $self->{_HTML_DOM_sheet} ||= do{
988 4         14 my $first_child = $self->firstChild;
989 4         10 local *@;
990 4         16 require CSS::DOM;
991 4         59 VERSION CSS::DOM .03;
992 4 50       25 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.057';
1000             our @ISA = 'HTML::DOM::Element';
1001 7     7   411 sub aLink { shift->_attr( aLink => @_) }
1002 7     7   843 sub background { shift->_attr( background => @_) }
1003 7     7   804 sub bgColor { shift->_attr('bgcolor' => @_) }
1004 7     7   809 sub link { shift->_attr('link' => @_) }
1005 7     7   780 sub text { shift->_attr('text' => @_) }
1006 7     7   818 sub vLink { shift->_attr('vlink' => @_) }
1007             sub event_handler {
1008 4     4   6 my $self = shift;
1009 4         9 my $target = $self->ownerDocument->event_parent;
1010 4 100       25 $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.057';
1025             our @ISA = 'HTML::DOM::Element';
1026 30 100   30   173 sub compact { shift->_attr( compact => @_ ? $_[0]?'compact': undef : () ) }
    100          
1027 5     5   463 sub type { lc shift->_attr( type => @_) }
1028              
1029             # ------- HTMLOListElement interface ---------- #
1030              
1031             package HTML::DOM::Element::OL;
1032             our $VERSION = '0.057';
1033             our @ISA = 'HTML::DOM::Element';
1034 5     5   468 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.057';
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.057';
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.057';
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.057';
1063             our @ISA = 'HTML::DOM::Element';
1064             *type =\& HTML::DOM::Element::Link::type;
1065 10     10   1596 sub value { shift->_attr( value => @_) }
1066              
1067             # ------- HTMLDivElement interface ---------- #
1068              
1069             package HTML::DOM::Element::Div;
1070             our $VERSION = '0.057';
1071             our @ISA = 'HTML::DOM::Element';
1072 40     40   4146 sub align { lc shift->_attr( align => @_) }
1073              
1074             # ------- HTMLParagraphElement interface ---------- #
1075              
1076             package HTML::DOM::Element::P;
1077             our $VERSION = '0.057';
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.057';
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.057';
1092             our @ISA = 'HTML::DOM::Element';
1093 10     10   893 sub cite { shift->_attr( cite => @_) }
1094              
1095             # ------- HTMLPreElement interface ---------- #
1096              
1097             package HTML::DOM::Element::Pre;
1098             our $VERSION = '0.057';
1099             our @ISA = 'HTML::DOM::Element';
1100 30     30   4717 sub width { shift->_attr( width => @_) }
1101              
1102             # ------- HTMLBRElement interface ---------- #
1103              
1104             package HTML::DOM::Element::Br;
1105             our $VERSION = '0.057';
1106             our @ISA = 'HTML::DOM::Element';
1107 5     5   515 sub clear { lc shift->_attr( clear => @_) }
1108              
1109             # ------- HTMLBaseFontElement interface ---------- #
1110              
1111             package HTML::DOM::Element::BaseFont;
1112             our $VERSION = '0.057';
1113             our @ISA = 'HTML::DOM::Element';
1114 10     10   823 sub color { shift->_attr( color => @_) }
1115 10     10   1689 sub face { shift->_attr( face => @_) }
1116 15     15   2477 sub size { shift->_attr( size => @_) }
1117              
1118             # ------- HTMLBaseFontElement interface ---------- #
1119              
1120             package HTML::DOM::Element::Font;
1121             our $VERSION = '0.057';
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.057';
1131             our @ISA = 'HTML::DOM::Element';
1132             *align =\& HTML::DOM::Element::Div::align;
1133 6 100   6   39 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.057';
1142             our @ISA = 'HTML::DOM::Element';
1143             *cite =\& HTML::DOM::Element::Quote::cite;
1144 5     5   1096 sub dateTime { shift->_attr( datetime => @_) }
1145              
1146             # ------- HTMLAnchorElement interface ---------- #
1147              
1148             package HTML::DOM::Element::A;
1149             our $VERSION = '0.057';
1150             our @ISA = 'HTML::DOM::Element';
1151 10     10   820 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   1605 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   317 my ($a,$evnt) = (shift,shift);
1169 119         360 $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   93 my $elem = shift;
1181 128         262 my $uri = new URI $elem->attr('href');
1182 128 100       10224 if(!$uri->scheme) {
1183 90         766 my $base = $elem->ownerDocument->base;
1184 90 100       520 return unless $base;
1185 6         13 $uri = $uri->abs($base);
1186 6 50       1165 return unless $uri->scheme;
1187             }
1188             $uri
1189 44         541 }
1190              
1191             sub hash {
1192 18     18   42 my $elem = shift;
1193 18 100       26 defined(my $uri = _get_abs_href $elem) or return '';
1194 6         7 my $old;
1195 6 50       13 if(defined wantarray) {
1196 6         18 $old = $uri->fragment;
1197 6 100       44 $old = "#$old" if defined $old;
1198             }
1199 6 100       10 if (@_){
1200 2         7 shift() =~ /#?(.*)/s;
1201 2         7 $uri->fragment($1);
1202 2         47 $elem->_attr(href => $uri);
1203             }
1204 6 100       39 $old||''
1205             }
1206              
1207             sub host {
1208 18     18   1155 my $elem = shift;
1209 18 100       28 defined(my $uri = _get_abs_href $elem) or return '';
1210 6 50       28 my $old = $uri->host_port if defined wantarray;
1211 6 100       132 if (@_) {
1212 2         7 $uri->port("");
1213 2         79 $uri->host_port(shift);
1214 2         139 $elem->attr(href => $uri);
1215             }
1216             $old
1217 6         21 }
1218              
1219             sub hostname {
1220 18     18   1123 my $elem = shift;
1221 18 100       28 defined(my $uri = _get_abs_href $elem) or return '';
1222 6 50       24 my $old = $uri->host if defined wantarray;
1223 6 100       124 if (@_) {
1224 2         6 $uri->host(shift);
1225 2         102 $elem->attr(href => $uri);
1226             }
1227             $old
1228 6         23 }
1229              
1230             sub pathname {
1231 18     18   1138 my $elem = shift;
1232 18 100       25 defined(my $uri = _get_abs_href $elem) or return '';
1233 6 50       30 my $old = $uri->path if defined wantarray;
1234 6 100       55 if (@_) {
1235 2         5 $uri->path(shift);
1236 2         35 $elem->attr(href => $uri);
1237             }
1238             $old
1239 6         24 }
1240              
1241             sub port {
1242 18     18   1239 my $elem = shift;
1243 18 100       30 defined(my $uri = _get_abs_href $elem) or return '';
1244 6 50       26 my $old = $uri->port if defined wantarray;
1245 6 100       115 if (@_) {
1246 2         6 $uri->port(shift);
1247 2         72 $elem->attr(href => $uri);
1248             }
1249             $old
1250 6         20 }
1251              
1252             sub protocol {
1253 18     18   1096 my $elem = shift;
1254 18 100       27 defined(my $uri = _get_abs_href $elem) or return '';
1255 6 50       20 my $old = $uri->scheme . ':' if defined wantarray;
1256 6 100       59 if (@_) {
1257 2         6 shift() =~ /(.*):?/s;
1258 2         9 $uri->scheme("$1");
1259 2         1610 $elem->attr(href => $uri);
1260             }
1261             $old
1262              
1263 6         23 }
1264              
1265             sub search {
1266 20     20   1123 my $elem = shift;
1267 20 100       28 defined(my $uri = _get_abs_href $elem) or return '';
1268 8         9 my $old;
1269 8 100       16 if(defined wantarray) {
1270 6         24 my $q = $uri->query;
1271 6 100       56 $old = defined $q ? "?$q" : "";
1272             }
1273 8 100       18 if (@_){
1274 4         9 shift() =~ /(\??)(.*)/s;
1275 4 50 33     22 $uri->query(
1276             $1||length$2 ? "$2" : undef
1277             );
1278 4         76 $elem->attr(href => $uri);
1279             }
1280             $old
1281 8         23 }
1282              
1283              
1284             # ------- HTMLImageElement interface ---------- #
1285              
1286             package HTML::DOM::Element::Img;
1287             our $VERSION = '0.057';
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   2330 sub alt { shift->_attr( alt => @_) }
1293 5     5   776 sub border { shift->_attr( border => @_) }
1294 20     20   3379 sub height { shift->_attr( height => @_) }
1295 15     15   2354 sub hspace { shift->_attr( hspace => @_) }
1296 6 100   6   406 sub isMap { shift->_attr( ismap => @_ ? $_[0] ? 'ismap' : undef : () ) }
    100          
1297 5     5   794 sub longDesc { shift->_attr( longdesc => @_) }
1298 22     22   3567 sub src { shift->_attr( src => @_) }
1299 10     10   1600 sub useMap { shift->_attr( usemap => @_) }
1300 15     15   2358 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.057';
1307             our @ISA = 'HTML::DOM::Element';
1308             *form=\&HTML::DOM::Element::Select::form;
1309 10     10   1220 sub code { shift->_attr( code => @_) }
1310             * align = \&HTML::DOM::Element::Div::align ;
1311 10     10   1602 sub archive { shift->_attr( archive => @_) }
1312 5     5   776 sub border { shift->_attr( border => @_) }
1313 10     10   1552 sub codeBase { shift->_attr( codebase => @_) }
1314 5     5   773 sub codeType { shift->_attr( codetype => @_) }
1315 5     5   815 sub data { shift->_attr( data => @_) }
1316 6 100   6   36 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   779 sub standby { shift->_attr( standby => @_) }
1321 15     15   2384 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.057';
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   783 sub valueType{lc shift->_attr(valuetype=>@_)}
1337              
1338             # ------- HTMLAppletElement interface ---------- #
1339              
1340             package HTML::DOM::Element::Applet;
1341             our $VERSION = '0.057';
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   774 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.057';
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   9 sub { grep tag $_ eq 'area', $self->descendants }
1369 1         15 ));
1370 1         3 $self->ownerDocument-> _register_magic_node_list($list);
1371 1         3 $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.057';
1380             our @ISA = 'HTML::DOM::Element';
1381             * alt = \ & HTML::DOM::Element::Img::alt ;
1382 10     10   1599 sub coords { shift -> _attr ( coords => @_ ) }
1383             * href = \ & HTML::DOM::Element::Link::href ;
1384 5 100   5   23 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   409547 no strict 'refs';
  25         37  
  25         13531  
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.057';
1398             our @ISA = 'HTML::DOM::Element';
1399             * text = \ &HTML::DOM::Element::Title::text ;
1400 5     5   837 sub htmlFor { shift -> _attr ( for => @_ ) }
1401 5     5   405 sub event { shift -> _attr ( event => @_ ) }
1402             * charset = \ &HTML::DOM::Element::Link::charset ;
1403 6 100   6   38 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.057';
1411             our @ISA = 'HTML::DOM::Element';
1412 5     5   778 sub rows { shift -> _attr ( rows => @_ ) }
1413 5     5   437 sub cols { shift -> _attr ( cols => @_ ) }
1414              
1415             # ------- HTMLFrameElement interface ---------- #
1416              
1417             package HTML::DOM::Element::Frame;
1418             our $VERSION = '0.057';
1419             our @ISA = 'HTML::DOM::Element';
1420 12     12   1387 sub frameBorder { lc shift -> _attr ( frameBorder => @_ ) }
1421 10     10   1744 sub longDesc { shift -> _attr ( longdesc => @_ ) }
1422 10     10   1744 sub marginHeight{ shift -> _attr ( marginheight => @_ ) }
1423 10     10   1838 sub marginWidth { shift -> _attr ( marginwidth => @_ ) }
1424             * name = \ &HTML::DOM::Element::Meta::name ;
1425 6 100   6   36 sub noResize { shift->_attr(noresize => @_ ? $_[0]?'noresize':undef : ()) }
    100          
1426 10     10   1968 sub scrolling { lc shift -> _attr ( scrolling => @_ ) }
1427             * src = \ &HTML::DOM::Element::Img::src ;
1428 6   100 6   28 sub contentDocument{ (shift->{_HTML_DOM_view} || return)->document }
1429             sub contentWindow {
1430 8     8   21 my $old = (my $self = shift)->{_HTML_DOM_view};
1431 8 100       22 @_ and $self->{_HTML_DOM_view} = shift;
1432 8 100       32 defined $old ? $old : ()
1433             };
1434              
1435             # ------- HTMLIFrameElement interface ---------- #
1436              
1437             package HTML::DOM::Element::IFrame;
1438             our $VERSION = '0.057';
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