| lib/CGI/FormBuilder/Multi.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 56 | 80 | 70.0 |
| branch | 16 | 40 | 40.0 |
| condition | 3 | 11 | 27.2 |
| subroutine | 9 | 10 | 90.0 |
| pod | 5 | 5 | 100.0 |
| total | 89 | 146 | 60.9 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 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 | 1 | 1 | 533 | use strict; | |||
| 1 | 2 | ||||||
| 1 | 24 | ||||||
| 100 | 1 | 1 | 3 | use warnings; | |||
| 1 | 1 | ||||||
| 1 | 24 | ||||||
| 101 | 1 | 1 | 3 | no warnings 'uninitialized'; | |||
| 1 | 1 | ||||||
| 1 | 30 | ||||||
| 102 | |||||||
| 103 | 1 | 1 | 5 | use CGI::FormBuilder; | |||
| 1 | 1 | ||||||
| 1 | 24 | ||||||
| 104 | 1 | 1 | 5 | use CGI::FormBuilder::Util; | |||
| 1 | 1 | ||||||
| 1 | 755 | ||||||
| 105 | |||||||
| 106 | our $VERSION = '3.10'; | ||||||
| 107 | |||||||
| 108 | our %DEFAULT = ( | ||||||
| 109 | pagename => '_page', | ||||||
| 110 | navbar => 0, | ||||||
| 111 | ); | ||||||
| 112 | |||||||
| 113 | sub new { | ||||||
| 114 | 1 | 1 | 1 | 53 | my $mod = shift; | ||
| 115 | 1 | 33 | 5 | 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 | 1 | 2 | my @forms = (); | ||||
| 120 | 1 | 3 | while (ref $_[0]) { | ||||
| 121 | 3 | 5 | push @forms, shift; | ||||
| 122 | } | ||||||
| 123 | |||||||
| 124 | # Remaining options are form opts | ||||||
| 125 | 1 | 6 | my %opt = arghash(@_); | ||||
| 126 | |||||||
| 127 | # If no forms, and specified number of pages, use that instead | ||||||
| 128 | 1 | 50 | 3 | if ($opt{pages}) { | |||
| 129 | 0 | 0 | 0 | puke "Can't specify pages and form hashrefs" if @forms; | |||
| 130 | 0 | 0 | my $p = 0; | ||||
| 131 | 0 | 0 | push @forms, {} while $p++ < $opt{pages}; | ||||
| 132 | } | ||||||
| 133 | 1 | 50 | 3 | 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 | 1 | 50 | 33 | 4 | unless ($opt{params} && ref $opt{params} ne 'HASH') { | ||
| 139 | 1 | 756 | require CGI; | ||||
| 140 | 1 | 21190 | $CGI::USE_PARAM_SEMICOLONS = 0; # fuck ; in urls | ||||
| 141 | 1 | 10 | $opt{params} = CGI->new($opt{params}); | ||||
| 142 | } | ||||||
| 143 | |||||||
| 144 | # Options for me | ||||||
| 145 | 1 | 556 | my %me; | ||||
| 146 | 1 | 10 | while (my($k,$v) = each %DEFAULT) { | ||||
| 147 | 2 | 100 | 14 | $me{$k} = exists $opt{$k} ? delete $opt{$k} : $v; | |||
| 148 | } | ||||||
| 149 | 1 | 3 | $me{forms} = \@forms; | ||||
| 150 | |||||||
| 151 | # Plop in our defaults per-form unless it's an object | ||||||
| 152 | 1 | 50 | 3 | @forms = map { ref $_ eq 'HASH' ? { %opt, %$_ } : $_ } @forms; | |||
| 3 | 33 | ||||||
| 153 | |||||||
| 154 | # Top-level multi | ||||||
| 155 | 1 | 10 | my $self = bless \%me, $class; | ||||
| 156 | |||||||
| 157 | # Copy CGI object into self, and get page | ||||||
| 158 | 1 | 7 | $self->{params} = $opt{params}; | ||||
| 159 | 1 | 3 | $self->{keepextras} = $opt{keepextras}; | ||||
| 160 | 1 | 50 | 5 | $self->{page} = $self->{params}->param($self->{pagename}) || 1; | |||
| 161 | |||||||
| 162 | 1 | 33 | return $self; | ||||
| 163 | } | ||||||
| 164 | |||||||
| 165 | # return an lvalue to allow $multi->page++ and $multi->page--; | ||||||
| 166 | sub page : lvalue { | ||||||
| 167 | 22 | 22 | 1 | 27 | my $self = shift; | ||
| 168 | 22 | 100 | 77 | $self->{page} = shift if @_; # rvalue | |||
| 169 | 22 | 75 | $self->{page}; # lvalue | ||||
| 170 | } | ||||||
| 171 | |||||||
| 172 | *forms = \&pages; | ||||||
| 173 | sub pages { | ||||||
| 174 | 4 | 4 | 1 | 167 | my $self = shift; | ||
| 175 | 4 | 50 | 10 | puke "No arguments allowed to \$multi->pages or \$multi->forms" if @_; | |||
| 176 | 4 | 5 | return @{$self->{forms}}; | ||||
| 4 | 12 | ||||||
| 177 | } | ||||||
| 178 | |||||||
| 179 | # return the form from this page, as a new object | ||||||
| 180 | sub form { | ||||||
| 181 | 9 | 9 | 1 | 19 | my $self = shift; | ||
| 182 | 9 | 50 | 19 | puke "No arguments allowed to \$multi->form" if @_; | |||
| 183 | 9 | 18 | my $page = $self->page; | ||||
| 184 | 9 | 11 | my $idx = $page - 1; | ||||
| 185 | |||||||
| 186 | 9 | 100 | 35 | return $self->{_cache}{forms}[$idx] if $self->{_cache}{forms}[$idx]; | |||
| 187 | puke "Invalid page $page, no form present" | ||||||
| 188 | 4 | 100 | 14 | unless my $form = $self->{forms}[$idx]; | |||
| 189 | |||||||
| 190 | 3 | 50 | 7 | if (ref $form eq 'CGI::FormBuilder') { | |||
| 191 | # already constructed | ||||||
| 192 | } else { | ||||||
| 193 | 3 | 23 | $form = CGI::FormBuilder->new(%$form); | ||||
| 194 | } | ||||||
| 195 | |||||||
| 196 | # hooks | ||||||
| 197 | 3 | 7 | $form->page($self->page); | ||||
| 198 | 3 | 50 | 6 | $form->text(scalar $self->navbar) if $self->{navbar}; # cheat | |||
| 199 | |||||||
| 200 | # create new $form and cache for re-get | ||||||
| 201 | 3 | 8 | $self->{_cache}{forms}[$idx] = $form; | ||||
| 202 | } | ||||||
| 203 | |||||||
| 204 | # allow jumps between pages | ||||||
| 205 | sub navbar { | ||||||
| 206 | 0 | 0 | 1 | my $self = shift; | |||
| 207 | 0 | 0 | $self->{navbar} = shift if @_; | ||||
| 208 | 0 | my $base = basename; | |||||
| 209 | 0 | my $pnam = $self->{pagename}; | |||||
| 210 | 0 | 0 | return '' unless $self->pages > 1; | ||||
| 211 | |||||||
| 212 | # Look for extra params to keep | ||||||
| 213 | # Algorithm here is a bit different | ||||||
| 214 | 0 | my @keep; | |||||
| 215 | 0 | 0 | if ($self->{keepextras}) { | ||||
| 216 | 0 | 0 | unless (ref $self->{keepextras}) { | ||||
| 217 | 0 | $self->{keepextras} = [ $self->{params}->param ]; | |||||
| 218 | } | ||||||
| 219 | 0 | for my $k (@{$self->{keepextras}}) { | |||||
| 0 | |||||||
| 220 | 0 | 0 | next if $k eq $pnam; | ||||
| 221 | 0 | for my $v ($self->{params}->param($k)) { | |||||
| 222 | 0 | push @keep, { name => $k, value => $v }; | |||||
| 223 | } | ||||||
| 224 | } | ||||||
| 225 | } | ||||||
| 226 | |||||||
| 227 | 0 | my @html = (); | |||||
| 228 | 0 | for (my $p=1; $p <= $self->pages; $p++) { | |||||
| 229 | 0 | 0 | my $cl = $self->page == $p ? 'fb_multi_page' : 'fb_multi_link'; | ||||
| 230 | |||||||
| 231 | # this looks like gibberish | ||||||
| 232 | my $purl = basename . '?' . join '&', | ||||||
| 233 | 0 | map { "$_->{name}=$_->{value}" } @keep, | |||||
| 0 | |||||||
| 234 | { name => $pnam, value => $p }; | ||||||
| 235 | |||||||
| 236 | push @html, htmltag('a', href => $purl, class => $cl) | ||||||
| 237 | 0 | 0 | . ($self->{forms}[$p-1]{title} || "Page $p") . ''; | ||||
| 238 | } | ||||||
| 239 | |||||||
| 240 | 0 | 0 | return wantarray ? @html : ' '. join(' | ', @html) . ' '; |
||||
| 241 | } | ||||||
| 242 | |||||||
| 243 | 1; | ||||||
| 244 | __END__ |