File Coverage

lib/HTML/FormWidgets/File.pm
Criterion Covered Total %
statement 52 123 42.2
branch 6 26 23.0
condition 0 3 0.0
subroutine 12 22 54.5
pod 2 2 100.0
total 72 176 40.9


line stmt bran cond sub pod time code
1             package HTML::FormWidgets::File;
2              
3 1     1   954 use strict;
  1         1  
  1         45  
4 1     1   6 use warnings;
  1         2  
  1         38  
5 1     1   6 use parent 'HTML::FormWidgets';
  1         2  
  1         7  
6              
7 1     1   85 use English qw( -no_match_vars );
  1         2  
  1         10  
8 1     1   1384 use IO::File;
  1         11714  
  1         190  
9 1     1   759 use PPI;
  1         131068  
  1         71  
10 1     1   885 use PPI::HTML;
  1         7521  
  1         54  
11 1     1   13 use Text::ParseWords;
  1         3  
  1         185  
12 1     1   874 use Text::Tabs;
  1         847  
  1         1962  
13              
14             __PACKAGE__->mk_accessors( qw( header header_class number
15             path select subtype tabstop ) );
16              
17             my $HASH_CHAR = chr 35;
18              
19             # Private functions
20             my $_even_or_odd = sub {
21                return ($_[ 0 ] + 1) % 2 == 0 ? ' even' : ' odd';
22             };
23              
24             my $_column_class = sub {
25                return $_even_or_odd->( $_[ 0 ] ).'_col';
26             };
27              
28             my $_row_class = sub {
29                return $_even_or_odd->( $_[ 0 ] ).'_row';
30             };
31              
32             # Private methods
33             my $_add_line_number = sub {
34                my ($self, $r_no, $c_no) = @_;
35              
36                my $class = 'first lineNumber'.$_column_class->( $c_no );
37              
38                return $self->hacc->td( { class => $class }, $r_no + 1 );
39             };
40              
41             my $_add_row_count = sub {
42                my ($self, $n_rows) = @_;
43              
44                return $self->add_hidden( '_'.($self->name || q()).'_nrows', $n_rows );
45             };
46              
47             my $_add_select_box = sub {
48                my ($self, $r_no, $c_no, $val) = @_; my $hacc = $self->hacc;
49              
50                my $args = { label => q(), name => $self->name.".select${r_no}",
51                              value => $val };
52                my $class = $self->subtype.$_column_class->( $c_no );
53              
54                return $hacc->td( { class => $class }, $hacc->checkbox( $args ) );
55             };
56              
57             my $_build_table = sub {
58                my ($self, $text, $header_cells, $row_cells) = @_; my $hacc = $self->hacc;
59              
60                my ($cells, $class, $val); my $r_no = 0; my $rows = q(); my $c_max = 1;
61              
62                for my $line (split m{ \n }mx, $text) {
63                   my $c_no = 0; my $lead = q();
64              
65                   my ($ncells, $cells, $val) = $row_cells->( $line, $r_no );
66              
67                   if ($cells) {
68                      $self->number and $lead = $self->$_add_line_number( $r_no, $c_no++ );
69                      $self->select >= 0
70                         and $lead .= $self->$_add_select_box( $r_no, $c_no++, $val );
71                      $class = $self->subtype.$_row_class->( $r_no );
72                      $rows .= $hacc->tr( { class => $class }, $lead.$cells );
73                      $r_no++;
74                   }
75              
76                   $c_no += $ncells; $c_no > $c_max and $c_max = $c_no;
77                }
78              
79                $class = $self->header_class.' minimal';
80                $self->number
81                   and $cells = $hacc->th( { class => $class }, $self->loc( $HASH_CHAR ) );
82                $self->select >= 0
83                   and $cells .= $hacc->th( { class => $class }, $self->loc( 'M' ) );
84                $cells .= $header_cells->( $c_max, $self->select < 0 ? 1 : 2 );
85                $rows = $hacc->tr( $cells ).$rows;
86                $self->$_add_row_count( $r_no );
87              
88                return $hacc->table( { cellspacing => 0, class => $self->subtype }, $rows );
89             };
90              
91             sub _render_csv {
92 0     0   0    my ($self, $text) = @_; my $hacc = $self->hacc;
  0         0  
93              
94                my $header_cells = sub {
95 0     0   0       my ($c_max, $c_no) = @_; my $cells = q();
  0         0  
96              
97 0 0       0       my @headers = $self->header->[ 0 ] ? @{ $self->header } : ('A' .. 'Z');
  0         0  
98              
99 0         0       for my $header (@headers) {
100 0         0          $cells .= $hacc->th( { class => $self->header_class }, $header );
101 0 0       0          ++$c_no >= $c_max and last;
102                   }
103              
104 0         0       return $cells;
105 0         0    };
106                my $row_cells = sub {
107 0     0   0       my ($line, $r_no) = @_;
108              
109 0         0       my $cells = q(); my $f_no = 0; my $val = q();
  0         0  
  0         0  
110              
111 0         0       for my $fld (parse_line( ',', 0, $hacc->escape_html( $line, 0 ) )) {
112 0 0 0     0          if ($r_no == 0 and $line =~ m{ \A \# }mx) {
113 0 0       0             $f_no == 0 and $fld = substr $fld, 1;
114 0         0             $self->header->[ $f_no ] = $fld;
115                      }
116                      else {
117 0 0       0             my $class = $self->subtype
118                                    .$_column_class->( ($self->select < 0 ? 1 : 2) + $f_no );
119              
120 0         0             $cells .= $hacc->td( { class => $class }, $fld );
121                      }
122              
123 0 0       0          $f_no == $self->select and $val = $fld; $f_no++;
  0         0  
124                   }
125              
126 0         0       return ($f_no, $cells, $val);
127 0         0    };
128              
129 0         0    return $self->$_build_table( $text, $header_cells, $row_cells );
130             }
131              
132             sub _render_html {
133 0     0   0    my ($self, $path) = @_; my $hacc = $self->hacc;
  0         0  
134              
135 0         0    my $pat = $self->options->{root}; $self->container( 0 );
  0         0  
136              
137 0 0       0    $path =~ m{ \A $pat }msx and $path =~ s{ \A $pat }{/}msx;
138              
139 0         0    return $hacc->iframe( { class => $self->subtype,
140                                        src => $self->uri_for( $path ),
141                                        scrolling => q(auto) }, '&#160;' );
142             }
143              
144             sub _render_logfile {
145 0     0   0    my ($self, $text) = @_; my $hacc = $self->hacc;
  0         0  
146              
147 0         0    my $r_no = 0; my $rows = q(); my $cells; $self->container( 0 );
  0         0  
  0         0  
  0         0  
148              
149             # TODO: Add Prev and next links to append div. Interior log file sequences
150                my $header_cells = sub {
151 0     0   0       my ($c_max, $c_no) = @_; my $text = $self->loc( 'Logfile' );
  0         0  
152              
153 0         0       return $hacc->th( { class => $self->header_class }, $text );
154 0         0    };
155                my $row_cells = sub {
156 0     0   0       my ($line, $r_no) = @_; $line = $hacc->escape_html( $line, 0 );
  0         0  
157              
158 0         0       my $class = $self->subtype.$_column_class->( 1 );
159 0         0       my $cells = $hacc->td( { class => $class }, $line );
160              
161 0         0       return (1, $cells, $line);
162 0         0    };
163              
164 0         0    return $self->$_build_table( $text, $header_cells, $row_cells );
165             }
166              
167             sub _render_source {
168 0     0   0    my ($self, $text) = @_; my $hacc = $self->hacc; $self->container( 0 );
  0         0  
  0         0  
169              
170 0         0    $tabstop = $self->tabstop; $text = expand( $text ); # Text::Tabs
  0         0  
171              
172 0         0    my $document = PPI::Document->new( \$text );
173 0         0    my $highlight = PPI::HTML->new( line_numbers => 1 );
174 0         0    my @lines = split m{ <br>\n }msx, $highlight->html( $document );
175              
176 0         0    for my $lno (0 .. $#lines) {
177 0 0       0       $lines[ $lno ] =~ s{ \A </span> }{}msx and $lines[ $lno-1 ] .= q(</span>);
178 0         0       $lines[ $lno ] =~ s{ <span\s+class="line_number">\s*\d+:\s+</span> }{}msx;
179                }
180              
181 0         0    $text = join "\n", @lines;
182              
183                my $header_cells = sub {
184 0     0   0       my ($c_max, $c_no) = @_; my $heading = $self->loc( 'Source Code' );
  0         0  
185              
186 0         0       return $hacc->th( { class => $self->header_class }, $heading );
187 0         0    };
188                my $row_cells = sub {
189 0     0   0       my ($line, $r_no) = @_;
190              
191 0         0       my $class = $self->subtype.$_column_class->( 1 );
192 0         0       my $cells = $hacc->td( { class => $class }, $line );
193              
194 0         0       return (1, $cells, $line);
195 0         0    };
196              
197 0         0    return $self->$_build_table( $text, $header_cells, $row_cells );
198             }
199              
200             sub _render_text {
201 1     1   1    my ($self, $text) = @_; my $hacc = $self->hacc;
  1         3  
202              
203 1         5    $self->container_class( 'container textfile' );
204              
205 1         9    return $hacc->pre( $hacc->escape_html( $text, 0 ) );
206             }
207              
208             # Public methods
209             sub init {
210 1     1 1 3    my ($self, $args) = @_;
211              
212 1         5    $self->header ( [] );
213 1         8    $self->header_class( 'normal' );
214 1         6    $self->number ( 1 );
215 1         5    $self->path ( undef );
216 1         7    $self->select ( -1 );
217 1         13    $self->subtype ( 'text' );
218 1         6    $self->tabstop ( 3 );
219 1         6    return;
220             }
221              
222             sub render_field { # Subtypes: csv, html, logfile, source, and text
223 2     2 1 5    my ($self, $args) = @_;
224              
225 2 50       6    my $path = $self->path or return $self->loc( 'Path not specified' );
226              
227 2 50       16    $self->subtype or return $self->loc( 'Subtype not specified' );
228 2 50       13    $self->subtype eq 'html' and return $self->_render_html( $path );
229              
230 2 100       56    -f $path or return $self->loc( 'Path [_1] not found', $path );
231              
232 1 50       13    my $rdr = IO::File->new( $path, 'r' )
233                   or return $self->loc( 'Path [_1] cannot open', $path );
234 1         135    my $text = do { local $RS = undef; <$rdr> }; $rdr->close;
  1         5  
  1         22  
  1         8  
235 1         14    my $method = '_render_'.$self->subtype;
236              
237 1         8    return $self->$method( $text );
238             }
239              
240             1;
241              
242             # Local Variables:
243             # mode: perl
244             # tab-width: 3
245             # End:
246