~ubuntu-branches/ubuntu/vivid/libcgi-formbuilder-perl/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/0004-Avoid-unneeded-warning-from-CGI.pm-4.05-or-newer.patch/lib/CGI/FormBuilder/Multi.pm

  • Committer: Package Import Robot
  • Author(s): Jonas Smedegaard, Simon McVittie
  • Date: 2014-11-15 15:58:40 UTC
  • Revision ID: package-import@ubuntu.com-20141115155840-efg9763exm6xjs0r
Tags: 3.09-2
[ Simon McVittie ]
Merge patches 0005-0006 into 0004, and adapt to retain support for
objects that mimic the CGI.pm API but do not have param_fetch.
Closes: bug#769240. Thanks to Simon McVittie.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
###########################################################################
 
3
# Copyright (c) Nate Wiger http://nateware.com. All Rights Reserved.
 
4
# Please visit http://formbuilder.org for tutorials, support, and examples.
 
5
###########################################################################
 
6
 
 
7
package CGI::FormBuilder::Multi;
 
8
 
 
9
=head1 NAME
 
10
 
 
11
CGI::FormBuilder::Multi - Create multi-page FormBuilder forms 
 
12
 
 
13
=head1 SYNOPSIS
 
14
 
 
15
    use CGI::FormBuilder::Multi;
 
16
    use CGI::Session;   # or something similar
 
17
 
 
18
    # Top-level "meta-form"
 
19
    my $multi = CGI::FormBuilder::Multi->new(
 
20
 
 
21
        # form 1 options
 
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)],
 
27
        },
 
28
 
 
29
        # form 2 options
 
30
        { fields   => [qw(billing_name billing_card billing_exp
 
31
                          billing_address billing_city billing_state
 
32
                          billing_zip billing_phone)],
 
33
          title    => 'Billing',
 
34
          template => 'page2.tmpl',
 
35
          required => 'ALL',
 
36
        },
 
37
 
 
38
        # form 3 options
 
39
        { fields   => [qw(same_as_billing shipping_address
 
40
                          shipping_city shipping_state shipping_zip)],
 
41
          title    => 'Shipping',
 
42
          template => 'page3.tmpl',
 
43
          required => 'ALL',
 
44
        },
 
45
 
 
46
        # a couple options specific to this module
 
47
        navbar => 1,
 
48
 
 
49
        # remaining options (not in hashrefs) apply to all forms
 
50
        header => 1,
 
51
        method => 'POST',
 
52
        submit => 'Continue',
 
53
        values => $dbi_hashref_query,
 
54
    );
 
55
 
 
56
    # Get current page's form
 
57
    my $form = $multi->form;
 
58
 
 
59
    if ($form->submitted && $form->validate) {
 
60
 
 
61
        # Retrieve session id
 
62
        my $sid = $form->sessionid;
 
63
 
 
64
        # Initialize session
 
65
        my $session = CGI::Session->new("driver:File", $sid, {Directory=>'/tmp'});
 
66
 
 
67
        # Automatically store updated data in session
 
68
        $session->save_param($form);
 
69
 
 
70
        # last page?
 
71
        if ($multi->page == $multi->pages) {
 
72
            print $form->confirm;
 
73
            exit;
 
74
        }
 
75
 
 
76
        # Still here, goto next page
 
77
        $multi->page++;
 
78
 
 
79
        # And re-get form (no "my" on $form!)
 
80
        $form = $multi->form;
 
81
 
 
82
        # Make sure it has the right sessionid
 
83
        $form->sessionid($session->id);
 
84
 
 
85
        # on page 3 we have special field handling
 
86
        if ($multi->page == 3) {
 
87
            $form->field(name    => 'same_as_billing',
 
88
                         type    => 'checkbox',
 
89
                         options => 'Yes',
 
90
                         jsclick => 'this.form.submit()');
 
91
        }
 
92
    }
 
93
 
 
94
    # Fall through and print next page's form
 
95
    print $form->render;
 
96
 
 
97
=cut
 
98
 
 
99
use strict;
 
