File Coverage

lib/HTML/FormWidgets.pm
Criterion Covered Total %
statement 107 166 64.4
branch 27 68 39.7
condition 13 53 24.5
subroutine 21 31 67.7
pod 18 18 100.0
total 186 336 55.3


line stmt bran cond sub pod time code
1             package HTML::FormWidgets;
2              
3 1     1   1140 use 5.01;
  1         3  
4 1     1   5 use strict;
  1         2  
  1         25  
5 1     1   5 use warnings;
  1         2  
  1         33  
6 1     1   5 use version; our $VERSION = qv( sprintf '0.25.%d', q$Rev: 1 $ =~ /\d+/gmx );
  1         1  
  1         10  
7 1     1   815 use parent 'Class::Accessor::Fast';
  1         285  
  1         6  
8              
9 1     1   4775 use Class::Load qw( is_class_loaded load_class );
  1         20117  
  1         67  
10 1     1   912 use English qw( -no_match_vars );
  1         2145  
  1         7  
11 1     1   1241 use HTML::Accessors;
  1         6511  
  1         33  
12 1     1   7 use List::Util qw( any );
  1         2  
  1         89  
13 1     1   5 use Scalar::Util qw( blessed );
  1         3  
  1         44  
14 1     1   5 use Try::Tiny;
  1         4  
  1         4608  
