File Coverage

blib/lib/HTML/Element/Library.pm
Criterion Covered Total %
statement 39 366 10.6
branch 0 178 0.0
condition 0 8 0.0
subroutine 13 62 20.9
pod 1 36 2.7
total 53 650 8.1


line stmt bran cond sub pod time code
1             package HTML::Element::Library;
2 2     2   68802 use strict;
  2         3  
  2         46  
3 2     2   7 use warnings;
  2         2  
  2         73  
4              
5             our $VERSION = '5.220000';
6             our $DEBUG = 0;
7              
8 2     2   720 use Array::Group ':all';
  2         912  
  2         189  
9 2     2   8 use Carp 'confess';
  2         2  
  2         78  
10 2     2   976 use Data::Dumper;
  2         12576  
  2         90  
11 2     2   888 use Data::Rmap 'rmap_array';
  2         2009  
  2         97  
12 2     2   9 use HTML::Element;
  2         2  
  2         23  
13 2     2   909 use HTML::FillInForm;
  2         4443  
  2         54  
14 2     2   843 use List::MoreUtils ':all';
  2         15427  
  2         9  
15 2     2   5629 use List::Rotation::Cycle;
  2         5274  
  2         54  
16 2     2   9 use List::Util 'first';
  2         2  
  2         128  
17 2     2   881 use Params::Validate ':all';
  2         12014  
  2         293  
18 2     2   702 use Scalar::Listify;
  2         442  
  2         6221  
