| blib/lib/Mojolicious/Plugin/TagHelpers.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 138 | 138 | 100.0 |
| branch | 58 | 58 | 100.0 |
| condition | 26 | 28 | 92.8 |
| subroutine | 42 | 42 | 100.0 |
| pod | 1 | 1 | 100.0 |
| total | 265 | 267 | 99.2 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package Mojolicious::Plugin::TagHelpers; | ||||||
| 2 | 49 | 49 | 409 | use Mojo::Base 'Mojolicious::Plugin'; | |||
| 49 | 118 | ||||||
| 49 | 398 | ||||||
| 3 | |||||||
| 4 | 49 | 49 | 586 | use Mojo::ByteStream; | |||
| 49 | 168 | ||||||
| 49 | 2636 | ||||||
| 5 | 49 | 49 | 408 | use Mojo::DOM::HTML qw(tag_to_html); | |||
| 49 | 188 | ||||||
| 49 | 3700 | ||||||
| 6 | 49 | 49 | 398 | use Scalar::Util qw(blessed); | |||
| 49 | 174 | ||||||
| 49 | 160172 | ||||||
| 7 | |||||||
| 8 | sub register { | ||||||
| 9 | 105 | 105 | 1 | 405 | my ($self, $app) = @_; | ||
| 10 | |||||||
| 11 | # Text field variations | ||||||
| 12 | 105 | 374 | my @time = qw(date month time week); | ||||
| 13 | 105 | 343 | for my $name (@time, qw(color email number range search tel text url)) { | ||||
| 14 | 1260 | 76 | 6468 | $app->helper("${name}_field" => sub { _input(@_, type => $name) }); | |||
| 76 | 346 | ||||||
| 15 | } | ||||||
| 16 | 105 | 2 | 1086 | $app->helper(datetime_field => sub { _input(@_, type => 'datetime-local') }); | |||
| 2 | 17 | ||||||
| 17 | |||||||
| 18 | 105 | 586 | my @helpers = ( | ||||
| 19 | qw(asset_tag csrf_field form_for hidden_field javascript label_for link_to select_field stylesheet submit_button), | ||||||
| 20 | qw(tag_with_error text_area) | ||||||
| 21 | ); | ||||||
| 22 | 105 | 1254 | $app->helper($_ => __PACKAGE__->can("_$_")) for @helpers; | ||||
| 23 | |||||||
| 24 | 105 | 5 | 947 | $app->helper(button_to => sub { _button_to(0, @_) }); | |||
| 5 | 14 | ||||||
| 25 | 105 | 24 | 812 | $app->helper(check_box => sub { _input(@_, type => 'checkbox') }); | |||
| 24 | 62 | ||||||
| 26 | 105 | 9 | 758 | $app->helper(csrf_button_to => sub { _button_to(1, @_) }); | |||
| 9 | 35 | ||||||
| 27 | 105 | 46 | 872 | $app->helper(favicon => sub { _favicon(@_) }); | |||
| 46 | 254 | ||||||
| 28 | 105 | 6 | 749 | $app->helper(file_field => sub { _empty_field('file', @_) }); | |||
| 6 | 27 | ||||||
| 29 | 105 | 16 | 829 | $app->helper(image => sub { _tag('img', src => _file_url(shift, shift), @_) }); | |||
| 16 | 71 | ||||||
| 30 | 105 | 11 | 827 | $app->helper(input_tag => sub { _input(@_) }); | |||
| 11 | 29 | ||||||
| 31 | 105 | 8 | 926 | $app->helper(password_field => sub { _empty_field('password', @_) }); | |||
| 8 | 31 | ||||||
| 32 | 105 | 6 | 879 | $app->helper(radio_button => sub { _input(@_, type => 'radio') }); | |||
| 6 | 20 | ||||||
| 33 | |||||||
| 34 | # "t" is just a shortcut for the "tag" helper | ||||||
| 35 | 105 | 139 | 913 | $app->helper($_ => sub { shift; _tag(@_) }) for qw(t tag); | |||
| 139 | 239 | ||||||
| 139 | 322 | ||||||
| 36 | } | ||||||
| 37 | |||||||
| 38 | sub _asset_tag { | ||||||
| 39 | 10 | 10 | 27 | my ($c, $target) = (shift, shift); | |||
| 40 | |||||||
| 41 | 10 | 39 | my $url = $c->url_for_asset($target); | ||||
| 42 | |||||||
| 43 | 10 | 100 | 60 | return $c->helpers->javascript($url, @_) if $target =~ /\.js$/; | |||
| 44 | 7 | 100 | 49 | return $c->helpers->stylesheet($url, @_) if $target =~ /\.css$/; | |||
| 45 | 3 | 10 | return $c->helpers->image($url, @_); | ||||
| 46 | } | ||||||
| 47 | |||||||
| 48 | sub _button_to { | ||||||
| 49 | 14 | 14 | 34 | my ($csrf, $c, $text) = (shift, shift, shift); | |||
| 50 | 14 | 100 | 46 | my $prefix = $csrf ? _csrf_field($c) : ''; | |||
| 51 | 14 | 14 | 95 | return _form_for($c, @_, sub { $prefix . _submit_button($c, $text) }); | |||
| 14 | 46 | ||||||
| 52 | } | ||||||
| 53 | |||||||
| 54 | sub _csrf_field { | ||||||
| 55 | 18 | 18 | 34 | my $c = shift; | |||
| 56 | 18 | 57 | return _hidden_field($c, csrf_token => $c->helpers->csrf_token, @_); | ||||
| 57 | } | ||||||
| 58 | |||||||
| 59 | sub _empty_field { | ||||||
| 60 | 14 | 14 | 41 | my ($type, $c, $name) = (shift, shift, shift); | |||
| 61 | 14 | 38 | return _validation($c, $name, 'input', name => $name, @_, type => $type); | ||||
| 62 | } | ||||||
| 63 | |||||||
| 64 | sub _favicon { | ||||||
| 65 | 46 | 46 | 593 | my ($c, $file) = @_; | |||
| 66 | 46 | 100 | 324 | return _tag('link', rel => 'icon', href => _file_url($c, $file // 'favicon.ico')); | |||
| 67 | } | ||||||
| 68 | |||||||
| 69 | sub _file_url { | ||||||
| 70 | 305 | 305 | 719 | my ($c, $url) = @_; | |||
| 71 | 305 | 100 | 66 | 1856 | return blessed $url && $url->isa('Mojo::URL') ? $url : $c->url_for_file($url); | ||
| 72 | } | ||||||
| 73 | |||||||
| 74 | sub _form_for { | ||||||
| 75 | 65 | 65 | 218 | my ($c, @url) = (shift, shift); | |||
| 76 | 65 | 100 | 236 | push @url, shift if ref $_[0] eq 'HASH'; | |||
| 77 | |||||||
| 78 | # Method detection | ||||||
| 79 | 65 | 201 | my $r = $c->app->routes->lookup($url[0]); | ||||
| 80 | 65 | 100 | 258 | my $method = $r ? $r->suggested_method : 'GET'; | |||
| 81 | 65 | 100 | 184 | my @post = $method ne 'GET' ? (method => 'POST') : (); | |||
| 82 | |||||||
| 83 | 65 | 238 | my $url = $c->url_for(@url); | ||||
| 84 | 65 | 100 | 100 | 284 | $url->query({_method => $method}) if @post && $method ne 'POST'; | ||
| 85 | 65 | 237 | return _tag('form', action => $url, @post, @_); | ||||
| 86 | } | ||||||
| 87 | |||||||
| 88 | sub _hidden_field { | ||||||
| 89 | 84 | 84 | 287 | my ($c, $name, $value) = (shift, shift, shift); | |||
| 90 | 84 | 266 | return _tag('input', name => $name, value => $value, @_, type => 'hidden'); | ||||
| 91 | } | ||||||
| 92 | |||||||
| 93 | sub _input { | ||||||
| 94 | 119 | 119 | 292 | my ($c, $name) = (shift, shift); | |||
| 95 | 119 | 100 | 572 | my %attrs = @_ % 2 ? (value => shift, @_) : @_; | |||
| 96 | |||||||
| 97 | 119 | 100 | 208 | if (my @values = @{$c->every_param($name)}) { | |||
| 119 | 452 | ||||||
| 98 | |||||||
| 99 | # Checkbox or radiobutton | ||||||
| 100 | 45 | 100 | 145 | my $type = $attrs{type} || ''; | |||
| 101 | 45 | 100 | 100 | 162 | if ($type eq 'checkbox' || $type eq 'radio') { | ||
| 102 | 23 | 100 | 67 | my $value = $attrs{value} // 'on'; | |||
| 103 | 23 | 41 | delete $attrs{checked}; | ||||
| 104 | 23 | 100 | 40 | $attrs{checked} = undef if grep { $_ eq $value } @values; | |||
| 36 | 118 | ||||||
| 105 | } | ||||||
| 106 | |||||||
| 107 | # Others | ||||||
| 108 | 22 | 53 | else { $attrs{value} = $values[-1] } | ||||
| 109 | } | ||||||
| 110 | |||||||
| 111 | 119 | 581 | return _validation($c, $name, 'input', name => $name, %attrs); | ||||
| 112 | } | ||||||
| 113 | |||||||
| 114 | sub _javascript { | ||||||
| 115 | 138 | 138 | 307 | my $c = shift; | |||
| 116 | 138 | 100 | 449 | my $content = ref $_[-1] eq 'CODE' ? "//() . "\n//]]>" : ''; | |||
| 117 | 138 | 100 | 542 | my @src = @_ % 2 ? (src => _file_url($c, shift)) : (); | |||
| 118 | 138 | 138 | 951 | return _tag('script', @src, @_, sub {$content}); | |||
| 138 | 439 | ||||||
| 119 | } | ||||||
| 120 | |||||||
| 121 | sub _label_for { | ||||||
| 122 | 10 | 10 | 32 | my ($c, $name) = (shift, shift); | |||
| 123 | 10 | 100 | 32 | my $content = ref $_[-1] eq 'CODE' ? pop : shift; | |||
| 124 | 10 | 33 | return _validation($c, $name, 'label', for => $name, @_, $content); | ||||
| 125 | } | ||||||
| 126 | |||||||
| 127 | sub _link_to { | ||||||
| 128 | 41 | 41 | 133 | my ($c, $content) = (shift, shift); | |||
| 129 | 41 | 108 | my @url = ($content); | ||||
| 130 | |||||||
| 131 | # Content | ||||||
| 132 | 41 | 100 | 148 | unless (ref $_[-1] eq 'CODE') { | |||
| 133 | 27 | 57 | @url = (shift); | ||||
| 134 | 27 | 76 | push @_, $content; | ||||
| 135 | } | ||||||
| 136 | |||||||
| 137 | # Captures | ||||||
| 138 | 41 | 100 | 123 | push @url, shift if ref $_[0] eq 'HASH'; | |||
| 139 | |||||||
| 140 | 41 | 154 | return _tag('a', href => $c->url_for(@url), @_); | ||||
| 141 | } | ||||||
| 142 | |||||||
| 143 | sub _option { | ||||||
| 144 | 64 | 64 | 123 | my ($values, $pair) = @_; | |||
| 145 | |||||||
| 146 | 64 | 100 | 184 | $pair = [$pair => $pair] unless ref $pair eq 'ARRAY'; | |||
| 147 | 64 | 228 | my %attrs = (value => $pair->[1], @$pair[2 .. $#$pair]); | ||||
| 148 | 64 | 100 | 179 | delete $attrs{selected} if keys %$values; | |||
| 149 | 64 | 100 | 165 | $attrs{selected} = undef if $values->{$pair->[1]}; | |||
| 150 | |||||||
| 151 | 64 | 174 | return _tag('option', %attrs, $pair->[0]); | ||||
| 152 | } | ||||||
| 153 | |||||||
| 154 | sub _select_field { | ||||||
| 155 | 26 | 26 | 87 | my ($c, $name, $options, %attrs) = (shift, shift, shift, @_); | |||
| 156 | |||||||
| 157 | 26 | 50 | my %values = map { $_ => 1 } grep {defined} @{$c->every_param($name)}; | ||||
| 16 | 68 | ||||||
| 17 | 51 | ||||||
| 26 | 90 | ||||||
| 158 | |||||||
| 159 | 26 | 66 | my $groups = ''; | ||||
| 160 | 26 | 60 | for my $group (@$options) { | ||||
| 161 | |||||||
| 162 | # "optgroup" tag | ||||||
| 163 | 50 | 100 | 66 | 585 | if (blessed $group && $group->isa('Mojo::Collection')) { | ||
| 164 | 10 | 32 | my ($label, $values, %attrs) = @$group; | ||||
| 165 | 10 | 20 | my $content = join '', map { _option(\%values, $_) } @$values; | ||||
| 24 | 54 | ||||||
| 166 | 10 | 10 | 83 | $groups .= _tag('optgroup', label => $label, %attrs, sub {$content}); | |||
| 10 | 27 | ||||||
| 167 | } | ||||||
| 168 | |||||||
| 169 | # "option" tag | ||||||
| 170 | 40 | 102 | else { $groups .= _option(\%values, $group) } | ||||
| 171 | } | ||||||
| 172 | |||||||
| 173 | 26 | 26 | 149 | return _validation($c, $name, 'select', name => $name, %attrs, sub {$groups}); | |||
| 26 | 115 | ||||||
| 174 | } | ||||||
| 175 | |||||||
| 176 | sub _stylesheet { | ||||||
| 177 | 109 | 109 | 246 | my $c = shift; | |||
| 178 | 109 | 100 | 359 | my $content = ref $_[-1] eq 'CODE' ? "/*() . "\n/*]]>*/" : ''; | |||
| 179 | 109 | 100 | 2 | 363 | return _tag('style', @_, sub {$content}) unless @_ % 2; | ||
| 2 | 6 | ||||||
| 180 | 107 | 336 | return _tag('link', rel => 'stylesheet', href => _file_url($c, shift), @_); | ||||
| 181 | } | ||||||
| 182 | |||||||
| 183 | sub _submit_button { | ||||||
| 184 | 50 | 100 | 50 | 210 | my ($c, $value) = (shift, shift // 'Ok'); | ||
| 185 | 50 | 143 | return _tag('input', value => $value, @_, type => 'submit'); | ||||
| 186 | } | ||||||
| 187 | |||||||
| 188 | 941 | 941 | 2932 | sub _tag { Mojo::ByteStream->new(tag_to_html(@_)) } | |||
| 189 | |||||||
| 190 | sub _tag_with_error { | ||||||
| 191 | 8 | 8 | 27 | my ($c, $tag) = (shift, shift); | |||
| 192 | 8 | 100 | 49 | my ($content, %attrs) = (@_ % 2 ? pop : undef, @_); | |||
| 193 | 8 | 100 | 49 | $attrs{class} .= $attrs{class} ? ' field-with-error' : 'field-with-error'; | |||
| 194 | 8 | 100 | 41 | return _tag($tag, %attrs, defined $content ? $content : ()); | |||
| 195 | } | ||||||
| 196 | |||||||
| 197 | sub _text_area { | ||||||
| 198 | 13 | 13 | 38 | my ($c, $name) = (shift, shift); | |||
| 199 | |||||||
| 200 | 13 | 100 | 43 | my $cb = ref $_[-1] eq 'CODE' ? pop : undef; | |||
| 201 | 13 | 100 | 36 | my $content = @_ % 2 ? shift : undef; | |||
| 202 | 13 | 100 | 49 | $content = $c->param($name) // $content // $cb // ''; | |||
| 100 | |||||||
| 100 | |||||||
| 203 | |||||||
| 204 | 13 | 47 | return _validation($c, $name, 'textarea', name => $name, @_, $content); | ||||
| 205 | } | ||||||
| 206 | |||||||
| 207 | sub _validation { | ||||||
| 208 | 182 | 182 | 423 | my ($c, $name) = (shift, shift); | |||
| 209 | 182 | 100 | 586 | return _tag(@_) unless $c->helpers->validation->has_error($name); | |||
| 210 | 11 | 56 | return $c->helpers->tag_with_error(@_); | ||||
| 211 | } | ||||||
| 212 | |||||||
| 213 | 1; | ||||||
| 214 | |||||||
| 215 | =encoding utf8 | ||||||
| 216 | |||||||
| 217 | =head1 NAME | ||||||
| 218 | |||||||
| 219 | Mojolicious::Plugin::TagHelpers - Tag helpers plugin | ||||||
| 220 | |||||||
| 221 | =head1 SYNOPSIS | ||||||
| 222 | |||||||
| 223 | # Mojolicious | ||||||
| 224 | $app->plugin('TagHelpers'); | ||||||
| 225 | |||||||
| 226 | # Mojolicious::Lite | ||||||
| 227 | plugin 'TagHelpers'; | ||||||
| 228 | |||||||
| 229 | =head1 DESCRIPTION | ||||||
| 230 | |||||||
| 231 | L | ||||||
| 232 | Standard|https://html.spec.whatwg.org>. | ||||||
| 233 | |||||||
| 234 | Most form helpers can automatically pick up previous input values and will show them as default. You can also use | ||||||
| 235 | L |
||||||
| 236 | automatically. | ||||||
| 237 | |||||||
| 238 | % param country => 'germany' unless param 'country'; | ||||||
| 239 | <%= radio_button country => 'germany' %> Germany | ||||||
| 240 | <%= radio_button country => 'france' %> France | ||||||
| 241 | <%= radio_button country => 'uk' %> UK | ||||||
| 242 | |||||||
| 243 | For fields that failed validation with L |
||||||
| 244 | class will be automatically added through L"tag_with_error">, to make styling with CSS easier. | ||||||
| 245 | |||||||
| 246 | |||||||
| 247 | |||||||
| 248 | This is a core plugin, that means it is always enabled and its code a good example for learning how to build new | ||||||
| 249 | plugins, you're welcome to fork it. | ||||||
| 250 | |||||||
| 251 | See L |
||||||
| 252 | |||||||
| 253 | =head1 HELPERS | ||||||
| 254 | |||||||
| 255 | L |
||||||
| 256 | |||||||
| 257 | =head2 asset_tag | ||||||
| 258 | |||||||
| 259 | %= asset_tag '/app.js' | ||||||
| 260 | %= asset_tag '/app.js', async => 'async' | ||||||
| 261 | |||||||
| 262 | Generate C | ||||||
| 475 | |||||||
| 476 | |||||||
| 479 | |||||||
| 480 | =head2 label_for | ||||||
| 481 | |||||||
| 482 | %= label_for first_name => 'First name' | ||||||
| 483 | %= label_for first_name => 'First name', class => 'user' | ||||||
| 484 | %= label_for first_name => begin | ||||||
| 485 | First name | ||||||
| 486 | % end | ||||||
| 487 | %= label_for first_name => (class => 'user') => begin | ||||||
| 488 | First name | ||||||
| 489 | % end | ||||||
| 490 | |||||||
| 491 | Generate C | ||||||
| 492 | |||||||
| 493 | |||||||
| 494 | |||||||
| 495 | |||||||
| 496 | First name | ||||||
| 497 | |||||||
| 498 | |||||||
| 499 | First name | ||||||
| 500 | |||||||
| 501 | |||||||
| 502 | =head2 link_to | ||||||
| 503 | |||||||
| 504 | %= link_to Home => 'index' | ||||||
| 505 | %= link_to Home => 'index' => {format => 'txt'} => (class => 'menu') | ||||||
| 506 | %= link_to index => {format => 'txt'} => (class => 'menu') => begin | ||||||
| 507 | Home | ||||||
| 508 | % end | ||||||
| 509 | %= link_to Contact => 'mailto:sri@example.com' | ||||||
| 510 | <%= link_to index => begin %>Home<% end %> | ||||||
| 511 | <%= link_to '/file.txt' => begin %>File<% end %> | ||||||
| 512 | <%= link_to 'https://mojolicious.org' => begin %>Mojolicious<% end %> | ||||||
| 513 | <%= link_to url_for->query(foo => 'bar')->to_abs => begin %>Retry<% end %> | ||||||
| 514 | |||||||
| 515 | Generate portable C tag with L |
||||||
| 516 | content. | ||||||
| 517 | |||||||
| 518 | Home | ||||||
| 519 | Home | ||||||
| 520 | |||||||
| 521 | Home | ||||||
| 522 | |||||||
| 523 | Contact | ||||||
| 524 | Home | ||||||
| 525 | File | ||||||
| 526 | Mojolicious | ||||||
| 527 | Retry | ||||||
| 528 | |||||||
| 529 | The first argument to C |
||||||
| 530 | final argument is Perl code such as a template block (created with the | ||||||
| 531 | C |
||||||
| 532 | omitted at the start of the argument list, and the block will become | ||||||
| 533 | the link content. | ||||||
| 534 | |||||||
| 535 | =head2 month_field | ||||||
| 536 | |||||||
| 537 | %= month_field 'vacation' | ||||||
| 538 | %= month_field vacation => '2012-12' | ||||||
| 539 | %= month_field vacation => '2012-12', id => 'foo' | ||||||
| 540 | |||||||
| 541 | Generate C tag of type C |
||||||
| 542 | |||||||
| 543 | |||||||
| 544 | |||||||
| 545 | |||||||
| 546 | |||||||
| 547 | =head2 number_field | ||||||
| 548 | |||||||
| 549 | %= number_field 'age' | ||||||
| 550 | %= number_field age => 25 | ||||||
| 551 | %= number_field age => 25, id => 'foo', min => 0, max => 200 | ||||||
| 552 | |||||||
| 553 | Generate C tag of type C |
||||||
| 554 | |||||||
| 555 | |||||||
| 556 | |||||||
| 557 | |||||||
| 558 | |||||||
| 559 | =head2 password_field | ||||||
| 560 | |||||||
| 561 | %= password_field 'pass' | ||||||
| 562 | %= password_field 'pass', id => 'foo' | ||||||
| 563 | |||||||
| 564 | Generate C tag of type C |
||||||
| 565 | |||||||
| 566 | |||||||
| 567 | |||||||
| 568 | |||||||
| 569 | =head2 radio_button | ||||||
| 570 | |||||||
| 571 | %= radio_button 'test' | ||||||
| 572 | %= radio_button country => 'germany' | ||||||
| 573 | %= radio_button country => 'germany', checked => undef, id => 'foo' | ||||||
| 574 | |||||||
| 575 | Generate C tag of type C |
||||||
| 576 | |||||||
| 577 | |||||||
| 578 | |||||||
| 579 | |||||||
| 580 | |||||||
| 581 | =head2 range_field | ||||||
| 582 | |||||||
| 583 | %= range_field 'age' | ||||||
| 584 | %= range_field age => 25 | ||||||
| 585 | %= range_field age => 25, id => 'foo', min => 0, max => 200 | ||||||
| 586 | |||||||
| 587 | Generate C tag of type C |
||||||
| 588 | |||||||
| 589 | |||||||
| 590 | |||||||
| 591 | |||||||
| 592 | |||||||
| 593 | =head2 search_field | ||||||
| 594 | |||||||
| 595 | %= search_field 'q' | ||||||
| 596 | %= search_field q => 'perl' | ||||||
| 597 | %= search_field q => 'perl', id => 'foo' | ||||||
| 598 | |||||||
| 599 | Generate C tag of type C |
||||||
| 600 | |||||||
| 601 | |||||||
| 602 | |||||||
| 603 | |||||||
| 604 | |||||||
| 605 | =head2 select_field | ||||||
| 606 | |||||||
| 607 | %= select_field country => ['de', 'en'] | ||||||
| 608 | %= select_field country => [[Germany => 'de'], 'en'], id => 'eu' | ||||||
| 609 | %= select_field country => [[Germany => 'de', selected => 'selected'], 'en'] | ||||||
| 610 | %= select_field country => [c(EU => [[Germany => 'de'], 'en'], id => 'eu')] | ||||||
| 611 | %= select_field country => [c(EU => ['de', 'en']), c(Asia => ['cn', 'jp'])] | ||||||
| 612 | |||||||
| 613 | Generate C | ||||||
| 614 | Previous input values will automatically get picked up and shown as default. | ||||||
| 615 | |||||||
| 616 | |||||||
| 617 | |||||||
| 618 | |||||||
| 619 | |||||||
| 620 | |||||||
| 621 | |||||||
| 622 | |||||||
| 623 | |||||||
| 624 | |||||||
| 625 | |||||||
| 626 | |||||||
| 627 | |||||||
| 628 | |||||||
| 629 | |||||||
| 630 | |||||||
| 631 | |||||||
| 632 | |||||||
| 633 | |||||||
| 634 | |||||||
| 635 | |||||||
| 636 | |||||||
| 637 | |||||||
| 638 | |||||||
| 639 | |||||||
| 640 | |||||||
| 641 | |||||||
| 642 | |||||||
| 643 | |||||||
| 644 | |||||||
| 645 | =head2 stylesheet | ||||||
| 646 | |||||||
| 647 | %= stylesheet '/foo.css' | ||||||
| 648 | %= stylesheet '/foo.css', title => 'Foo style' | ||||||
| 649 | %= stylesheet begin | ||||||
| 650 | body {color: #000} | ||||||
| 651 | % end | ||||||
| 652 | |||||||
| 653 | Generate portable C | ||||||
| 660 | |||||||
| 661 | =head2 submit_button | ||||||
| 662 | |||||||
| 663 | %= submit_button | ||||||
| 664 | %= submit_button 'Ok!', id => 'foo' | ||||||
| 665 | |||||||
| 666 | Generate C tag of type C |
||||||
| 667 | |||||||
| 668 | |||||||
| 669 | |||||||
| 670 | |||||||
| 671 | =head2 t | ||||||
| 672 | |||||||
| 673 | %= t div => 'test & 123' | ||||||
| 674 | |||||||
| 675 | Alias for L"tag">. | ||||||
| 676 | |||||||
| 677 | test & 123 |
||||||
| 678 | |||||||
| 679 | =head2 tag | ||||||
| 680 | |||||||
| 681 | %= tag 'br' | ||||||
| 682 | %= tag 'div' | ||||||
| 683 | %= tag 'div', id => 'foo', hidden => undef | ||||||
| 684 | %= tag 'div', 'test & 123' | ||||||
| 685 | %= tag 'div', id => 'foo', 'test & 123' | ||||||
| 686 | %= tag 'div', data => {my_id => 1, Name => 'test'}, 'test & 123' | ||||||
| 687 | %= tag div => begin | ||||||
| 688 | test & 123 | ||||||
| 689 | % end | ||||||
| 690 | <%= tag div => (id => 'foo') => begin %>test & 123<% end %> | ||||||
| 691 | |||||||
| 692 | Alias for L |
||||||
| 693 | |||||||
| 694 | |
||||||
| 695 | |||||||
| 696 | |||||||
| 697 | test & 123 |
||||||
| 698 | test & 123 |
||||||
| 699 | test & 123 |
||||||
| 700 | |
||||||
| 701 | test & 123 | ||||||
| 702 | |||||||
| 703 | test & 123 |
||||||
| 704 | |||||||
| 705 | Very useful for reuse in more specific tag helpers. | ||||||
| 706 | |||||||
| 707 | my $output = $c->tag('meta'); | ||||||
| 708 | my $output = $c->tag('meta', charset => 'UTF-8'); | ||||||
| 709 | my $output = $c->tag('div', ' This will be escaped '); |
||||||
| 710 | my $output = $c->tag('div', sub { ' This will not be escaped ' }); |
||||||
| 711 | |||||||
| 712 | Results are automatically wrapped in L |
||||||
| 713 | templates. | ||||||
| 714 | |||||||
| 715 | =head2 tag_with_error | ||||||
| 716 | |||||||
| 717 | %= tag_with_error 'input', class => 'foo' | ||||||
| 718 | |||||||
| 719 | Same as L"tag">, but adds the class C |
||||||
| 720 | |||||||
| 721 | |||||||
| 722 | |||||||
| 723 | =head2 tel_field | ||||||
| 724 | |||||||
| 725 | %= tel_field 'work' | ||||||
| 726 | %= tel_field work => '123456789' | ||||||
| 727 | %= tel_field work => '123456789', id => 'foo' | ||||||
| 728 | |||||||
| 729 | Generate C tag of type C |
||||||
| 730 | |||||||
| 731 | |||||||
| 732 | |||||||
| 733 | |||||||
| 734 | |||||||
| 735 | =head2 text_area | ||||||
| 736 | |||||||
| 737 | %= text_area 'story' | ||||||
| 738 | %= text_area 'story', cols => 40 | ||||||
| 739 | %= text_area story => 'Default', cols => 40 | ||||||
| 740 | %= text_area story => (cols => 40) => begin | ||||||
| 741 | Default | ||||||
| 742 | % end | ||||||
| 743 | |||||||
| 744 | Generate C | ||||||
| 745 | |||||||
| 746 | |||||||
| 747 | |||||||
| 748 | |||||||
| 749 | |||||||
| 750 | Default | ||||||
| 751 | |||||||
| 752 | |||||||
| 753 | =head2 text_field | ||||||
| 754 | |||||||
| 755 | %= text_field 'first_name' | ||||||
| 756 | %= text_field first_name => 'Default' | ||||||
| 757 | %= text_field first_name => 'Default', class => 'user' | ||||||
| 758 | |||||||
| 759 | Generate C tag of type C |
||||||
| 760 | |||||||
| 761 | |||||||
| 762 | |||||||
| 763 | |||||||
| 764 | |||||||
| 765 | =head2 time_field | ||||||
| 766 | |||||||
| 767 | %= time_field 'start' | ||||||
| 768 | %= time_field start => '23:59:59' | ||||||
| 769 | %= time_field start => '23:59:59', id => 'foo' | ||||||
| 770 | |||||||
| 771 | Generate C tag of type C | ||||||
| 772 | |||||||
| 773 | |||||||
| 774 | |||||||
| 775 | |||||||
| 776 | |||||||
| 777 | =head2 url_field | ||||||
| 778 | |||||||
| 779 | %= url_field 'address' | ||||||
| 780 | %= url_field address => 'https://mojolicious.org' | ||||||
| 781 | %= url_field address => 'https://mojolicious.org', id => 'foo' | ||||||
| 782 | |||||||
| 783 | Generate C tag of type C |
||||||
| 784 | |||||||
| 785 | |||||||
| 786 | |||||||
| 787 | |||||||
| 788 | |||||||
| 789 | =head2 week_field | ||||||
| 790 | |||||||
| 791 | %= week_field 'vacation' | ||||||
| 792 | %= week_field vacation => '2012-W17' | ||||||
| 793 | %= week_field vacation => '2012-W17', id => 'foo' | ||||||
| 794 | |||||||
| 795 | Generate C tag of type C |
||||||
| 796 | |||||||
| 797 | |||||||
| 798 | |||||||
| 799 | |||||||
| 800 | |||||||
| 801 | =head1 METHODS | ||||||
| 802 | |||||||
| 803 | L |
||||||
| 804 | ones. | ||||||
| 805 | |||||||
| 806 | =head2 register | ||||||
| 807 | |||||||
| 808 | $plugin->register(Mojolicious->new); | ||||||
| 809 | |||||||
| 810 | Register helpers in L |
||||||
| 811 | |||||||
| 812 | =head1 SEE ALSO | ||||||
| 813 | |||||||
| 814 | L |
||||||
| 815 | |||||||
| 816 | =cut |