| blib/lib/Dancer/Template/TemplateFlute.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 7 | 9 | 77.7 |
| branch | n/a | ||
| condition | n/a | ||
| subroutine | 3 | 3 | 100.0 |
| pod | n/a | ||
| total | 10 | 12 | 83.3 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package Dancer::Template::TemplateFlute; | ||||||
| 2 | |||||||
| 3 | 1 | 1 | 13246 | use strict; | |||
| 1 | 2 | ||||||
| 1 | 28 | ||||||
| 4 | 1 | 1 | 3 | use warnings; | |||
| 1 | 1 | ||||||
| 1 | 20 | ||||||
| 5 | |||||||
| 6 | 1 | 1 | 167 | use Template::Flute; | |||
| 0 | |||||||
| 0 | |||||||
| 7 | use Template::Flute::Iterator; | ||||||
| 8 | use Template::Flute::Utils; | ||||||
| 9 | use Template::Flute::I18N; | ||||||
| 10 | use Module::Load; | ||||||
| 11 | use Scalar::Util qw/blessed/; | ||||||
| 12 | |||||||
| 13 | use Dancer::Config; | ||||||
| 14 | |||||||
| 15 | use base 'Dancer::Template::Abstract'; | ||||||
| 16 | |||||||
| 17 | our $VERSION = '0.0142'; | ||||||
| 18 | |||||||
| 19 | =head1 NAME | ||||||
| 20 | |||||||
| 21 | Dancer::Template::TemplateFlute - Template::Flute wrapper for Dancer | ||||||
| 22 | |||||||
| 23 | =head1 VERSION | ||||||
| 24 | |||||||
| 25 | Version 0.0142 | ||||||
| 26 | |||||||
| 27 | =head1 DESCRIPTION | ||||||
| 28 | |||||||
| 29 | This class is an interface between Dancer's template engine abstraction layer | ||||||
| 30 | and the L |
||||||
| 31 | |||||||
| 32 | In order to use this engine, use the template setting: | ||||||
| 33 | |||||||
| 34 | template: template_flute | ||||||
| 35 | |||||||
| 36 | The default template extension is ".html". | ||||||
| 37 | |||||||
| 38 | =head2 LAYOUT | ||||||
| 39 | |||||||
| 40 | Each layout needs a specification file and a template file. To embed | ||||||
| 41 | the content of your current view into the layout, put the following | ||||||
| 42 | into your specification file, e.g. F |
||||||
| 43 | |||||||
| 44 | |
||||||
| 45 | |
||||||
| 46 | |||||||
| 47 | |||||||
| 48 | This replaces the contents of the following block in your HTML | ||||||
| 49 | template, e.g. F |
||||||
| 50 | |||||||
| 51 | |
||||||
| 52 | Your content | ||||||
| 53 | |||||||
| 54 | |||||||
| 55 | =head2 ITERATORS | ||||||
| 56 | |||||||
| 57 | Iterators can be specified explicitly in the configuration file as below. | ||||||
| 58 | |||||||
| 59 | engines: | ||||||
| 60 | template_flute: | ||||||
| 61 | iterators: | ||||||
| 62 | fruits: | ||||||
| 63 | class: JSON | ||||||
| 64 | file: fruits.json | ||||||
| 65 | |||||||
| 66 | =head2 FILTER OPTIONS | ||||||
| 67 | |||||||
| 68 | Filter options and classes can be specified in the configuration file as below. | ||||||
| 69 | |||||||
| 70 | engines: | ||||||
| 71 | template_flute: | ||||||
| 72 | filters: | ||||||
| 73 | currency: | ||||||
| 74 | options: | ||||||
| 75 | int_curr_symbol: "$" | ||||||
| 76 | image: | ||||||
| 77 | class: "Flowers::Filters::Image" | ||||||
| 78 | |||||||
| 79 | =head2 ADJUSTING URIS | ||||||
| 80 | |||||||
| 81 | We automatically adjust links in the templates if the value of | ||||||
| 82 | C |
||||||
| 83 | |||||||
| 84 | =head2 EMBEDDING IMAGES IN EMAILS | ||||||
| 85 | |||||||
| 86 | If you pass a value named C |
||||||
| 87 | reference, all the images C |
||||||
| 88 | the CIDs, and the reference will be populated with an hashref, as | ||||||
| 89 | documented in L |
||||||
| 90 | |||||||
| 91 | Further options for the CIDs should be passed in an optional value | ||||||
| 92 | named C |
||||||
| 93 | |||||||
| 94 | |||||||
| 95 | =head2 DISABLE OBJECT AUTODETECTION | ||||||
| 96 | |||||||
| 97 | Sometimes you want to pass values to a template which are objects, but | ||||||
| 98 | don't have an accessor, so they should be treated like hashrefs instead. | ||||||
| 99 | |||||||
| 100 | By default, the class C |
||||||
| 101 | can specify additional classes with the following syntax: | ||||||
| 102 | |||||||
| 103 | engines: | ||||||
| 104 | template_flute: | ||||||
| 105 | autodetect: | ||||||
| 106 | disable: | ||||||
| 107 | - My::Class1 | ||||||
| 108 | - My::Class2 | ||||||
| 109 | |||||||
| 110 | |||||||
| 111 | The class matching is checked by L |
||||||
| 112 | any parent class would do. | ||||||
| 113 | |||||||
| 114 | =head2 LOCALIZATION | ||||||
| 115 | |||||||
| 116 | Templates can be localized using the Template::Flute::I18N module. You | ||||||
| 117 | can define a class that provides a method which takes as first (and | ||||||
| 118 | only argument) the string to translate, and returns the translated | ||||||
| 119 | one. You have to provide the class and the method. If the class is not | ||||||
| 120 | provided, no localization is done. If no method is specified, | ||||||
| 121 | 'localize' will be used. The app will crash if the class doesn't | ||||||
| 122 | provide such method. | ||||||
| 123 | |||||||
| 124 | B | ||||||
| 125 | translate the string>. | ||||||
| 126 | |||||||
| 127 | Example configuration, assuming the class C |
||||||
| 128 | C |
||||||
| 129 | |||||||
| 130 | engines: | ||||||
| 131 | template_flute: | ||||||
| 132 | i18n: | ||||||
| 133 | class: MyApp::Lexicon | ||||||
| 134 | method: try_to_translate | ||||||
| 135 | |||||||
| 136 | |||||||
| 137 | A class could be something like this: | ||||||
| 138 | |||||||
| 139 | package MyTestApp::Lexicon; | ||||||
| 140 | use Dancer ':syntax'; | ||||||
| 141 | |||||||
| 142 | sub new { | ||||||
| 143 | my $class = shift; | ||||||
| 144 | debug "Loading up $class"; | ||||||
| 145 | my $self = { | ||||||
| 146 | dictionary => { | ||||||
| 147 | en => { | ||||||
| 148 | 'TRY' => 'Try', | ||||||
| 149 | }, | ||||||
| 150 | it => { | ||||||
| 151 | 'TRY' => 'Prova', | ||||||
| 152 | }, | ||||||
| 153 | } | ||||||
| 154 | }; | ||||||
| 155 | bless $self, $class; | ||||||
| 156 | } | ||||||
| 157 | |||||||
| 158 | sub dictionary { | ||||||
| 159 | return shift->{dictionary}; | ||||||
| 160 | } | ||||||
| 161 | |||||||
| 162 | sub try_to_translate { | ||||||
| 163 | my ($self, $string) = @_; | ||||||
| 164 | my $lang = session('lang') || var('lang'); | ||||||
| 165 | return $string unless $lang; | ||||||
| 166 | return $string unless $self->dictionary->{$lang}; | ||||||
| 167 | my $tr = $self->dictionary->{$lang}->{$string}; | ||||||
| 168 | defined $tr ? return $tr : return $string; | ||||||
| 169 | } | ||||||
| 170 | |||||||
| 171 | 1; | ||||||
| 172 | |||||||
| 173 | Optionally, you can pass the options to instantiate the class in the | ||||||
| 174 | configuration. Like this: | ||||||
| 175 | |||||||
| 176 | engines: | ||||||
| 177 | template_flute: | ||||||
| 178 | i18n: | ||||||
| 179 | class: MyApp::Lexicon | ||||||
| 180 | method: localize | ||||||
| 181 | options: | ||||||
| 182 | append: 'X' | ||||||
| 183 | prepend: 'Y' | ||||||
| 184 | lexicon: 'path/to/po/files' | ||||||
| 185 | |||||||
| 186 | This will call | ||||||
| 187 | |||||||
| 188 | MyApp::Lexicon->new(append => 'X', prepend => 'Y', lexicon => 'path/to/po/files'); | ||||||
| 189 | |||||||
| 190 | when the engine is initialized, and will call the C |
||||||
| 191 | on it to get the translations. | ||||||
| 192 | |||||||
| 193 | =head2 DEBUG TOOLS | ||||||
| 194 | |||||||
| 195 | If you set C |
||||||
| 196 | will run a check (using the L |
||||||
| 197 | C |
||||||
| 198 | of the specifications which are not bound to any HTML elements. | ||||||
| 199 | |||||||
| 200 | In this case a debug message is issued (so keep in mind that with | ||||||
| 201 | higher logging level you are not going to see it). | ||||||
| 202 | |||||||
| 203 | Example configuration: | ||||||
| 204 | |||||||
| 205 | engines: | ||||||
| 206 | template_flute: | ||||||
| 207 | check_dangling: 1 | ||||||
| 208 | |||||||
| 209 | When the environment is set to C |
||||||
| 210 | on by default. You can silence the logs by setting: | ||||||
| 211 | |||||||
| 212 | engines: | ||||||
| 213 | template_flute: | ||||||
| 214 | disable_check_dangling: 1 | ||||||
| 215 | |||||||
| 216 | =head2 FORMS | ||||||
| 217 | |||||||
| 218 | Dancer::Template::TemplateFlute includes a form plugin L |
||||||
| 219 | which supports L |
||||||
| 220 | |||||||
| 221 | The token C | ||||||
| 222 | L |
||||||
| 223 | L |
||||||
| 224 | |||||||
| 225 | =head3 Typical usage for a single form. | ||||||
| 226 | |||||||
| 227 | =head4 XML Specification | ||||||
| 228 | |||||||
| 229 | |
||||||
| 230 | |||||||
| 231 | |
||||||
| 232 | |
||||||
| 233 | |
||||||
| 234 | |||||||
| 235 | |||||||
| 236 | |||||||
| 237 | =head4 HTML | ||||||
| 238 | |||||||
| 239 | |||||||
| 240 | |||||||
| 241 | Info |
||||||
| 242 | |
||||||
| 243 | |
||||||
| 244 | |||||||
| 245 | |||||||
| 246 | |||||||
| 247 | |
||||||
| 248 | |||||||
| 249 | |||||||
| 250 | |||||||
| 251 | |
||||||
| 252 | |||||||
| 253 | |||||||
| 254 | |||||||
| 255 | |
||||||
| 256 | |||||||
| 257 | |||||||
| 258 | |||||||
| 259 | |||||||
| 260 | |||||||
| 261 | |||||||
| 262 | =head4 Code | ||||||
| 263 | |||||||
| 264 | any [qw/get post/] => '/register' => sub { | ||||||
| 265 | my $form = form('registration'); | ||||||
| 266 | my %values = %{$form->values}; | ||||||
| 267 | # VALIDATE, filter, etc. the values | ||||||
| 268 | $form->fill(\%values); | ||||||
| 269 | template register => {form => $form }; | ||||||
| 270 | }; | ||||||
| 271 | |||||||
| 272 | =head3 Usage example for multiple forms | ||||||
| 273 | |||||||
| 274 | =head4 Specification | ||||||
| 275 | |||||||
| 276 | |
||||||
| 277 | |||||||
| 278 | |
||||||
| 279 | |
||||||
| 280 | |
||||||
| 281 | |||||||
| 282 | |||||||
| 283 | |
||||||
| 284 | |
||||||
| 285 | |||||||
| 286 | |||||||
| 287 | |||||||
| 288 | =head4 HTML | ||||||
| 289 | |||||||
| 290 | Register |
||||||
| 291 | |||||||
| 292 | |||||||
| 293 | Info |
||||||
| 294 | |
||||||
| 295 | |
||||||
| 296 | |||||||
| 297 | |||||||
| 298 | |||||||
| 299 | |
||||||
| 300 | |||||||
| 301 | |||||||
| 302 | |||||||
| 303 | |
||||||
| 304 | |||||||
| 305 | |||||||
| 306 | |||||||
| 307 | |
||||||
| 308 | |||||||
| 309 | |||||||
| 310 | |||||||
| 311 | |||||||
| 312 | |||||||
| 313 | Login |
||||||
| 314 | |||||||
| 315 | |||||||
| 316 | Info |
||||||
| 317 | |
||||||
| 318 | |
||||||
| 319 | |||||||
| 320 | |||||||
| 321 | |||||||
| 322 | |
||||||
| 323 | |||||||
| 324 | |||||||
| 325 | |||||||
| 326 | |
||||||
| 327 | |||||||
| 328 | |||||||
| 329 | |||||||
| 330 | |||||||
| 331 | |||||||
| 332 | |||||||
| 333 | |||||||
| 334 | =head4 Code | ||||||
| 335 | |||||||
| 336 | any [qw/get post/] => '/multiple' => sub { | ||||||
| 337 | my $login = form('logintest'); | ||||||
| 338 | debug to_dumper({params}); | ||||||
| 339 | if (params->{login}) { | ||||||
| 340 | my %vals = %{$login->values}; | ||||||
| 341 | # VALIDATE %vals here | ||||||
| 342 | $login->fill(\%vals); | ||||||
| 343 | } | ||||||
| 344 | else { | ||||||
| 345 | # pick from session | ||||||
| 346 | $login->fill; | ||||||
| 347 | } | ||||||
| 348 | my $registration = form('registrationtest'); | ||||||
| 349 | if (params->{register}) { | ||||||
| 350 | my %vals = %{$registration->values}; | ||||||
| 351 | # VALIDATE %vals here | ||||||
| 352 | $registration->fill(\%vals); | ||||||
| 353 | } | ||||||
| 354 | else { | ||||||
| 355 | # pick from session | ||||||
| 356 | $registration->fill; | ||||||
| 357 | } | ||||||
| 358 | template multiple => { form => [ $login, $registration ] }; | ||||||
| 359 | }; | ||||||
| 360 | |||||||
| 361 | =head1 METHODS | ||||||
| 362 | |||||||
| 363 | =head2 default_tmpl_ext | ||||||
| 364 | |||||||
| 365 | Returns default template extension. | ||||||
| 366 | |||||||
| 367 | =head2 render TEMPLATE TOKENS | ||||||
| 368 | |||||||
| 369 | Renders template TEMPLATE with values from TOKENS. | ||||||
| 370 | |||||||
| 371 | =cut | ||||||
| 372 | |||||||
| 373 | sub default_tmpl_ext { | ||||||
| 374 | return 'html'; | ||||||
| 375 | } | ||||||
| 376 | |||||||
| 377 | sub _i18n_obj { | ||||||
| 378 | my $self = shift; | ||||||
| 379 | unless (exists $self->{_i18n_obj}) { | ||||||
| 380 | my $conf = $self->config; | ||||||
| 381 | my $localize; | ||||||
| 382 | if ($conf and exists $conf->{i18n} and exists $conf->{i18n}->{class}) { | ||||||
| 383 | my $class = $conf->{i18n}->{class}; | ||||||
| 384 | load $class; | ||||||
| 385 | my %args; | ||||||
| 386 | if ($conf->{i18n}->{options}) { | ||||||
| 387 | # do a shallow copy and pass that | ||||||
| 388 | %args = %{ $conf->{i18n}->{options} }; | ||||||
| 389 | } | ||||||
| 390 | my $obj = $class->new(%args); | ||||||
| 391 | my $method = $conf->{i18n}->{method} || 'localize'; | ||||||
| 392 | # store the closure in the object to avoid loading it up each time | ||||||
| 393 | $localize = sub { | ||||||
| 394 | my $to_translate = shift; | ||||||
| 395 | return $obj->$method($to_translate); | ||||||
| 396 | }; | ||||||
| 397 | } | ||||||
| 398 | # provide a common interface with Template::Flute::I18N | ||||||
| 399 | $self->{_i18n_obj} = Template::Flute::I18N->new($localize); | ||||||
| 400 | } | ||||||
| 401 | return $self->{_i18n_obj}; | ||||||
| 402 | } | ||||||
| 403 | |||||||
| 404 | |||||||
| 405 | sub render ($$$) { | ||||||
| 406 | my ($self, $template, $tokens) = @_; | ||||||
| 407 | my (%args, $flute, $html, $name, $value, %parms, %template_iterators, %iterators, $class); | ||||||
| 408 | |||||||
| 409 | %args = (template_file => $template, | ||||||
| 410 | scopes => 1, | ||||||
| 411 | auto_iterators => 1, | ||||||
| 412 | values => $tokens, | ||||||
| 413 | filters => $self->config->{filters}, | ||||||
| 414 | autodetect => { disable => [qw/Dancer::Session::Abstract/] }, | ||||||
| 415 | ); | ||||||
| 416 | |||||||
| 417 | # determine whether we need to pass an adjust URI to Template::Flute | ||||||
| 418 | if (my $request = $tokens->{request}) { | ||||||
| 419 | my $pos = index($request->path, $request->path_info); | ||||||
| 420 | if ($pos > 0) { | ||||||
| 421 | $args{uri} = substr($request->path, 0, $pos); | ||||||
| 422 | } | ||||||
| 423 | } | ||||||
| 424 | |||||||
| 425 | if (my $i18n = $self->_i18n_obj) { | ||||||
| 426 | $args{i18n} = $i18n; | ||||||
| 427 | } | ||||||
| 428 | |||||||
| 429 | if (my $email_cids = $tokens->{email_cids}) { | ||||||
| 430 | $args{email_cids} = $email_cids; | ||||||
| 431 | # use the 'cids' tokens only if email_cids is defined | ||||||
| 432 | if (my $cid_options = $tokens->{cids}) { | ||||||
| 433 | $args{cids} = { %$cid_options }; | ||||||
| 434 | } | ||||||
| 435 | } | ||||||
| 436 | |||||||
| 437 | if ($self->config->{autodetect} && $self->config->{autodetect}->{disable}) { | ||||||
| 438 | push @{$args{autodetect}{disable}}, | ||||||
| 439 | @{$self->config->{autodetect}->{disable}}; | ||||||
| 440 | } | ||||||
| 441 | |||||||
| 442 | $flute = Template::Flute->new(%args); | ||||||
| 443 | |||||||
| 444 | # process HTML template to determine iterators used by template | ||||||
| 445 | $flute->process_template(); | ||||||
| 446 | |||||||
| 447 | # instantiate iterators where object isn't yet available | ||||||
| 448 | if (%template_iterators = $flute->template()->iterators) { | ||||||
| 449 | my $selector; | ||||||
| 450 | |||||||
| 451 | for my $name (keys %template_iterators) { | ||||||
| 452 | if ($value = $self->config->{iterators}->{$name}) { | ||||||
| 453 | %parms = %$value; | ||||||
| 454 | |||||||
| 455 | $class = "Template::Flute::Iterator::$parms{class}"; | ||||||
| 456 | |||||||
| 457 | if ($parms{file}) { | ||||||
| 458 | $parms{file} = Template::Flute::Utils::derive_filename($template, | ||||||
| 459 | $parms{file}, 1); | ||||||
| 460 | } | ||||||
| 461 | |||||||
| 462 | if ($selector = delete $parms{selector}) { | ||||||
| 463 | if ($selector eq '*') { | ||||||
| 464 | $parms{selector} = '*'; | ||||||
| 465 | } | ||||||
| 466 | elsif ($tokens->{$selector}) { | ||||||
| 467 | $parms{selector} = {$selector => $tokens->{$selector}}; | ||||||
| 468 | } | ||||||
| 469 | } | ||||||
| 470 | |||||||
| 471 | eval "require $class"; | ||||||
| 472 | if ($@) { | ||||||
| 473 | die "Failed to load class $class for iterator $name: $@\n"; | ||||||
| 474 | } | ||||||
| 475 | |||||||
| 476 | eval { | ||||||
| 477 | $iterators{$name} = $class->new(%parms); | ||||||
| 478 | }; | ||||||
| 479 | |||||||
| 480 | if ($@) { | ||||||
| 481 | die "Failed to instantiate class $class for iterator $name: $@\n"; | ||||||
| 482 | } | ||||||
| 483 | |||||||
| 484 | $flute->specification->set_iterator($name, $iterators{$name}); | ||||||
| 485 | } | ||||||
| 486 | } | ||||||
| 487 | } | ||||||
| 488 | |||||||
| 489 | # check for forms | ||||||
| 490 | if (my @forms = $flute->template->forms()) { | ||||||
| 491 | if ($tokens->{form}) { | ||||||
| 492 | $self->_tf_manage_forms($flute, $tokens, @forms); | ||||||
| 493 | } | ||||||
| 494 | else { | ||||||
| 495 | Dancer::Logger::debug('Missing form parameters for forms ' . | ||||||
| 496 | join(", ", sort map { $_->name } @forms)); | ||||||
| 497 | } | ||||||
| 498 | } | ||||||
| 499 | elsif ($tokens->{form}) { | ||||||
| 500 | my $form_name = blessed($tokens->{form}) ? $tokens->{form}->name : $tokens->{form}; | ||||||
| 501 | |||||||
| 502 | Dancer::Logger::debug("Form $form_name passed, but no forms found in the template $template."); | ||||||
| 503 | } | ||||||
| 504 | |||||||
| 505 | $html = $flute->process(); | ||||||
| 506 | |||||||
| 507 | if ($self->config->{check_dangling} or | ||||||
| 508 | ($tokens->{settings}->{environment} eq 'development' && | ||||||
| 509 | !$self->config->{disable_check_dangling})) { | ||||||
| 510 | |||||||
| 511 | if (my @warnings = $flute->specification->dangling) { | ||||||
| 512 | foreach my $warn (@warnings) { | ||||||
| 513 | Dancer::Logger::debug('Found dangling element ' | ||||||
| 514 | . $warn->{type} . ' ' . $warn->{name} | ||||||
| 515 | . ' (' , $warn->{dump} , ')'); | ||||||
| 516 | } | ||||||
| 517 | } | ||||||
| 518 | } | ||||||
| 519 | return $html; | ||||||
| 520 | } | ||||||
| 521 | |||||||
| 522 | sub _tf_manage_forms { | ||||||
| 523 | my ($self, $flute, $tokens, @forms) = @_; | ||||||
| 524 | |||||||
| 525 | # simple case: only one form passed and one in the flute | ||||||
| 526 | if (ref($tokens->{form}) ne 'ARRAY') { | ||||||
| 527 | my $form_name = $tokens->{form}->name; | ||||||
| 528 | if (@forms == 1) { | ||||||
| 529 | my $form = shift @forms; | ||||||
| 530 | if ($form_name eq 'main' or | ||||||
| 531 | $form_name eq $form->name) { | ||||||
| 532 | # Dancer::Logger::debug("Filling the template form with" . Dumper($tokens->{form}->values)); | ||||||
| 533 | $self->_tf_fill_forms($flute, $tokens->{form}, $form, $tokens); | ||||||
| 534 | } | ||||||
| 535 | } | ||||||
| 536 | else { | ||||||
| 537 | my $found = 0; | ||||||
| 538 | foreach my $form (@forms) { | ||||||
| 539 | # Dancer::Logger::debug("Filling the template form with" . Dumper($tokens->{form}->values)); | ||||||
| 540 | if ($form_name eq $form->name) { | ||||||
| 541 | $self->_tf_fill_forms($flute, $tokens->{form}, $form, $tokens); | ||||||
| 542 | $found++; | ||||||
| 543 | } | ||||||
| 544 | } | ||||||
| 545 | if ($found != 1) { | ||||||
| 546 | Dancer::Logger::error("Multiple form are not being managed correctly, found $found corresponding forms, but we expected just one!") | ||||||
| 547 | } | ||||||
| 548 | } | ||||||
| 549 | } | ||||||
| 550 | else { | ||||||
| 551 | foreach my $passed_form (@{$tokens->{form}}) { | ||||||
| 552 | foreach my $form (@forms) { | ||||||
| 553 | if ($passed_form->name eq $form->name) { | ||||||
| 554 | $self->_tf_fill_forms($flute, $passed_form, $form, $tokens); | ||||||
| 555 | } | ||||||
| 556 | } | ||||||
| 557 | } | ||||||
| 558 | } | ||||||
| 559 | } | ||||||
| 560 | |||||||
| 561 | |||||||
| 562 | sub _tf_fill_forms { | ||||||
| 563 | my ($self, $flute, $passed_form, $form, $tokens) = @_; | ||||||
| 564 | # arguments: | ||||||
| 565 | # $flute is the template object. | ||||||
| 566 | |||||||
| 567 | # $passed_form is the Dancer::Plugin::Form object we got from the | ||||||
| 568 | # tokens, which is $tokens->{form} when we have just a single one. | ||||||
| 569 | |||||||
| 570 | # $form is the form object we got from the template itself, with | ||||||
| 571 | # $flute->template->forms | ||||||
| 572 | |||||||
| 573 | # $tokens is the hashref passed to the template. We need it for the | ||||||
| 574 | # iterators. | ||||||
| 575 | |||||||
| 576 | my ($iter, $action); | ||||||
| 577 | for my $name ($form->iterators) { | ||||||
| 578 | if (ref($tokens->{$name}) eq 'ARRAY') { | ||||||
| 579 | $iter = Template::Flute::Iterator->new($tokens->{$name}); | ||||||
| 580 | $flute->specification->set_iterator($name, $iter); | ||||||
| 581 | } | ||||||
| 582 | } | ||||||
| 583 | if ($action = $passed_form->action()) { | ||||||
| 584 | $form->set_action($action); | ||||||
| 585 | } | ||||||
| 586 | $passed_form->fields([map {$_->{name}} @{$form->fields()}]); | ||||||
| 587 | $form->fill($passed_form->fill()); | ||||||
| 588 | |||||||
| 589 | if (Dancer::Config::settings->{session}) { | ||||||
| 590 | $passed_form->to_session; | ||||||
| 591 | } | ||||||
| 592 | } | ||||||
| 593 | |||||||
| 594 | |||||||
| 595 | =head1 SEE ALSO | ||||||
| 596 | |||||||
| 597 | L |
||||||
| 598 | |||||||
| 599 | =head1 AUTHOR | ||||||
| 600 | |||||||
| 601 | Stefan Hornburg (Racke), |
||||||
| 602 | |||||||
| 603 | =head1 BUGS | ||||||
| 604 | |||||||
| 605 | Please report any bugs or feature requests to C |
||||||
| 606 | the web interface at L |
||||||
| 607 | |||||||
| 608 | =head1 SUPPORT | ||||||
| 609 | |||||||
| 610 | You can find documentation for this module with the perldoc command. | ||||||
| 611 | |||||||
| 612 | perldoc Template::Flute | ||||||
| 613 | |||||||
| 614 | You can also look for information at: | ||||||
| 615 | |||||||
| 616 | =over 4 | ||||||
| 617 | |||||||
| 618 | =item * RT: CPAN's request tracker | ||||||
| 619 | |||||||
| 620 | L |
||||||
| 621 | |||||||
| 622 | =item * AnnoCPAN: Annotated CPAN documentation | ||||||
| 623 | |||||||
| 624 | L |
||||||
| 625 | |||||||
| 626 | =item * CPAN Ratings | ||||||
| 627 | |||||||
| 628 | L |
||||||
| 629 | |||||||
| 630 | =item * Search CPAN | ||||||
| 631 | |||||||
| 632 | L |
||||||
| 633 | |||||||
| 634 | =back | ||||||
| 635 | |||||||
| 636 | =head1 LICENSE AND COPYRIGHT | ||||||
| 637 | |||||||
| 638 | Copyright 2011-2015 Stefan Hornburg (Racke) |
||||||
| 639 | |||||||
| 640 | This program is free software; you can redistribute it and/or modify it | ||||||
| 641 | under the terms of either: the GNU General Public License as published | ||||||
| 642 | by the Free Software Foundation; or the Artistic License. | ||||||
| 643 | |||||||
| 644 | See http://dev.perl.org/licenses/ for more information. | ||||||
| 645 | |||||||
| 646 | =cut | ||||||
| 647 | |||||||
| 648 | 1; |