File Coverage

blib/lib/Tree/Simple/View/HTML.pm
Criterion Covered Total %
statement 139 141 98.5
branch 53 56 94.6
condition 15 24 62.5
subroutine 21 21 100.0
pod 4 4 100.0
total 232 246 94.3


line stmt bran cond sub pod time code
1              
2             package Tree::Simple::View::HTML;
3              
4 3     3   30716 use strict;
  3         3  
  3         69  
5 3     3   8 use warnings;
  3         3  
  3         95  
6              
7             our $VERSION = '0.180001';
8              
9 3     3   10 use base 'Tree::Simple::View';
  3         3  
  3         1134  
10              
11 3     3   20 use Tree::Simple::View::Exceptions;
  3         1  
  3         46  
12              
13 3     3   9 use constant OPEN_TAG => 1;
  3         3  
  3         201  
14 3     3   12 use constant CLOSE_TAG => 2;
  3         3  
  3         100  
15 3     3   9 use constant EXPANDED => 3;
  3         4  
  3         2498  
16              
17             my %tags = (
18             xhtml => { OL => 'ol', UL => 'ul', LI => 'li', STYLE => q{ style='}, CLASS => q{ class='} },
19             html => { OL => 'OL', UL => 'UL', LI => 'LI', STYLE => q{ STYLE='}, CLASS => q{ CLASS='} },
20             );
21              
22             ## public methods
23              
24             sub expandPathSimple {
25 8     8 1 15 my ($self, $tree, $current_path, @path) = @_;
26 8         5 my @results;
27             # if we were not called from this routine, and
28             # include trunk has been turned on then, this is
29             # the first time we have been called, so ...
30 8 100 100     60 if ($self->{include_trunk} && (caller(1))[3] !~ /expandPathSimple$/) {
31 1         2 push @results => "
    ";
32 1         4 push @results => ("
  • " . $tree->getNodeValue() . "
  • ");
    33             # now recurse but dont change any of the args,
    34             # (if we are supposed to that is, based on the path)
    35 1 50 33     7 push @results => ($self->expandPathSimple($tree, @path))
    36             if (defined $current_path && $tree->getNodeValue() eq $current_path);
    37 1         2 push @results => "";
    38             }
    39             else {
    40 7         8 push @results => "
      ";
    41 7         13 foreach my $child ($tree->getAllChildren()) {
    42 22 100 100     88 if (defined $current_path && $self->_compareNodeToPath($current_path, $child)) {
    43 4         18 push @results => ("
  • " . $child->getNodeValue() . "
  • ");
    44 4         26 push @results => ($self->expandPathSimple($child, @path));
    45             }
    46             else {
    47 18         50 push @results => ("
  • " . $child->getNodeValue() . "
  • ");
    48             }
    49             }
    50 7         21 push @results => "";
    51             }
    52 8         23 return (join "\n" => @results);
    53             }
    54              
    55             sub expandPathComplex {
    56 10     10 1 13 my ($self, $tree, $config, $current_path, @path) = @_;
    57             # get the config
    58 10         18 my ($list_func, $list_item_func) = $self->_processConfig($config);
    59            
    60             # use the helper function to recurse
    61             my $_expandPathComplex = sub {
    62 20     20   42 my ($self_func, $list_func, $list_item_func, $tree, $current_path, @path) = @_;
    63 20         344 my @results = ($list_func->(OPEN_TAG));
    64 20         39 foreach my $child ($tree->getAllChildren()) {
    65 64 100 100     323 if (defined $current_path && $self->_compareNodeToPath($current_path, $child)) {
    66 10 50       49 unless ($child->isLeaf()) {
    67 10         231 push @results => ($list_item_func->($child, EXPANDED));
    68 10         66 push @results => ($self_func->($self_func, $list_func, $list_item_func, $child, @path));
    69             }
    70             else {
    71 0         0 push @results => ($list_item_func->($child));
    72             }
    73             }
    74             else {
    75 54         1004 push @results => ($list_item_func->($child));
    76             }
    77             }
    78 20         419 push @results => ($list_func->(CLOSE_TAG));
    79 20         68 return (join "\n" => @results);
    80 10         31 };
    81            
    82 10         11 my @results;
    83 10 100       18 if ($self->{include_trunk}) {
    84 2         37 push @results => ($list_func->(OPEN_TAG));
    85 2 50 33     12 if (defined $current_path && $self->_compareNodeToPath($current_path, $tree)) {
    86 2         49 push @results => ($list_item_func->($tree, EXPANDED));
    87 2         11 push @results => $_expandPathComplex->($_expandPathComplex, $list_func, $list_item_func, $tree, @path);
    88             }
    89             else {
    90 0         0 push @results => ($list_item_func->($tree));
    91             }
    92 2         36 push @results => ($list_func->(CLOSE_TAG));
    93             }
    94             else {
    95 8         16 push @results => $_expandPathComplex->($_expandPathComplex, $list_func, $list_item_func, $tree, $current_path, @path);
    96             }
    97            
    98 10         233 return (join "\n" => @results);
    99             }
    100              
    101             sub expandAllSimple {
    102 2     2 1 2 my ($self) = @_;
    103 2         4 my @results = ("
      ");
    104 2         5 my $root_depth = $self->{tree}->getDepth() + 1;
    105 2         5 my $last_depth = -1;
    106             my $traversal_sub = sub {
    107 31     31   216 my ($t) = @_;
    108 31         45 my $current_depth = $t->getDepth();
    109 31 100       72 push @results => ("" x ($last_depth - $current_depth)) if ($last_depth > $current_depth);
    110 31         35 push @results => ("
  • " . $t->getNodeValue() . "
  • ");
    111 31 100       77 push @results => "
      " unless $t->isLeaf();
    112 31         123 $last_depth = $current_depth;
    113 2         9 };
    114 2 100       6 $traversal_sub->($self->{tree}) if $self->{include_trunk};
    115 2         4 $self->{tree}->traverse($traversal_sub);
    116 2         16 $last_depth -= $root_depth;
    117 2 100       9 $last_depth++ if $self->{include_trunk};
    118 2         4 push @results => ("" x ($last_depth + 1));
    119 2         17 return (join "\n" => @results);
    120             }
    121              
    122             sub expandAllComplex {
    123 9     9 1 9 my ($self, $config) = @_;
    124            
    125 9         18 my ($list_func, $list_item_func) = $self->_processConfig($config);
    126            
    127 8         146 my @results = $list_func->(OPEN_TAG);
    128 8         23 my $root_depth = $self->{tree}->getDepth() + 1;
    129 8         20 my $last_depth = -1;
    130             my $traversal_sub = sub {
    131 122     122   947 my ($t) = @_;
    132 122         147 my $current_depth = $t->getDepth();
    133 122 100       777 push @results => ($list_func->(CLOSE_TAG) x ($last_depth - $current_depth)) if ($last_depth > $current_depth);
    134 122 100       148 if ($t->isLeaf()) {
    135 80         1544 push @results => ($list_item_func->($t));
    136             }
    137             else {
    138 42         840 push @results => ($list_item_func->($t, EXPANDED));
    139             }
    140 122 100       506 push @results => $list_func->(OPEN_TAG) unless $t->isLeaf();
    141 122         382 $last_depth = $current_depth;
    142 8         26 };
    143 8 100       16 $traversal_sub->($self->{tree}) if $self->{include_trunk};
    144 8         19 $self->{tree}->traverse($traversal_sub);
    145 8         69 $last_depth -= $root_depth;
    146 8 100       22 $last_depth++ if $self->{include_trunk};
    147 8         135 push @results => ($list_func->(CLOSE_TAG) x ($last_depth + 1));
    148 8         204 return (join "\n" => @results);
    149             }
    150              
    151             ## private methods
    152              
    153             # process configurations
    154              
    155             sub _processConfig {
    156 31     31   27 my ($self, $config) = @_;
    157 31         26 my %config = %{$config};
      31         100  
    158            
    159             # Make sure the tag style is always set to something we know &
    160             # set tags to be the hashref of tags we want to save extra indirection later
    161 31 100       72 if ( !exists $config{ tag_style } ) {
        100          
    162 21         27 $config{ tags } = $tags{ html };
    163             }
    164             elsif ( !exists( $tags{ $config{ tag_style } }) ) {
    165 1         12 throw Tree::Simple::View::CompilationFailed "unknown tag_style $config{ tag_style }";
    166             }
    167             else {
    168 9         12 $config{ tags } = $tags{ $config{ tag_style } };
    169             }
    170            
    171 30   33     68 my $list_func = $self->_buildListFunction(%config)
    172             || throw Tree::Simple::View::CompilationFailed "list function didn't compile", $@;
    173 30   33     99 my $list_item_func = $self->_buildListItemFunction(%config)
    174             || throw Tree::Simple::View::CompilationFailed "list item function didn't compile", $@;
    175              
    176 30         85 return ($list_func, $list_item_func);
    177             }
    178              
    179             ## code strings to be evaluated
    180              
    181 3         147 use constant LIST_FUNCTION_CODE_STRING => q|
    182             sub {
    183             my ($tag_type) = @_;
    184             return '<' . $config{tags}->{$list_type} . ${list_css} . '>' if ($tag_type == OPEN_TAG);
    185             return '{$list_type} .'>' if ($tag_type == CLOSE_TAG);
    186             }
    187 3     3   13 |;
      3         3  
    188              
    189 3         1032 use constant LIST_ITEM_FUNCTION_CODE_STRING => q|;
    190             sub {
    191             my ($t, $is_expanded) = @_;
    192             my $item_css = $list_item_css;
    193             $item_css = $expanded_item_css if ($is_expanded && $expanded_item_css);
    194             return '<'.$config{tags}->{LI}.$item_css.'>' . (($node_formatter) ? $node_formatter->($t) : $t->getNodeValue()) . '{LI}.'>';
    195             }
    196 3     3   10 |;
      3         4  
    197              
    198             ## list config processing
    199             sub _processListConfig {
    200 30     30   46 my ($self, %config) = @_;
    201            
    202 30         24 my $list_type = "UL";
    203 30 100       69 $list_type = (($config{list_type} eq "unordered") ? "UL" : "OL") if exists $config{list_type};
        100          
    204              
    205 30         24 my $list_css = "";
    206 30 100       60 if (exists $config{list_css}) {
        100          
    207             # make sure we have a proper ';' at the end
    208             # of the CSS code here, it is needed by the
    209             # DHTML subclass when we add the display property
    210             # to it, no other element requires this so far,
    211             # but if it did, this same idiom could be reused
    212 6         9 my $_list_css = $config{list_css};
    213 6 100       23 $_list_css .= ";" unless ($_list_css =~ /\;$/);
    214 6         14 $list_css = $config{tags}->{STYLE} . "${_list_css}'";
    215             }
    216             elsif (exists $config{list_css_class}) {
    217 9         21 $list_css = $config{tags}->{CLASS} . $config{list_css_class} . "'";
    218             }
    219             # otherwise do nothing and stick with default
    220            
    221 30         58 return ($list_type, $list_css);
    222             }
    223              
    224             sub _buildListFunction {
    225 30     30   48 my ($self, %config) = @_;
    226             # process the configuration directives
    227 30         65 my ($list_type, $list_css) = $self->_processListConfig(%config);
    228             # now compile the subroutine in the current environment
    229 30         4014 return eval $self->LIST_FUNCTION_CODE_STRING;
    230             }
    231              
    232             ## list item config processing
    233              
    234             sub _processListItemConfig {
    235 30     30   43 my ($self, %config) = @_;
    236            
    237 30         42 my $list_item_css = "";
    238 30 100       73 if (exists $config{list_item_css}) {
        100          
    239 6         16 $list_item_css = $config{tags}->{STYLE} . $config{list_item_css} . "'";
    240             }
    241             elsif (exists $config{list_item_css_class}) {
    242 9         21 $list_item_css = $config{tags}->{CLASS} . $config{list_item_css_class} . "'";
    243             }
    244             # otherwise do nothing and stick with default
    245              
    246 30         22 my $expanded_item_css = "";
    247 30 100       56 if (exists $config{expanded_item_css}) {
        100          
    248 6         9 $expanded_item_css = $config{tags}->{STYLE} . $config{expanded_item_css} . "'";
    249             }
    250             elsif (exists $config{expanded_item_css_class}) {
    251 9         20 $expanded_item_css = $config{tags}->{CLASS} . $config{expanded_item_css_class} . "'";
    252             }
    253             # otherwise do nothing and stick with default
    254            
    255 30         21 my $node_formatter;
    256             $node_formatter = $config{node_formatter}
    257 30 100 66     98 if (exists $config{node_formatter} && ref($config{node_formatter}) eq "CODE");
    258            
    259 30         70 return ($list_item_css, $expanded_item_css, $node_formatter);
    260             }
    261              
    262             sub _buildListItemFunction {
    263 18     18   39 my ($self, %config) = @_;
    264             # process the configuration directives
    265 18         39 my ($list_item_css, $expanded_item_css, $node_formatter) = $self->_processListItemConfig(%config);
    266             # now compile the subroutine in the current environment
    267 18         1768 return eval $self->LIST_ITEM_FUNCTION_CODE_STRING;
    268             }
    269              
    270             1;
    271              
    272             __END__