19              
20             # https://rt.cpan.org/Ticket/Display.html?id=44105
21             sub HTML::Element::fillinform {
22 0     0 0   my ($tree, $hashref, $return_tree, $guts) = @_;
23 0 0         (ref $hashref) eq 'HASH' or confess 'hashref not supplied as argument' ;
24              
25 0           my $html = $tree->as_HTML;
26 0           my $new_html = HTML::FillInForm->fill(\$html, $hashref);
27              
28 0 0         if ($return_tree) {
29 0           $tree = HTML::TreeBuilder->new_from_content($new_html);
30 0 0         $tree = $guts ? $tree->guts : $tree ;
31             } else {
32 0           $new_html;
33             }
34             }
35              
36             sub HTML::Element::siblings {
37 0     0 0   my $element = shift;
38 0           my $p = $element->parent;
39 0 0         return () unless $p;
40 0           $p->content_list;
41             }
42              
43             sub HTML::Element::defmap {
44 0     0 0   my($tree, $attr, $hashref, $debug) = @_;
45              
46 0           while (my ($k, $v) = (each %$hashref)) {
47 0 0         warn "defmap looks for ($attr => $k)" if $debug;
48 0           my $found = $tree->look_down($attr => $k);
49 0 0         if ($found) {
50 0 0         warn "($attr => $k) was found.. replacing with '$v'" if $debug;
51 0           $found->replace_content( $v );
52             }
53             }
54             }
55              
56             sub HTML::Element::_only_empty_content {
57 0     0     my ($self) = @_;
58 0           my @c = $self->content_list;
59 0           my $length = scalar @c;
60              
61 0 0         scalar @c == 1 and not length $c[0];
62             }
63              
64             sub HTML::Element::prune {
65 0     0 0   my ($self) = @_;
66              
67 0           for my $c ($self->content_list) {
68 0 0         next unless ref $c;
69 0           $c->prune;
70             }
71              
72             # post-order:
73 0 0 0       $self->delete if ($self->is_empty or $self->_only_empty_content);
74 0           $self;
75             }
76              
77             sub HTML::Element::newchild {
78 0     0 0   my ($lol, $parent_label, @newchild) = @_;
79             rmap_array {
80 0 0   0     if ($_->[0] eq $parent_label) {
81 0           $_ = [ $parent_label => @newchild ];
82 0           Data::Rmap::cut($_);
83             } else {
84 0           $_;
85             }
86 0           } $lol;
87             }
88              
89             sub HTML::Element::crunch { ## no critic (RequireArgUnpacking)
90 0     0 0   my $container = shift;
91              
92 0           my %p = validate(@_, {
93             look_down => { type => ARRAYREF },
94             leave => { default => 1 },
95             });
96              
97 0           my @look_down = @{$p{look_down}} ;
  0            
98 0           my @elem = $container->look_down(@look_down) ;
99              
100 0           my $detached;
101              
102 0           for my $elem (@elem) {
103 0 0         $elem->detach if $detached++ >= $p{leave};
104             }
105             }
106              
107             sub HTML::Element::hash_map { ## no critic (RequireArgUnpacking)
108 0     0 0   my $container = shift;
109              
110 0           my %p = validate(@_, {
111             hash => { type => HASHREF },
112             to_attr => 1,
113             excluding => { type => ARRAYREF , default => [] },
114             debug => { default => 0 },
115             });
116              
117 0 0         warn 'The container tag is ', $container->tag if $p{debug} ;
118 0 0         warn 'hash' . Dumper($p{hash}) if $p{debug} ;
119             #warn 'at_under' . Dumper(\@_) if $p{debug} ;
120              
121 0           my @same_as = $container->look_down( $p{to_attr} => qr/.+/s ) ;
122              
123 0 0         warn 'Found ' . scalar(@same_as) . ' nodes' if $p{debug} ;
124              
125 0           for my $same_as (@same_as) {
126 0           my $attr_val = $same_as->attr($p{to_attr}) ;
127 0 0   0     if (first { $attr_val eq $_ } @{$p{excluding}}) {
  0            
  0            
128 0 0         warn "excluding $attr_val" if $p{debug} ;
129 0           next;
130             }
131 0 0         warn "processing $attr_val" if $p{debug} ;
132 0           $same_as->replace_content($p{hash}->{$attr_val});
133             }
134             }
135              
136             sub HTML::Element::hashmap {
137 0     0 0   my ($container, $attr_name, $hashref, $excluding, $debug) = @_;
138              
139 0   0       $excluding ||= [] ;
140              
141 0           $container->hash_map(
142             hash => $hashref,
143             to_attr => $attr_name,
144             excluding => $excluding,
145             debug => $debug);
146             }
147              
148              
149             sub HTML::Element::passover {
150 0     0 0   my ($tree, @to_preserve) = @_;
151              
152 0 0         warn "ARGS: my ($tree, @to_preserve)" if $DEBUG;
153 0 0         warn $tree->as_HTML(undef, ' ') if $DEBUG;
154              
155 0           my $exodus = $tree->look_down(id => $to_preserve[0]);
156              
157 0 0         warn "E: $exodus" if $DEBUG;
158              
159 0           my @s = HTML::Element::siblings($exodus);
160              
161 0           for my $s (@s) {
162 0 0         next unless ref $s;
163 0 0   0     $s->delete unless first { $s->attr('id') eq $_ } @to_preserve;
  0            
164             }
165              
166 0           return $exodus; # Goodbye Egypt! http://en.wikipedia.org/wiki/Passover
167             }
168              
169             sub HTML::Element::sibdex {
170 0     0 0   my $element = shift;
171 0     0     firstidx { $_ eq $element } $element->siblings
  0            
172             }
173              
174 0     0 0   sub HTML::Element::addr { goto &HTML::Element::sibdex }
175              
176             sub HTML::Element::replace_content {
177 0     0 0   my $elem = shift;
178 0           $elem->delete_content;
179 0           $elem->push_content(@_);
180             }
181              
182             sub HTML::Element::wrap_content {
183 0     0 0   my($self, $wrap) = @_;
184 0           my $content = $self->content;
185 0 0         if (ref $content) {
186 0           $wrap->push_content(@$content);
187 0           @$content = ($wrap);
188             }
189             else {
190 0           $self->push_content($wrap);
191             }
192 0           $wrap;
193             }
194              
195             sub HTML::Element::Library::super_literal {
196 0     0 1   my($text) = @_;
197 0           HTML::Element->new('~literal', text => $text);
198             }
199              
200             sub HTML::Element::position {
201             # Report coordinates by chasing addr's up the
202             # HTML::ElementSuper tree. We know we've reached
203             # the top when a) there is no parent, or b) the
204             # parent is some HTML::Element unable to report
205             # it's position.
206 0     0 0   my $p = shift;
207 0           my @pos;
208 0           while ($p) {
209 0           my $a = $p->addr;
210 0 0         unshift @pos, $a if defined $a;
211 0           $p = $p->parent;
212             }
213 0           @pos;
214             }
215              
216             sub HTML::Element::content_handler {
217 0     0 0   my ($tree, %content_hash) = @_;
218              
219 0           for my $k (keys %content_hash) {
220 0           $tree->set_child_content(id => $k, $content_hash{$k});
221             }
222             }
223              
224 0     0 0   sub HTML::Element::assign { goto &HTML::Element::content_handler }
225              
226             sub make_counter {
227 0     0 0   my $i = 1;
228             sub {
229 0     0     shift() . ':' . $i++
230             }
231 0           }
232              
233             sub HTML::Element::iter {
234 0     0 0   my ($tree, $p, @data) = @_;
235              
236             # warn 'P: ' , $p->attr('id') ;
237             # warn 'H: ' , $p->as_HTML;
238              
239             # my $id_incr = make_counter;
240             my @item = map {
241 0           my $new_item = clone $p;
  0            
242 0           $new_item->replace_content($_);
243 0           $new_item;
244             } @data;
245              
246 0           $p->replace_with(@item);
247             }
248              
249             sub HTML::Element::itercb {
250 0     0 0   my ($self, $data, $code) = @_;
251 0           my $orig = $self;
252 0           my $prev = $orig;
253 0           for my $el (@$data) {
254 0           my $current = $orig->clone;
255 0           $code->($el, $current);
256 0           $prev->postinsert($current);
257 0           $prev = $current;
258             }
259 0           $orig->detach;
260             }
261              
262             sub HTML::Element::iter2 { ## no critic (RequireArgUnpacking)
263 0     0 0   my $tree = shift;
264              
265             #warn "INPUT TO TABLE2: ", Dumper \@_;
266              
267             my %p = validate(
268             @_, {
269             wrapper_ld => { default => ['_tag' => 'dl'] },
270             wrapper_data => 1,
271             wrapper_proc => { default => undef },
272             item_ld => {
273             default => sub {
274 0     0     my $tr = shift;
275             [
276 0           $tr->look_down('_tag' => 'dt'),
277             $tr->look_down('_tag' => 'dd')
278             ];
279             }},
280             item_data => {
281             default => sub {
282 0     0     my ($wrapper_data) = @_;
283 0           shift @{$wrapper_data};
  0            
284             }},
285             item_proc => {
286             default => sub {
287 0     0     my ($item_elems, $item_data, $row_count) = @_;
288 0           $item_elems->[$_]->replace_content($item_data->[$_]) for (0,1) ;
289 0           $item_elems;
290             }},
291             splice => {
292             default => sub {
293 0     0     my ($container, @item_elems) = @_;
294 0           $container->splice_content(0, 2, @item_elems);
295             }
296             },
297 0           debug => {default => 0}
298             }
299             );
300              
301 0 0         warn 'wrapper_data: ' . Dumper $p{wrapper_data} if $p{debug} ;
302              
303 0           my $container = ref_or_ld($tree, $p{wrapper_ld});
304 0 0         warn 'container: ' . $container if $p{debug} ;
305 0 0         warn 'wrapper_(preproc): ' . $container->as_HTML if $p{debug} ;
306 0 0         $p{wrapper_proc}->($container) if defined $p{wrapper_proc} ;
307 0 0         warn 'wrapper_(postproc): ' . $container->as_HTML if $p{debug} ;
308              
309 0           my $_item_elems = $p{item_ld}->($container);
310              
311 0           my $row_count;
312             my @item_elem;
313 0           while(1){
314 0           my $item_data = $p{item_data}->($p{wrapper_data});
315 0 0         last unless defined $item_data;
316              
317 0 0         warn Dumper('item_data', $item_data) if $p{debug};
318              
319 0           my $item_elems = [ map { $_->clone } @{$_item_elems} ] ;
  0            
  0            
320              
321 0 0         if ($p{debug}) {
322 0           for (@{$item_elems}) {
  0            
323 0 0         warn 'ITEM_ELEMS ', $_->as_HTML if $p{debug};
324             }
325             }
326              
327 0           my $new_item_elems = $p{item_proc}->($item_elems, $item_data, ++$row_count);
328              
329 0 0         if ($p{debug}) {
330 0           for (@{$new_item_elems}) {
  0            
331 0 0         warn 'NEWITEM_ELEMS ', $_->as_HTML if $p{debug};
332             }
333             }
334              
335 0           push @item_elem, @{$new_item_elems} ;
  0            
336             }
337              
338 0 0         warn 'pushing ' . @item_elem . ' elems' if $p{debug} ;
339              
340 0           $p{splice}->($container, @item_elem);
341             }
342              
343             sub HTML::Element::dual_iter {
344 0     0 0   my ($parent, $data) = @_;
345              
346 0           my ($prototype_a, $prototype_b) = $parent->content_list;
347              
348             # my $id_incr = make_counter;
349              
350 0           my $i;
351              
352 0 0         @$data %2 == 0 or confess 'dataset does not contain an even number of members';
353              
354 0           my @iterable_data = ngroup 2 => @$data;
355              
356             my @item = map {
357 0           my ($new_a, $new_b) = map { clone $_ } ($prototype_a, $prototype_b) ;
  0            
  0            
358 0           $new_a->splice_content(0,1, $_->[0]);
359 0           $new_b->splice_content(0,1, $_->[1]);
360             #$_->attr('id', $id_incr->($_->attr('id'))) for ($new_a, $new_b) ;
361 0           ($new_a, $new_b)
362             } @iterable_data;
363              
364 0           $parent->splice_content(0, 2, @item);
365             }
366              
367             sub HTML::Element::set_child_content { ## no critic (RequireArgUnpacking)
368 0     0 0   my $tree = shift;
369 0           my $content = pop;
370 0           my @look_down = @_;
371              
372 0           my $content_tag = $tree->look_down(@look_down);
373              
374 0 0         unless ($content_tag) {
375 0           warn "criteria [@look_down] not found";
376 0           return;
377             }
378              
379 0           $content_tag->replace_content($content);
380             }
381              
382             sub HTML::Element::highlander {
383 0     0 0   my ($tree, $local_root_id, $aref, @arg) = @_;
384              
385 0 0         ref $aref eq 'ARRAY' or confess 'must supply array reference';
386              
387 0           my @aref = @$aref;
388 0 0         @aref % 2 == 0 or confess 'supplied array ref must have an even number of entries';
389              
390 0 0         warn __PACKAGE__ if $DEBUG;
391              
392 0           my $survivor;
393 0           while (my ($id, $test) = splice @aref, 0, 2) {
394 0 0         warn $id if $DEBUG;
395 0 0         if ($test->(@arg)) {
396 0           $survivor = $id;
397 0           last;
398             }
399             }
400              
401 0           my @id_survivor = (id => $survivor);
402 0           my $survivor_node = $tree->look_down(@id_survivor);
403             # warn $survivor;
404             # warn $local_root_id;
405             # warn $node;
406              
407 0 0         warn "survivor: $survivor" if $DEBUG;
408 0 0         warn 'tree: ' . $tree->as_HTML if $DEBUG;
409              
410 0 0         $survivor_node or die "search for @id_survivor failed in tree($tree): " . $tree->as_HTML;
411              
412 0           my $survivor_node_parent = $survivor_node->parent;
413 0           $survivor_node = $survivor_node->clone;
414 0           $survivor_node_parent->replace_content($survivor_node);
415              
416 0 0         warn 'new tree: ' . $tree->as_HTML if $DEBUG;
417              
418 0           $survivor_node;
419             }
420              
421             sub HTML::Element::highlander2 { ## no critic (RequireArgUnpacking)
422 0     0 0   my $tree = shift;
423              
424 0           my %p = validate(@_, {
425             cond => { type => ARRAYREF },
426             cond_arg => {
427             type => ARRAYREF,
428             default => []
429             },
430             debug => { default => 0 }
431             });
432              
433 0           my @cond = @{$p{cond}};
  0            
434 0 0         @cond % 2 == 0 or confess 'supplied array ref must have an even number of entries';
435              
436 0 0         warn __PACKAGE__ if $p{debug};
437              
438 0           my @cond_arg = @{$p{cond_arg}};
  0            
439              
440 0           my $survivor; my $then;
441 0           while (my ($id, $if_then) = splice @cond, 0, 2) {
442 0 0         warn $id if $p{debug};
443 0           my ($if, $_then);
444              
445 0 0         if (ref $if_then eq 'ARRAY') {
446 0           ($if, $_then) = @$if_then;
447             } else {
448 0     0     ($if, $_then) = ($if_then, sub {});
449             }
450              
451 0 0         if ($if->(@cond_arg)) {
452 0           $survivor = $id;
453 0           $then = $_then;
454 0           last;
455             }
456             }
457              
458 0 0         my @ld = (ref $survivor eq 'ARRAY') ? @$survivor : (id => $survivor);
459              
460 0 0         warn 'survivor: ', $survivor if $p{debug};
461 0 0         warn 'survivor_ld: ', Dumper \@ld if $p{debug};
462              
463 0           my $survivor_node = $tree->look_down(@ld);
464              
465 0 0         $survivor_node or confess "search for @ld failed in tree($tree): " . $tree->as_HTML;
466              
467 0           my $survivor_node_parent = $survivor_node->parent;
468 0           $survivor_node = $survivor_node->clone;
469 0           $survivor_node_parent->replace_content($survivor_node);
470              
471             # **************** NEW FUNCTIONALITY *******************
472             # apply transforms on survivor node
473              
474 0 0         warn 'SURV::pre_trans ' . $survivor_node->as_HTML if $p{debug};
475 0           $then->($survivor_node, @cond_arg);
476 0 0         warn 'SURV::post_trans ' . $survivor_node->as_HTML if $p{debug};
477             # **************** NEW FUNCTIONALITY *******************
478              
479 0           $survivor_node;
480             }
481              
482             sub overwrite_action {
483 0     0 0   my ($mute_node, %X) = @_;
484              
485 0           $mute_node->attr($X{local_attr}{name} => $X{local_attr}{value}{new});
486             }
487              
488             sub HTML::Element::overwrite_attr {
489 0     0 0   my $tree = shift;
490              
491 0           $tree->mute_elem(@_, \&overwrite_action);
492             }
493              
494             sub HTML::Element::mute_elem {
495 0     0 0   my ($tree, $mute_attr, $closures, $post_hook) = @_;
496              
497 0           my @mute_node = $tree->look_down($mute_attr => qr/.*/s) ;
498              
499 0           for my $mute_node (@mute_node) {
500 0           my ($local_attr,$mute_key) = split /\s+/s, $mute_node->attr($mute_attr);
501 0           my $local_attr_value_current = $mute_node->attr($local_attr);
502 0           my $local_attr_value_new = $closures->{$mute_key}->($tree, $mute_node, $local_attr_value_current);
503 0 0         $post_hook->(
504             $mute_node,
505             tree => $tree,
506             local_attr => {
507             name => $local_attr,
508             value => {
509             current => $local_attr_value_current,
510             new => $local_attr_value_new
511             }
512             }
513             ) if ($post_hook) ;
514             }
515             }
516              
517              
518              
519             sub HTML::Element::table {
520 0     0 0   my ($s, %table) = @_;
521 0           my $table = {};
522              
523             # Get the table element
524 0           $table->{table_node} = $s->look_down(id => $table{gi_table});
525 0 0         $table->{table_node} or confess "table tag not found via (id => $table{gi_table}";
526              
527             # Get the prototype tr element(s)
528 0           my @table_gi_tr = listify $table{gi_tr} ;
529             my @iter_node = map {
530 0           my $tr = $table->{table_node}->look_down(id => $_);
  0            
531 0 0         $tr or confess "tr with id => $_ not found";
532 0           $tr;
533             } @table_gi_tr;
534              
535 0 0         warn 'found ' . @iter_node . ' iter nodes ' if $DEBUG;
536 0           my $iter_node = List::Rotation::Cycle->new(@iter_node);
537              
538             # warn $iter_node;
539 0 0         warn Dumper ($iter_node, \@iter_node) if $DEBUG;
540              
541             # $table->{content} = $table{content};
542             # $table->{parent} = $table->{table_node}->parent;
543              
544             # $table->{table_node}->detach;
545             # $_->detach for @iter_node;
546              
547 0           my @table_rows;
548              
549 0           while (1) {
550 0           my $row = $table{tr_data}->($table, $table{table_data});
551 0 0         last unless defined $row;
552              
553             # get a sample table row and clone it.
554 0           my $I = $iter_node->next;
555 0 0         warn "I: $I" if $DEBUG;
556 0           my $new_iter_node = $I->clone;
557              
558 0           $table{td_data}->($new_iter_node, $row);
559 0           push @table_rows, $new_iter_node;
560             }
561              
562 0 0         if (@table_rows) {
563 0           my $replace_with_elem = $s->look_down(id => shift @table_gi_tr) ;
564 0           $s->look_down(id => $_)->detach for @table_gi_tr;
565 0           $replace_with_elem->replace_with(@table_rows);
566             }
567             }
568              
569             sub ref_or_ld {
570 0     0 0   my ($tree, $slot) = @_;
571              
572 0 0         if (ref($slot) eq 'CODE') {
573 0           $slot->($tree);
574             } else {
575 0           $tree->look_down(@$slot);
576             }
577             }
578              
579             sub HTML::Element::table2 { ## no critic (RequireArgUnpacking)
580 0     0 0   my $tree = shift;
581              
582             my %p = validate(
583             @_, {
584             table_ld => { default => ['_tag' => 'table'] },
585             table_data => 1,
586             table_proc => { default => undef },
587             tr_ld => { default => ['_tag' => 'tr'] },
588             tr_data => {
589             default => sub {
590 0     0     my ($self, $data) = @_;
591 0           shift @{$data};
  0            
592             }},
593             tr_base_id => { default => undef },
594       0     tr_proc => { default => sub {} },
595 0           td_proc => 1,
596             debug => {default => 0}
597             }
598             );
599              
600 0 0         warn 'INPUT TO TABLE2: ', Dumper \@_ if $p{debug};
601 0 0         warn 'table_data: ' . Dumper $p{table_data} if $p{debug} ;
602              
603 0           my $table = {};
604              
605             # Get the table element
606 0           $table->{table_node} = ref_or_ld( $tree, $p{table_ld} ) ;
607 0 0         $table->{table_node} or confess 'table tag not found via ' . Dumper($p{table_ld}) ;
608              
609 0 0         warn 'table: ' . $table->{table_node}->as_HTML if $p{debug};
610              
611             # Get the prototype tr element(s)
612 0           my @proto_tr = ref_or_ld( $table->{table_node}, $p{tr_ld} ) ;
613              
614 0 0         warn 'found ' . @proto_tr . ' iter nodes' if $p{debug};
615              
616 0 0         return unless @proto_tr;
617              
618 0 0         if ($p{debug}) {
619 0           warn $_->as_HTML for @proto_tr;
620             }
621 0           my $proto_tr = List::Rotation::Cycle->new(@proto_tr);
622              
623 0           my $tr_parent = $proto_tr[0]->parent;
624 0 0         warn 'parent element of trs: ' . $tr_parent->as_HTML if $p{debug};
625              
626 0           my $row_count;
627              
628             my @table_rows;
629              
630 0           while(1) {
631 0           my $row = $p{tr_data}->($table, $p{table_data}, $row_count);
632 0 0         warn 'data row: ' . Dumper $row if $p{debug};
633 0 0         last unless defined $row;
634              
635             # wont work: my $new_iter_node = $table->{iter_node}->clone;
636 0           my $new_tr_node = $proto_tr->next->clone;
637 0 0         warn "new_tr_node: $new_tr_node" if $p{debug};
638              
639 0 0         $p{tr_proc}->($tree, $new_tr_node, $row, $p{tr_base_id}, ++$row_count) if defined $p{tr_proc};
640              
641 0 0         warn 'data row redux: ' . Dumper $row if $p{debug};
642              
643 0           $p{td_proc}->($new_tr_node, $row);
644 0           push @table_rows, $new_tr_node;
645             }
646              
647 0           $_->detach for @proto_tr;
648              
649 0 0         $tr_parent->push_content(@table_rows) if (@table_rows) ;
650             }
651              
652             sub HTML::Element::unroll_select {
653 0     0 0   my ($s, %select) = @_;
654              
655 0           my $select = {};
656 0 0         warn 'Select Hash: ' . Dumper(\%select) if $select{debug};
657              
658 0           my $select_node = $s->look_down(id => $select{select_label});
659 0 0         warn "Select Node: $select_node" if $select{debug};
660              
661 0 0         unless ($select{append}) {
662 0           for my $option ($select_node->look_down('_tag' => 'option')) {
663 0           $option->delete;
664             }
665             }
666              
667 0           my $option = HTML::Element->new('option');
668 0 0         warn "Option Node: $option" if $select{debug};
669              
670 0           $option->detach;
671              
672 0           while (my $row = $select{data_iter}->($select{data})) {
673 0 0         warn 'Data Row: ' . Dumper($row) if $select{debug};
674 0           my $o = $option->clone;
675 0           $o->attr('value', $select{option_value}->($row));
676 0 0 0       $o->attr('SELECTED', 1) if (exists $select{option_selected} and $select{option_selected}->($row));
677              
678 0           $o->replace_content($select{option_content}->($row));
679 0           $select_node->push_content($o);
680 0 0         warn $o->as_HTML if $select{debug};
681             }
682             }
683              
684             sub HTML::Element::set_sibling_content {
685 0     0 0   my ($elt, $content) = @_;
686              
687 0           $elt->parent->splice_content($elt->pindex + 1, 1, $content);
688             }
689              
690             sub HTML::TreeBuilder::parse_string {
691 0     0 0   my ($package, $string) = @_;
692              
693 0           my $h = HTML::TreeBuilder->new;
694 0           HTML::TreeBuilder->parse($string);
695             }
696              
697 0     0 0   sub HTML::Element::fid { shift->look_down(id => $_[0]) }
698 0     0 0   sub HTML::Element::fclass { shift->look_down(class => qr/\b$_[0]\b/s) }
699              
700             1;
701             __END__