source: text-formbuilder/trunk/lib/Text/FormBuilder.pm @ 66

Last change on this file since 66 was 66, checked in by peichman, 20 years ago

worked on the rules for parsing lists in the grammar
allow end of field line comments
growable fields can specify a limit; e.g. "person*4" to limit to 4
use '+other' to specify that a field should have an 'Other' option (FB 3.02)
rearranged TODOs in the main documentation

File size: 36.9 KB
Line 
1package Text::FormBuilder;
2
3use strict;
4use warnings;
5
6use base qw(Exporter Class::ParseText::Base);
7use vars qw($VERSION @EXPORT);
8
9$VERSION = '0.10';
10@EXPORT = qw(create_form);
11
12#$::RD_TRACE = 1;
13
14use Carp;
15use Text::FormBuilder::Parser;
16use CGI::FormBuilder;
17
18# the static default options passed to CGI::FormBuilder->new
19my %DEFAULT_OPTIONS = (
20    method => 'GET',
21    keepextras => 1,
22);
23
24# the built in CSS for the template
25my $DEFAULT_CSS = <<END;
26table { padding: 1em; }
27td table { padding: 0; } /* exclude the inner checkbox tables */
28#author, #footer { font-style: italic; }
29caption h2 { padding: .125em .5em; background: #ccc; text-align: left; }
30th { text-align: left; }
31th h3 { padding: .125em .5em; background: #eee; }
32th.label { font-weight: normal; text-align: right; vertical-align: top; }
33td ul { list-style: none; padding-left: 0; margin-left: 0; }
34.note { background: #eee; }
35.sublabel { color: #999; }
36.invalid { background: red; }
37END
38
39# default messages that can be localized
40my %DEFAULT_MESSAGES = (
41    text_author   => 'Created by %s',
42    text_madewith => 'Made with %s version %s',
43    text_required => '(Required fields are marked in <strong>bold</strong>.)',
44    text_invalid  => 'Missing or invalid value.',
45);
46
47my $DEFAULT_CHARSET = 'iso-8859-1';
48
49# options to clean up the code with Perl::Tidy
50my $TIDY_OPTIONS = '-nolq -ci=4 -ce';
51
52my $HTML_EXTS   = qr/\.html?$/;
53my $MODULE_EXTS = qr/\.pm$/;
54my $SCRIPT_EXTS = qr/\.(pl|cgi)$/;
55
56# superautomagical exported function
57sub create_form {
58    my ($source, $options, $destination) = @_;
59    my $parser = __PACKAGE__->parse($source);
60    $parser->build(%{ $options || {} });
61    if ($destination) {
62        if (ref $destination) {
63            croak '[' . (caller(0))[3] . "] Don't know what to do with a ref for $destination";
64            #TODO: what DO ref dests mean?
65        } else {
66            # write webpage, script, or module
67            if ($destination =~ $MODULE_EXTS) {
68                $parser->write_module($destination, 1);
69            } elsif ($destination =~ $SCRIPT_EXTS) {
70                $parser->write_script($destination, 1);
71            } else {
72                $parser->write($destination);
73            }
74        }
75    } else {
76        defined wantarray ? return $parser->form : $parser->write;
77    }
78}
79
80# subclass of Class::ParseText::Base
81sub init {
82    my $self = shift;
83    $self->{parser}         = Text::FormBuilder::Parser->new;
84    $self->{start_rule}     = 'form_spec';
85    $self->{ensure_newline} = 1;
86    return $self;
87}
88
89# this is where a lot of the magic happens
90sub build {
91    my ($self, %options) = @_;
92   
93    # our custom %options:
94    # form_only: use only the form part of the template
95    my $form_only = $options{form_only};
96   
97    # css, extra_css: allow for custom inline stylesheets
98    #   neat trick: css => '@import(my_external_stylesheet.css);'
99    #   will let you use an external stylesheet
100    #   CSS Hint: to get multiple sections to all line up their fields,
101    #   set a standard width for th.label
102    my $css;
103    $css = $options{css} || $DEFAULT_CSS;
104    $css .= $options{extra_css} if $options{extra_css};
105   
106    # messages
107    # code pulled (with modifications) from CGI::FormBuilder
108    if ($options{messages}) {
109        # if its a hashref, we'll just pass it on to CGI::FormBuilder
110       
111        if (my $ref = ref $options{messages}) {
112            # hashref pass on to CGI::FormBuilder
113            croak "[Text::FormBuilder] Argument to 'messages' option must be a filename or hashref" unless $ref eq 'HASH';
114            while (my ($key,$value) = each %DEFAULT_MESSAGES) {
115                $options{messages}{$key} ||= $DEFAULT_MESSAGES{$key};
116            }
117        } else {
118            # filename, just *warn* on missing, and use defaults
119            if (-f $options{messages} && -r _ && open(MESSAGES, "< $options{messages}")) {
120                $options{messages} = { %DEFAULT_MESSAGES };
121                while(<MESSAGES>) {
122                    next if /^\s*#/ || /^\s*$/;
123                    chomp;
124                    my($key,$value) = split ' ', $_, 2;
125                    ($options{messages}{$key} = $value) =~ s/\s+$//;
126                }
127                close MESSAGES;
128            } else {
129                carp '[' . (caller(0))[3] . "] Could not read messages file $options{messages}: $!";
130            }
131        }
132    } else {
133        $options{messages} = { %DEFAULT_MESSAGES };
134    }
135   
136    # character set
137    my $charset = $options{charset};
138   
139    # save the build options so they can be used from write_module
140    $self->{build_options} = { %options };
141   
142    # remove our custom options before we hand off to CGI::FormBuilder
143    delete $options{$_} foreach qw(form_only css extra_css charset);
144   
145    # expand groups
146    if (my %groups = %{ $self->{form_spec}{groups} || {} }) {
147        for my $section (@{ $self->{form_spec}{sections} || [] }) {
148            foreach (grep { $$_[0] eq 'group' } @{ $$section{lines} }) {
149                $$_[1]{group} =~ s/^\%//;       # strip leading % from group var name
150               
151                if (exists $groups{$$_[1]{group}}) {
152                    my @fields; # fields in the group
153                    push @fields, { %$_ } foreach @{ $groups{$$_[1]{group}} };
154                    for my $field (@fields) {
155                        $$field{label} ||= ucfirst $$field{name};
156                        $$field{name} = "$$_[1]{name}_$$field{name}";               
157                    }
158                    $_ = [ 'group', { label => $$_[1]{label} || ucfirst(join(' ',split('_',$$_[1]{name}))), group => \@fields } ];
159                }
160            }
161        }
162    }
163   
164    # the actual fields that are given to CGI::FormBuilder
165    # make copies so that when we trim down the sections
166    # we don't lose the form field information
167    $self->{form_spec}{fields} = [];
168   
169    for my $section (@{ $self->{form_spec}{sections} || [] }) {
170        for my $line (@{ $$section{lines} }) {
171            if ($$line[0] eq 'group') {
172                push @{ $self->{form_spec}{fields} }, { %{$_} } foreach @{ $$line[1]{group} };
173            } elsif ($$line[0] eq 'field') {
174                push @{ $self->{form_spec}{fields} }, { %{$$line[1]} };
175            }
176        }
177    }
178   
179    # substitute in custom validation subs and pattern definitions for field validation
180    my %patterns = %{ $self->{form_spec}{patterns} || {} };
181    my %subs = %{ $self->{form_spec}{subs} || {} };
182   
183    foreach (@{ $self->{form_spec}{fields} }) {
184        if ($$_{validate}) {
185            if (exists $patterns{$$_{validate}}) {
186                $$_{validate} = $patterns{$$_{validate}};
187            # TODO: need the Data::Dumper code to work for this
188            # for now, we just warn that it doesn't work
189            } elsif (exists $subs{$$_{validate}}) {
190                warn '[' . (caller(0))[3] . "] validate coderefs don't work yet";
191                delete $$_{validate};
192##                 $$_{validate} = $subs{$$_{validate}};
193            }
194        }
195    }
196   
197    # get user-defined lists; can't make this conditional because
198    # we need to be able to fall back to CGI::FormBuilder's lists
199    # even if the user didn't define any
200    my %lists = %{ $self->{form_spec}{lists} || {} };
201   
202    # substitute in list names
203    foreach (@{ $self->{form_spec}{fields} }) {
204        next unless $$_{list};
205       
206        $$_{list} =~ s/^\@//;   # strip leading @ from list var name
207       
208        # a hack so we don't get screwy reference errors
209        if (exists $lists{$$_{list}}) {
210            my @list;
211            push @list, { %$_ } foreach @{ $lists{$$_{list}} };
212            $$_{options} = \@list;
213        } else {
214            # assume that the list name is a builtin
215            # and let it fall through to CGI::FormBuilder
216            $$_{options} = $$_{list};
217        }
218    } continue {
219        delete $$_{list};
220    }
221   
222    # special case single-value checkboxes
223    foreach (grep { $$_{type} && $$_{type} eq 'checkbox' } @{ $self->{form_spec}{fields} }) {
224        unless ($$_{options}) {
225            $$_{options} = [ { $$_{name} => $$_{label} || ucfirst join(' ',split(/_/,$$_{name})) } ];
226        }
227    }
228   
229    # use columns for displaying checkbox fields larger than 2 items
230    foreach (@{ $self->{form_spec}{fields} }) {
231        if (ref $$_{options} and @{ $$_{options} } >= 3) {
232            $$_{columns} = int(@{ $$_{options} } / 8) + 1;
233        }
234    }
235   
236    # remove extraneous undefined values
237    # also check for approriate version of CGI::FormBuilder
238    # for some advanced options
239    my $FB_version = CGI::FormBuilder->VERSION;
240    for my $field (@{ $self->{form_spec}{fields} }) {
241        defined $$field{$_} or delete $$field{$_} foreach keys %{ $field };
242       
243        unless ($FB_version >= '3.02') {
244            for (qw(growable other)) {
245                if ($$field{$_}) {
246                    warn '[' . (caller(0))[3] . "] '$_' fields not supported by FB $FB_version (requires 3.02)";
247                    delete $$field{$_};
248                }
249            }
250        }
251    }   
252   
253    # remove false $$_{required} params because this messes up things at
254    # the CGI::FormBuilder::field level; it seems to be marking required
255    # based on the existance of a 'required' param, not whether it is
256    # true or defined
257    # TODO: check if this is still needed
258    $$_{required} or delete $$_{required} foreach @{ $self->{form_spec}{fields} };
259   
260    # assign the field names to the sections
261    foreach (@{ $self->{form_spec}{sections} }) {
262        for my $line (@{ $$_{lines} }) {
263            if ($$line[0] eq 'field') {
264                $$line[1] = $$line[1]{name};
265            }
266        }
267    }
268   
269    $self->{form} = CGI::FormBuilder->new(
270        %DEFAULT_OPTIONS,
271        # need to explicity set the fields so that simple text fields get picked up
272        fields   => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
273        required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
274        title => $self->{form_spec}{title},
275        text  => $self->{form_spec}{description},
276        template => {
277            type => 'Text',
278            engine => {
279                TYPE       => 'STRING',
280                SOURCE     => $form_only ? $self->_form_template : $self->_template($css, $charset),
281                DELIMITERS => [ qw(<% %>) ],
282            },
283            data => {
284                sections    => $self->{form_spec}{sections},
285                author      => $self->{form_spec}{author},
286                description => $self->{form_spec}{description},
287            },
288        },
289        %options,
290    );
291    $self->{form}->field(%{ $_ }) foreach @{ $self->{form_spec}{fields} };
292   
293    # mark structures as built
294    $self->{built} = 1;
295   
296    return $self;
297}
298
299sub write {
300    my ($self, $outfile) = @_;
301   
302    # automatically call build if needed to
303    # allow the new->parse->write shortcut
304    $self->build unless $self->{built};
305   
306    if ($outfile) {
307        open FORM, "> $outfile";
308        print FORM $self->form->render;
309        close FORM;
310    } else {
311        print $self->form->render;
312    }
313}
314
315# generates the core code to create the $form object
316# the generated code assumes that you have a CGI.pm
317# object named $q
318sub _form_code {
319    my $self = shift;
320   
321    # automatically call build if needed to
322    # allow the new->parse->write shortcut
323    $self->build unless $self->{built};
324   
325    # conditionally use Data::Dumper
326    eval 'use Data::Dumper;';
327    die "Can't write module; need Data::Dumper. $@" if $@;
328   
329    $Data::Dumper::Terse = 1;           # don't dump $VARn names
330    $Data::Dumper::Quotekeys = 0;       # don't quote simple string keys
331   
332    my $css;
333    $css = $self->{build_options}{css} || $DEFAULT_CSS;
334    $css .= $self->{build_options}{extra_css} if $self->{build_options}{extra_css};
335   
336    my %options = (
337        %DEFAULT_OPTIONS,
338        title => $self->{form_spec}{title},
339        text  => $self->{form_spec}{description},
340        fields   => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
341        required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
342        template => {
343            type => 'Text',
344            engine => {
345                TYPE       => 'STRING',
346                SOURCE     => $self->{build_options}{form_only} ? 
347                                $self->_form_template : 
348                                $self->_template($css, $self->{build_options}{charset}),
349                DELIMITERS => [ qw(<% %>) ],
350            },
351            data => {
352                sections    => $self->{form_spec}{sections},
353                author      => $self->{form_spec}{author},
354                description => $self->{form_spec}{description},
355            },
356        }, 
357        %{ $self->{build_options} },
358    );
359   
360    # remove our custom options
361    delete $options{$_} foreach qw(form_only css extra_css);
362   
363    my %module_subs;
364    my $d = Data::Dumper->new([ \%options ], [ '*options' ]);
365   
366    my $form_options = keys %options > 0 ? $d->Dump : '';
367   
368    my $field_setup = join(
369        "\n", 
370        map { '$form->field' . Data::Dumper->Dump([$_],['*field']) . ';' } @{ $self->{form_spec}{fields} }
371    );
372   
373    return <<END;
374my \$form = CGI::FormBuilder->new(
375    params => \$q,
376    $form_options
377);
378
379$field_setup
380END
381}
382
383sub write_module {
384    my ($self, $package, $use_tidy) = @_;
385
386    croak '[' . (caller(0))[3] . '] Expecting a package name' unless $package;
387   
388    # remove a trailing .pm
389    $package =~ s/\.pm$//;
390##     warn  "[Text::FromBuilder::write_module] Removed extra '.pm' from package name\n" if $package =~ s/\.pm$//;
391   
392    my $form_code = $self->_form_code;
393   
394    my $module = <<END;
395package $package;
396use strict;
397use warnings;
398
399use CGI::FormBuilder;
400
401sub get_form {
402    my \$q = shift;
403
404    $form_code
405   
406    return \$form;
407}
408
409# module return
4101;
411END
412
413    _write_output_file($module, (split(/::/, $package))[-1] . '.pm', $use_tidy);
414    return $self;
415}
416
417sub write_script {
418    my ($self, $script_name, $use_tidy) = @_;
419
420    croak '[' . (caller(0))[3] . '] Expecting a script name' unless $script_name;
421   
422    my $form_code = $self->_form_code;
423   
424    my $script = <<END;
425#!/usr/bin/perl
426use strict;
427use warnings;
428
429use CGI;
430use CGI::FormBuilder;
431
432my \$q = CGI->new;
433
434$form_code
435   
436unless (\$form->submitted && \$form->validate) {
437    print \$form->render;
438} else {
439    # do something with the entered data
440}
441END
442   
443    _write_output_file($script, $script_name, $use_tidy);   
444    return $self;
445}
446
447sub _write_output_file {
448    my ($source_code, $outfile, $use_tidy) = @_;
449    if ($use_tidy) {
450        # clean up the generated code, if asked
451        eval 'use Perl::Tidy';
452        unless ($@) {
453            Perl::Tidy::perltidy(source => \$source_code, destination => $outfile, argv => $TIDY_OPTIONS);
454        } else {
455            carp '[' . (caller(0))[3] . "] Can't tidy the code: $@" if $@;
456            # fallback to just writing it as-is
457            open OUT, "> $outfile" or die $!;
458            print OUT $source_code;
459            close OUT;
460        }
461    } else {
462        # otherwise, just print as is
463        open OUT, "> $outfile" or die $!;
464        print OUT $source_code;
465        close OUT;
466    }
467}
468
469
470sub form {
471    my $self = shift;
472   
473    # automatically call build if needed to
474    # allow the new->parse->write shortcut
475    $self->build unless $self->{built};
476
477    return $self->{form};
478}
479
480sub _form_template {
481    my $self = shift;
482    my $msg_required = $self->{build_options}{messages}{text_required};
483    my $msg_invalid = $self->{build_options}{messages}{text_invalid};
484    return q{<% $description ? qq[<p id="description">$description</p>] : '' %>
485<% (grep { $_->{required} } @fields) ? qq[<p id="instructions">} . $msg_required . q{</p>] : '' %>
486<% $start %>
487<%
488    # drop in the hidden fields here
489    $OUT = join("\n", map { $$_{field} } grep { $$_{type} eq 'hidden' } @fields);
490%>} .
491q[
492<%
493    SECTION: while (my $section = shift @sections) {
494        $OUT .= qq[<table id="] . ($$section{id} || '_default') . qq[">\n];
495        $OUT .= qq[  <caption><h2 class="sectionhead">$$section{head}</h2></caption>] if $$section{head};
496        TABLE_LINE: for my $line (@{ $$section{lines} }) {
497            if ($$line[0] eq 'head') {
498                $OUT .= qq[  <tr><th class="subhead" colspan="2"><h3>$$line[1]</h3></th></tr>\n]
499            } elsif ($$line[0] eq 'note') {
500                $OUT .= qq[  <tr><td class="note" colspan="2">$$line[1]</td></tr>\n]
501            } elsif ($$line[0] eq 'field') {
502                local $_ = $field{$$line[1]};
503               
504                # skip hidden fields in the table
505                next TABLE_LINE if $$_{type} eq 'hidden';
506               
507                $OUT .= $$_{invalid} ? qq[  <tr class="invalid">] : qq[  <tr>];
508               
509                # special case single value checkboxes
510                if ($$_{type} eq 'checkbox' && @{ $$_{options} } == 1) {
511                    $OUT .= qq[<th></th>];
512                } else {
513                    $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}</strong>] : "$$_{label}") . '</th>';
514                }
515               
516                # mark invalid fields
517                if ($$_{invalid}) {
518                    $OUT .= "<td>$$_{field} $$_{comment} ] . $msg_invalid . q[</td>";
519                } else {
520                    $OUT .= qq[<td>$$_{field} $$_{comment}</td>];
521                }
522               
523                $OUT .= qq[</tr>\n];
524               
525            } elsif ($$line[0] eq 'group') {
526                my @group_fields = map { $field{$_} } map { $$_{name} } @{ $$line[1]{group} };
527                $OUT .= (grep { $$_{invalid} } @group_fields) ? qq[  <tr class="invalid">\n] : qq[  <tr>\n];
528               
529                $OUT .= '    <th class="label">';
530                $OUT .= (grep { $$_{required} } @group_fields) ? qq[<strong class="required">$$line[1]{label}:</strong>] : "$$line[1]{label}:";
531                $OUT .= qq[</th>\n];
532               
533                $OUT .= qq[    <td><span class="fieldgroup">];
534                $OUT .= join(' ', map { qq[<small class="sublabel">$$_{label}</small> $$_{field} $$_{comment}] } @group_fields);
535                #TODO: allow comments on field groups
536                $OUT .= " ] . $msg_invalid . q[" if grep { $$_{invalid} } @group_fields;
537               
538                $OUT .= qq[    </span></td>\n];
539                $OUT .= qq[  </tr>\n];
540            }   
541        }
542        # close the table if there are sections remaining
543        # but leave the last one open for the submit button
544        $OUT .= qq[</table>\n] if @sections;
545    }
546%>
547  <tr><th></th><td style="padding-top: 1em;"><% $submit %></td></tr>
548</table>
549<% $end %>
550];
551}
552
553# usage: $self->_pre_template($css, $charset)
554sub _pre_template {
555    my $self = shift;
556    my $css = shift || $DEFAULT_CSS;
557    my $charset = shift || $DEFAULT_CHARSET;
558    my $msg_author = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_author}) . '", $author)';
559    return 
560q[<html>
561<head>
562  <meta http-equiv="Content-Type" content="text/html; charset=] . $charset . q[" />
563  <title><% $title %><% $author ? ' - ' . ucfirst $author : '' %></title>
564  <style type="text/css">
565] . $css . q[  </style>
566  <% $jshead %>
567</head>
568<body>
569
570<h1><% $title %></h1>
571<% $author ? qq[<p id="author">] . ] . $msg_author . q{ . q[</p>] : '' %>
572};
573}
574
575sub _post_template {
576    my $self = shift;
577    my $msg_madewith = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_madewith}) .
578        '", q[<a href="http://formbuilder.org/">CGI::FormBuilder</a>], CGI::FormBuilder->VERSION)';
579   
580    return qq[<hr />
581<div id="footer">
582  <p id="creator"><% $msg_madewith %></p>
583</div>
584</body>
585</html>
586];
587}
588
589# usage: $self->_template($css, $charset)
590sub _template {
591    my $self = shift;
592    return $self->_pre_template(@_) . $self->_form_template . $self->_post_template;
593}
594
595sub dump { 
596    eval "use YAML;";
597    unless ($@) {
598        print YAML::Dump(shift->{form_spec});
599    } else {
600        warn '[' . (caller(0))[3] . "] Can't dump form spec structure using YAML: $@";
601    }
602}
603
604
605# module return
6061;
607
608=head1 NAME
609
610Text::FormBuilder - Create CGI::FormBuilder objects from simple text descriptions
611
612=head1 SYNOPSIS
613
614    use Text::FormBuilder;
615   
616    my $parser = Text::FormBuilder->new;
617    $parser->parse($src_file);
618   
619    # returns a new CGI::FormBuilder object with
620    # the fields from the input form spec
621    my $form = $parser->form;
622   
623    # write a My::Form module to Form.pm
624    $parser->write_module('My::Form');
625
626=head1 REQUIRES
627
628L<Parse::RecDescent>,
629L<CGI::FormBuilder>,
630L<Text::Template>,
631L<Class::Base>
632
633=head1 DESCRIPTION
634
635This module is intended to extend the idea of making it easy to create
636web forms by allowing you to describe them with a simple langauge. These
637I<formspecs> are then passed through this module's parser and converted
638into L<CGI::FormBuilder> objects that you can easily use in your CGI
639scripts. In addition, this module can generate code for standalone modules
640which allow you to separate your form design from your script code.
641
642A simple formspec looks like this:
643
644    name//VALUE
645    email//EMAIL
646    langauge:select{English,Spanish,French,German}
647    moreinfo|Send me more information:checkbox
648    interests:checkbox{Perl,karate,bass guitar}
649
650This will produce a required C<name> test field, a required C<email> text
651field that must look like an email address, an optional select dropdown
652field C<langauge> with the choices English, Spanish, French, and German,
653an optional C<moreinfo> checkbox labeled ``Send me more information'', and
654finally a set of checkboxes named C<interests> with the choices Perl,
655karate, and bass guitar.
656
657=head1 METHODS
658
659=head2 new
660
661    my $parser = Text::FormBuilder->new;
662
663=head2 parse
664
665    # parse a file (regular scalar)
666    $parser->parse($filename);
667   
668    # or pass a scalar ref for parse a literal string
669    $parser->parse(\$string);
670   
671    # or an array ref to parse lines
672    $parser->parse(\@lines);
673
674Parse the file or string. Returns the parser object. This method,
675along with all of its C<parse_*> siblings, may be called as a class
676method to construct a new object.
677
678=head2 parse_file
679
680    $parser->parse_file($src_file);
681   
682    # or as a class method
683    my $parser = Text::FormBuilder->parse($src_file);
684
685=head2 parse_text
686
687    $parser->parse_text($src);
688
689Parse the given C<$src> text. Returns the parser object.
690
691=head2 parse_array
692
693    $parser->parse_array(@lines);
694
695Concatenates and parses C<@lines>. Returns the parser object.
696
697=head2 build
698
699    $parser->build(%options);
700
701Builds the CGI::FormBuilder object. Options directly used by C<build> are:
702
703=over
704
705=item C<form_only>
706
707Only uses the form portion of the template, and omits the surrounding html,
708title, author, and the standard footer. This does, however, include the
709description as specified with the C<!description> directive.
710
711=item C<css>, C<extra_css>
712
713These options allow you to tell Text::FormBuilder to use different
714CSS styles for the built in template. A value given a C<css> will
715replace the existing CSS, and a value given as C<extra_css> will be
716appended to the CSS. If both options are given, then the CSS that is
717used will be C<css> concatenated with C<extra_css>.
718
719If you want to use an external stylesheet, a quick way to get this is
720to set the C<css> parameter to import your file:
721
722    css => '@import(my_external_stylesheet.css);'
723
724=item C<messages>
725
726This works the same way as the C<messages> parameter to
727C<< CGI::FormBuilder->new >>; you can provide either a hashref of messages
728or a filename.
729
730The default messages used by Text::FormBuilder are:
731
732    text_author       Created by %s
733    text_madewith     Made with %s version %s
734    text_required     (Required fields are marked in <strong>bold</strong>.)
735    text_invalid      Missing or invalid value.
736
737Any messages you set here get passed on to CGI::FormBuilder, which means
738that you should be able to put all of your customization messages in one
739big file.
740
741=item C<charset>
742
743Sets the character encoding for the generated page. The default is ISO-8859-1.
744
745=back
746
747All other options given to C<build> are passed on verbatim to the
748L<CGI::FormBuilder> constructor. Any options given here override the
749defaults that this module uses.
750
751The C<form>, C<write>, and C<write_module> methods will all call
752C<build> with no options for you if you do not do so explicitly.
753This allows you to say things like this:
754
755    my $form = Text::FormBuilder->new->parse('formspec.txt')->form;
756
757However, if you need to specify options to C<build>, you must call it
758explictly after C<parse>.
759
760=head2 form
761
762    my $form = $parser->form;
763
764Returns the L<CGI::FormBuilder> object. Remember that you can modify
765this object directly, in order to (for example) dynamically populate
766dropdown lists or change input types at runtime.
767
768=head2 write
769
770    $parser->write($out_file);
771    # or just print to STDOUT
772    $parser->write;
773
774Calls C<render> on the FormBuilder form, and either writes the resulting
775HTML to a file, or to STDOUT if no filename is given.
776
777=head2 write_module
778
779    $parser->write_module($package, $use_tidy);
780
781Takes a package name, and writes out a new module that can be used by your
782CGI script to render the form. This way, you only need CGI::FormBuilder on
783your server, and you don't have to parse the form spec each time you want
784to display your form. The generated module has one function (not exported)
785called C<get_form>, that takes a CGI object as its only argument, and returns
786a CGI::FormBuilder object.
787
788First, you parse the formspec and write the module, which you can do as a one-liner:
789
790    $ perl -MText::FormBuilder -e"Text::FormBuilder->parse('formspec.txt')->write_module('My::Form')"
791
792And then, in your CGI script, use the new module:
793
794    #!/usr/bin/perl -w
795    use strict;
796   
797    use CGI;
798    use My::Form;
799   
800    my $q = CGI->new;
801    my $form = My::Form::get_form($q);
802   
803    # do the standard CGI::FormBuilder stuff
804    if ($form->submitted && $form->validate) {
805        # process results
806    } else {
807        print $q->header;
808        print $form->render;
809    }
810
811If you pass a true value as the second argument to C<write_module>, the parser
812will run L<Perl::Tidy> on the generated code before writing the module file.
813
814    # write tidier code
815    $parser->write_module('My::Form', 1);
816
817=head2 write_script
818
819    $parser->write_script($filename, $use_tidy);
820
821If you don't need the reuseability of a separate module, you can have
822Text::FormBuilder write the form object to a script for you, along with
823the simplest framework for using it, to which you can add your actual
824form processing code.
825
826The generated script looks like this:
827
828    #!/usr/bin/perl
829    use strict;
830    use warnings;
831   
832    use CGI;
833    use CGI::FormBuilder;
834   
835    my $q = CGI->new;
836   
837    my $form = CGI::FormBuilder->new(
838        params => $q,
839        # ... lots of other stuff to set up the form ...
840    );
841   
842    $form->field( name => 'month' );
843    $form->field( name => 'day' );
844   
845    unless ( $form->submitted && $form->validate ) {
846        print $form->render;
847    } else {
848        # do something with the entered data ...
849        # this is where your form processing code should go
850    }
851
852Like C<write_module>, you can optionally pass a true value as the second
853argument to have Perl::Tidy make the generated code look nicer.
854
855=head2 dump
856
857Uses L<YAML> to print out a human-readable representation of the parsed
858form spec.
859
860=head1 EXPORTS
861
862There is one exported function, C<create_form>, that is intended to ``do the
863right thing'' in simple cases.
864
865=head2 create_form
866
867    # get a CGI::FormBuilder object
868    my $form = create_form($source, $options, $destination);
869   
870    # or just write the form immediately
871    create_form($source, $options, $destination);
872
873C<$source> accepts any of the types of arguments that C<parse> does. C<$options>
874is a hashref of options that should be passed to C<build>. Finally, C<$destination>
875is a simple scalar that determines where and what type of output C<create_form>
876should generate.
877
878    /\.pm$/             ->write_module($destination)
879    /\.(cgi|pl)$/       ->write_script($destination)
880    everything else     ->write($destination)
881
882For anything more than simple, one-off cases, you are usually better off using the
883object-oriented interface, since that gives you more control over things.
884
885=head1 DEFAULTS
886
887These are the default settings that are passed to C<< CGI::FormBuilder->new >>:
888
889    method => 'GET'
890    javascript => 0
891    keepextras => 1
892
893Any of these can be overriden by the C<build> method:
894
895    # use POST instead
896    $parser->build(method => 'POST')->write;
897
898=head1 LANGUAGE
899
900    field_name[size]|descriptive label[hint]:type=default{option1[display string],...}//validate
901   
902    !title ...
903   
904    !author ...
905   
906    !description {
907        ...
908    }
909   
910    !pattern NAME /regular expression/
911   
912    !list NAME {
913        option1[display string],
914        option2[display string],
915        ...
916    }
917   
918    !list NAME &{ CODE }
919   
920    !group NAME {
921        field1
922        field2
923        ...
924    }
925   
926    !section id heading
927   
928    !head ...
929   
930    !note {
931        ...
932    }
933
934=head2 Directives
935
936=over
937
938=item C<!pattern>
939
940Defines a validation pattern.
941
942=item C<!list>
943
944Defines a list for use in a C<radio>, C<checkbox>, or C<select> field.
945
946=item C<!group>
947
948Define a named group of fields that are displayed all on one line. Use with
949the C<!field> directive.
950
951=item C<!field>
952
953Include a named instance of a group defined with C<!group>.
954
955=item C<!title>
956
957Title of the form.
958
959=item C<!author>
960
961Author of the form.
962
963=item C<!description>
964
965A brief description of the form. Suitable for special instructions on how to
966fill out the form.
967
968=item C<!section>
969
970Starts a new section. Each section has its own heading and id, which are
971written by default into spearate tables.
972
973=item C<!head>
974
975Inserts a heading between two fields. There can only be one heading between
976any two fields; the parser will warn you if you try to put two headings right
977next to each other.
978
979=item C<!note>
980
981A text note that can be inserted as a row in the form. This is useful for
982special instructions at specific points in a long form.
983
984=back
985
986=head2 Fields
987
988First, a note about multiword strings in the fields. Anywhere where it says
989that you may use a multiword string, this means that you can do one of two
990things. For strings that consist solely of alphanumeric characters (i.e.
991C<\w+>) and spaces, the string will be recognized as is:
992
993    field_1|A longer label
994
995If you want to include non-alphanumerics (e.g. punctuation), you must
996single-quote the string:
997
998    field_2|'Dept./Org.'
999
1000To include a literal single-quote in a single-quoted string, escape it with
1001a backslash:
1002
1003    field_3|'\'Official\' title'
1004
1005Now, back to the beginning. Form fields are each described on a single line.
1006The simplest field is just a name (which cannot contain any whitespace):
1007
1008    color
1009
1010This yields a form with one text input field of the default size named `color'.
1011The generated label for this field would be ``Color''. To add a longer or more\
1012descriptive label, use:
1013
1014    color|Favorite color
1015
1016The descriptive label can be a multiword string, as described above. So if you
1017want punctuation in the label, you should single quote it:
1018
1019    color|'Fav. color'
1020
1021To use a different input type:
1022
1023    color|Favorite color:select{red,blue,green}
1024
1025Recognized input types are the same as those used by CGI::FormBuilder:
1026
1027    text        # the default
1028    textarea
1029    password
1030    file
1031    checkbox
1032    radio
1033    select
1034    hidden
1035    static
1036
1037To change the size of the input field, add a bracketed subscript after the
1038field name (but before the descriptive label):
1039
1040    # for a single line field, sets size="40"
1041    title[40]:text
1042   
1043    # for a multiline field, sets rows="4" and cols="30"
1044    description[4,30]:textarea
1045
1046To also set the C<maxlength> attribute for text fields, add a C<!> after
1047the size:
1048
1049    # ensure that all titles entered are 40 characters or less
1050    title[40!]:text
1051
1052This currently only works for single line text fields.
1053
1054To create a growable field, add a C<*> after the name (and size, if
1055given). Growable fields have a button that allows the user to add a
1056copy of the field input. Currently, this only works for C<text> and
1057C<file> fields, and you must have L<CGI::FormBuilder> 3.02 or higher.
1058Growable fields also require JavaScript to function correctly.
1059
1060    # you can have as many people as you like
1061    person*:text
1062
1063For the input types that can have options (C<select>, C<radio>, and
1064C<checkbox>), here's how you do it:
1065
1066    color|Favorite color:select{red,blue,green}
1067
1068Values are in a comma-separated list of single words or multiword strings
1069inside curly braces. Whitespace between values is irrelevant.
1070
1071To add more descriptive display text to a value in a list, add a square-bracketed
1072``subscript,'' as in:
1073
1074    ...:select{red[Scarlet],blue[Azure],green[Olive Drab]}
1075
1076If you have a list of options that is too long to fit comfortably on one line,
1077you should use the C<!list> directive:
1078
1079    !list MONTHS {
1080        1[January],
1081        2[February],
1082        3[March],
1083        # and so on...
1084    }
1085   
1086    month:select@MONTHS
1087
1088If you want to have a single checkbox (e.g. for a field that says ``I want to
1089recieve more information''), you can just specify the type as checkbox without
1090supplying any options:
1091
1092    moreinfo|I want to recieve more information:checkbox
1093
1094In this case, the label ``I want to recieve more information'' will be
1095printed to the right of the checkbox.
1096
1097You can also supply a default value to the field. To get a default value of
1098C<green> for the color field:
1099
1100    color|Favorite color:select=green{red,blue,green}
1101
1102Default values can also be either single words or multiword strings.
1103
1104To validate a field, include a validation type at the end of the field line:
1105
1106    email|Email address//EMAIL
1107
1108Valid validation types include any of the builtin defaults from L<CGI::FormBuilder>,
1109or the name of a pattern that you define with the C<!pattern> directive elsewhere
1110in your form spec:
1111
1112    !pattern DAY /^([1-3][0-9])|[1-9]$/
1113   
1114    last_day//DAY
1115
1116If you just want a required value, use the builtin validation type C<VALUE>:
1117
1118    title//VALUE
1119
1120By default, adding a validation type to a field makes that field required. To
1121change this, add a C<?> to the end of the validation type:
1122
1123    contact//EMAIL?
1124
1125In this case, you would get a C<contact> field that was optional, but if it
1126were filled in, would have to validate as an C<EMAIL>.
1127
1128=head2 Field Groups
1129
1130You can define groups of fields using the C<!group> directive:
1131
1132    !group DATE {
1133        month:select@MONTHS//INT
1134        day[2]//INT
1135        year[4]//INT
1136    }
1137
1138You can then include instances of this group using the C<!field> directive:
1139
1140    !field %DATE birthday
1141
1142This will create a line in the form labeled ``Birthday'' which contains
1143a month dropdown, and day and year text entry fields. The actual input field
1144names are formed by concatenating the C<!field> name (e.g. C<birthday>) with
1145the name of the subfield defined in the group (e.g. C<month>, C<day>, C<year>).
1146Thus in this example, you would end up with the form fields C<birthday_month>,
1147C<birthday_day>, and C<birthday_year>.
1148
1149You can also use groups in normal field lines:
1150   
1151    birthday|Your birthday:DATE
1152
1153The only (currently) supported pieces of a fieldspec that may be used with a
1154group in this notation are name and label.
1155
1156=head2 Comments
1157
1158    # comment ...
1159
1160Any line beginning with a C<#> is considered a comment.
1161
1162=head1 TODO
1163
1164=head2 Documentation/Tests
1165
1166Document use of the parser as a standalone module
1167
1168Better tests!
1169
1170=head2 Language/Parser
1171
1172Allow renaming of the submit button; allow renaming and inclusion of a
1173reset button
1174
1175Allow comments on group fields (rendered after the all the fields)
1176
1177Pieces that wouldn't make sense in a group field: size, row/col, options,
1178validate. These should cause C<build> to emit a warning before ignoring them.
1179
1180C<!include> directive to include external formspec files
1181
1182=head2 Code generation/Templates
1183
1184Alternative format using C<< <fieldset> >> tags instead of C<< <h2> >>
1185section headers
1186
1187Make the generated modules into subclasses of CGI::FormBuilder
1188
1189Better integration with L<CGI::FormBuilder>'s templating system
1190
1191Allow for custom wrappers around the C<form_template>
1192
1193Maybe use HTML::Template instead of Text::Template for the built in template
1194(since CGI::FormBuilder users may be more likely to already have HTML::Template)
1195
1196=head1 BUGS
1197
1198Creating two $parsers in the same script causes the second one to get the data
1199from the first one.
1200
1201I'm sure there are more in there, I just haven't tripped over any new ones lately. :-)
1202
1203Suggestions on how to improve the (currently tiny) test suite would be appreciated.
1204
1205=head1 SEE ALSO
1206
1207L<http://textformbuilder.berlios.de>
1208
1209L<CGI::FormBuilder>, L<http://formbuilder.org>
1210
1211=head1 THANKS
1212
1213Thanks to eszpee for pointing out some bugs in the default value parsing,
1214as well as some suggestions for i18n/l10n and splitting up long forms into
1215sections.
1216
1217And of course, to Nathan Wiger, for giving use CGI::FormBuilder in the
1218first place. Thanks Nate!
1219
1220=head1 AUTHOR
1221
1222Peter Eichman C<< <peichman@cpan.org> >>
1223
1224=head1 COPYRIGHT AND LICENSE
1225
1226Copyright E<copy>2004-2005 by Peter Eichman.
1227
1228This program is free software; you can redistribute it and/or
1229modify it under the same terms as Perl itself.
1230
1231=cut
Note: See TracBrowser for help on using the repository browser.