15              
16             my $COLON = ' : ';
17             my $LSB = '[';
18             my $NB = ' † ';
19             my $NUL = q();
20             my $SPACE = ' ' x 3;
21             my $SPC = q( );
22             my $TTS = ' ~ ';
23             my $OPTIONS = {
24                content_type => 'text/html',
25                hidden => sub { {} },
26                js_object => 'html_formwidgets',
27                language => 'en',
28                l10n => undef,
29                list_key => 'items',
30                literal_js => sub { [] },
31                max_pwidth => undef,
32                ns => 'default',
33                optional_js => sub { [] },
34                pwidth => 30,
35                skip => sub { return { qw( options 1 id 1 name 1 type 1 ) } },
36                uri_for => undef,
37                width => 1000, };
38             my $ATTRS = {
39                check_field => undef, class => $NUL,
40                clear => $NUL, container => 1,
41                container_class => 'container', container_id => undef,
42                default => undef, frame_class => $NUL,
43                hacc => undef, hint_title => undef,
44                id => undef, name => undef,
45                onblur => undef, onchange => undef,
46                onkeypress => undef, options => undef,
47                pclass => 'prompt', pwidth => undef,
48                prompt => $NUL, readonly => 0,
49                required => 0, sep => undef,
50                stepno => undef, text => $NUL,
51                tip => $NUL, tiptype => 'dagger',
52                type => undef, };
53              
54             __PACKAGE__->mk_accessors( keys %{ $ATTRS } );
55              
56             # Private functions
57             my $_arg_list = sub {
58                my (@args) = @_; $args[ 0 ] or return {};
59              
60                return ref $args[ 0 ] eq 'HASH' ? $args[ 0 ] : { @args };
61             };
62              
63             my $_collect_items = sub {
64                my ($nitems, $stack) = @_; my $html = $NUL; $nitems or return $NUL;
65              
66                for (1 .. $nitems) {
67                   my $args = pop @{ $stack }; $html = ($args->{content} // $NUL).$html;
68                }
69              
70                return $html;
71             };
72              
73             my $_form_wrapper = sub {
74                my ($options, $item, $stack) = @_; my $content = $item->{content};
75              
76                my $hacc = $options->{hacc};
77                my $html = $_collect_items->( $content->{nitems}, $stack );
78                my $attr = $content->{config} // $content->{attrs} // {};
79              
80                $item->{content} = "\n".$hacc->form( $attr, "\n".$html );
81              
82                return $item;
83             };
84              
85             my $_group_fields = sub {
86                my ($options, $item, $stack) = @_; my $content = $item->{content}; my $class;
87              
88                $class = delete $content->{frame_class} and $item->{class} = $class;
89              
90                my $hacc = $options->{hacc};
91                my $legend = $hacc->legend( $content->{text} );
92                my $html = $_collect_items->( $content->{nitems}, $stack );
93              
94                $item->{content} = "\n".$hacc->fieldset( "\n".$legend.$html );
95                return $item;
96             };
97              
98             my $_inject = sub {
99                return { %{ $_[ 0 ] }, options => $_[ 1 ] };
100             };
101              
102             my $_merge_attributes = sub {
103                my ($dest, $src) = @_;
104              
105                for my $k (grep { not exists $dest->{ $_ } or not defined $dest->{ $_ } }
106                           keys %{ $src }) {
107                   my $v = $src->{ $k };
108              
109                   defined $v and ref $v eq 'CODE' and $v = $v->();
110                   defined $v and $dest->{ $k } = $v;
111                }
112              
113                return $dest;
114             };
115              
116             my $_build_widget = sub {
117                my ($class, $opts, $item, $stack) = @_; $item or return;
118              
119                (ref $item and (ref $item->{content} eq 'HASH' or blessed $item->{content}))
120                   or return $item;
121              
122                my $content = $item->{content};
123              
124                $content->{form} and return $_form_wrapper->( $opts, $item, $stack );
125              
126                if ($content->{group}) {
127                   $opts->{skip_groups} and return;
128                   return $_group_fields->( $opts, $item, $stack );
129                }
130              
131                my $widget = blessed $content ? $content
132                           : $content->{widget} ? $class->new( $_inject->( $content, $opts ))
133                                                : undef;
134              
135                $widget or return $item;
136                $widget->frame_class and $item->{class} = $widget->frame_class;
137                $item->{content} = $widget->render;
138                return $item;
139             };
140              
141             # Private object methods
142             my $_bootstrap = sub { # Bare minimum is fields + id to get a useful widget
143                my ($self, $args) = @_;
144              
145                for my $attr (grep { exists $args->{ $_ } } qw( id name type )) {
146                   $self->$attr( $args->{ $attr } );
147                }
148              
149             # Defaults id from name
150                my $id = $self->id; my $name = $self->name; my $type = $self->type;
151              
152                if ($id and not $name) {
153                   $name = $self->name( $id =~ m{ \. }mx ? (split m{ \. }mx, $id)[ 1 ]
154                                                         : (split m{ \_ }mx, $id)[ -1 ] );
155                }
156              
157                not $id and $name and $id = $self->id( $name ); $args->{options} //= {};
158              
159             # We can get the widget type from the config file
160                if (not $type and $id and exists $args->{options}->{fields}) {
161                   my $fields = $args->{options}->{fields};
162              
163                   exists $fields->{ $id } and exists $fields->{ $id }->{type}
164                      and $type = $self->type( $fields->{ $id }->{type} );
165                }
166                else { $args->{options}->{fields} //= {} }
167              
168             # This is the default widget type if not overidden in the config
169                $type or $type = $self->type( 'textfield' );
170                $name or $self->name( $type );
171                return;
172             };
173              
174             my $_build_hacc = sub {
175             # Now we can create HTML elements like we could with CGI.pm
176                my $self = shift; my $hacc = $self->options->{hacc};
177              
178                $hacc or $hacc = HTML::Accessors->new
179                   ( { content_type => $self->options->{content_type} } );
180                return $hacc
181             };
182              
183             my $_build_pwidth = sub { # Calculate the prompt width
184                my $self = shift;
185                my $opts = $self->options;
186                my $width = $opts->{width} || 1024;
187                my $pwidth = defined $self->pwidth ? $self->pwidth : $opts->{pwidth};
188              
189                if ($pwidth and $pwidth =~ m{ \A \d+ \z }mx) {
190                   $pwidth = int $pwidth * $width / 100;
191                   $opts->{max_pwidth} and $pwidth > $opts->{max_pwidth}
192                      and $pwidth = $opts->{max_pwidth};
193                   $pwidth .= 'px';
194                }
195              
196                return $pwidth;
197             };
198              
199             my $_build_sep = sub {
200                my $self = shift; my $sep = $self->sep;
201              
202                not defined $sep and $self->prompt and $sep = $COLON;
203                    defined $sep and $sep eq 'space' and $sep = $SPACE;
204                    defined $sep and $sep eq 'none' and $sep = $NUL;
205                return $sep;
206             };
207              
208             my $_init_args = sub {
209                my ($self, $args) = @_; my $skip = $self->options->{skip}; my $v;
210              
211                for (grep { not $skip->{ $_ } } keys %{ $args }) {
212                   exists $self->{ $_ } and defined ($v = $args->{ $_ }) and $self->$_( $v );
213                }
214              
215                return;
216             };
217              
218             my $_init_fields = sub {
219                my ($self, $args) = @_; my $fields = $args->{options}->{fields}; my $id;
220              
221                $fields and $id = $self->id and exists $fields->{ $id }
222                   and $self->$_init_args( $fields->{ $id } );
223                return;
224             };
225              
226             my $_init_hint_title = sub {
227                my ($self, $args) = @_;
228              
229                $args->{hint_title} and return $self->hint_title( $args->{hint_title} );
230              
231                return $self->hint_title( $self->loc( 'Hint' ) );
232             };
233              
234             my $_init_options = sub {
235                $_[ 0 ]->options( $_merge_attributes->( $_[ 1 ]->{options}, $OPTIONS ) );
236                return;
237             };
238              
239             my $_next_step = sub {
240                return $_[ 0 ]->options->{iterator}->();
241             };
242              
243             my $_render_field = sub {
244                my $self = shift; my $id = $self->id; my $args = {};
245              
246                $id and $args->{id } = $id;
247                $self->name and $args->{name } = $self->name;
248                $self->check_field and $args->{class } = 'server';
249                $self->required and $args->{class } .= ' required';
250                $self->onblur and $args->{onblur } = $self->onblur;
251                $self->onkeypress and $args->{onkeypress} = $self->onkeypress;
252                $self->readonly and $args->{readonly } = 'readonly';
253              
254                defined $self->default and $args->{default} = $self->default;
255              
256                my $html = $self->render_field( $args );
257                my $name = $self->options->{name} // $NUL;
258                my $ns = $self->options->{ns } // $NUL;
259              
260                $self->check_field and $self->add_literal_js( 'server', $id, {
261                   args => "[ '${id}', '${name}', '${ns}' ]", event => "'blur'",
262                   method => "'checkField'" } );
263                return $html;
264             };
265              
266             my $_set_error = sub {
267                my ($self, $error) = @_; return $self->text( $error );
268             };
269              
270             my $_build_stepno = sub {
271                my $self = shift; my $stepno = $self->stepno;
272              
273                defined $stepno and ref $stepno eq 'HASH' and return $stepno;
274                defined $stepno and $stepno eq 'none' and return $NUL;
275                defined $stepno and $stepno == -1 and $stepno = $self->$_next_step;
276                defined $stepno and $stepno == 0 and $stepno = $SPACE;
277                        $stepno and $stepno ne $SPACE and $stepno = "${stepno}.";
278                return $stepno;
279             };
280              
281             my $_ensure_class_loaded = sub {
282                my ($self, $class) = @_; my $error;
283              
284                try { load_class( $class ) } catch { $error = $self->$_set_error( $_ ) };
285              
286                $error and return;
287              
288                is_class_loaded( $class )
289                   or ( $self->$_set_error
290                        ( "Class ${class} loaded but package undefined" ) and return );
291              
292                return bless $self, $class; # Rebless ourself as subclass
293             };
294              
295             my $_init = sub {
296                my ($self, $args) = @_;
297              
298                $self->$_init_options ( $args );
299                $self->init ( $args ); # Allow subclass to set it's own defaults
300                $self->$_init_fields ( $args );
301                $self->$_init_args ( $args );
302                $self->$_init_hint_title( $args );
303                $self->hacc ( $self->$_build_hacc );
304                $self->pwidth ( $self->$_build_pwidth );
305                $self->sep ( $self->$_build_sep );
306                $self->stepno ( $self->$_build_stepno );
307                return;
308             };
309              
310             # Class methods
311             sub build {
312 0   0 0 1 0    my ($class, $options) = @_; $options //= {}; my $step = 0;
  0         0  
  0         0  
313              
314 0   0     0    my $data = delete $options->{data } // [];
315 0   0     0    my $key = $options->{list_key } //= $OPTIONS->{list_key };
316 0   0     0    my $type = $options->{content_type} //= $OPTIONS->{content_type};
317              
318 0   0     0    $options->{hacc } //= HTML::Accessors->new( content_type => $type );
319 0   0 0   0    $options->{iterator} //= sub { return ++$step };
  0         0  
320              
321 0 0       0    for my $list (grep { $_ and ref $_ eq 'HASH' } @{ $data }) {
  0         0  
  0         0  
322 0 0       0       ref $list->{ $key } eq 'ARRAY' or next; my @stack = ();
  0         0  
323              
324 0         0       for my $item (@{ $list->{ $key } }) {
  0         0  
325 0         0          my $built = $_build_widget->( $class, $options, $item, \@stack );
326              
327 0 0       0          $built and push @stack, $built;
328                   }
329              
330 0         0       $list->{ $key } = \@stack;
331                }
332              
333 0         0    return $data;
334             }
335              
336             sub new {
337 27     27 1 25796    my ($self, @args) = @_; my $args = $_arg_list->( @args );
  27         71  
338              
339             # Start with some hard coded defaults
340 27   33     42    my $new = bless { %{ $ATTRS } }, blessed $self || $self;
  27         497  
341              
342             # Set minimum requirements from the supplied args and the defaults
343 27         103    $new->$_bootstrap( $args );
344              
345             # Your basic factory method trick
346 27         74    my $class = ucfirst $new->type;
347 27 50       214       $class = ('+' eq substr $class, 0, 1)
348                          ? (substr $class, 1) : __PACKAGE__."::${class}";
349              
350 27         55    $new->$_ensure_class_loaded( $class );
351 27         60    $new->$_init( $args ); # Complete the initialization
352              
353 27         128    return $new;
354             }
355              
356             # Public object methods
357             sub add_hidden {
358 1     1 1 11    my ($self, $name, $value) = @_;
359              
360 1   50     3    my $key = $self->options->{list_key} // 'items';
361 1   50     9    my $hidden = $self->options->{hidden } // {}; $hidden->{ $key } //= [];
  1   50     12  
362              
363 1         2    push @{ $hidden->{ $key } }, {
  1         5  
364                   content => "\n".$self->hacc->input( {
365                      name => $name, type => 'hidden', value => $value } ) };
366 1         48    return;
367             }
368              
369             sub add_literal_js {
370 3     3 1 38    my ($self, $js_class, $id, $config) = @_; my $list = $NUL;
  3         6  
371              
372 3 50 33     29    ($js_class and $id and $config) or return;
      33        
373              
374 3 50       8    if (ref $config eq 'HASH') {
375 3         6       while (my ($k, $v) = each %{ $config }) {
  17         54  
376 14 100 100     28          if ($k) { $list and $list .= ', '; $list .= "${k}: ".($v || 'null') }
  14 50       24  
  14         52  
377                   }
378                }
379 0         0    else { $list = $config };
380              
381 3   50     10    my $obj = $self->options->{js_object}; $self->options->{literal_js} //= [];
  3         19  
382              
383 3         17    push @{ $self->options->{literal_js} },
  3         10  
384                   "${obj}.config.${js_class}[ '${id}' ] = { ${list} };";
385 3         30    return;
386             }
387              
388             sub add_optional_js {
389 1   50 1 1 3    my ($self, @args) = @_; my $scripts = $self->options->{optional_js} //= [];
  1         4  
390              
391 1         7    for my $file (@args) {
392 2 50   1   7       any { $_ eq $file } @{ $scripts } or push @{ $scripts }, $file;
  2         8  
  1         3  
  2         16  
393                }
394              
395 1         4    return;
396             }
397              
398             sub inflate {
399 4     4 1 6    my ($self, $args) = @_;
400              
401 4 50 33     26    (defined $args and ref $args eq 'HASH') or return $args;
402              
403 4         12    return __PACKAGE__->new( $_inject->( $args, $self->options ) )->render;
404             }
405              
406       0 1   sub init { # Can be overridden in factory subclass
407             }
408              
409             sub is_xml {
410 0 0   0 1 0    return $_[ 0 ]->options->{content_type} =~ m{ / (.*) xml \z }mx ? 1 : 0;
411             }
412              
413             sub loc {
414 34     34 1 92    my ($self, $text, @rest) = @_; my $opts = $self->options; my $l10n;
  34         85  
  34         134  
415              
416 34 50       88    if (defined ($l10n = $opts->{l10n})) {
417 0         0       my $args = { language => $opts->{language}, ns => $opts->{ns} };
418              
419 0         0       return $l10n->( $args, $text, @rest );
420                }
421              
422 34 50       68    $text or return; $text = $NUL.$text; # Stringify
  34         80  
423              
424             # Expand positional parameters of the form [_<n>]
425 34 100       264    0 > index $text, $LSB and return $text;
426              
427 1 50 33     12    my @args = $rest[0] && ref $rest[0] eq 'ARRAY' ? @{ $rest[0] } : @rest;
  0         0  
428              
429 1         3    push @args, map { '[?]' } 0 .. 10;
  11         20  
430 1         14    $text =~ s{ \[ _ (\d+) \] }{$args[ $1 - 1 ]}gmx;
431 1         5    return $text;
432             }
433              
434             sub render {
435 28 50 0 28 1 1041    my $self = shift; $self->type or return $self->text || $NUL;
  28         123  
436              
437 28 50       164    my $field = $self->$_render_field or return $NUL; my $lead = $NUL;
  28         49  
438              
439 28 50       76    $self->stepno and $lead .= $self->render_stepno;
440 28 50       181    $self->prompt and $lead .= $self->render_prompt;
441 28 50       165    $self->sep and $lead .= $self->render_separator;
442 28 50       256    $self->tip and $field = $self->render_tip( $field );
443 28 50       162    $self->check_field and $field = $self->render_check_field( $field );
444              
445 28         152    $field = $lead.$field;
446              
447 28 100       122    $self->container and $field = $self->render_container( $field );
448 28 50       707    $self->clear eq 'left' and $field = $self->hacc->br.$field;
449 28         234    return "\n${field}";
450             }
451              
452             sub render_check_field {
453 0     0 1 0    my ($self, $field) = @_; my $hacc = $self->hacc; my $id = $self->id;
  0         0  
  0         0  
454              
455 0         0    $field .= $hacc->span( { class => 'hidden', id => "${id}_ajax" } );
456              
457 0         0    return $hacc->div( { class => 'field_group' }, $field );
458             }
459              
460             sub render_container {
461 17     17 1 154    my ($self, $field) = @_; my $args = { class => $self->container_class };
  17         74  
462              
463 17 50       147    $self->container_id and $args->{id} = $self->container_id;
464              
465 17         98    return $self->hacc->div( $args, $field );
466             }
467              
468             sub render_field {
469 0 0   0 1 0    my ($self, $args) = @_; $self->text and return $self->text;
  0         0  
470              
471 0   0     0    my $id = $args->{id} || '*unknown id*';
472              
473 0         0    return $self->$_set_error( "No render_field method for field ${id}" );
474             }
475              
476             sub render_prompt {
477 0     0 1 0    my $self = shift; my $args = { class => $self->pclass };
  0         0  
478              
479 0 0 0     0    $self->id and $args->{for} = $self->id and $args->{id} = $self->id.'_label';
480              
481 0 0       0    $self->pwidth and $args->{style} .= 'width: '.$self->pwidth.';';
482              
483 0         0    return $self->hacc->label( $args, $self->prompt );
484             }
485              
486             sub render_separator {
487 0     0 1 0    my $self = shift; my $class = 'separator';
  0         0  
488              
489 0 0       0    if ($self->sep eq 'break') {
490 0         0       $class = 'separator_break'; $self->sep( $NUL );
  0         0  
491                }
492              
493 0         0    return $self->hacc->span( { class => $class }, $self->sep );
494             }
495              
496             sub render_stepno {
497 0     0 1 0    my $self = shift; my $stepno = $self->stepno;
  0         0  
498              
499 0 0       0    ref $stepno eq 'HASH' and return $self->inflate( $stepno );
500              
501 0         0    return $self->hacc->span( { class => 'step_number' }, $stepno );
502             }
503              
504             sub render_tip {
505 0     0 1 0    my ($self, $field) = @_; my $hacc = $self->hacc; my $break = 'EOL';
  0         0  
  0         0  
506              
507 0         0    (my $tip = $self->tip) =~ s{ \n }{$break}gmx;
508              
509 0 0       0    $tip !~ m{ $TTS }mx and $tip = $self->hint_title.$TTS.$tip;
510 0         0    $tip =~ s{ \s+ }{ }gmx;
511              
512 0         0    my $args = { class => 'help tips', title => $tip };
513              
514 0 0       0    $self->tiptype eq 'dagger' or return $hacc->span( $args, "\n${field}" );
515              
516 0         0    $field .= $hacc->span( $args, $NB );
517              
518 0         0    return $hacc->div( { class => 'field_group' }, "\n".$field );
519             }
520              
521             sub uri_for {
522 3 100   3 1 13    my ($self, @args) = @_; defined $args[ 0 ] or return;
  3         12  
523              
524                ($args[ 0 ] !~ m{ \A http[s]?: }mx and defined $self->options->{uri_for})
525 1 50 33     12       and return $self->options->{uri_for}->( @args );
526              
527 1         9    return $args[ 0 ];
528             }
529              
530             1;
531              
532             __END__
533            
534             =pod
535            
536             =encoding utf8
537            
538             =begin html
539            
540             <a href="https://travis-ci.org/pjfl/p5-html-formwidgets"><img src="https://travis-ci.org/pjfl/p5-html-formwidgets.svg?branch=master" alt="Travis CI Badge"></a>
541             <a href="http://badge.fury.io/pl/HTML-FormWidgets"><img src="https://badge.fury.io/pl/HTML-FormWidgets.svg" alt="CPAN Badge"></a>
542             <a href="http://cpants.cpanauthors.org/dist/HTML-FormWidgets"><img src="http://cpants.cpanauthors.org/dist/HTML-FormWidgets.png" alt="Kwalitee Badge"></a>
543            
544             =end html
545            
546             =head1 Name
547            
548             HTML::FormWidgets - Create HTML user interface components
549            
550             =head1 Version
551            
552             Describes version v0.25.$Rev: 1 $ of L<HTML::FormWidgets>
553            
554             =head1 Synopsis
555            
556             use HTML::FormWidgets;
557            
558             my $widget = HTML::FormWidgets->new( id => 'test' );
559            
560             print $widget->render;
561             # <div class="container">
562             # <input value="" name="test" type="text" id="test" class="ifield" size="40">
563             # </div>
564            
565             =head1 Description
566            
567             Transforms a Perl data structure which defines one or more "widgets"
568             into HTML or XHTML. Each widget is comprised of these optional
569             components: a line or question number, a prompt string, a separator,
570             an input field, additional field help, and Ajax field error string.
571            
572             Input fields are selected by the widget C<type> attribute. A factory
573             subclass implements the method that generates the HTML or XHTML for
574             that input field type. Adding more widget types is straightforward
575            
576             This module is using the L<MooTools|http://mootools.net/> Javascript
577             library to modify default browser behaviour
578            
579             This module is used by L<CatalystX::Usul::View> and as such its
580             main use is as a form generator within a L<Catalyst> application
581            
582             =head1 Configuration and Environment
583            
584             The following are passed to L</build> in the C<config> hash (they
585             reflect this modules primary use within a L<Catalyst> application):
586            
587             =over 3
588            
589             =item C<assets>
590            
591             Some of the widgets require image files. This attribute is used to
592             create the URI for those images
593            
594             =item C<content_type>
595            
596             Either C<application/xhtml+xml> which generates XHTML 1.1 or
597             C<text/html> which generates HTML 4.01 and is the default
598            
599             =item C<fields>
600            
601             This hash ref contains the fields definitions. Static parameters for
602             each widget can be stored in configuration files. This reduces the
603             number of attributes that have to be passed in the call to the
604             constructor
605            
606             =item C<hidden>
607            
608             So that the L</File> and L</Table> subclasses can store the number
609             of rows added as the hidden form attribute C<nRows>
610            
611             =item C<js_object>
612            
613             This is the name of the global Javascript variable that holds
614             C<config> object. Defaults to C<html_formwidgets>
615            
616             =item C<root>
617            
618             The path to the document root for this application
619            
620             =item C<width>
621            
622             Width in pixels of the browser window. This is used to calculate the
623             width of the field prompt. The field prompt needs to be a fixed length
624             so that the separator colons align vertically
625            
626             =item C<templatedir>
627            
628             The path to template files used by the L</Template> subclass
629            
630             =back
631            
632             Sensible defaults are provided by C<new> if any of the above are undefined
633            
634             =head1 Subroutines/Methods
635            
636             =head2 Public Methods
637            
638             =head3 build
639            
640             HTML::FormWidgets->build( $config_hash );
641            
642             The L</build> method iterates over a data structure that represents the
643             form. One or more lists of widget definitions are processed in
644             turn. New widgets are created and their rendered output replaces their
645             definitions in the data structure
646            
647             =head3 new
648            
649             $widget = HTML::FormWidgets->new( [{] key1 => value1, ... [}] );
650            
651             Construct a widget. Mostly this is called by the L</build> method. It
652             requires the factory subclass for the widget type.
653            
654             This method takes a large number of options with each widget using
655             only few of them. Each option is described in the factory subclasses
656             which use that option
657            
658             =head3 add_hidden
659            
660             $widget->add_hidden( $key, $value );
661            
662             The key / value pair are added to list of hidden input elements that will
663             be included in the page
664            
665             =head3 add_literal_js
666            
667             $widet->add_literal_js( $js_class_name, $id, $config );
668            
669             The config hash will be serialised and added to the literal Javascript on
670             the page
671            
672             =head3 add_optional_js
673            
674             $widget->add_optional_js( @filenames );
675            
676             The list of Javascript filenames (with extension, without path) are added
677             to the list of files which will be included on the page
678            
679             =head3 inflate
680            
681             $widget->inflate( $args );
682            
683             Creates L<new|HTML::FormWidgets/new> objects and returns their rendered output.
684             Called by the L</_render> methods in the factory subclasses to inflate
685             embeded widget definitions
686            
687             =head3 init
688            
689             $widget->init( $args );
690            
691             Initialises this object with data from the passed arguments. This is
692             usually overridden in the factory subclass which sets the default for
693             it's own attributes. In the base class this method does nothing
694            
695             =head3 is_xml
696            
697             $bool = $widget->is_xml;
698            
699             Returns true if the content type matches C<xml>
700            
701             =head3 loc
702            
703             $message_text = $widget->loc( $message_id, @args );
704            
705             Use the supplied key to return a value from the C<l10n> object. This
706             object was passed to the constructor and should localise the key to
707             the required language. The C<@args> list contains parameters to substituted
708             in place of the placeholders which have the form C<[_n]>
709            
710             =head3 render
711            
712             $html = $widget->render;
713            
714             Assemble the components of the generated widget. Each component is
715             concatenated onto a scalar which is the returned value. This method
716             calls L</render_field> which should be defined in the factory subclass for
717             this widget type.
718            
719             This method uses these attributes:
720            
721             =over 3
722            
723             =item C<clear>
724            
725             If set to C<left> the widget begins with an C<< <br> >> element
726            
727             =item C<stepno>
728            
729             If true it's value is wrapped in a C<< <span class="lineNumber"> >>
730             element and appended to the return value
731            
732             =item C<prompt>
733            
734             If true it's value is wrapped in a C<< <label class="prompt_class"> >>
735             element and appended to the return value. The prompt class is set by
736             the C<pclass> attribute. The C<id> attribute is used to set the C<for>
737             attribute of the C<< <label> >> element. The C<pwidth> attribute sets
738             the width style attribute in the C<< <label> >> element
739            
740             =item C<sep>
741            
742             If true it's value is wrapped in a C<< <span class="separator"> >>
743             element and appended to the return value
744            
745             =item C<container>
746            
747             If true the value return by the L</_render> method is wrapped in
748             C<< <span class="container"> >> element
749            
750             =item C<tip>
751            
752             The text of the field help. If C<tiptype> is set to C<dagger>
753             (which is the default) then a dagger symbol is
754             wrapped in a C<< <span class="help tips"> >> and this is appended to the
755             returned input field. The tip text is used as the C<title>
756             attribute. If the C<tiptype> is not set to C<dagger> then the help
757             text is wrapped around the input field itself
758            
759             =item C<check_field>
760            
761             Boolean which if true causes the field to generate server side check field
762             requests
763            
764             =back
765            
766             =head3 render_check_field
767            
768             Adds markup for the Ajax field validation
769            
770             =head3 render_container
771            
772             Wraps the rendered field in a containing div
773            
774             =head3 render_field
775            
776             Should be overridden in the factory subclass. It should return the markup
777             for the specified field type
778            
779             =head3 render_prompt
780            
781             Adds a label element to the generated markup
782            
783             =head3 render_separator
784            
785             Insert a spacing element between the prompt and the field
786            
787             =head3 render_stepno
788            
789             Markup containing the step number on the form if required
790            
791             =head3 render_tip
792            
793             Flyover tooltip field help text
794            
795             =head3 uri_for
796            
797             Makes absolute URI from relative paths by calling the supplied function
798            
799             =head2 Private Methods
800            
801             =head3 _bootstrap
802            
803             $widget->$_bootstrap( $args );
804            
805             Determine the C<id>, C<name> and C<type> attributes of the widget from
806             the supplied arguments
807            
808             =head3 _ensure_class_loaded
809            
810             $widget->$_ensure_class_loaded( $class );
811            
812             Once the factory subclass is known this method ensures that it is loaded
813             and then re-blesses the self referential object into the correct class
814            
815             =head3 _set_error
816            
817             $widget->$_set_error( $error_text );
818            
819             Stores the passed error message in the C<text> attribute so that it
820             gets rendered in place of the widget
821            
822             =head2 Private Subroutines
823            
824             =head3 _arg_list
825            
826             $args = $_arg_list->( @args );
827            
828             Accepts either a single argument of a hash ref or a list of key/value
829             pairs. Returns a hash ref in either case.
830            
831             =head3 _form_wrapper
832            
833             $item = $_form_wrapper->( $options, $item, $stack );
834            
835             Wraps the top C<nitems> number of widgets on the build stack in a C<<
836             <form> >> element
837            
838             =head3 _group_fields
839            
840             $item = $_group_fields->( $options, $item, $stack );
841            
842             Wraps the top C<nitems> number of widgets on the build stack in a C<<
843             <fieldset> >> element with a legend
844            
845             =head1 Factory Subclasses
846            
847             These are the possible values for the C<type> attribute which defaults
848             to C<textfield>. Each subclass implements the L</_render> method, it
849             receives a hash ref of options an returns a scalar containing some
850             XHTML.
851            
852             The distribution ships with the following factory subclasses:
853            
854             =head2 Anchor
855            
856             Returns an C<< <anchor> >> element with a class set from the C<class>
857             argument (which defaults to C<linkFade>). It's C<href> attribute
858             set to the C<href> argument. The anchor body is set to the C<text>
859             argument
860            
861             =head2 Async
862            
863             Returns a C<< <div> >> element with a class set from the C<class>
864             argument (which defaults to C<server>). The div body is set to the
865             C<text> argument. When the JavaScript C<onload> event handler fires it
866             will asynchronously load the content of the div if it is visible
867            
868             =head2 Button
869            
870             Generates an image button where C<name> identifies the image
871             file in C<assets> and is also used as the return value. The
872             button name is set to C<_verb>. If the image file does not
873             exist a regular input button is rendered instead
874            
875             =head2 Checkbox
876            
877             Return a C<< <checkbox> >> element of value C<value>. Use the
878             element's value as key to the C<labels> hash. The hash value
879             (which defaults null) is used as the displayed label. The
880             C<checked> argument determines the checkbox's initial
881             setting
882            
883             =head2 Chooser
884            
885             Creates a popup window which allows one item to be selected from a
886             long list of items
887            
888             =head2 Cloud
889            
890             Creates list of links from the data set supplied in the C<data> argument
891            
892             =head2 Date
893            
894             Return another C<< <textfield> >>, this time with a calendar icon
895             which when clicked pops up a Javascript date picker. Requires the
896             appropriate JavaScript library to have been loaded by the page. Attribute
897             C<width> controls the size of the C<< <textfield> >> (default 10
898             characters) and C<format> defaults to C<dd/mm/yyyy>. Setting the
899             C<readonly> attribute to true (which is the default) causes the input
900             C<< <textfield> >> to become read only
901            
902             =head2 File
903            
904             Display the contents of a file pointed to by C<path>. Supports the
905             following subtypes:
906            
907             =over 3
908            
909             =item C<csv>
910            
911             Return a table containing the CSV formatted file. This and the C<file>
912             subtype are selectable if C<select> >= 0 and represents the
913             column number of the key field
914            
915             =item C<file>
916            
917             Default subtype. Like the logfile subtype but without the C<< <pre> >> tags
918            
919             =item C<html>
920            
921             The L</_render> method returns an C<< <iframe> >> element whose C<src>
922             attribute is set to C<path>. Paths that do not
923             begin with C<http:> will passed to L</uri_for>
924            
925             =item C<logfile>
926            
927             The L</_render> method returns a table where each line of the logfile
928             appears as a separate row containing one cell. The logfile lines are
929             each wrapped in C<< <pre> >> tags
930            
931             =item C<source>
932            
933             The module L<Syntax::Highlight::Perl> is used to provide colour
934             highlights for the Perl source code. Tabs are expanded to
935             C<tabstop> spaces and the result is returned wrapped in
936             C<< <pre> >> tags
937            
938             =back
939            
940             =head2 Freelist
941            
942             New values entered into a text field can be added to the
943             list. Existing list values (passed in C<values>) can be
944             removed. The height of the list is set by C<height>.
945            
946             =head2 GroupMembership
947            
948             Displays two lists which allow for membership of a group. The first
949             scrolling list contains "all" values (C<all>), the second
950             contains those values currently selected (C<current>). The
951             height of the scrolling lists is set by C<height>
952            
953             =head2 Hidden
954            
955             Generates a hidden input field. Uses the C<default> attribute as the value
956            
957             =head2 Image
958            
959             Generates an image tag. The C<text> attribute contains the source URI. The
960             C<fhelp> attribute contains the alt text and the C<tiptype> attribute is
961             defaulted to C<normal> (wraps the image in a span with a JavaScript tooltip)
962            
963             =head2 Label
964            
965             Calls L</loc> with the C<text> attribute if set otherwise returns nothing.
966             If C<dropcap> is true the first character of the text is wrapped
967             in a C<< <span class="dropcap"> >>. Wraps the text in a span of class
968             C<class> which defaults to C<label_text>
969            
970             =head2 List
971            
972             Generates an ordered and unordered lists of items. Set the C<ordered>
973             attribute to true for an ordered list. Defaults to false
974            
975             =head2 Menu
976            
977             Generates an unordered list of links. Used with some applied CSS to
978             implement a navigation menu
979            
980             =head2 Note
981            
982             Calls L</localize> with the C<name> attribute as the message key. If
983             the message does not exist the value if the C<text> attribute is
984             used. The text is wrapped in a c<< <span class="note"> >> with
985             C<width> setting the style width
986            
987             =head2 POD
988            
989             Uses L<Pod::Html> to render the POD in the given module as HTML
990            
991             =head2 Paragraphs
992            
993             Newspaper like paragraphs rendered in a given number of columns, each
994             approximately the same length. Defines these attributes;
995            
996             =over 3
997            
998             =item C<column_class>
999            
1000             CSS class name of the C<< <span> >> wrapped around each column. Defaults
1001             to null
1002            
1003             =item C<columns>
1004            
1005             Number of columns to render the paragraphs in. Defaults to 1
1006            
1007             =item C<data>
1008            
1009             Paragraphs of text. A hash ref whose C<values> attribute is an array
1010             ref. The values of that array are the hash refs that define each
1011             paragraph. The keys of the paragraph hash ref are C<class>, C<heading>, and
1012             C<text>.
1013            
1014             =item C<hclass>
1015            
1016             Each paragraph can have a heading. This is the class of the C<<
1017             <div> >> that wraps the heading text. Defaults to null
1018            
1019             =item C<max_width>
1020            
1021             Maximum width of all paragraphs expressed as a percentage. Defaults
1022             to 90
1023            
1024             =item C<para_lead>
1025            
1026             Paragraph leading. This value is in characters. It is added to the size of
1027             each paragraph to account for the leading applied by the CSS to each
1028             paragraph. If a paragraph is split, then the first part must by greater
1029             than twice this value or the widows and orphans trap will reap it
1030            
1031             =back
1032            
1033             =head2 Password
1034            
1035             Returns a password field of width C<width> which defaults to
1036             twenty characters. If C<subtype> equals C<verify> then the
1037             message C<vPasswordPrompt> and another password field are
1038             appended. The fields C<id> and C<name> are expected
1039             to contain the digit 1 which will be substituted for the digit 2 in
1040             the attributes of the second field
1041            
1042             =head2 PopupMenu
1043            
1044             Returns a list of C<< <option> >> elements wrapped in a C<< <select> >>
1045             element. The list of options is passed in C<values> with the
1046             display labels in C<labels>. The C<onchange> event handler will
1047             be set to the C<onchange> attribute value
1048            
1049             =head2 RadioGroup
1050            
1051             The attribute C<columns> sets the number of columns for the
1052             returned table of radio buttons. The list of button values is passed in
1053             C<values> with the display labels in C<labels>. The
1054             C<onchange> event handler will be set to C<onchange>
1055            
1056             =head2 Rule
1057            
1058             Generates a horizontal rule with optional clickable action
1059            
1060             =head2 ScrollPin
1061            
1062             Implements clickable navigation markers that scroll the page to given
1063             location. Returns an unordered list of class C<class> which defaults
1064             to C<pintray>. This is the default selector class for the JavaScript
1065             C<ScrollPins> object
1066            
1067             =head2 ScrollingList
1068            
1069             The C<height> attribute controls the number of options the scrolling
1070             list displays. The list of options is passed in C<values> with the
1071             display labels in C<labels>. The C<onchange> event handler will
1072             be set to C<onchange>
1073            
1074             =head2 SidebarPanel
1075            
1076             Generates the markup for a sidebar accordion panel (a "header" C<div>
1077             and a "body" C<div>). The panel contents are requested asynchronously
1078             by the browser. The L</SidebarPanel> widget defines these attributes:
1079            
1080             =over 3
1081            
1082             =item C<config>
1083            
1084             A hash ref whose keys and values are written out as literal JavaScript by
1085             L</add_literal_js>
1086            
1087             =item C<header>
1088            
1089             A hash that provides the C<id>, C<class>, and C<text> for header C<div>
1090            
1091             =item C<panel>
1092            
1093             A hash that provides the C<id> and C<class> for body C<div>
1094            
1095             =back
1096            
1097             =head2 Slider
1098            
1099             Implements a dragable slider which returns an integer value. The L</Slider>
1100             widget defines these attributes:
1101            
1102             =over 3
1103            
1104             =item C<display>
1105            
1106             Boolean which if true causes the widget to display a read only text
1107             field containing the sliders current value. If false a C< <hidden> >>
1108             element is generated instead. Defaults to C<1>
1109            
1110             =item C<element>
1111            
1112             Name of the Javascript instance variable. This will need setting to a
1113             unique value for each slider on the same form. Defaults to
1114             C<behaviour.sliderElement>
1115            
1116             =item C<hide>
1117            
1118             If the C<display> attribute is false the current value is pushed onto
1119             this array. Defaults to C<[]>
1120            
1121             =item C<mode>
1122            
1123             Which orientation to render in. Defaults to C<horizontal>
1124            
1125             =item C<offset>
1126            
1127             Sets the minimum value for the slider. Defaults to C<0>
1128            
1129             =item C<range>
1130            
1131             The range is either the offset plus the number of steps or the two
1132             values of this array if it is set. Defaults to C<false>
1133            
1134             =item C<snap>
1135            
1136             Snap to the nearest step value? Defaults to C<1>
1137            
1138             =item C<steps>
1139            
1140             Sets the number of steps. Defaults to C<100>
1141            
1142             =item C<wheel>
1143            
1144             Use the mouse wheel? Defaults to C<1>
1145            
1146             =back
1147            
1148             =head2 TabSwapper
1149            
1150             A list of C<div>s is constructed that can be styled to display only one at
1151             a time. Clicking the tab header displays the corresponding C<div>
1152            
1153             =head2 Table
1154            
1155             The input data is in C<< $data->{values} >> which is an array
1156             ref for which each element is an array ref containing the list of
1157             field values.
1158            
1159             =head2 TableRow
1160            
1161             Returns markup for a table row. Used to generate responses for the C<LiveGrid>
1162             JavaScript class
1163            
1164             =head2 Template
1165            
1166             This provides for a "user defined" widget type.
1167             Looks in C<templatedir> for a L<Template::Toolkit> template
1168             called C<id> with a F<.tt> extension. Slurp it in and return
1169             it as the content for this widget. Alternatively take the template data
1170             from the C<text> attribute
1171            
1172             =head2 Textarea
1173            
1174             A text area. It defaults to five lines high (C<height>) and
1175             sixty characters wide (C<width>)
1176            
1177             =head2 Textfield
1178            
1179             This is the default widget type. Your basic text field which defaults
1180             to sixty characters wide (C<width>)
1181            
1182             =head2 Tree
1183            
1184             Implements an expanding tree of selectable objects. The tree information is
1185             contained in the C<data> attribute which is a hash reference. If the data
1186             hash reference has an attribute C<_keys> then this array reference will contain
1187             the list of keys for this level of the tree in the correct display order. If
1188             this attribute is missing the keys in the C<data> hash reference are displayed
1189             in their natural sort order
1190            
1191             =head1 Diagnostics
1192            
1193             None
1194            
1195             =head1 Dependencies
1196            
1197             =over 3
1198            
1199             =item L<Class::Accessor::Fast>
1200            
1201             =item L<Class::Load>
1202            
1203             =item L<HTML::Accessors>
1204            
1205             =item L<Syntax::Highlight::Perl>
1206            
1207             =item L<Text::ParseWords>
1208            
1209             =item L<Text::Tabs>
1210            
1211             =item L<Try::Tiny>
1212            
1213             =back
1214            
1215             Included in the distribution are the Javascript files whose methods
1216             are called by the event handlers associated with these widgets
1217            
1218             =head2 F<05htmlparser.js>
1219            
1220             HTML Parser By John Resig (ejohn.org)
1221             Original code by Erik Arvidsson, Mozilla Public License
1222             http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
1223            
1224             Used to reimplement C<innerHTML> assignments from XHTML
1225            
1226             =head2 F<10mootools.js>
1227            
1228             Mootools - My Object Oriented javascript.
1229             License: MIT-style license.
1230             WWW: http://mootools.net/
1231            
1232             This is the main JavaScript library used with this package
1233            
1234             =head2 F<15html-formwidgets.js>
1235            
1236             Replaces Mootools' C<setHTML> method with one that uses the HTML
1237             parser. The included copy has a few hacks that improve the Accordion
1238             widget
1239            
1240             =head2 F<50calendar.js>
1241            
1242             Copyright Mihai Bazon, 2002-2005 | www.bazon.net/mishoo
1243             The DHTML Calendar, version 1.0 | www.dynarch.com/projects/calendar
1244             License: GNU Lesser General Public License
1245            
1246             Implements the calendar popup used by the C<::Date> subclass
1247            
1248             =head2 F<behaviour.js>
1249            
1250             Is included from the L<App::Munchies> default skin. It uses the
1251             MooTools library to implement the server side field validation
1252            
1253             Also included in the C<images> subdirectory of the distribution are
1254             example PNG files used by some of the widgets.
1255            
1256             =head1 Incompatibilities
1257            
1258             There are no known incompatibilities in this module.
1259            
1260             =head1 Bugs and Limitations
1261            
1262             The installation script does nothing with the Javascript or PNG files
1263             which are included in the distribution for completeness
1264            
1265             There are no known bugs in this module. Please report problems to
1266             http://rt.cpan.org/NoAuth/Bugs.html?Dist=HTML-FormWidgets. Patches are
1267             welcome
1268            
1269             =head1 Author
1270            
1271             Peter Flanigan, C<< <pjfl@cpan.org> >>
1272            
1273             =head1 License and Copyright
1274            
1275             Copyright (c) 2015 Peter Flanigan. All rights reserved
1276            
1277             This program is free software; you can redistribute it and/or modify it
1278             under the same terms as Perl itself. See L<perlartistic>
1279            
1280             This program is distributed in the hope that it will be useful,
1281             but WITHOUT WARRANTY; without even the implied warranty of
1282             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
1283            
1284             =cut
1285            
1286             # Local Variables:
1287             # mode: perl
1288             # tab-width: 3
1289             # End:
1290