Revision d4458803
Von Moritz Bunkus vor fast 12 Jahren hinzugefügt
SL/Controller/Base.pm | ||
---|---|---|
9 | 9 |
use List::Util qw(first); |
10 | 10 |
use SL::Request qw(flatten); |
11 | 11 |
use SL::MoreCommon qw(uri_encode); |
12 |
use SL::Presenter; |
|
12 | 13 |
|
13 | 14 |
use Rose::Object::MakeMethods::Generic |
14 | 15 |
( |
... | ... | |
62 | 63 |
$options->{type} = lc($options->{type} || 'html'); |
63 | 64 |
$options->{no_layout} = 1 if $options->{type} eq 'js'; |
64 | 65 |
|
65 |
my $source; |
|
66 |
if ($options->{inline}) { |
|
67 |
$source = \$template; |
|
68 |
|
|
69 |
} elsif($options->{raw}) { |
|
70 |
$source = $template; |
|
71 |
|
|
72 |
} else { |
|
73 |
$source = "templates/webpages/${template}." . $options->{type}; |
|
74 |
croak "Template file ${source} not found" unless -f $source; |
|
75 |
} |
|
76 |
|
|
77 | 66 |
if (!$options->{partial} && !$options->{inline} && !$::form->{header}) { |
78 | 67 |
if ($options->{no_layout}) { |
79 | 68 |
$::form->{header} = 1; |
... | ... | |
88 | 77 |
} |
89 | 78 |
} |
90 | 79 |
|
91 |
my %params = ( %locals, |
|
92 |
AUTH => $::auth, |
|
93 |
FLASH => $::form->{FLASH}, |
|
94 |
FORM => $::form, |
|
95 |
INSTANCE_CONF => $::instance_conf, |
|
96 |
LOCALE => $::locale, |
|
97 |
LXCONFIG => \%::lx_office_conf, |
|
98 |
LXDEBUG => $::lxdebug, |
|
99 |
MYCONFIG => \%::myconfig, |
|
100 |
SELF => $self, |
|
101 |
); |
|
102 |
|
|
103 | 80 |
my $output; |
104 |
if (!$options->{raw}) { |
|
105 |
my $parser = $self->_template_obj; |
|
106 |
$parser->process($source, \%params, \$output) || croak $parser->error; |
|
81 |
if ($options->{raw}) { |
|
82 |
$output = $$template; |
|
107 | 83 |
} else { |
108 |
$output = $$source; |
|
84 |
$output = $self->presenter->render( |
|
85 |
$template, $options, |
|
86 |
%locals, |
|
87 |
SELF => $self, |
|
88 |
); |
|
109 | 89 |
} |
110 | 90 |
|
111 | 91 |
print $output unless $options->{inline} || $options->{no_output}; |
... | ... | |
129 | 109 |
$file->close; |
130 | 110 |
} |
131 | 111 |
|
112 |
sub presenter { |
|
113 |
return SL::Presenter->get; |
|
114 |
} |
|
115 |
|
|
132 | 116 |
sub controller_name { |
133 | 117 |
my $class = ref($_[0]) || $_[0]; |
134 | 118 |
$class =~ s/^SL::Controller:://; |
... | ... | |
233 | 217 |
} |
234 | 218 |
} |
235 | 219 |
|
236 |
sub _template_obj { |
|
237 |
my ($self) = @_; |
|
238 |
|
|
239 |
$self->{__basepriv_template_obj} ||= |
|
240 |
Template->new({ INTERPOLATE => 0, |
|
241 |
EVAL_PERL => 0, |
|
242 |
ABSOLUTE => 1, |
|
243 |
CACHE_SIZE => 0, |
|
244 |
PLUGIN_BASE => 'SL::Template::Plugin', |
|
245 |
INCLUDE_PATH => '.:templates/webpages', |
|
246 |
COMPILE_EXT => '.tcc', |
|
247 |
COMPILE_DIR => $::lx_office_conf{paths}->{userspath} . '/templates-cache', |
|
248 |
ERROR => 'templates/webpages/generic/exception.html', |
|
249 |
}) || croak; |
|
250 |
|
|
251 |
return $self->{__basepriv_template_obj}; |
|
252 |
} |
|
253 |
|
|
254 | 220 |
1; |
255 | 221 |
|
256 | 222 |
__END__ |
... | ... | |
369 | 335 |
parameters are slurped into C<%locals>. |
370 | 336 |
|
371 | 337 |
What is rendered and how C<$template> is interpreted is determined by |
372 |
the options I<type>, I<inline>, I<partial> and I<no_layout>. |
|
338 |
the options I<type>, I<inline>, I<partial> and I<no_layout>. The |
|
339 |
actual rendering is handled by L<SL::Presenter/render>. |
|
373 | 340 |
|
374 | 341 |
If C<< $options->{inline} >> is trueish then C<$template> is a string |
375 | 342 |
containing the template code to interprete. Additionally the output |
376 | 343 |
will not be sent to the browser. Instead it is only returned to the |
377 | 344 |
caller. |
378 | 345 |
|
379 |
If C<< $options->{raw} >> is trueish, the function will treat the input as |
|
380 |
already parsed, and will not filter the input through Template. Unlike |
|
381 |
C<inline>, the input is taked as a reference. |
|
346 |
If C<< $options->{raw} >> is trueish, the function will treat the |
|
347 |
input as already parsed, and will not filter the input through |
|
348 |
Template. This also means that L<SL::Presenter/render> is not |
|
349 |
called either. Unlike C<inline>, the input is taken as a reference. |
|
382 | 350 |
|
383 | 351 |
If C<< $options->{inline} >> is falsish then C<$template> is |
384 | 352 |
interpreted as the name of a template file. It is prefixed with |
... | ... | |
400 | 368 |
trueish). Setting C<< $options->{no_layout} >> to trueish will prevent |
401 | 369 |
this. |
402 | 370 |
|
403 |
The template itself has access to the following variables: |
|
404 |
|
|
405 |
=over 2 |
|
406 |
|
|
407 |
=item * C<AUTH> -- C<$::auth> |
|
408 |
|
|
409 |
=item * C<FORM> -- C<$::form> |
|
410 |
|
|
411 |
=item * C<LOCALE> -- C<$::locale> |
|
412 |
|
|
413 |
=item * C<LXCONFIG> -- all parameters from C<config/kivitendo.conf> |
|
414 |
with the same name they appear in the file (first level is the |
|
415 |
section, second the actual variable, e.g. C<system.dbcharset>, |
|
416 |
C<features.webdav> etc) |
|
417 |
|
|
418 |
=item * C<LXDEBUG> -- C<$::lxdebug> |
|
419 |
|
|
420 |
=item * C<MYCONFIG> -- C<%::myconfig> |
|
421 |
|
|
422 |
=item * C<SELF> -- the controller instance |
|
423 |
|
|
424 |
=item * All items from C<%locals> |
|
425 |
|
|
426 |
=back |
|
371 |
The template itself has access to several variables. These are listed |
|
372 |
in the documentation to L<SL::Presenter/render>. |
|
427 | 373 |
|
428 | 374 |
Unless C<< $options->{inline} >> is trueish the function will send the |
429 | 375 |
output to the browser. |
... | ... | |
563 | 509 |
mechanism was used then this is not C<dispatch> but the actual method |
564 | 510 |
name the dispatching resolved to. |
565 | 511 |
|
512 |
=item C<presenter> |
|
513 |
|
|
514 |
Returns the global presenter object by calling |
|
515 |
L<SL::Presenter/get>. |
|
516 |
|
|
566 | 517 |
=back |
567 | 518 |
|
568 | 519 |
=head2 PRIVATE FUNCTIONS |
SL/Presenter.pm | ||
---|---|---|
1 |
package SL::Presenter; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use parent qw(Rose::Object); |
|
6 |
|
|
7 |
use Carp; |
|
8 |
use Template; |
|
9 |
|
|
10 |
use SL::Presenter::CustomerVendor; |
|
11 |
use SL::Presenter::DeliveryOrder; |
|
12 |
use SL::Presenter::EscapedText; |
|
13 |
use SL::Presenter::Invoice; |
|
14 |
use SL::Presenter::Order; |
|
15 |
use SL::Presenter::Project; |
|
16 |
use SL::Presenter::Record; |
|
17 |
|
|
18 |
sub get { |
|
19 |
$::request->{presenter} ||= SL::Presenter->new; |
|
20 |
return $::request->{presenter}; |
|
21 |
} |
|
22 |
|
|
23 |
sub render { |
|
24 |
my $self = shift; |
|
25 |
my $template = shift; |
|
26 |
my ($options, %locals) = (@_ && ref($_[0])) ? @_ : ({ }, @_); |
|
27 |
|
|
28 |
$options->{type} = lc($options->{type} || 'html'); |
|
29 |
|
|
30 |
my $source; |
|
31 |
if ($options->{inline}) { |
|
32 |
$source = \$template; |
|
33 |
|
|
34 |
} else { |
|
35 |
$source = "templates/webpages/${template}." . $options->{type}; |
|
36 |
croak "Template file ${source} not found" unless -f $source; |
|
37 |
} |
|
38 |
|
|
39 |
my %params = ( %locals, |
|
40 |
AUTH => $::auth, |
|
41 |
FLASH => $::form->{FLASH}, |
|
42 |
FORM => $::form, |
|
43 |
INSTANCE_CONF => $::instance_conf, |
|
44 |
LOCALE => $::locale, |
|
45 |
LXCONFIG => \%::lx_office_conf, |
|
46 |
LXDEBUG => $::lxdebug, |
|
47 |
MYCONFIG => \%::myconfig, |
|
48 |
PRESENTER => $self, |
|
49 |
); |
|
50 |
|
|
51 |
my $output; |
|
52 |
my $parser = $self->get_template; |
|
53 |
$parser->process($source, \%params, \$output) || croak $parser->error; |
|
54 |
|
|
55 |
return SL::Presenter::EscapedText->new(text => $output, is_escaped => 1); |
|
56 |
} |
|
57 |
|
|
58 |
sub get_template { |
|
59 |
my ($self) = @_; |
|
60 |
|
|
61 |
$self->{template} ||= |
|
62 |
Template->new({ INTERPOLATE => 0, |
|
63 |
EVAL_PERL => 0, |
|
64 |
ABSOLUTE => 1, |
|
65 |
CACHE_SIZE => 0, |
|
66 |
PLUGIN_BASE => 'SL::Template::Plugin', |
|
67 |
INCLUDE_PATH => '.:templates/webpages', |
|
68 |
COMPILE_EXT => '.tcc', |
|
69 |
COMPILE_DIR => $::lx_office_conf{paths}->{userspath} . '/templates-cache', |
|
70 |
ERROR => 'templates/webpages/generic/exception.html', |
|
71 |
}) || croak; |
|
72 |
|
|
73 |
return $self->{template}; |
|
74 |
} |
|
75 |
|
|
76 |
sub escape { |
|
77 |
my ($self, $text) = @_; |
|
78 |
|
|
79 |
return SL::Presenter::EscapedText->new(text => $text); |
|
80 |
} |
|
81 |
|
|
82 |
sub escaped_text { |
|
83 |
my ($self, $text) = @_; |
|
84 |
|
|
85 |
return SL::Presenter::EscapedText->new(text => $text, is_escaped => 1); |
|
86 |
} |
|
87 |
|
|
88 |
1; |
|
89 |
|
|
90 |
__END__ |
|
91 |
|
|
92 |
=head1 NAME |
|
93 |
|
|
94 |
SL::Presenter - presentation layer class |
|
95 |
|
|
96 |
=head1 SYNOPSIS |
|
97 |
|
|
98 |
use SL::Presenter; |
|
99 |
my $presenter = SL::Presenter->get; |
|
100 |
|
|
101 |
# Lower-level template parsing: |
|
102 |
my $html = $presenter->render( |
|
103 |
'presenter/dir/template.html', |
|
104 |
var1 => 'value', |
|
105 |
); |
|
106 |
|
|
107 |
# Higher-level rendering of certain objects: |
|
108 |
use SL::DB::Customer; |
|
109 |
|
|
110 |
my $linked_customer_name = $presenter->customer($customer, display => 'table-cell'); |
|
111 |
|
|
112 |
# Render a list of links to sales/purchase records: |
|
113 |
use SL::DB::Order; |
|
114 |
|
|
115 |
my $quotation = SL::DB::Manager::Order->get_first(where => { quotation => 1 }); |
|
116 |
my $records = $quotation->linked_records(direction => 'to'); |
|
117 |
my $html = $presenter->grouped_record_list($records); |
|
118 |
|
|
119 |
=head1 CLASS FUNCTIONS |
|
120 |
|
|
121 |
=over 4 |
|
122 |
|
|
123 |
=item C<get> |
|
124 |
|
|
125 |
Returns the global presenter object and creates it if it doesn't exist |
|
126 |
already. |
|
127 |
|
|
128 |
=back |
|
129 |
|
|
130 |
=head1 INSTANCE FUNCTIONS |
|
131 |
|
|
132 |
=over 4 |
|
133 |
|
|
134 |
=item C<render $template, [ $options, ] %locals> |
|
135 |
|
|
136 |
Renders the template C<$template>. Provides other variables than |
|
137 |
C<Form::parse_html_template> does. |
|
138 |
|
|
139 |
C<$options>, if present, must be a hash reference. All remaining |
|
140 |
parameters are slurped into C<%locals>. |
|
141 |
|
|
142 |
This is the backend function that L<SL::Controller::Base/render> |
|
143 |
calls. The big difference is that the presenter's L<render> function |
|
144 |
always returns the input and never sends anything to the browser while |
|
145 |
the controller's function usually sends the result to the |
|
146 |
controller. Therefore the presenter's L<render> function does not use |
|
147 |
all of the parameters for controlling the output that the controller's |
|
148 |
function does. |
|
149 |
|
|
150 |
What is rendered and how C<$template> is interpreted is determined by |
|
151 |
the options I<type> and I<inline>. |
|
152 |
|
|
153 |
If C<< $options->{inline} >> is trueish then C<$template> is a string |
|
154 |
containing the template code to interprete. |
|
155 |
|
|
156 |
If C<< $options->{inline} >> is falsish then C<$template> is |
|
157 |
interpreted as the name of a template file. It is prefixed with |
|
158 |
"templates/webpages/" and postfixed with a file extension based on |
|
159 |
C<< $options->{type} >>. C<< $options->{type} >> can be either C<html> |
|
160 |
or C<js> and defaults to C<html>. An exception will be thrown if that |
|
161 |
file does not exist. |
|
162 |
|
|
163 |
The template itself has access to the following variables: |
|
164 |
|
|
165 |
=over 2 |
|
166 |
|
|
167 |
=item * C<AUTH> -- C<$::auth> |
|
168 |
|
|
169 |
=item * C<FORM> -- C<$::form> |
|
170 |
|
|
171 |
=item * C<LOCALE> -- C<$::locale> |
|
172 |
|
|
173 |
=item * C<LXCONFIG> -- all parameters from C<config/kivitendo.conf> |
|
174 |
with the same name they appear in the file (first level is the |
|
175 |
section, second the actual variable, e.g. C<system.dbcharset>, |
|
176 |
C<features.webdav> etc) |
|
177 |
|
|
178 |
=item * C<LXDEBUG> -- C<$::lxdebug> |
|
179 |
|
|
180 |
=item * C<MYCONFIG> -- C<%::myconfig> |
|
181 |
|
|
182 |
=item * C<SELF> -- the controller instance |
|
183 |
|
|
184 |
=item * All items from C<%locals> |
|
185 |
|
|
186 |
=back |
|
187 |
|
|
188 |
The function will always return the output and never send anything to |
|
189 |
the browser. |
|
190 |
|
|
191 |
Example: Render a HTML template with a certain title and a few locals |
|
192 |
|
|
193 |
$presenter->render('todo/list', |
|
194 |
title => 'List TODO items', |
|
195 |
TODO_ITEMS => SL::DB::Manager::Todo->get_all_sorted); |
|
196 |
|
|
197 |
Example: Render a string and return its content for further processing |
|
198 |
by the calling function. |
|
199 |
|
|
200 |
my $content = $presenter->render( |
|
201 |
'[% USE JavaScript %][% JavaScript.replace_with("#someid", "js/something") %]', |
|
202 |
{ type => 'js' } |
|
203 |
); |
|
204 |
|
|
205 |
=item C<escape $text> |
|
206 |
|
|
207 |
Returns an HTML-escaped version of C<$text>. Instead of a string an |
|
208 |
instance of the thin proxy-object L<SL::Presenter::EscapedText> is |
|
209 |
returned. |
|
210 |
|
|
211 |
It is safe to call C<escape> on an instance of |
|
212 |
L<SL::Presenter::EscapedText>. This is a no-op (the same instance will |
|
213 |
be returned). |
|
214 |
|
|
215 |
=item C<escaped_text $text> |
|
216 |
|
|
217 |
Returns an instance of L<SL::Presenter::EscapedText>. C<$text> is |
|
218 |
assumed to be a string that has already been HTML-escaped. |
|
219 |
|
|
220 |
It is safe to call C<escaped_text> on an instance of |
|
221 |
L<SL::Presenter::EscapedText>. This is a no-op (the same instance will |
|
222 |
be returned). |
|
223 |
|
|
224 |
=item C<get_template> |
|
225 |
|
|
226 |
Returns the global instance of L<Template> and creates it if it |
|
227 |
doesn't exist already. |
|
228 |
|
|
229 |
=back |
|
230 |
|
|
231 |
=head1 AUTHOR |
|
232 |
|
|
233 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
234 |
|
|
235 |
=cut |
SL/Presenter/EscapedText.pm | ||
---|---|---|
1 |
package SL::Presenter::EscapedText; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use overload '""' => \&escaped; |
|
6 |
|
|
7 |
sub new { |
|
8 |
my ($class, %params) = @_; |
|
9 |
|
|
10 |
return $params{text} if ref($params{text}) eq $class; |
|
11 |
|
|
12 |
my $self = bless {}, $class; |
|
13 |
$self->{text} = $params{is_escaped} ? $params{text} : $::locale->quote_special_chars('HTML', $params{text}); |
|
14 |
|
|
15 |
return $self; |
|
16 |
} |
|
17 |
|
|
18 |
sub escaped { |
|
19 |
my ($self) = @_; |
|
20 |
return $self->{text}; |
|
21 |
} |
|
22 |
|
|
23 |
1; |
|
24 |
__END__ |
|
25 |
|
|
26 |
=pod |
|
27 |
|
|
28 |
=encoding utf8 |
|
29 |
|
|
30 |
=head1 NAME |
|
31 |
|
|
32 |
SL::Presenter::EscapedText - Thin proxy object around HTML-escaped strings |
|
33 |
|
|
34 |
=head1 SYNOPSIS |
|
35 |
|
|
36 |
use SL::Presenter::EscapedText; |
|
37 |
|
|
38 |
sub blackbox { |
|
39 |
my ($text) = @_; |
|
40 |
return SL::Presenter::EscapedText->new(text => $text); |
|
41 |
} |
|
42 |
|
|
43 |
sub build_output { |
|
44 |
my $output_of_other_component = blackbox('Hello & Goodbye'); |
|
45 |
|
|
46 |
# The following is safe, text will not be escaped twice: |
|
47 |
return SL::Presenter::EscapedText->new(text => $output_of_other_component); |
|
48 |
} |
|
49 |
|
|
50 |
my $output = build_output(); |
|
51 |
print "Yeah: $output\n"; |
|
52 |
|
|
53 |
=head1 OVERVIEW |
|
54 |
|
|
55 |
Sometimes it's nice to let a sub-component build its own |
|
56 |
representation. However, you always have to be very careful about |
|
57 |
whose responsibility escaping is. Only the building function knows |
|
58 |
enough about the structure to be able to HTML escape properly. |
|
59 |
|
|
60 |
But higher functions should not have to care if the output is already |
|
61 |
escaped -- they should be able to simply escape it again. Without |
|
62 |
producing stuff like '&amp;'. |
|
63 |
|
|
64 |
Stringification is overloaded. It will return the same as L<escaped>. |
|
65 |
|
|
66 |
This works together with the template plugin |
|
67 |
L<SL::Template::Plugin::P> and its C<escape> method. |
|
68 |
|
|
69 |
=head1 FUNCTIONS |
|
70 |
|
|
71 |
=over 4 |
|
72 |
|
|
73 |
=item C<new %params> |
|
74 |
|
|
75 |
Creates an instance of C<EscapedText>. |
|
76 |
|
|
77 |
The parameter C<text> is the text to escape. If it is already an |
|
78 |
instance of C<EscapedText> then C<$params{text}> is returned |
|
79 |
unmodified. |
|
80 |
|
|
81 |
Otherwise C<text> is HTML-escaped and stored in the new instance. This |
|
82 |
can be overridden by setting C<$params{is_escaped}> to a trueish |
|
83 |
value. |
|
84 |
|
|
85 |
=item C<escaped> |
|
86 |
|
|
87 |
Returns the escaped string (not an instance of C<EscapedText> but an |
|
88 |
actual string). |
|
89 |
|
|
90 |
=back |
|
91 |
|
|
92 |
=head1 BUGS |
|
93 |
|
|
94 |
Nothing here yet. |
|
95 |
|
|
96 |
=head1 AUTHOR |
|
97 |
|
|
98 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
99 |
|
|
100 |
=cut |
SL/Template/Plugin/L.pm | ||
---|---|---|
6 | 6 |
use List::Util qw(max); |
7 | 7 |
use Scalar::Util qw(blessed); |
8 | 8 |
|
9 |
use SL::Presenter; |
|
10 |
|
|
9 | 11 |
use strict; |
10 | 12 |
|
11 | 13 |
{ # This will give you an id for identifying html tags and such. |
... | ... | |
675 | 677 |
}, |
676 | 678 |
); |
677 | 679 |
|
678 |
my $output; |
|
679 |
$controller->_template_obj->process('templates/webpages/common/paginate.html', \%template_params, \$output); |
|
680 |
return $output; |
|
680 |
return SL::Presenter->get->render('common/paginate', %template_params); |
|
681 | 681 |
} |
682 | 682 |
|
683 | 683 |
1; |
SL/Template/Plugin/P.pm | ||
---|---|---|
1 |
package SL::Template::Plugin::P; |
|
2 |
|
|
3 |
use base qw( Template::Plugin ); |
|
4 |
|
|
5 |
use SL::Presenter; |
|
6 |
use SL::Presenter::EscapedText; |
|
7 |
|
|
8 |
use strict; |
|
9 |
|
|
10 |
sub new { |
|
11 |
my ($class, $context, @args) = @_; |
|
12 |
|
|
13 |
return bless { |
|
14 |
CONTEXT => $context, |
|
15 |
}, $class; |
|
16 |
} |
|
17 |
|
|
18 |
sub escape { |
|
19 |
my ($self, $string) = @_; |
|
20 |
return SL::Presenter::EscapedText->new(text => $string); |
|
21 |
} |
|
22 |
|
|
23 |
sub AUTOLOAD { |
|
24 |
our $AUTOLOAD; |
|
25 |
|
|
26 |
my ($self, @args) = @_; |
|
27 |
|
|
28 |
my $presenter = SL::Presenter->get; |
|
29 |
my $method = $AUTOLOAD; |
|
30 |
$method =~ s/.*:://; |
|
31 |
|
|
32 |
return '' unless $presenter->can($method); |
|
33 |
|
|
34 |
splice @args, -1, 1, %{ $args[-1] } if @args && (ref($args[-1]) eq 'HASH'); |
|
35 |
|
|
36 |
$presenter->$method(@args); |
|
37 |
} |
|
38 |
|
|
39 |
1; |
|
40 |
|
|
41 |
__END__ |
|
42 |
|
|
43 |
=pod |
|
44 |
|
|
45 |
=encoding utf8 |
|
46 |
|
|
47 |
=head1 NAME |
|
48 |
|
|
49 |
SL::Template::Plugin::P - Template plugin for the presentation layer |
|
50 |
|
|
51 |
=head1 SYNOPSIS |
|
52 |
|
|
53 |
[% USE P %] |
|
54 |
|
|
55 |
Customer: [% P.customer(customer) %] |
|
56 |
|
|
57 |
Linked records: |
|
58 |
[% P.grouped_record_list(RECORDS) %] |
|
59 |
|
|
60 |
=head1 FUNCTIONS |
|
61 |
|
|
62 |
=over 4 |
|
63 |
|
|
64 |
=item C<AUTOLOAD> |
|
65 |
|
|
66 |
All unknown functions called on C<P> are forwarded to functions with |
|
67 |
the same name in the global presenter object. |
|
68 |
|
|
69 |
The presenter's functions use hashes for named-argument |
|
70 |
passing. Unfortunately L<Template> groups named arguments into hash |
|
71 |
references. This makes mixing intentional hash references and named |
|
72 |
arguments a bit hairy. For example, the following calls from a |
|
73 |
template are undistinguishable for a plugin: |
|
74 |
|
|
75 |
[% P.some_func({ arg1 => 42, arg2 => 'Charlie' }) %] |
|
76 |
[% P.some_func(arg1 => 42, arg2 => 'Charlie') %] |
|
77 |
[% P.some_func(arg1=42, arg2='Charlie') %] |
|
78 |
[% P.some_func(arg1=42, arg2='Charlie') %] |
|
79 |
|
|
80 |
C<AUTOLOAD> tries to be clever and unpacks a hash reference into a |
|
81 |
normal hash if and only if it is the very last parameter to the |
|
82 |
function call. |
|
83 |
|
|
84 |
Returns the result of the corresponding function in the presenter. |
|
85 |
|
|
86 |
=item C<escape $text> |
|
87 |
|
|
88 |
Returns an HTML-escaped version of C<$text>. Instead of a string an |
|
89 |
instance of the thin proxy-object L<SL::Presenter::EscapedText> is |
|
90 |
returned. |
|
91 |
|
|
92 |
It is safe to call C<escape> on an instance of |
|
93 |
L<SL::Presenter::EscapedText>. This is a no-op (the same instance will |
|
94 |
be returned). |
|
95 |
|
|
96 |
=back |
|
97 |
|
|
98 |
=head1 BUGS |
|
99 |
|
|
100 |
Nothing here yet. |
|
101 |
|
|
102 |
=head1 AUTHOR |
|
103 |
|
|
104 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
105 |
|
|
106 |
=cut |
Auch abrufbar als: Unified diff
SL::Presenter -- die neue Präsentationsschicht