100
use warnings;
 
101
no  warnings 'uninitialized';
 
102
 
 
103
use CGI::FormBuilder;
 
104
use CGI::FormBuilder::Util;
 
105
 
 
106
our $VERSION = '3.09';
 
107
 
 
108
our %DEFAULT = (
 
109
    pagename => '_page',
 
110
    navbar   => 0,
 
111
);
 
112
 
 
113
sub new {
 
114
    my $mod = shift;
 
115
    my $class = ref($mod) || $mod;
 
116
 
 
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
 
119
    my @forms = ();
 
120
    while (ref $_[0]) {
 
121
        push @forms, shift;
 
122
    }
 
123
 
 
124
    # Remaining options are form opts
 
125
    my %opt  = arghash(@_);
 
126
 
 
127
    # If no forms, and specified number of pages, use that instead
 
128
    if ($opt{pages}) {
 
129
        puke "Can't specify pages and form hashrefs" if @forms;
 
130
        my $p = 0;
 
131
        push @forms, {} while $p++ < $opt{pages};
 
132
    }
 
133
    puke "Must specify at least one form or 'pages' option for ::Multi" unless @forms;
 
134
 
 
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') {
 
139
        require CGI;
 
140
        $CGI::USE_PARAM_SEMICOLONS = 0;     # fuck ; in urls
 
141
        $opt{params} = CGI->new($opt{params});
 
142
    }               
 
143
 
 
144
    # Options for me
 
145
    my %me;
 
146
    while (my($k,$v) = each %DEFAULT) {
 
147
        $me{$k} = exists $opt{$k} ? delete $opt{$k} : $v;
 
148
    }
 
149
    $me{forms} = \@forms;
 
150
 
 
151
    # Plop in our defaults per-form unless it's an object
 
152
    @forms = map { ref $_ eq 'HASH' ? { %opt, %$_ } : $_ } @forms;
 
153
 
 
154
    # Top-level multi
 
155
    my $self = bless \%me, $class;
 
156
 
 
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;
 
161
 
 
162
    return $self;
 
163
}
 
164
 
 
165
# return an lvalue to allow $multi->page++ and $multi->page--;
 
166
sub page : lvalue {
 
167
    my $self = shift;
 
168
    $self->{page} = shift if @_;    # rvalue
 
169
    $self->{page};                  # lvalue
 
170
}
 
171
 
 
172
*forms = \&pages;
 
173
sub pages {
 
174
    my $self = shift;
 
175
    puke "No arguments allowed to \$multi->pages or \$multi->forms" if @_;
 
176
    return @{$self->{forms}};
 
177
}
 
178
 
 
179
# return the form from this page, as a new object
 
180
sub form {
 
181
    my $self = shift;
 
182
    puke "No arguments allowed to \$multi->form" if @_;
 
183
    my $page = $self->page;
 
184
    my $idx  = $page - 1;
 
185
 
 
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];
 
189
 
 
190
    if (ref $form eq 'CGI::FormBuilder') {
 
191
        # already constructed
 
192
    } else {
 
193
        $form = CGI::FormBuilder->new(%$form);
 
194
    }
 
195
 
 
196
    # hooks
 
197
    $form->page($self->page);
 
198
    $form->text(scalar $self->navbar) if $self->{navbar}; # cheat
 
199
 
 
200
    # create new $form and cache for re-get
 
201
    $self->{_cache}{forms}[$idx] = $form;
 
202
}
 
203
 
 
204
# allow jumps between pages
 
