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

Last change on this file since 38 was 38, checked in by peter, 20 years ago

more documentation
upped version number

File size: 28.8 KB
Line 
1package Text::FormBuilder;
2
3use strict;
4use warnings;
5
6use vars qw($VERSION);
7
8$VERSION = '0.07_01';
9
10use Carp;
11use Text::FormBuilder::Parser;
12use CGI::FormBuilder;
13
14# the static default options passed to CGI::FormBuilder->new
15my %DEFAULT_OPTIONS = (
16    method => 'GET',
17    javascript => 0,
18    keepextras => 1,
19);
20
21# the built in CSS for the template
22my $DEFAULT_CSS = <<END;
23table { padding: 1em; }
24#author, #footer { font-style: italic; }
25caption h2 { padding: .125em .5em; background: #ccc; text-align: left; }
26th { text-align: left; }
27th h3 { padding: .125em .5em; background: #eee; }
28th.label { font-weight: normal; text-align: right; vertical-align: top; }
29td ul { list-style: none; padding-left: 0; margin-left: 0; }
30.sublabel { color: #999; }
31.invalid { background: red; }
32END
33
34# default messages that can be localized
35my %DEFAULT_MESSAGES = (
36    text_author   => 'Created by %s',
37    text_madewith => 'Made with %s version %s',
38    text_required => '(Required fields are marked in <strong>bold</strong>.)',
39    text_invalid  => 'Missing or invalid value.',
40);
41
42my $DEFAULT_CHARSET = 'iso-8859-1';
43
44sub new {
45    my $invocant = shift;
46    my $class = ref $invocant || $invocant;
47    my $self = {
48        parser => Text::FormBuilder::Parser->new,
49    };
50    return bless $self, $class;
51}
52
53sub parse {
54    my ($self, $source) = @_;
55    if (ref $source && ref $source eq 'SCALAR') {
56        $self->parse_text($$source);
57    } else {
58        $self->parse_file($source);
59    }
60}
61
62sub parse_file {
63    my ($self, $filename) = @_;
64   
65    # so it can be called as a class method
66    $self = $self->new unless ref $self;
67   
68    local $/ = undef;
69    open SRC, "< $filename" or croak "[Text::FormBuilder::parse_file] Can't open $filename: $!" and return;
70    my $src = <SRC>;
71    close SRC;
72   
73    return $self->parse_text($src);
74}
75
76sub parse_text {
77    my ($self, $src) = @_;
78   
79    # so it can be called as a class method
80    $self = $self->new unless ref $self;
81   
82    # append a newline so that it can be called on a single field easily
83    $src .= "\n";
84   
85    $self->{form_spec} = $self->{parser}->form_spec($src);
86   
87    # mark structures as not built (newly parsed text)
88    $self->{built} = 0;
89   
90    return $self;
91}
92
93# this is where a lot of the magic happens
94sub build {
95    my ($self, %options) = @_;
96   
97    # our custom %options:
98    # form_only: use only the form part of the template
99    my $form_only = $options{form_only};
100   
101    # css, extra_css: allow for custom inline stylesheets
102    #   neat trick: css => '@import(my_external_stylesheet.css);'
103    #   will let you use an external stylesheet
104    #   CSS Hint: to get multiple sections to all line up their fields,
105    #   set a standard width for th.label
106    my $css;
107    $css = $options{css} || $DEFAULT_CSS;
108    $css .= $options{extra_css} if $options{extra_css};
109   
110    # messages
111    # code pulled (with modifications) from CGI::FormBuilder
112    if ($options{messages}) {
113        # if its a hashref, we'll just pass it on to CGI::FormBuilder
114       
115        if (my $ref = ref $options{messages}) {
116            # hashref pass on to CGI::FormBuilder
117            croak "[Text::FormBuilder] Argument to 'messages' option must be a filename or hashref" unless $ref eq 'HASH';
118            while (my ($key,$value) = each %DEFAULT_MESSAGES) {
119                $options{messages}{$key} ||= $DEFAULT_MESSAGES{$key};
120            }
121        } else {
122            # filename, just *warn* on missing, and use defaults
123            if (-f $options{messages} && -r _ && open(MESSAGES, "< $options{messages}")) {
124                $options{messages} = { %DEFAULT_MESSAGES };
125                while(<MESSAGES>) {
126                    next if /^\s*#/ || /^\s*$/;
127                    chomp;
128                    my($key,$value) = split ' ', $_, 2;
129                    ($options{messages}{$key} = $value) =~ s/\s+$//;
130                }
131                close MESSAGES;
132            } else {
133                carp "[Text::FormBuilder] Could not read messages file $options{messages}: $!";
134            }
135        }
136    } else {
137        $options{messages} = { %DEFAULT_MESSAGES };
138    }
139   
140    my $charset = $options{charset};
141   
142    # save the build options so they can be used from write_module
143    $self->{build_options} = { %options };
144   
145    # remove our custom options before we hand off to CGI::FormBuilder
146    delete $options{$_} foreach qw(form_only css extra_css charset);
147   
148    # expand groups
149    my %groups = %{ $self->{form_spec}{groups} || {} };
150    for my $section (@{ $self->{form_spec}{sections} || [] }) {
151        foreach (grep { $$_[0] eq 'group' } @{ $$section{lines} }) {
152            $$_[1]{group} =~ s/^\%//;       # strip leading % from group var name
153           
154            if (exists $groups{$$_[1]{group}}) {
155                my @fields; # fields in the group
156                push @fields, { %$_ } foreach @{ $groups{$$_[1]{group}} };
157                for my $field (@fields) {
158                    $$field{label} ||= ucfirst $$field{name};
159                    $$field{name} = "$$_[1]{name}_$$field{name}";               
160                }
161                $_ = [ 'group', { label => $$_[1]{label} || ucfirst(join(' ',split('_',$$_[1]{name}))), group => \@fields } ];
162            }
163        }
164    }
165   
166    # the actual fields that are given to CGI::FormBuilder
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 pattern definitions for field validation
180    if (my %patterns = %{ $self->{form_spec}{patterns} || {} }) {
181        foreach (@{ $self->{form_spec}{fields} }) {
182            if ($$_{validate} and exists $patterns{$$_{validate}}) {
183                $$_{validate} = $patterns{$$_{validate}};
184            }
185        }
186    }
187   
188    # substitute in list names
189    my %lists = %{ $self->{form_spec}{lists} || {} };
190    foreach (@{ $self->{form_spec}{fields} }) {
191        next unless $$_{list};
192       
193        $$_{list} =~ s/^\@//;   # strip leading @ from list var name
194       
195        # a hack so we don't get screwy reference errors
196        if (exists $lists{$$_{list}}) {
197            my @list;
198            push @list, { %$_ } foreach @{ $lists{$$_{list}} };
199            $$_{options} = \@list;
200        } else {
201            # assume that the list name is a builtin
202            # and let it fall through to CGI::FormBuilder
203            $$_{options} = $$_{list};
204        }
205    } continue {
206        delete $$_{list};
207    }
208   
209    # special case single-value checkboxes
210    foreach (grep { $$_{type} && $$_{type} eq 'checkbox' } @{ $self->{form_spec}{fields} }) {
211        unless ($$_{options}) {
212            $$_{options} = [ { $$_{name} => $$_{label} || ucfirst join(' ',split(/_/,$$_{name})) } ];
213        }
214    }
215   
216    foreach (@{ $self->{form_spec}{fields} }) {
217        $$_{ulist} = 1 if ref $$_{options} and @{ $$_{options} } >= 3;
218    }
219   
220    # remove extraneous undefined values
221    for my $field (@{ $self->{form_spec}{fields} }) {
222        defined $$field{$_} or delete $$field{$_} foreach keys %{ $field };
223    }
224   
225    # remove false $$_{required} params because this messes up things at
226    # the CGI::FormBuilder::field level; it seems to be marking required
227    # based on the existance of a 'required' param, not whether it is
228    # true or defined
229    $$_{required} or delete $$_{required} foreach @{ $self->{form_spec}{fields} };
230
231    $self->{form} = CGI::FormBuilder->new(
232        %DEFAULT_OPTIONS,
233        # need to explicity set the fields so that simple text fields get picked up
234        fields   => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
235        required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
236        title => $self->{form_spec}{title},
237        text  => $self->{form_spec}{description},
238        template => {
239            type => 'Text',
240            engine => {
241                TYPE       => 'STRING',
242                SOURCE     => $form_only ? $self->_form_template : $self->_template($css, $charset),
243                DELIMITERS => [ qw(<% %>) ],
244            },
245            data => {
246                sections    => $self->{form_spec}{sections},
247                author      => $self->{form_spec}{author},
248                description => $self->{form_spec}{description},
249            },
250        },
251        %options,
252    );
253    $self->{form}->field(%{ $_ }) foreach @{ $self->{form_spec}{fields} };
254   
255    # mark structures as built
256    $self->{built} = 1;
257   
258    return $self;
259}
260
261sub write {
262    my ($self, $outfile) = @_;
263   
264    # automatically call build if needed to
265    # allow the new->parse->write shortcut
266    $self->build unless $self->{built};
267   
268    if ($outfile) {
269        open FORM, "> $outfile";
270        print FORM $self->form->render;
271        close FORM;
272    } else {
273        print $self->form->render;
274    }
275}
276
277sub write_module {
278    my ($self, $package, $use_tidy) = @_;
279
280    croak '[Text::FormBuilder::write_module] Expecting a package name' unless $package;
281   
282    # automatically call build if needed to
283    # allow the new->parse->write shortcut
284    $self->build unless $self->{built};
285   
286    # conditionally use Data::Dumper
287    eval 'use Data::Dumper;';
288    die "Can't write module; need Data::Dumper. $@" if $@;
289   
290    $Data::Dumper::Terse = 1;           # don't dump $VARn names
291    $Data::Dumper::Quotekeys = 0;       # don't quote simple string keys
292   
293    my $css;
294    $css = $self->{build_options}{css} || $DEFAULT_CSS;
295    $css .= $self->{build_options}{extra_css} if $self->{build_options}{extra_css};
296   
297    my %options = (
298        %DEFAULT_OPTIONS,
299        title => $self->{form_spec}{title},
300        text  => $self->{form_spec}{description},
301        fields   => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
302        required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
303        template => {
304            type => 'Text',
305            engine => {
306                TYPE       => 'STRING',
307                SOURCE     => $self->{build_options}{form_only} ? 
308                                $self->_form_template : 
309                                $self->_template($css, $self->{build_options}{charset}),
310                DELIMITERS => [ qw(<% %>) ],
311            },
312            data => {
313                sections    => $self->{form_spec}{sections},
314                author      => $self->{form_spec}{author},
315                description => $self->{form_spec}{description},
316            },
317        }, 
318        %{ $self->{build_options} },
319    );
320   
321    # remove our custom options
322    delete $options{$_} foreach qw(form_only css extra_css);
323   
324    my $form_options = keys %options > 0 ? Data::Dumper->Dump([\%options],['*options']) : '';
325   
326    my $field_setup = join(
327        "\n", 
328        map { '$cgi_form->field' . Data::Dumper->Dump([$_],['*field']) . ';' } @{ $self->{form_spec}{fields} }
329    );
330   
331    my $module = <<END;
332package $package;
333use strict;
334use warnings;
335
336use CGI::FormBuilder;
337
338sub get_form {
339    my \$cgi = shift;
340    my \$cgi_form = CGI::FormBuilder->new(
341        params => \$cgi,
342        $form_options
343    );
344   
345    $field_setup
346   
347    return \$cgi_form;
348}
349
350# module return
3511;
352END
353
354    my $outfile = (split(/::/, $package))[-1] . '.pm';
355   
356    if ($use_tidy) {
357        # clean up the generated code, if asked
358        eval 'use Perl::Tidy';
359        die "Can't tidy the code: $@" if $@;
360        Perl::Tidy::perltidy(source => \$module, destination => $outfile, argv => '-nolq -ci=4');
361    } else {
362        # otherwise, just print as is
363        open FORM, "> $outfile";
364        print FORM $module;
365        close FORM;
366    }
367}
368
369sub form {
370    my $self = shift;
371   
372    # automatically call build if needed to
373    # allow the new->parse->write shortcut
374    $self->build unless $self->{built};
375
376    return $self->{form};
377}
378
379sub _form_template {
380    my $self = shift;
381    my $msg_required = $self->{build_options}{messages}{text_required};
382    my $msg_invalid = $self->{build_options}{messages}{text_invalid};
383    return q{<% $description ? qq[<p id="description">$description</p>] : '' %>
384<% (grep { $_->{required} } @fields) ? qq[<p id="instructions">} . $msg_required . q{</p>] : '' %>
385<% $start %>
386<%
387    # drop in the hidden fields here
388    $OUT = join("\n", map { $$_{field} } grep { $$_{type} eq 'hidden' } @fields);
389%>} .
390q[
391<%
392    SECTION: while (my $section = shift @sections) {
393        $OUT .= qq[<table id="] . ($$section{id} || '_default') . qq[">\n];
394        $OUT .= qq[  <caption><h2 class="sectionhead">$$section{head}</h2></caption>] if $$section{head};
395        TABLE_LINE: for my $line (@{ $$section{lines} }) {
396            if ($$line[0] eq 'head') {
397                $OUT .= qq[  <tr><th class="subhead" colspan="2"><h3>$$line[1]</h3></th></tr>\n]
398            } elsif ($$line[0] eq 'field') {
399                #TODO: we only need the field names, not the full field spec in the lines strucutre
400                local $_ = $field{$$line[1]{name}};
401               
402                # skip hidden fields in the table
403                next TABLE_LINE if $$_{type} eq 'hidden';
404               
405                $OUT .= $$_{invalid} ? qq[  <tr class="invalid">] : qq[  <tr>];
406               
407                # special case single value checkboxes
408                if ($$_{type} eq 'checkbox' && @{ $$_{options} } == 1) {
409                    $OUT .= qq[<th></th>];
410                } else {
411                    $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}:</strong>] : "$$_{label}:") . '</th>';
412                }
413               
414                # mark invalid fields
415                if ($$_{invalid}) {
416                    $OUT .= "<td>$$_{field} $$_{comment} ] . $msg_invalid . q[</td>";
417                } else {
418                    $OUT .= qq[<td>$$_{field} $$_{comment}</td>];
419                }
420               
421                $OUT .= qq[</tr>\n];
422               
423            } elsif ($$line[0] eq 'group') {
424                my @field_names = map { $$_{name} } @{ $$line[1]{group} };
425                my @group_fields = map { $field{$_} } @field_names;
426                $OUT .= (grep { $$_{invalid} } @group_fields) ? qq[  <tr class="invalid">\n] : qq[  <tr>\n];
427               
428                $OUT .= '    <th class="label">';
429                $OUT .= (grep { $$_{required} } @group_fields) ? qq[<strong class="required">$$line[1]{label}:</strong>] : "$$line[1]{label}:";
430                $OUT .= qq[</th>\n];
431               
432                $OUT .= qq[    <td>];
433                $OUT .= join(' ', map { qq[<small class="sublabel">$$_{label}</small> $$_{field} $$_{comment}] } @group_fields);
434                $OUT .= qq[    </td>\n];
435                $OUT .= qq[  </tr>\n];
436            }   
437        }
438        # close the table if there are sections remaining
439        # but leave the last one open for the submit button
440        $OUT .= qq[</table>\n] if @sections;
441    }
442%>
443  <tr><th></th><td style="padding-top: 1em;"><% $submit %></td></tr>
444</table>
445<% $end %>
446];
447}
448
449# usage: $self->_pre_template($css, $charset)
450sub _pre_template {
451    my $self = shift;
452    my $css = shift || $DEFAULT_CSS;
453    my $charset = shift || $DEFAULT_CHARSET;
454    my $msg_author = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_author}) . '", $author)';
455    return 
456q[<html>
457<head>
458  <meta http-equiv="Content-Type" content="text/html; charset=] . $charset . q[" />
459  <title><% $title %><% $author ? ' - ' . ucfirst $author : '' %></title>
460  <style type="text/css">
461] .
462$css .
463q[  </style>
464  <% $jshead %>
465</head>
466<body>
467
468<h1><% $title %></h1>
469<% $author ? qq[<p id="author">] . ] . $msg_author . q{ . q[</p>] : '' %>
470};
471}
472
473sub _post_template {
474    my $self = shift;
475    my $msg_madewith = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_madewith}) .
476        '", q[<a href="http://formbuilder.org/">CGI::FormBuilder</a>], CGI::FormBuilder->VERSION)';
477   
478    return qq[<hr />
479<div id="footer">
480  <p id="creator"><% $msg_madewith %></p>
481</div>
482</body>
483</html>
484];
485}
486
487sub _template {
488    my $self = shift;
489    return $self->_pre_template(@_) . $self->_form_template . $self->_post_template;
490}
491
492sub dump { 
493    eval "use YAML;";
494    unless ($@) {
495        print YAML::Dump(shift->{form_spec});
496    } else {
497        warn "Can't dump form spec structure: $@";
498    }
499}
500
501
502# module return
5031;
504
505=head1 NAME
506
507Text::FormBuilder - Create CGI::FormBuilder objects from simple text descriptions
508
509=head1 SYNOPSIS
510
511    use Text::FormBuilder;
512   
513    my $parser = Text::FormBuilder->new;
514    $parser->parse($src_file);
515   
516    # returns a new CGI::FormBuilder object with
517    # the fields from the input form spec
518    my $form = $parser->form;
519   
520    # write a My::Form module to Form.pm
521    $parser->write_module('My::Form');
522
523=head1 REQUIRES
524
525L<Parse::RecDescent>, L<CGI::FormBuilder>, L<Text::Template>
526
527=head1 DESCRIPTION
528
529This module is intended to extend the idea of making it easy to create
530web forms by allowing you to describe them with a simple langauge. These
531I<formspecs> are then passed through this module's parser and converted
532into L<CGI::FormBuilder> objects that you can easily use in your CGI
533scripts. In addition, this module can generate code for standalone modules
534which allow you to separate your form design from your script code.
535
536A simple formspec looks like this:
537
538    name//VALUE
539    email//EMAIL
540    langauge:select{English,Spanish,French,German}
541    moreinfo|Send me more information:checkbox
542    interests:checkbox{Perl,karate,bass guitar}
543
544This will produce a required C<name> test field, a required C<email> text
545field that must look like an email address, an optional select dropdown
546field C<langauge> with the choices English, Spanish, French, and German,
547an optional C<moreinfo> checkbox labeled ``Send me more information'', and
548finally a set of checkboxes named C<interests> with the choices Perl,
549karate, and bass guitar.
550
551=head2 new
552
553    my $parser = Text::FormBuilder->new;
554
555=head2 parse
556
557    # parse a file
558    $parser->parse($filename);
559   
560    # or pass a scalar ref for parse a literal string
561    $parser->parse(\$string);
562
563Parse the file or string. Returns the parser object.
564
565=head2 parse_file
566
567    $parser->parse_file($src_file);
568   
569    # or as a class method
570    my $parser = Text::FormBuilder->parse($src_file);
571
572=head2 parse_text
573
574    $parser->parse_text($src);
575
576Parse the given C<$src> text. Returns the parser object.
577
578=head2 build
579
580    $parser->build(%options);
581
582Builds the CGI::FormBuilder object. Options directly used by C<build> are:
583
584=over
585
586=item C<form_only>
587
588Only uses the form portion of the template, and omits the surrounding html,
589title, author, and the standard footer. This does, however, include the
590description as specified with the C<!description> directive.
591
592=item C<css>, C<extra_css>
593
594These options allow you to tell Text::FormBuilder to use different
595CSS styles for the built in template. A value given a C<css> will
596replace the existing CSS, and a value given as C<extra_css> will be
597appended to the CSS. If both options are given, then the CSS that is
598used will be C<css> concatenated with C<extra_css>.
599
600If you want to use an external stylesheet, a quick way to get this is
601to set the C<css> parameter to import your file:
602
603    css => '@import(my_external_stylesheet.css);'
604
605=item C<messages>
606
607This works the same way as the C<messages> parameter to
608C<< CGI::FormBuilder->new >>; you can provide either a hashref of messages
609or a filename.
610
611The default messages used by Text::FormBuilder are:
612
613    text_author       Created by %s
614    text_madewith     Made with %s version %s
615    text_required     (Required fields are marked in <strong>bold</strong>.)
616    text_invalid      Missing or invalid value.
617
618Any messages you set here get passed on to CGI::FormBuilder, which means
619that you should be able to put all of your customization messages in one
620big file.
621
622=item C<charset>
623
624Sets the character encoding for the generated page. The default is ISO-8859-1.
625
626=back
627
628All other options given to C<build> are passed on verbatim to the
629L<CGI::FormBuilder> constructor. Any options given here override the
630defaults that this module uses.
631
632The C<form>, C<write>, and C<write_module> methods will all call
633C<build> with no options for you if you do not do so explicitly.
634This allows you to say things like this:
635
636    my $form = Text::FormBuilder->new->parse('formspec.txt')->form;
637
638However, if you need to specify options to C<build>, you must call it
639explictly after C<parse>.
640
641=head2 form
642
643    my $form = $parser->form;
644
645Returns the L<CGI::FormBuilder> object. Remember that you can modify
646this object directly, in order to (for example) dynamically populate
647dropdown lists or change input types at runtime.
648
649=head2 write
650
651    $parser->write($out_file);
652    # or just print to STDOUT
653    $parser->write;
654
655Calls C<render> on the FormBuilder form, and either writes the resulting
656HTML to a file, or to STDOUT if no filename is given.
657
658=head2 write_module
659
660    $parser->write_module($package, $use_tidy);
661
662Takes a package name, and writes out a new module that can be used by your
663CGI script to render the form. This way, you only need CGI::FormBuilder on
664your server, and you don't have to parse the form spec each time you want
665to display your form. The generated module has one function (not exported)
666called C<get_form>, that takes a CGI object as its only argument, and returns
667a CGI::FormBuilder object.
668
669First, you parse the formspec and write the module, which you can do as a one-liner:
670
671    $ perl -MText::FormBuilder -e"Text::FormBuilder->parse('formspec.txt')->write_module('My::Form')"
672
673And then, in your CGI script, use the new module:
674
675    #!/usr/bin/perl -w
676    use strict;
677   
678    use CGI;
679    use My::Form;
680   
681    my $q = CGI->new;
682    my $form = My::Form::get_form($q);
683   
684    # do the standard CGI::FormBuilder stuff
685    if ($form->submitted && $form->validate) {
686        # process results
687    } else {
688        print $q->header;
689        print $form->render;
690    }
691
692If you pass a true value as the second argument to C<write_module>, the parser
693will run L<Perl::Tidy> on the generated code before writing the module file.
694
695    # write tidier code
696    $parser->write_module('My::Form', 1);
697
698=head2 dump
699
700Uses L<YAML> to print out a human-readable representation of the parsed
701form spec.
702
703=head1 DEFAULTS
704
705These are the default settings that are passed to C<< CGI::FormBuilder->new >>:
706
707    method => 'GET'
708    javascript => 0
709    keepextras => 1
710
711Any of these can be overriden by the C<build> method:
712
713    # use POST instead
714    $parser->build(method => 'POST')->write;
715
716=head1 LANGUAGE
717
718    field_name[size]|descriptive label[hint]:type=default{option1[display string],...}//validate
719   
720    !title ...
721   
722    !author ...
723   
724    !description {
725        ...
726    }
727   
728    !pattern name /regular expression/
729   
730    !list name {
731        option1[display string],
732        option2[display string],
733        ...
734    }
735   
736    !list name &{ CODE }
737   
738    !section id heading
739   
740    !head ...
741
742=head2 Directives
743
744=over
745
746=item C<!pattern>
747
748Defines a validation pattern.
749
750=item C<!list>
751
752Defines a list for use in a C<radio>, C<checkbox>, or C<select> field.
753
754=item C<!title>
755
756=item C<!author>
757
758=item C<!description>
759
760A brief description of the form. Suitable for special instructions on how to
761fill out the form.
762
763=item C<!section>
764
765Starts a new section. Each section has its own heading and id, which are
766written by default into spearate tables.
767
768=item C<!head>
769
770Inserts a heading between two fields. There can only be one heading between
771any two fields; the parser will warn you if you try to put two headings right
772next to each other.
773
774=back
775
776=head2 Fields
777
778First, a note about multiword strings in the fields. Anywhere where it says
779that you may use a multiword string, this means that you can do one of two
780things. For strings that consist solely of alphanumeric characters (i.e.
781C<\w+>) and spaces, the string will be recognized as is:
782
783    field_1|A longer label
784
785If you want to include non-alphanumerics (e.g. punctuation), you must
786single-quote the string:
787
788    field_2|'Dept./Org.'
789
790To include a literal single-quote in a single-quoted string, escape it with
791a backslash:
792
793    field_3|'\'Official\' title'
794
795Now, back to the beginning. Form fields are each described on a single line.
796The simplest field is just a name (which cannot contain any whitespace):
797
798    color
799
800This yields a form with one text input field of the default size named `color'.
801The generated label for this field would be ``Color''. To add a longer or more\
802descriptive label, use:
803
804    color|Favorite color
805
806The descriptive label can be a multiword string, as described above. So if you
807want punctuation in the label, you should single quote it:
808
809    color|'Fav. color'
810
811To use a different input type:
812
813    color|Favorite color:select{red,blue,green}
814
815Recognized input types are the same as those used by CGI::FormBuilder:
816
817    text        # the default
818    textarea
819    password
820    file
821    checkbox
822    radio
823    select
824    hidden
825    static
826
827To change the size of the input field, add a bracketed subscript after the
828field name (but before the descriptive label):
829
830    # for a single line field, sets size="40"
831    title[40]:text
832   
833    # for a multiline field, sets rows="4" and cols="30"
834    description[4,30]:textarea
835
836For the input types that can have options (C<select>, C<radio>, and
837C<checkbox>), here's how you do it:
838
839    color|Favorite color:select{red,blue,green}
840
841Values are in a comma-separated list of single words or multiword strings
842inside curly braces. Whitespace between values is irrelevant.
843
844To add more descriptive display text to a value in a list, add a square-bracketed
845``subscript,'' as in:
846
847    ...:select{red[Scarlet],blue[Azure],green[Olive Drab]}
848
849If you have a list of options that is too long to fit comfortably on one line,
850you should use the C<!list> directive:
851
852    !list MONTHS {
853        1[January],
854        2[February],
855        3[March],
856        # and so on...
857    }
858   
859    month:select@MONTHS
860
861There is another form of the C<!list> directive: the dynamic list:
862
863    !list RANDOM &{ map { rand } (0..5) }
864
865The code inside the C<&{ ... }> is C<eval>ed by C<build>, and the results
866are stuffed into the list. The C<eval>ed code can either return a simple
867list, as the example does, or the fancier C<< ( { value1 => 'Description 1'},
868{ value2 => 'Description 2}, ... ) >> form.
869
870I<B<NOTE:> This feature of the language may go away unless I find a compelling
871reason for it in the next few versions. What I really wanted was lists that
872were filled in at run-time (e.g. from a database), and that can be done easily
873enough with the CGI::FormBuilder object directly.>
874
875If you want to have a single checkbox (e.g. for a field that says ``I want to
876recieve more information''), you can just specify the type as checkbox without
877supplying any options:
878
879    moreinfo|I want to recieve more information:checkbox
880
881In this case, the label ``I want to recieve more information'' will be
882printed to the right of the checkbox.
883
884You can also supply a default value to the field. To get a default value of
885C<green> for the color field:
886
887    color|Favorite color:select=green{red,blue,green}
888
889Default values can also be either single words or multiword strings.
890
891To validate a field, include a validation type at the end of the field line:
892
893    email|Email address//EMAIL
894
895Valid validation types include any of the builtin defaults from L<CGI::FormBuilder>,
896or the name of a pattern that you define with the C<!pattern> directive elsewhere
897in your form spec:
898
899    !pattern DAY /^([1-3][0-9])|[1-9]$/
900   
901    last_day//DAY
902
903If you just want a required value, use the builtin validation type C<VALUE>:
904
905    title//VALUE
906
907By default, adding a validation type to a field makes that field required. To
908change this, add a C<?> to the end of the validation type:
909
910    contact//EMAIL?
911
912In this case, you would get a C<contact> field that was optional, but if it
913were filled in, would have to validate as an C<EMAIL>.
914
915=head2 Comments
916
917    # comment ...
918
919Any line beginning with a C<#> is considered a comment.
920
921=head1 TODO
922
923Allow for custom wrappers around the C<form_template>
924
925Maybe use HTML::Template instead of Text::Template for the built in template
926(since CGI::FormBuilder users may be more likely to already have HTML::Template)
927
928Better examples in the docs (maybe a standalone or two as well)
929
930C<!include> directive to include external formspec files
931
932Better tests!
933
934=head1 BUGS
935
936I'm sure they're in there, I just haven't tripped over any new ones lately. :-)
937
938=head1 SEE ALSO
939
940L<CGI::FormBuilder>
941
942=head1 THANKS
943
944Thanks to eszpee for pointing out some bugs in the default value parsing,
945as well as some suggestions for i18n/l10n and splitting up long forms into
946sections.
947
948=head1 AUTHOR
949
950Peter Eichman C<< <peichman@cpan.org> >>
951
952=head1 COPYRIGHT AND LICENSE
953
954Copyright E<copy>2004 by Peter Eichman.
955
956This program is free software; you can redistribute it and/or
957modify it under the same terms as Perl itself.
958
959=cut
Note: See TracBrowser for help on using the repository browser.