Changeset 21 in text-formbuilder for trunk/lib/Text/FormBuilder.pm


Ignore:
Timestamp:
11/12/04 16:54:23 (19 years ago)
Author:
peter
Message:

added !group and !field directive to the language to allow for horizontal groups of input fields
moving to a new representation of the parsed formspec based on lines as opposed to fields

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/Text/FormBuilder.pm

    r19 r21  
    66use vars qw($VERSION); 
    77 
    8 $VERSION = '0.05'; 
     8$VERSION = '0.06'; 
    99 
    1010use Carp; 
     
    8787        delete $$_{validate} unless $$_{validate}; 
    8888    } 
     89 
     90    # expand groups 
     91    my %groups = %{ $self->{form_spec}{groups} }; 
     92    foreach (grep { $$_[0] eq 'group' } @{ $self->{form_spec}{lines} }) { 
     93        $$_[1]{group} =~ s/^\%//;       # strip leading % from group var name 
     94         
     95        if (exists $groups{$$_[1]{group}}) { 
     96            my @fields; # fields in the group 
     97            push @fields, { %$_ } foreach @{ $groups{$$_[1]{group}} }; 
     98            for my $field (@fields) { 
     99                $$field{label} ||= ucfirst $$field{name}; 
     100                $$field{name} = "$$_[1]{name}_$$field{name}";                 
     101            } 
     102            $_ = [ 'group', { label => $$_[1]{label} || ucfirst(join(' ',split('_',$$_[1]{name}))), group => \@fields } ]; 
     103        } 
     104    } 
     105     
     106    $self->{form_spec}{fields} = []; 
     107    for my $line (@{ $self->{form_spec}{lines} }) { 
     108        if ($$line[0] eq 'group') { 
     109            push @{ $self->{form_spec}{fields} }, $_ foreach @{ $$line[1]{group} }; 
     110        } elsif ($$line[0] eq 'field') { 
     111            push @{ $self->{form_spec}{fields} }, $$line[1]; 
     112        } 
     113    } 
     114     
    89115     
    90116    # substitute in list names 
     
    105131        } 
    106132    } 
    107  
     133     
     134     
     135     
     136 
     137     
     138    # TODO: use lines instead of fields 
     139    # TODO: change template to do groups 
     140     
    108141    # TODO: configurable threshold for this 
    109142    foreach (@{ $self->{form_spec}{fields} }) { 
     
    116149        keepextras => 1, 
    117150        title => $self->{form_spec}{title}, 
    118         fields => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ], 
     151        #fields => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ], 
    119152        template => { 
    120153            type => 'Text', 
     
    125158            }, 
    126159            data => { 
     160                lines       => $self->{form_spec}{lines}, 
    127161                headings    => $self->{form_spec}{headings}, 
    128162                author      => $self->{form_spec}{author}, 
     
    137171    $self->{built} = 1; 
    138172     
     173    # TEMP: dump @lines structure 
     174    use YAML; 
     175    warn YAML::Dump($self->{form_spec}->{lines}), "\n"; 
     176     
    139177    return $self; 
    140178} 
     
    182220    my $source = $options{form_only} ? $self->_form_template : $self->_template; 
    183221     
    184     delete $options{fomr_only}; 
     222    delete $options{form_only}; 
    185223     
    186224    my $form_options = keys %options > 0 ? Data::Dumper->Dump([$self->{build_options}],['*options']) : ''; 
     
    262300<% $start %> 
    263301<table> 
    264 <% my $i; foreach(@fields) { 
    265     $OUT .= qq[  <tr><th class="sectionhead" colspan="2"><h2>$headings[$i]</h2></th></tr>\n] if $headings[$i]; 
    266     $OUT .= $$_{invalid} ? qq[  <tr class="invalid">] : qq[  <tr>]; 
    267     $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}:</strong>] : "$$_{label}:") . '</th>'; 
    268     if ($$_{invalid}) { 
    269         $OUT .= qq[<td>$$_{field} $$_{comment} Missing or invalid value.</td></tr>\n]; 
    270     } else { 
    271         $OUT .= qq[<td>$$_{field} $$_{comment}</td></tr>\n]; 
    272     } 
    273     $i++; 
     302 
     303<% for my $line (@lines) { 
     304 
     305    if ($$line[0] eq 'head') { 
     306        $OUT .= qq[  <tr><th class="sectionhead" colspan="2"><h2>$$line[1]</h2></th></tr>\n] 
     307    } elsif ($$line[0] eq 'field') { 
     308        #TODO: we only need the field names, not the full field spec in the lines strucutre 
     309        local $_ = $field{$$line[1]{name}}; 
     310        $OUT .= $$_{invalid} ? qq[  <tr class="invalid">] : qq[  <tr>]; 
     311        $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}:</strong>] : "$$_{label}:") . '</th>'; 
     312        if ($$_{invalid}) { 
     313            $OUT .= qq[<td>$$_{field} $$_{comment} Missing or invalid value.</td></tr>\n]; 
     314        } else { 
     315            $OUT .= qq[<td>$$_{field} $$_{comment}</td></tr>\n]; 
     316        } 
     317    } elsif ($$line[0] eq 'group') { 
     318        my @field_names = map { $$_{name} } @{ $$line[1]{group} }; 
     319        my @group_fields = map { $field{$_} } @field_names; 
     320        $OUT .= (grep { $$_{invalid} } @group_fields) ? qq[  <tr class="invalid">\n] : qq[  <tr>\n]; 
     321         
     322         
     323        #TODO: validated but not required fields 
     324        # in a form spec: //EMAIL? 
     325         
     326        #TODO: this doesn't seem to be working; all groups are getting marked as required         
     327        $OUT .= '    <th class="label">'; 
     328        $OUT .= (grep { $$_{required} } @group_fields) ? qq[<strong class="required">$$line[1]{label}:</strong>] : "$$line[1]{label}:"; 
     329        $OUT .= qq[</th>\n]; 
     330         
     331        $OUT .= qq[    <td>]; 
     332        $OUT .= join(' ', map { qq[<small class="sublabel">$$_{label}</small> $$_{field} $$_{comment}] } @group_fields); 
     333        $OUT .= qq[    </td>\n]; 
     334        $OUT .= qq[  </tr>\n]; 
     335    }    
     336     
     337 
    274338} %> 
    275339  <tr><th></th><td style="padding-top: 1em;"><% $submit %></td></tr> 
     
    290354    th.label { font-weight: normal; text-align: right; vertical-align: top; } 
    291355    td ul { list-style: none; padding-left: 0; margin-left: 0; } 
     356    .sublabel { color: #999; } 
    292357  </style> 
    293358</head> 
     
    321386=head1 NAME 
    322387 
    323 Text::FormBuilder - Parser for a minilanguage for generating web forms 
     388Text::FormBuilder - Create CGI::FormBuilder objects from simple text descriptions 
    324389 
    325390=head1 SYNOPSIS 
     
    536601    static 
    537602 
    538 This example also shows how you can list multiple values for the input types 
    539 that take multiple values (C<select>, C<radio>, and C<checkbox>). Values are 
    540 in a comma-separated list inside curly braces. Whitespace between values is 
    541 irrelevant, although there cannot be any whitespace within a value. 
     603To change the size of the input field, add a bracketed subscript after the 
     604field name (but before the descriptive label): 
     605 
     606    # for a single line field, sets size="40" 
     607    title[40]:text 
     608     
     609    # for a multiline field, sets rows="4" and cols="30" 
     610    description[4,30]:textarea 
     611 
     612For the input types that can have options (C<select>, C<radio>, and 
     613C<checkbox>), here's how you do it: 
     614 
     615    color|Favorite color:select{red,blue,green} 
     616 
     617Values are in a comma-separated list inside curly braces. Whitespace 
     618between values is irrelevant, although there cannot be any whitespace 
     619within a value. 
    542620 
    543621To add more descriptive display text to a vlaue in a list, add a square-bracketed 
     
    566644The code inside the C<&{ ... }> is C<eval>ed by C<build>, and the results 
    567645are stuffed into the list. The C<eval>ed code can either return a simple 
    568 list, as the example does, or the fancier C<( { value1 => 'Description 1'}, 
    569 { value2 => 'Description 2}, ...)> form. 
     646list, as the example does, or the fancier C<< ( { value1 => 'Description 1'}, 
     647{ value2 => 'Description 2}, ... ) >> form. 
    570648 
    571649B<NOTE:> This feature of the language may go away unless I find a compelling 
     
    583661    email|Email address//EMAIL 
    584662 
    585 Valid validation types include any of the builtin defaults from CGI::FormBuilder, 
     663Valid validation types include any of the builtin defaults from L<CGI::FormBuilder>, 
    586664or the name of a pattern that you define with the C<!pattern> directive elsewhere 
    587665in your form spec: 
Note: See TracChangeset for help on using the changeset viewer.