205
sub navbar {
 
206
    my $self = shift;
 
207
    $self->{navbar} = shift if @_;
 
208
    my $base = basename; 
 
209
    my $pnam = $self->{pagename};
 
210
    return '' unless $self->pages > 1;
 
211
 
 
212
    # Look for extra params to keep
 
213
    # Algorithm here is a bit different
 
214
    my @keep;
 
215
    if ($self->{keepextras}) {
 
216
        unless (ref $self->{keepextras}) {
 
217
            $self->{keepextras} = [ $self->{params}->param ];
 
218
        }
 
219
        for my $k (@{$self->{keepextras}}) {
 
220
            next if $k eq $pnam;
 
221
            for my $v ($self->{params}->param($k)) {
 
222
                push @keep, { name => $k, value => $v };
 
223
            }
 
224
        }
 
225
    }
 
226
 
 
227
    my @html = ();
 
228
    for (my $p=1; $p <= $self->pages; $p++) {
 
229
        my $cl = $self->page == $p ? 'fb_multi_page' : 'fb_multi_link';
 
230
         
 
231
        # this looks like gibberish
 
232
        my $purl = basename . '?' . join '&',
 
233
            map { "$_->{name}=$_->{value}" } @keep,
 
234
                     { name => $pnam, value => $p };
 
235
 
 
236
        push @html, htmltag('a', href => $purl, class => $cl)
 
237
                    . ($self->{forms}[$p-1]{title} || "Page $p") . '</a>';
 
238
    }
 
239
 
 
240
    return wantarray ? @html : '<p>'. join(' | ', @html) . '<p>';
 
241
}
 
242
 
 
243
1;
 
244
__END__
 
245
 
 
246
=head1 DESCRIPTION
 
247
 
 
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.
 
251
 
 
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:
 
256
 
 
257
    my $multi = CGI::FormBuilder::Multi->new(...);
 
258
 
 
259
    # current form
 
260
    my $form  = $multi->form;
 
261
 
 
262
    $multi->page++;         # page forward
 
263
    $multi->page--;         # and back
 
264
    $multi->page = $multi->pages;   # goto last page
 
265
 
 
266
    # current form
 
267
    $form = $multi->form;
 
268
 
 
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".
 
272
 
 
273
=head1 METHODS
 
274
 
 
275
The following methods are provided:
 
276
 
 
277
=head2 new(\%form1, \%form2, opt => val)
 
278
 
 
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.
 
283
 
 
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.
 
287
 
 
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
 
293
basis.
 
294
 
 
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:
 
297
 
 
298
    my $multi = CGI::FormBuilder::Multi->new(pages => 3);
 
299
 
 
300
With this approach, you will have to dynamically assemble each
 
301
page as you come to them. The mailing list can help.
 
302
 
 
303
The L</"SYNOPSIS"> above is very representative of typical usage.
 
304
 
 
305
=head2 form()
 
306
 
 
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()>.
 
311
 
 
312
=head2 page($num)
 
313
 
 
314
This sets and returns the current page. It can accept a page number
 
315
either as an argument, or directly as an assignment:
 
316
 
 
317
    $multi->page(1);    # page 1
 
318
    $multi->page = 1;   # same thing
 
319
 
 
320
    $multi->page++;     # next page
 
321
    $multi->page--;     # back one
 
322
 
 
323
    if ($multi->page == $multi->pages) {
 
324
        # last page
 
325
    }
 
326
 
 
327
Hint: Usually, you should only change pages once you have validated
 
328
the current page's form appropriately.
 
329
 
 
330
=head2 pages()
 
331
 
 
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.
 
336
 
 
337
=head2 navbar($onoff)
 
338
 
 
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.
 
343
 
 
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:
 
346
 
 
347
    my $html = $multi->navbar;      # scalar HTML
 
348
    my @link = $multi->navbar;      # array of links
 
349
 
 
350
This is useful in something like this:
 
351
 
 
352
    my $nav = $multi->navbar;
 
353
    $form = $multi->form;
 
354
    $form->tmpl_param(navbar => $navbar);
 
355
 
 
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.
 
358
 
 
359
=head1 SEE ALSO
 
360
 
 
361
L<CGI::FormBuilder>
 
362
 
 
363
=head1 REVISION
 
364
 
 
365
$Id: Multi.pm 100 2007-03-02 18:13:13Z nwiger $
 
366
 
 
367
=head1 AUTHOR
 
368
 
 
369
Copyright (c) L<Nate Wiger|http://nateware.com>. All Rights Reserved.
 
370
 
 
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.
 
374
 
 
375
=cut
 
376