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

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

documented how to do blank labels on fields
changed !head from <h3> to <h2>
improved the default stylesheet (better looking fieldsets) and removed the <hr> from above the submit button

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