Mercurial > pub > Impl
comparison Lib/IMPL/Web/View/TTContext.pm @ 359:833e663796c4
TTView: added view variable to pass rendering context between controls
TTView: display function renamed to display_for
WebResource: resources now marked with roles for searching a desired resource by a role in the resource chain
author | sergey |
---|---|
date | Mon, 25 Nov 2013 02:19:31 +0400 |
parents | 97131d500f16 |
children | cbf4febf0930 |
comparison
equal
deleted
inserted
replaced
358:248f95c1762a | 359:833e663796c4 |
---|---|
21 ] | 21 ] |
22 }; | 22 }; |
23 | 23 |
24 BEGIN { | 24 BEGIN { |
25 no strict 'refs'; | 25 no strict 'refs'; |
26 # modules is a global (for the whole document) templates cache | |
27 # tt_cache is a local (for the current context only) templtes cache | |
28 # view is a special variable, which will be cloned and passed to the nested context | |
26 foreach my $prop (qw( | 29 foreach my $prop (qw( |
27 root | 30 root |
28 base | 31 base |
29 tt_ext | 32 tt_ext |
30 tt_cache | 33 tt_cache |
33 cache | 36 cache |
34 includes | 37 includes |
35 modules | 38 modules |
36 aliases | 39 aliases |
37 id | 40 id |
41 view | |
38 )) { | 42 )) { |
39 my $t = $prop; | 43 my $t = $prop; |
40 | 44 |
41 *{__PACKAGE__ . '::' . $prop} = sub { | 45 *{__PACKAGE__ . '::' . $prop} = sub { |
42 my $this = shift; | 46 my $this = shift; |
73 $this->stash->set('document.nextId', $id + 1); | 77 $this->stash->set('document.nextId', $id + 1); |
74 return "w-$id"; | 78 return "w-$id"; |
75 } | 79 } |
76 | 80 |
77 sub find_template { | 81 sub find_template { |
78 my ($this,$name) = @_; | 82 my ($this,$name, $nothrow) = @_; |
79 | 83 |
80 my $cache = $this->tt_cache; | 84 my $cache = $this->tt_cache; |
81 | 85 |
82 $this->tt_cache($cache = {}) unless $cache; | 86 $this->tt_cache($cache = {}) unless $cache; |
83 | 87 |
127 $this->modules->{$file} = undef; | 131 $this->modules->{$file} = undef; |
128 } | 132 } |
129 } | 133 } |
130 } | 134 } |
131 | 135 |
132 $this->throw(Template::Constants::ERROR_FILE, "$name: not found"); | 136 $this->throw(Template::Constants::ERROR_FILE, "$name: not found") |
133 } | 137 unless $nothrow; |
134 | 138 return; |
135 sub display { | 139 } |
140 | |
141 sub display_for { | |
136 my $this = shift; | 142 my $this = shift; |
137 my $model = shift; | 143 my $model = shift; |
138 my ($template, $args); | 144 my ($template, $args); |
139 | 145 |
140 if (ref $_[0] eq 'HASH') { | 146 if (ref $_[0] eq 'HASH') { |
201 $args | 207 $args |
202 ) | 208 ) |
203 ); | 209 ); |
204 } | 210 } |
205 | 211 |
212 # обеспечивает необходимый уровень изоляции между контекстами | |
213 # $code - код, который нужно выполнить в новом контексте | |
214 # $env - хеш с переменными, которые будут переданы в новый контекст | |
215 # в процессе будет создан клон корневого контекста, со всеми его свойствами | |
216 # затем новый контекст будет локализован и в него будут добавлены новые переменные из $env | |
217 # созданный контекст будет передан параметром в $code | |
206 sub invoke_environment { | 218 sub invoke_environment { |
207 my ($this,$code,$env) = @_; | 219 my ($this,$code,$env) = @_; |
208 | 220 |
209 $env ||= {}; | 221 $env ||= {}; |
210 | 222 |
211 my $ctx = ($this->root || $this)->clone(); | 223 my $ctx = ($this->root || $this)->clone(); |
212 | 224 |
225 my @includes = @{$this->includes || []}; | |
226 | |
227 if ($this->base) { | |
228 unshift @includes, $this->base; | |
229 } | |
230 | |
231 my $view = $this->view; | |
232 $view = ref $view eq 'HASH' ? { %{$view} } : {}; | |
233 | |
234 hashApply($view, delete $env->{view}); | |
235 | |
213 my $out = eval { | 236 my $out = eval { |
214 $ctx->localise( | 237 $ctx->localise( |
215 hashApply( | 238 hashApply( |
216 { | 239 { |
240 includes => \@includes, | |
217 aliases => $this->aliases || {}, | 241 aliases => $this->aliases || {}, |
218 root => $this->root || $ctx, | 242 root => $this->root || $ctx, |
219 modules => $this->modules || {}, | 243 modules => $this->modules || {}, |
220 cache => TypeKeyedCollection->new(), | 244 cache => TypeKeyedCollection->new(), |
221 display => sub { | 245 display_for => sub { |
222 $ctx->display(@_); | 246 $ctx->display_for(@_); |
223 }, | 247 }, |
224 render => sub { | 248 render => sub { |
225 $ctx->render(@_); | 249 $ctx->render(@_); |
226 }, | 250 }, |
227 display_model => sub { | 251 display_model => sub { |
228 $ctx->display_model(@_); | 252 $ctx->display_model(@_); |
229 }, | 253 }, |
230 tt_cache => {} | 254 tt_cache => {}, |
255 view => $view | |
231 }, | 256 }, |
232 $env | 257 $env |
233 ) | 258 ) |
234 ); | 259 ); |
235 | 260 |
242 die $e if $e; | 267 die $e if $e; |
243 | 268 |
244 return $out; | 269 return $out; |
245 } | 270 } |
246 | 271 |
272 # использует указанный шаблон для создания фрагмента документа | |
273 # шаблон может быть как именем, так и хешем, содержащим информацию | |
274 # о шаблоне. | |
275 # отдельно следует отметить, что данный метод создает новый контекст | |
276 # для выполнения шаблона в котором задает переменные base, parent, id | |
277 # а также создает переменные для строковых констант из labels | |
278 # хеш с переменными $args будет передан самому шаблону в момент выполнения | |
279 # если у шаблона указан класс элемента управления, то при выполнении шаблона | |
280 # будет создан экземпляр этого класса и процесс выполнения шаблона будет | |
281 # делегирован методу Render этого экземпляра. | |
247 sub render { | 282 sub render { |
248 my ($this,$template,$args) = @_; | 283 my ($this,$template,$args) = @_; |
249 | 284 |
250 $args ||= {}; | 285 $args ||= {}; |
251 | 286 |
274 $ctx->leave(); | 309 $ctx->leave(); |
275 } | 310 } |
276 } | 311 } |
277 | 312 |
278 if (my $class = $info->{class}) { | 313 if (my $class = $info->{class}) { |
279 $class->new($ctx,$info->{template},$args)->Render($args); | 314 $class->new($ctx,$info->{template},$args)->Render({}); |
280 } else { | 315 } else { |
281 return $ctx->include($info->{template},$args); | 316 return $ctx->include($info->{template},$args); |
282 } | 317 } |
283 }, | 318 }, |
284 hashMerge( | 319 hashMerge( |
311 prefix => $this->prefix ? $this->prefix . ".$prefix" : $prefix | 346 prefix => $this->prefix ? $this->prefix . ".$prefix" : $prefix |
312 }; | 347 }; |
313 } | 348 } |
314 | 349 |
315 sub find_template_for { | 350 sub find_template_for { |
316 my ($this,$model) = @_; | 351 my ($this,$model, $nothrow) = @_; |
317 | 352 |
318 my $type = typeof($model); | 353 my $type = typeof($model); |
319 | 354 |
320 return $this->find_template('templates/plain') unless $type; | 355 return $this->find_template('templates/plain') unless $type; |
321 | 356 |
329 | 364 |
330 while (@isa) { | 365 while (@isa) { |
331 my $sclass = shift @isa; | 366 my $sclass = shift @isa; |
332 | 367 |
333 (my $name = $sclass) =~ s/:+/_/g; | 368 (my $name = $sclass) =~ s/:+/_/g; |
334 | 369 my ($shortName) = ($sclass =~ m/(\w+)$/); |
335 $template = $this->find_template("templates/$name"); | 370 |
371 $template = $this->find_template("templates/$name",1) || $this->find_template("templates/$shortName",1); | |
336 | 372 |
337 if ($template) { | 373 if ($template) { |
338 $this->cache->Set($sclass,$template); | 374 $this->cache->Set($sclass,$template); |
339 return $template; | 375 return $template; |
340 } | 376 } |
341 | 377 |
342 push @isa, @{"${sclass}::ISA"}; | 378 push @isa, @{"${sclass}::ISA"}; |
343 } | 379 } |
344 | 380 |
345 } | 381 } |
346 | 382 $this->throw(Template::Constants::ERROR_FILE, "can't find a template for the model " . typeof($model)) |
383 unless $nothrow; | |
384 | |
347 return; | 385 return; |
348 } | 386 } |
349 | 387 |
350 sub get_real_file { | 388 sub get_real_file { |
351 my ($this,$fname) = @_; | 389 my ($this,$fname) = @_; |