2
###########################################################################
3
# Copyright (c) Nate Wiger http://nateware.com. All Rights Reserved.
4
# Please visit http://formbuilder.org for tutorials, support, and examples.
5
###########################################################################
7
package CGI::FormBuilder::Multi;
11
CGI::FormBuilder::Multi - Create multi-page FormBuilder forms
15
use CGI::FormBuilder::Multi;
16
use CGI::Session; # or something similar
18
# Top-level "meta-form"
19
my $multi = CGI::FormBuilder::Multi->new(
22
{ fields => [qw(name email daytime_phone evening_phone)],
23
title => 'Basic Info',
24
template => 'page1.tmpl',
25
validate => { name => 'NAME', email => 'EMAIL' },
26
required => [qw(name email daytime_phone)],
30
{ fields => [qw(billing_name billing_card billing_exp
31
billing_address billing_city billing_state
32
billing_zip billing_phone)],
34
template => 'page2.tmpl',
39
{ fields => [qw(same_as_billing shipping_address
40
shipping_city shipping_state shipping_zip)],
42
template => 'page3.tmpl',
46
# a couple options specific to this module
49
# remaining options (not in hashrefs) apply to all forms
53
values => $dbi_hashref_query,
56
# Get current page's form
57
my $form = $multi->form;
59
if ($form->submitted && $form->validate) {
62
my $sid = $form->sessionid;
65
my $session = CGI::Session->new("driver:File", $sid, {Directory=>'/tmp'});
67
# Automatically store updated data in session
68
$session->save_param($form);
71
if ($multi->page == $multi->pages) {
76
# Still here, goto next page
79
# And re-get form (no "my" on $form!)
82
# Make sure it has the right sessionid
83
$form->sessionid($session->id);
85
# on page 3 we have special field handling
86
if ($multi->page == 3) {
87
$form->field(name => 'same_as_billing',
90
jsclick => 'this.form.submit()');
94
# Fall through and print next page's form
101
no warnings 'uninitialized';
103
use CGI::FormBuilder;
104
use CGI::FormBuilder::Util;
106
our $VERSION = '3.09';
115
my $class = ref($mod) || $mod;
117
# Arg parsing is a little more complex than FormBuilder proper,
118
# since we keep going thru our options until we don't see hashrefs
124
# Remaining options are form opts
125
my %opt = arghash(@_);
127
# If no forms, and specified number of pages, use that instead
129
puke "Can't specify pages and form hashrefs" if @forms;
131
push @forms, {} while $p++ < $opt{pages};
133
puke "Must specify at least one form or 'pages' option for ::Multi" unless @forms;
135
# Check for CGI params
136
# This is duplicated code straight out of FormBuilder.pm,
137
# but it's needed here as well so we can get our _page
138
unless ($opt{params} && ref $opt{params} ne 'HASH') {
140
$CGI::USE_PARAM_SEMICOLONS = 0; # fuck ; in urls
141
$opt{params} = CGI->new($opt{params});
146
while (my($k,$v) = each %DEFAULT) {
147
$me{$k} = exists $opt{$k} ? delete $opt{$k} : $v;
149
$me{forms} = \@forms;
151
# Plop in our defaults per-form unless it's an object
152
@forms = map { ref $_ eq 'HASH' ? { %opt, %$_ } : $_ } @forms;
155
my $self = bless \%me, $class;
157
# Copy CGI object into self, and get page
158
$self->{params} = $opt{params};
159
$self->{keepextras} = $opt{keepextras};
160
$self->{page} = $self->{params}->param($self->{pagename}) || 1;
165
# return an lvalue to allow $multi->page++ and $multi->page--;
168
$self->{page} = shift if @_; # rvalue
169
$self->{page}; # lvalue
175
puke "No arguments allowed to \$multi->pages or \$multi->forms" if @_;
176
return @{$self->{forms}};
179
# return the form from this page, as a new object
182
puke "No arguments allowed to \$multi->form" if @_;
183
my $page = $self->page;
186
return $self->{_cache}{forms}[$idx] if $self->{_cache}{forms}[$idx];
187
puke "Invalid page $page, no form present"
188
unless my $form = $self->{forms}[$idx];
190
if (ref $form eq 'CGI::FormBuilder') {
191
# already constructed
193
$form = CGI::FormBuilder->new(%$form);
197
$form->page($self->page);
198
$form->text(scalar $self->navbar) if $self->{navbar}; # cheat
200
# create new $form and cache for re-get
201
$self->{_cache}{forms}[$idx] = $form;
204
# allow jumps between pages
207
$self->{navbar} = shift if @_;
209
my $pnam = $self->{pagename};
210
return '' unless $self->pages > 1;
212
# Look for extra params to keep
213
# Algorithm here is a bit different
215
if ($self->{keepextras}) {
216
unless (ref $self->{keepextras}) {
217
$self->{keepextras} = [ $self->{params}->param ];
219
for my $k (@{$self->{keepextras}}) {
221
for my $v ($self->{params}->param($k)) {
222
push @keep, { name => $k, value => $v };
228
for (my $p=1; $p <= $self->pages; $p++) {
229
my $cl = $self->page == $p ? 'fb_multi_page' : 'fb_multi_link';
231
# this looks like gibberish
232
my $purl = basename . '?' . join '&',
233
map { "$_->{name}=$_->{value}" } @keep,
234
{ name => $pnam, value => $p };
236
push @html, htmltag('a', href => $purl, class => $cl)
237
. ($self->{forms}[$p-1]{title} || "Page $p") . '</a>';
240
return wantarray ? @html : '<p>'. join(' | ', @html) . '<p>';
248
This module works with C<CGI::FormBuilder> to create multi-page forms.
249
Each form is specified using the same options you would pass directly
250
into B<FormBuilder>. See L<CGI::FormBuilder> for a list of these options.
252
The multi-page "meta-form" is a composite of the individual forms you
253
specify, tied together via the special C<_page> CGI param. The current
254
form is available via the C<form()> method, and the current page is
255
available via C<page()>. It's up to you to navigate appropriately:
257
my $multi = CGI::FormBuilder::Multi->new(...);
260
my $form = $multi->form;
262
$multi->page++; # page forward
263
$multi->page--; # and back
264
$multi->page = $multi->pages; # goto last page
267
$form = $multi->form;
269
To make things are fluid as possible, you should title each of your
270
forms, even if you're using a template. This will allow C<::Multi>
271
to create cross-links by-name instead of just "Page 2".
275
The following methods are provided:
277
=head2 new(\%form1, \%form2, opt => val)
279
This creates a new C<CGI::FormBuilder::Multi> object. Forms are
280
specified as hashrefs of options, in sequential order, similar to
281
how fields are specified. The order the forms are in is the order
282
that the pages will cycle through.
284
In addition to a hashref, forms can be directly specified as a
285
C<$form> object that has already been created. For existing objects,
286
the below does not apply.
288
When the first non-ref argument is seen, then all remaining args
289
are taken as common options that apply to all forms. In this way,
290
you can specify global settings for things like C<method> or
291
C<header> (which will likely be the same), and then override
292
individual settings like C<fields> and C<validate> on a per-form
295
If you do not wish to specify any options for your forms, you
296
can instead just specify the C<pages> option, for example:
298
my $multi = CGI::FormBuilder::Multi->new(pages => 3);
300
With this approach, you will have to dynamically assemble each
301
page as you come to them. The mailing list can help.
303
The L</"SYNOPSIS"> above is very representative of typical usage.
307
This returns the current page's form, as an object created
308
directly by C<< CGI::FormBuilder->new >>. All valid B<FormBuilder>
309
methods and options work on the form. To change which form is
310
returned, us C<page()>.
314
This sets and returns the current page. It can accept a page number
315
either as an argument, or directly as an assignment:
317
$multi->page(1); # page 1
318
$multi->page = 1; # same thing
320
$multi->page++; # next page
321
$multi->page--; # back one
323
if ($multi->page == $multi->pages) {
327
Hint: Usually, you should only change pages once you have validated
328
the current page's form appropriately.
332
This returns the total number of pages. Actually, what it returns
333
is an array of all forms (and hence it has the alias C<forms()>),
334
which just so happens to become the length in a scalar context,
335
just like anywhere else in Perl.
337
=head2 navbar($onoff)
339
This returns a navigation bar that allows the user to jump between
340
pages of the form. This is useful if you want to let a person fill
341
out different pages out of order. In most cases, you do I<not>
342
want this, so it's off by default.
344
To use it, the best way is setting C<< navbar => 1 >> in C<new()>.
345
However, you can also get it yourself to render your own HTML:
347
my $html = $multi->navbar; # scalar HTML
348
my @link = $multi->navbar; # array of links
350
This is useful in something like this:
352
my $nav = $multi->navbar;
353
$form = $multi->form;
354
$form->tmpl_param(navbar => $navbar);
356
The navbar will have two style classes: C<fb_multi_page> for the
357
current page's link, and C<fb_multi_link> for the others.
365
$Id: Multi.pm 100 2007-03-02 18:13:13Z nwiger $
369
Copyright (c) L<Nate Wiger|http://nateware.com>. All Rights Reserved.
371
This module is free software; you may copy this under the terms of
372
the GNU General Public License, or the Artistic License, copies of
373
which should have accompanied your Perl kit.