File Coverage

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


line stmt bran cond sub pod time code
1             package HTML::DOM::Element;
2              
3 25     25   505 use strict;
  25         48  
  25         567  
4 25     25   94 use warnings;
  25         33  
  25         616  
5              
6 25         1333 use HTML::DOM::Exception qw 'INVALID_CHARACTER_ERR
7 25     25   8869 INUSE_ATTRIBUTE_ERR NOT_FOUND_ERR SYNTAX_ERR';
  25         61  
8 25     25   9148 use HTML::DOM::Node 'ELEMENT_NODE';
  25         71  
  25         1537  
9 25     25   142 use HTML'Entities;
  25         53  
  25         1162  
10 25     25   135 use Scalar::Util qw'refaddr blessed weaken';
  25         37  
  25         20210  
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.058';
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 1403 100   1403 0 4995 $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.058
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 1409     1409 0 2112 my $tagname = $_[1];
141              
142             # Hack to make parsing comments work
143 1409 100       2716 $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 1402         1573 my $ret;
151 1402         1731 eval {
152 1402         3379 $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 1402 100       3953 and do { require HTML'DOM }; # paranoia
  162         755  
158             };
159 1402 50       3363 $@ 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 34720 uc $_[0]->tag;
191             }
192              
193 2718     2718 1 12166 sub id { shift->_attr(id => @_) }
194              
195 5     5 1 1476 sub title { shift->_attr(title => @_) }
196 5     5 1 1385 sub lang { shift->_attr(lang => @_) }
197 5     5 1 1264 sub dir { lc shift->_attr(dir => @_) }
198 5     5 1 1349 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 2913 my $self = shift;
209 38   66     84 ($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 550     550 1 904 my $old = (my $self = shift)->{_HTML_DOM_offset};
233 550 100       1191 @_ and $self->{_HTML_DOM_offset} = shift;
234 550         997 $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 5023     5023 1 12342 my $ret = $_[0]->attr($_[1]);
322 5023 100       9150 defined $ret ? "$ret" : do{
323 1170         2094 my $tag = $_[0]->tag;
324 1170 50       1890 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 1170 100 100     4648 and exists $_[0]->{_HTML_DOM_version};
      100        
      100        
      100        
329             $_[1] eq 'version'
330             ? $_[0]->{_HTML_DOM_version}
331 199 100       571 : $attr_defaults{$tag}{$_[1]}
332             };
333             }
334              
335             sub setAttribute {
336             # ~~~ INVALID_CHARACTER_ERR
337 802     802 1 2642 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         1779 my $attr = $self->attr($_[0]);
342 802 100 100     3090 if(defined blessed $attr && $attr->isa('HTML::DOM::Attr')){
343 216         552 $attr->value($_[1]);
344             }else{
345 586         971 my($name,$val) = @_;
346 586         859 my $str_val = "$val";
347 586         1010 my $old = $self->attr($name,$str_val);
348 25     25   164 no warnings 'uninitialized';
  25         53  
  25         28701  
349             $old ne $str_val
350             and $self->trigger_event('DOMAttrModified',
351             auto_viv => sub {
352 249     249   751 require HTML'DOM'Event'Mutation;
353 249 100       955 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       3192 );
363             }
364              
365             # possible event handler
366 802 100 100     5512 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       16 defined $eavesdropper and $self-> event_handler(
372             $name, $eavesdropper
373             );
374             }
375              
376             return # nothing;
377 802         1173 }
378              
379             # This is just like attr, except that it triggers events.
380             sub _attr {
381 5170     5170   7768 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 5170 100       10369 my $old = $self->getAttribute($name) if defined wantarray;
384             @_
385 5170 100       9940 and defined $_[0]
    100          
386             ? $self->setAttribute($name, shift)
387             : $self->removeAttribute($name);
388 5170         12616 $old;
389             }
390              
391              
392             sub removeAttribute {
393 47     47 1 2244 my $old = (my $self = shift)->attr(my $name = shift);
394 47         118 $self->attr($name => undef);
395 47 100 66     196 if(defined blessed $old and $old->isa('HTML::DOM::Attr')) {
396             # So the attr node can be reused:
397 7         25 $old->_element(undef);
398              
399 7         25 $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       72 return unless defined $old;
409             $self->trigger_event('DOMAttrModified',
410             auto_viv => sub {
411 2     2   13 (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         185 );
422             }
423              
424             return # nothing;
425 46         353 }
426              
427             sub getAttributeNode {
428 387     387 1 1530 my $elem = shift;
429 387         585 my $name = lc shift;
430              
431 387         862 my $attr = $elem->attr($name);
432 387 100       774 unless(defined $attr
433             ) { # check to see whether it has a default value
434 45         116 my $tag = $elem->tag;
435 45   100     163 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 100     243 and exists $elem->{_HTML_DOM_version};
      66        
      100        
      100        
440 21         57 my $attr = HTML::DOM::Attr->new($name);
441 21         58 $attr->_set_ownerDocument($elem->ownerDocument);
442 21         53 $attr->_element($elem);
443             $attr->value($name eq 'version'
444             ? $elem->{_HTML_DOM_version}
445 21 100       75 : $attr_defaults{$tag}{$name});
446 21         54 $attr;
447             };
448             }
449              
450 342 100       601 if(!ref $attr) {
451 304         917 $elem->attr($name, my $new_attr =
452             HTML::DOM::Attr->new($name, $attr));
453 304         632 $new_attr->_set_ownerDocument($elem->ownerDocument);
454 304         729 $new_attr->_element($elem);
455 304         1258 return $new_attr;
456             }
457 38         136 $attr;
458             }
459              
460             sub setAttributeNode {
461 19     19 1 568 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         59 $_[1]->_set_ownerDocument($doc);
466              
467 19         24 my $e;
468 19 100 66     65 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         69 my $old = $_[0]->attr(my $name = $_[1]->nodeName, $_[1]);
473 18         52 $_[1]->_element($_[0]);
474              
475             # possible event handler
476 18 50 33     67 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         27 my $ret;
493 18 100       36 if(defined $old) {
494 10 100 66     91 if(defined blessed $old and $old->isa("HTML::DOM::Attr")) {
495 9         31 $old->_element(undef);
496 9         15 $ret = $old;
497             } else {
498 1         3 $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       55 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         132 $_[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       123 return $ret if defined $ret;
522              
523             return # nothing;
524 8         25 }
525              
526             sub removeAttributeNode {
527 11     11 1 821 my($elem,$attr) = @_;
528              
529 11         31 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     80 : 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         18 delete $elem->{_HTML_DOM_unspecified}{$name};
539 8         22 $attr->_element(undef);
540              
541 8         28 $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         77 return $attr
551             }
552              
553              
554             sub getElementsByTagName {
555 10     10 1 31 my($self,$tagname) = @_;
556 10 100       22 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   6 ? sub { grep tag $_ !~ /^~/, $self->descendants }
568             : (
569             $tagname = lc $tagname,
570             sub {
571 9     9   24 grep tag $_ eq $tagname, $self->descendants
572             }
573 6 100       52 )[1]
574             );
575 6         14 $self->ownerDocument-> _register_magic_node_list($list);
576 6         45 $list;
577             }
578             }
579              
580             sub getElementsByClassName {
581 9     9 1 474 splice @_, 2; # Remove extra elements
582 9         50 goto &_getElementsByClassName;
583             }
584             sub _getElementsByClassName {
585 18     18   39 my($self,$names,$is_doc) = @_;
586              
587 18         35 my $cref;
588 18 50       36 if(defined $names) {
589 25     25   177 no warnings 'uninitialized';
  25         51  
  25         9630  
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         143 $names
594             = join ".*", map " $_ ", sort split /[ \t\n\f\r]+/, $names;
595             $cref = sub {
596 177     177   299 (" ".join(" ", sort split /[ \t\n\f\r]+/, $_[0]->attr('class'))
597             ." ")
598             =~ $names
599 18         103 };
600             }
601 0     0   0 else { $cref = sub {} }
602              
603 18 100       47 if (wantarray) {
604 14         40 return $self->look_down($cref);
605             }
606             else {
607             my $list = HTML::DOM::NodeList::Magic->new(
608 4     4   13 sub { $self->look_down($cref); }
609 4         18 );
610 4 100       17 ($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 876 my ($self,$attrname)= (shift, lc shift);
618 497         590 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     1037 }
      66        
      100        
      100        
625              
626 21     21   46 sub _attr_specified { defined shift->attr(shift) }
627              
628 2     2 1 8 sub click { shift->trigger_event('click') }
629              
630             # used by innerHTML and insertAdjacentHTML
631             sub _html_fragment_parser {
632 31     31   137 require HTML'DOM; # paranoia
633 31         102 (my $tb = new HTML::DOM::Element::HTML:: no_magic_forms=>1)
634             ->_set_ownerDocument(shift->ownerDocument);
635 31         219 $tb->parse(shift);
636 31         94 $tb->eof();
637 31         74 $_->implicit(1) for $tb, $tb->content_list; # more paranoia
638 31         57 $tb;
639             }
640              
641 25         111 use constant _html_element_adds_newline =>
642 25     25   195 new HTML::DOM::_Element 'foo' =>->as_HTML =~ /\n/;
  25         58  
643              
644             sub innerHTML {
645 44     44 0 1123 my $self = shift;
646 44 50       117 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       225 if(@_) {
655 26         65 my $tb = _html_fragment_parser($self,shift);
656 26         101 $self->delete_content;
657 26         101 $self->push_content($tb->guts);
658 26   50     32 {($self->ownerDocument||last)->_modified}
  26         69  
659             }
660 44         201 $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 9 my $elem = shift;
674            
675             die new HTML::DOM::Exception:: SYNTAX_ERR,
676             "$_[0]: invalid first argument to insertAdjacentHTML"
677 5 50       18 unless exists $mm{ my $where = lc $_[0] };
678            
679 5         9 my $tb = _html_fragment_parser($elem,$_[1]);
680 5         13 $elem->${\$mm{$where}}(guts $tb);
  5         28  
681              
682 5   50     7 {($elem->ownerDocument||last)->_modified}
  5         10  
683              
684             ()
685 5         70 }
686            
687             sub insertAdjacentElement {
688 5     5 0 6 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         8 $elem->${\$mm{$where}}($_[1]);
  5         19  
695              
696 5   50     6 {($elem->ownerDocument||last)->_modified}
  5         9  
697              
698             ()
699 5         10 }
700             }
701              
702             sub innerText {
703 3     3 0 9 my $self = shift;
704 3 50       17 my $old = $self->as_text
705             if defined wantarray;
706 3 100       7 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         5 $self->removeChild($_) for $self->childNodes;
711 1         8 $self->appendChild(
712             $self->ownerDocument->createTextNode(shift)
713             );
714             }
715 3         12 $old;
716             }
717              
718             sub starttag {
719 147     147 0 178 my $self = shift;
720 147         337 my $tag = $self->SUPER::starttag(@ _);
721 147         268 $tag =~ s/ \/>\z/>/;
722 147         321 $tag
723             }
724              
725             # ------- OVERRIDDEN NODE METHDOS ---------- #
726              
727             *nodeName = \&tagName;
728             *nodeType = \& ELEMENT_NODE;
729              
730             sub attributes {
731 30     30 1 450 my $self = shift;
732             $self->{_HTML_DOM_Element_map} ||=
733 30   66     117 HTML::DOM::NamedNodeMap->new($self);
734             }
735              
736              
737             sub cloneNode { # override of HTML::DOM::Node’s method
738 7     7 1 63 my $clown = shift->SUPER::cloneNode(@_);
739              
740 7 100       42 unless(shift) { # if it’s shallow
741             # Flatten attr nodes, effectively cloning them:
742 3         36 $$clown{$_} = "$$clown{$_}" for grep !/^_/, keys %$clown;
743 3         7 delete $clown->{_HTML_DOM_Element_map};
744             } # otherwise clone takes care of this, so we don’t need to here
745 7         24 $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 422 my $clown = shift->SUPER::clone;
751 201         937 $$clown{$_} = "$$clown{$_}" for grep !/^_/, keys %$clown;
752 201         304 delete $clown->{_HTML_DOM_Element_map};
753 201         524 $clown;
754             }
755              
756             sub trigger_event {
757 1574     1574 1 8656 my ($a,$evnt) = (shift,shift);
758             $a->SUPER::trigger_event(
759             $evnt,
760             click_default =>sub {
761             $_[0]->target->trigger_event(DOMActivate =>
762 17     17   36 detail => eval{$_[0]->detail}
  17         38  
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         241 for($targy, $targy->descendants) {
773 282         385 eval { $_->form(undef) };
  282         1014  
774             }
775 61         152 return; # give the eval void context
776             },
777 1574 50       5965 ) : (),
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.058';
804             our @ISA = 'HTML::DOM::Element';
805 5     5   506 sub profile { shift->_attr('profile' => @_) }
806              
807             # ------- HTMLLinkElement interface ---------- #
808              
809             package HTML::DOM::Element::Link;
810             our $VERSION = '0.058';
811             our @ISA = 'HTML::DOM::Element';
812 25     25   163 use Scalar::Util 'blessed';
  25         39  
  25         6232  
813             sub disabled {
814 6 100   6   15 if(@_ > 1) {
815 2         4 my $old = $_[0]->{_HTML_DOM_disabled};
816 2         5 $_[0]->{_HTML_DOM_disabled} = $_[1];
817 2         9 return $old;
818             }
819 4         15 else { $_[0]->{_HTML_DOM_disabled};}
820             }
821 15     15   2163 sub charset { shift->_attr('charset' => @_) }
822 43     43   3161 sub href { shift->_attr('href' => @_) }
823 10     10   1724 sub hreflang { shift->_attr( hreflang => @_) }
824 10     10   1708 sub media { shift->_attr('media' => @_) }
825 10     10   1745 sub rel { shift->_attr('rel' => @_) }
826 10     10   1755 sub rev { shift->_attr('rev' => @_) }
827 20     20   3457 sub target { shift->_attr('target' => @_) }
828 40     40   6650 sub type { shift->_attr('type' => @_) }
829              
830             sub sheet {
831 40     40   33776 my $self = shift;
832 25     25   153 no warnings 'uninitialized';
  25         37  
  25         1737  
833 40 100       85 $self->attr('rel') =~
834 25     25   9277 /(?:^|\p{IsSpacePerl})stylesheet(?:\z|\p{IsSpacePerl})/i
  25         226  
  25         310  
835             or return;
836              
837 16         30 my $old = $$self{_HTML_DOM_sheet};
838 16 100       30 @_ and $self->{_HTML_DOM_sheet} = shift;
839 16 100       76 $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   465 for(shift) {
846 29         80 $_->SUPER::setAttribute(@_);
847 29         67 $_->ownerDocument->_populate_sheet_list;
848             }
849             return # nothing;
850 29         52 }
851             sub removeAttribute {
852 1     1   303 for(shift) {
853 1         8 $_->SUPER::removeAttribute(@_);
854 1         4 $_->ownerDocument->_populate_sheet_list
855             }
856             return # nothing;
857 1         3 }
858             sub setAttributeNode {
859 3     3   14 (my $self = shift)->SUPER::setAttributeNode(@_);
860 3         7 $self->ownerDocument->_populate_sheet_list;
861             return # nothing;
862 3         7 }
863             sub removeAttributeNode {
864 1     1   2 my $self = shift;
865 1         7 my $attr = $self->SUPER::removeAttributeNode(@_);
866 1         4 $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   58 my $elem = shift;
874 38 50 33     224 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         116 my($event,%args) = @_;
885 38 100       78 $args{auto_viv} and %args = &{$args{auto_viv}}, @_ = ($event, %args);
  19         36  
886 38 100       118 $args{attr_name} eq 'href' and _reset_style_sheet($elem);
887             }
888 38         91 SUPER'trigger_event $elem @_;
889             }
890              
891             sub _reset_style_sheet {
892 21     21   32 my $elem = shift;
893             return
894 21 100 100     48 unless ($elem->attr('rel')||'')
895             =~ /(?:^|\p{IsSpacePerl})stylesheet(?:\z|\p{IsSpacePerl})/i;
896 7         31 my $doc = $elem->ownerDocument;
897 7 100       19 return unless my $fetcher = $doc->css_url_fetcher;
898 5         12 my $base = $doc->base;
899 5 50       18 my $url = defined $base
900             ? new_abs URI
901             $elem->href, $doc->base
902             : $elem->href;
903 5         16 my ($css_code, %args)
904             = $fetcher->($url);
905 5 100       22 return unless defined $css_code;
906 4         17 require CSS'DOM;
907 4         45 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         26 encoding_hint => $hint,
928             %args
929             )
930             );
931             }
932              
933             # ------- HTMLTitleElement interface ---------- #
934              
935             package HTML::DOM::Element::Title;
936             our $VERSION = '0.058';
937             our @ISA = 'HTML::DOM::Element';
938             # This is what I call FWP (no lexical vars):
939             sub text {
940 19   66 19   71 ($_[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.058';
952             our @ISA = 'HTML::DOM::Element';
953 5     5   457 sub content { shift->_attr('content' => @_) }
954 5     5   876 sub httpEquiv { shift->_attr('http-equiv' => @_) }
955 45     45   6478 sub name { shift->_attr('name' => @_) }
956 5     5   868 sub scheme { shift->_attr('scheme' => @_) }
957              
958             # ------- HTMLBaseElement interface ---------- #
959              
960             package HTML::DOM::Element::Base;
961             our $VERSION = '0.058';
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.058';
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   462 sub prompt { shift->_attr('prompt' => @_) }
975              
976             # ------- HTMLStyleElement interface ---------- #
977              
978             package HTML::DOM::Element::Style;
979             our $VERSION = '0.058';
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   1067 my $self = shift;
987 15   66     54 $self->{_HTML_DOM_sheet} ||= do{
988 4         16 my $first_child = $self->firstChild;
989 4         9 local *@;
990 4         17 require CSS::DOM;
991 4         43 VERSION CSS::DOM .03;
992 4 50       24 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.058';
1000             our @ISA = 'HTML::DOM::Element';
1001 7     7   481 sub aLink { shift->_attr( aLink => @_) }
1002 7     7   874 sub background { shift->_attr( background => @_) }
1003 7     7   850 sub bgColor { shift->_attr('bgcolor' => @_) }
1004 7     7   896 sub link { shift->_attr('link' => @_) }
1005 7     7   852 sub text { shift->_attr('text' => @_) }
1006 7     7   885 sub vLink { shift->_attr('vlink' => @_) }
1007             sub event_handler {
1008 4     4   7 my $self = shift;
1009 4         10 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.058';
1025             our @ISA = 'HTML::DOM::Element';
1026 30 100   30   183 sub compact { shift->_attr( compact => @_ ? $_[0]?'compact': undef : () ) }
    100          
1027 5     5   457 sub type { lc shift->_attr( type => @_) }
1028              
1029             # ------- HTMLOListElement interface ---------- #
1030              
1031             package HTML::DOM::Element::OL;
1032             our $VERSION = '0.058';
1033             our @ISA = 'HTML::DOM::Element';
1034 5     5   442 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.058';
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.058';
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.058';
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.058';
1063             our @ISA = 'HTML::DOM::Element';
1064             *type =\& HTML::DOM::Element::Link::type;
1065 10     10   1721 sub value { shift->_attr( value => @_) }
1066              
1067             # ------- HTMLDivElement interface ---------- #
1068              
1069             package HTML::DOM::Element::Div;
1070             our $VERSION = '0.058';
1071             our @ISA = 'HTML::DOM::Element';
1072 40     40   4531 sub align { lc shift->_attr( align => @_) }
1073              
1074             # ------- HTMLParagraphElement interface ---------- #
1075              
1076             package HTML::DOM::Element::P;
1077             our $VERSION = '0.058';
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.058';
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.058';
1092             our @ISA = 'HTML::DOM::Element';
1093 10     10   1149 sub cite { shift->_attr( cite => @_) }
1094              
1095             # ------- HTMLPreElement interface ---------- #
1096              
1097             package HTML::DOM::Element::Pre;
1098             our $VERSION = '0.058';
1099             our @ISA = 'HTML::DOM::Element';
1100 30     30   4816 sub width { shift->_attr( width => @_) }
1101              
1102             # ------- HTMLBRElement interface ---------- #
1103              
1104             package HTML::DOM::Element::Br;
1105             our $VERSION = '0.058';
1106             our @ISA = 'HTML::DOM::Element';
1107 5     5   441 sub clear { lc shift->_attr( clear => @_) }
1108              
1109             # ------- HTMLBaseFontElement interface ---------- #
1110              
1111             package HTML::DOM::Element::BaseFont;
1112             our $VERSION = '0.058';
1113             our @ISA = 'HTML::DOM::Element';
1114 10     10   884 sub color { shift->_attr( color => @_) }
1115 10     10   1699 sub face { shift->_attr( face => @_) }
1116 15     15   2523 sub size { shift->_attr( size => @_) }
1117              
1118             # ------- HTMLBaseFontElement interface ---------- #
1119              
1120             package HTML::DOM::Element::Font;
1121             our $VERSION = '0.058';
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.058';
1131             our @ISA = 'HTML::DOM::Element';
1132             *align =\& HTML::DOM::Element::Div::align;
1133 6 100   6   40 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.058';
1142             our @ISA = 'HTML::DOM::Element';
1143             *cite =\& HTML::DOM::Element::Quote::cite;
1144 5     5   1328 sub dateTime { shift->_attr( datetime => @_) }
1145              
1146             # ------- HTMLAnchorElement interface ---------- #
1147              
1148             package HTML::DOM::Element::A;
1149             our $VERSION = '0.058';
1150             our @ISA = 'HTML::DOM::Element';
1151 10     10   893 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   1755 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   4 sub blur { shift->trigger_event('blur') }
1165 1     1   5 sub focus { shift->trigger_event('focus') }
1166              
1167             sub trigger_event {
1168 119     119   236 my ($a,$evnt) = (shift,shift);
1169 119         282 $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   161 my $elem = shift;
1181 128         288 my $uri = new URI $elem->attr('href');
1182 128 100       12191 if(!$uri->scheme) {
1183 90         901 my $base = $elem->ownerDocument->base;
1184 90 100       480 return unless $base;
1185 6         17 $uri = $uri->abs($base);
1186 6 50       1482 return unless $uri->scheme;
1187             }
1188             $uri
1189 44         635 }
1190              
1191             sub hash {
1192 18     18   52 my $elem = shift;
1193 18 100       33 defined(my $uri = _get_abs_href $elem) or return '';
1194 6         10 my $old;
1195 6 50       11 if(defined wantarray) {
1196 6         20 $old = $uri->fragment;
1197 6 100       45 $old = "#$old" if defined $old;
1198             }
1199 6 100       14 if (@_){
1200 2         8 shift() =~ /#?(.*)/s;
1201 2         7 $uri->fragment($1);
1202 2         49 $elem->_attr(href => $uri);
1203             }
1204 6 100       42 $old||''
1205             }
1206              
1207             sub host {
1208 18     18   1778 my $elem = shift;
1209 18 100       29 defined(my $uri = _get_abs_href $elem) or return '';
1210 6 50       23 my $old = $uri->host_port if defined wantarray;
1211 6 100       157 if (@_) {
1212 2         6 $uri->port("");
1213 2         99 $uri->host_port(shift);
1214 2         178 $elem->attr(href => $uri);
1215             }
1216             $old
1217 6         25 }
1218              
1219             sub hostname {
1220 18     18   2060 my $elem = shift;
1221 18 100       33 defined(my $uri = _get_abs_href $elem) or return '';
1222 6 50       23 my $old = $uri->host if defined wantarray;
1223 6 100       165 if (@_) {
1224 2         7 $uri->host(shift);
1225 2         131 $elem->attr(href => $uri);
1226             }
1227             $old
1228 6         22 }
1229              
1230             sub pathname {
1231 18     18   1753 my $elem = shift;
1232 18 100       32 defined(my $uri = _get_abs_href $elem) or return '';
1233 6 50       26 my $old = $uri->path if defined wantarray;
1234 6 100       59 if (@_) {
1235 2         6 $uri->path(shift);
1236 2         48 $elem->attr(href => $uri);
1237             }
1238             $old
1239 6         25 }
1240              
1241             sub port {
1242 18     18   1722 my $elem = shift;
1243 18 100       35 defined(my $uri = _get_abs_href $elem) or return '';
1244 6 50       24 my $old = $uri->port if defined wantarray;
1245 6 100       131 if (@_) {
1246 2         7 $uri->port(shift);
1247 2         123 $elem->attr(href => $uri);
1248             }
1249             $old
1250 6         24 }
1251              
1252             sub protocol {
1253 18     18   1719 my $elem = shift;
1254 18 100       33 defined(my $uri = _get_abs_href $elem) or return '';
1255 6 50       18 my $old = $uri->scheme . ':' if defined wantarray;
1256 6 100       68 if (@_) {
1257 2         8 shift() =~ /(.*):?/s;
1258 2         9 $uri->scheme("$1");
1259 2         1907 $elem->attr(href => $uri);
1260             }
1261             $old
1262              
1263 6         24 }
1264              
1265             sub search {
1266 20     20   1695 my $elem = shift;
1267 20 100       37 defined(my $uri = _get_abs_href $elem) or return '';
1268 8         10 my $old;
1269 8 100       27 if(defined wantarray) {
1270 6         25 my $q = $uri->query;
1271 6 100       68 $old = defined $q ? "?$q" : "";
1272             }
1273 8 100       16 if (@_){
1274 4         11 shift() =~ /(\??)(.*)/s;
1275 4 50 33     24 $uri->query(
1276             $1||length$2 ? "$2" : undef
1277             );
1278 4         89 $elem->attr(href => $uri);
1279             }
1280             $old
1281 8         28 }
1282              
1283              
1284             # ------- HTMLImageElement interface ---------- #
1285              
1286             package HTML::DOM::Element::Img;
1287             our $VERSION = '0.058';
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   2638 sub alt { shift->_attr( alt => @_) }
1293 5     5   918 sub border { shift->_attr( border => @_) }
1294 20     20   3471 sub height { shift->_attr( height => @_) }
1295 15     15   2687 sub hspace { shift->_attr( hspace => @_) }
1296 6 100   6   459 sub isMap { shift->_attr( ismap => @_ ? $_[0] ? 'ismap' : undef : () ) }
    100          
1297 5     5   883 sub longDesc { shift->_attr( longdesc => @_) }
1298 22     22   3466 sub src { shift->_attr( src => @_) }
1299 10     10   1812 sub useMap { shift->_attr( usemap => @_) }
1300 15     15   2631 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.058';
1307             our @ISA = 'HTML::DOM::Element';
1308             *form=\&HTML::DOM::Element::Select::form;
1309 10     10   1376 sub code { shift->_attr( code => @_) }
1310             * align = \&HTML::DOM::Element::Div::align ;
1311 10     10   1809 sub archive { shift->_attr( archive => @_) }
1312 5     5   831 sub border { shift->_attr( border => @_) }
1313 10     10   1780 sub codeBase { shift->_attr( codebase => @_) }
1314 5     5   818 sub codeType { shift->_attr( codetype => @_) }
1315 5     5   894 sub data { shift->_attr( data => @_) }
1316 6 100   6   39 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   842 sub standby { shift->_attr( standby => @_) }
1321 15     15   2561 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.058';
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   907 sub valueType{lc shift->_attr(valuetype=>@_)}
1337              
1338             # ------- HTMLAppletElement interface ---------- #
1339              
1340             package HTML::DOM::Element::Applet;
1341             our $VERSION = '0.058';
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   850 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.058';
1359             our @ISA = 'HTML::DOM::Element';
1360             sub areas { # ~~~ I need to make this cache the resulting collection obj
1361 1     1   3 my $self = shift;
1362 1 50       4 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   8 sub { grep tag $_ eq 'area', $self->descendants }
1369 1         14 ));
1370 1         5 $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.058';
1380             our @ISA = 'HTML::DOM::Element';
1381             * alt = \ & HTML::DOM::Element::Img::alt ;
1382 10     10   1775 sub coords { shift -> _attr ( coords => @_ ) }
1383             * href = \ & HTML::DOM::Element::Link::href ;
1384 5 100   5   44 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   479967 no strict 'refs';
  25         47  
  25         13944  
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.058';
1398             our @ISA = 'HTML::DOM::Element';
1399             * text = \ &HTML::DOM::Element::Title::text ;
1400 5     5   842 sub htmlFor { shift -> _attr ( for => @_ ) }
1401 5     5   438 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.058';
1411             our @ISA = 'HTML::DOM::Element';
1412 5     5   890 sub rows { shift -> _attr ( rows => @_ ) }
1413 5     5   447 sub cols { shift -> _attr ( cols => @_ ) }
1414              
1415             # ------- HTMLFrameElement interface ---------- #
1416              
1417             package HTML::DOM::Element::Frame;
1418             our $VERSION = '0.058';
1419             our @ISA = 'HTML::DOM::Element';
1420 12     12   1325 sub frameBorder { lc shift -> _attr ( frameBorder => @_ ) }
1421 10     10   1704 sub longDesc { shift -> _attr ( longdesc => @_ ) }
1422 10     10   1779 sub marginHeight{ shift -> _attr ( marginheight => @_ ) }
1423 10     10   2045 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   1746 sub scrolling { lc shift -> _attr ( scrolling => @_ ) }
1427             * src = \ &HTML::DOM::Element::Img::src ;
1428 6   100 6   31 sub contentDocument{ (shift->{_HTML_DOM_view} || return)->document }
1429             sub contentWindow {
1430 8     8   28 my $old = (my $self = shift)->{_HTML_DOM_view};
1431 8 100       25 @_ and $self->{_HTML_DOM_view} = shift;
1432 8 100       39 defined $old ? $old : ()
1433             };
1434              
1435             # ------- HTMLIFrameElement interface ---------- #
1436              
1437             package HTML::DOM::Element::IFrame;
1438             our $VERSION = '0.058';
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