Mercurial > pub > Impl
view Lib/IMPL/Web/View/TTControl.pm @ 343:9bdccdf1f50b
Added a templates context
author | cin |
---|---|
date | Fri, 13 Sep 2013 12:53:15 +0400 |
parents | 1090c1dd7429 |
children | f05634287ac7 |
line wrap: on
line source
package IMPL::Web::View::TTControl; use strict; use IMPL::Const qw(:prop); use IMPL::lang qw(:hash :base); use Scalar::Util qw(blessed reftype); use IMPL::declare { require => { TemplateDocument => 'Template::Document', TTContext => 'IMPL::Web::View::TTContext', Exception => 'IMPL::Exception', ArgumentException => '-IMPL::InvalidArgumentException', OperationException => '-IMPL::InvalidOperationException' }, base => [ 'IMPL::Object' => undef ], props => [ id => PROP_RO, attributes => PROP_RW, context => PROP_RO, template => PROP_RO ] }; { my $nextId = 1; sub _GetNextId { return '_' . $nextId++; } } our $AUTOLOAD_REGEX = qr/^[a-z]/; my %mapSkipAttributes = map { $_, 1 } qw(attributes context); sub CTOR { my ($this,$template,$context,$attrs) = @_; $this->template( $template ) or die new IMPL::ArgumentException("A template is required"); die IMPL::ArgumentException->new(context => "A context is required, supplied: $context") unless is($context,TTContext); $this->context( $context ); $this->attributes({}); if(ref($attrs) eq 'HASH') { while (my($key,$value) = each %$attrs) { next if $mapSkipAttributes{$key}; $this->SetAttribute($key,$value); } } $this->id(_GetNextId()) unless $this->id; } sub GetAttribute { my ($this,$name) = (shift,shift); if (my $method = $this->can($name)) { unshift @_,$this; goto &$method; } else { return $this->attributes->{$name}; } } sub SetAttribute { my $this = shift; my $name = shift; if (my $method = $this->can($name)) { unshift @_, $this; goto &$method; } else { return $this->attributes->{$name} = shift; } } sub Render { my ($this,$args) = @_; $args = {} unless ref $args eq 'HASH'; return $this->context->include( $this->template->block, { %$args, this => $this, template => $this->template } ); } sub GetTemplate { my ($this,$name) = @_; return eval { $this->context->template($name) }; } sub Include { my ($this,$template, $args) = @_; my $tpl = $this->GetTemplate($template) or die OperationException->new("The specified template isn't found", $template); return $this->context->include( $tpl, $args ); } sub HasBlock { my ($this,$block) = @_; $this->GetTemplate ? 1 : 0; } sub AUTOLOAD { our $AUTOLOAD; my $method = ($AUTOLOAD =~ m/(\w+)$/)[0]; return if $method eq 'DESTROY'; if ($method =~ /$AUTOLOAD_REGEX/) { my $this = shift; die OperationException->new("can't invoke method '$method' on an unblessed reference") unless blessed $this; return @_ ? $this->SetAttribute($method,@_) : $this->GetAttribute($method); } else { die OperationException->new("The specified method '$method' doesn't exists"); } } sub CreateControlFromTemplate { my ($this,$template,$args) = @_; if (not ref($template)) { return $this->context->stash->get([ require => [ $template ] ])->new($args); } else { return $this->new( $template, $this->context->clone(), $args ); } } 1; __END__ =pod =head1 NAME C<IMPL::Web::View::TTControl> =head1 SYNPOSIS =begin text [% META version = 1; BLOCK INIT; # this is a document scope dojo.modules.push( 'dijit/form/Input' ); END; # local to this block TPreview = require('My/Org/TextPreview'); # init control props visualClass = this.visualClass || 'classic'; %] <div id="$id" class="$visualClass" data-dojo-type="dijit/form/Input"> [% FOREACH item IN model %] <div class="itemContainer"> [% Display(item) %] </div> [% END %] </div> =end text =head1 DESCRIPTION Легкая обертка вокруг шаблона, позволяет изолировать пространство имен шаблона, а также реализовать собственные методы по представлению данных (в случае если это проще сделать в виде методов класса). =head2 BLOCKS =head3 META Атрибуты C<META> C<layout>, C<title> будут перенесены в свойства элемента управления. =head3 INIT Данный блок шаблона управления выполняется один раз при создании первого экземпляра элемента управления, в пространстве имен документа. Может использоваться для формирования заголовочной части документа, скрипта подключающего C<js> модули и т.п. Выполнение данного блока производится фабрикой элементов управления. =head2 TEMPLATE VARS Каждый шаблон имеет собственное пространство имен, вложенное в пространство имен фабрики элементов (которая разделяет пространство имен документа). В шаблоне могут определяться новые переменные, однако они останутся локальными для блоков. Чтобы передать данные между блоками следует использовать ссылку на элемент управления C<this>. =begin text [% BLOCK CTOR; this.extraCssClass = 'active'; text = "this text will gone"; END; %] <div class="$this.extraCssClass">some text $text</div> =end text В примере выше переменная C<$text> установленная в конструкторе шаблона, при отображении элемента управления будет неопределена. =over =item * C<this> ссылка на объект элемента управления =item * C<component> ссылка на текущий шаблон, устанавливается автоматически в методе C<Template::Context::process>. =item * C<template> ссылка на шаблон элемента управления, для совместимости с C<TT> =back =head1 MEMBERS =head2 C<[get]context> Контекст элемента управления, хранит пременные шаблона. Фабрика элементов управления создает новый контекст пространство имен которого вложено в пространство имен документа. Контекст следует использовать только при рендеринге документа. =head2 C<[get,set]template> C<Template::Document> Шаблон элемента управления. =head2 C<AUTOLOAD> Для удобства работы с шаблоном, элементы управления предоставляю доступ к своим свойствам через метод C<AUTOLOAD>. Имена свойств должны начинаться со строчной буквы. =cut