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 |