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

Last change on this file since 68 was 68, checked in by peichman, 19 years ago

BUGFIX: option list items had an inadvertant minimum length of 2
cleaned up 'required' option handling

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