Mercurial > pub > Impl
view Lib/IMPL/Web/View/TTFactory.pm @ 344:f1d67615a5b1
uml diagram
author | cin |
---|---|
date | Mon, 23 Sep 2013 00:09:26 +0400 |
parents | 9bdccdf1f50b |
children |
line wrap: on
line source
package IMPL::Web::View::TTFactory; use strict; use Template::Context(); use Carp qw(carp); use IMPL::lang qw(:hash is); use IMPL::Exception(); use Scalar::Util qw(weaken); use IMPL::Resources::Format qw(FormatMessage); use IMPL::Resources::Strings(); use IMPL::Const qw(:prop); use IMPL::declare { require => { Loader => 'IMPL::Code::Loader', Resources => 'IMPL::Resources', OpException => '-IMPL::InvalidOperationException', ArgException => '-IMPL::InvalidArgumentException' }, base => [ 'IMPL::Object::Factory' => sub { shift; } ], props => [ template => PROP_RW, activation => PROP_RW, context => PROP_RW, baseLocation => PROP_RW, base => PROP_RW, registry => PROP_RO, blocks => PROP_RO, path => PROP_RO, _instance => PROP_RW, _labels => PROP_RW ] }; sub CTOR { my ($this,$class,$template,$context,$path,$registry) = @_; die ArgException->new("A control class must be specified") unless $class; die ArgException->new("A template is required") unless $template; Loader->safe->Require($class) unless ref $class ; $context ||= new Template::Context(); my $baseLocation = join( '/', splice( @{[split(/\//,$path)]}, 0, -1 ) ); $this->activation($template->activation || 'new'); $this->template($template); $this->context($context); $this->baseLocation($baseLocation); $this->path($path); $this->registry($registry); if (my $baseTplName = $template->extends) { $baseTplName =~ s{^\./}{$baseLocation/}; my $base = $registry->Require($baseTplName) or die OpException->new("The specified base template isn't found"); $this->base($base); $this->blocks(hashMerge($base->blocks, $template->blocks)); # блок BASE должен меняться в процессе выполнения, в зависимости от # шаблона, который рендерится, по мере перехода в BASE my @baseStack; $this->blocks->{BASE} = sub { my $ctx = shift; die OpException->new("This tamplate doesn't have a base template") unless $base; push @baseStack, $base; my $block = $base->template->block; $base = $base->base; my $result = eval { $ctx->process($block); }; my $e = $@; $base = pop @baseStack; die $e if $e; return $result; }; } else { $this->blocks( $template->blocks ); } if(my $blocks = $this->blocks) { while (my ($name,$block) = each %$blocks) { $context->define_block($name,$block); } } $context->stash->update({ require => sub { my ($module) = @_; $module =~ s/^\.\//$baseLocation\//; return $registry->Require($module); } }); $this->LoadLabelsToContext($context); } sub LoadLabelsToContext { my ($this,$context) = @_; my %vars; %vars = %{$this->base->_labels || {}} if $this->base; $this->_labels(\%vars); if(my $fname = $this->registry->loader->ResolveFileName($this->path)) { my $flabels = "$fname.labels"; if (-f $flabels) { my %labels; $labels{default} = IMPL::Resources::Strings::ParseStringsMap($flabels); while(my($label,$text) = each %{$labels{default}}) { $vars{$label} = sub { my ($params) = @_; my $locale = Resources->currentLocale; unless ($labels{$locale}) { $labels{$locale} = -f "$fname.$locale" ? IMPL::Resources::Strings::ParseStringsMap("$fname.$locale") : {}; } return FormatMessage(($labels{$locale}{$label} || $text),$params); } } } } $context->stash->update(\%vars); } sub MergeParameters { my $this = shift; my $refProps = shift || {}; unless (ref($refProps) eq 'HASH') { carp "Passing control name through the first parameter is deprecated"; my $name = $refProps; $refProps = shift; $refProps->{name} ||= $name; } $refProps->{factory} = $this; my $ctx = $this->context->clone(); return ($this->template, $ctx, $refProps); } sub CreateObject { my $this = shift; $this->activation eq 'singleton' ? $this->_instance || $this->_instance($this->next::method(@_)) : $this->next::method(@_); } sub Render { my ($this, $args) = @_; return $this->new()->Render($args); } sub save { die new IMPL::NotImplementedException("This class doesn't support serialization"); } sub restore { die new IMPL::NotImplementedException("This class doesn't support serialization"); } 1; __END__ =pod =head1 NAME C<IMPL::Web::View::TTFactory> - фабрика элементов управления =head1 SYNOPSIS =begin code my $factory = new IMPL::Web::View::TTFactory( 'IMPL::Web::View::TTControl', $doc, $context, { TRIM => 1 }, { myprop => 'my value' }, ); my $input1 = $factory->new('login', { class => "required" } ); my $propval = $input->nodeProperty('myprop'); # 'my value' =end code =begin text [% this.appendChild( my.org.input.new('login', class = this.errors('login') ? "invalid" : "" ) ); %] =end text =head1 DESCRIPTION C< Inherits L<IMPL::Object::Factory> > Соединяет в себе шаблон и заранее подготовленный контекст, который будет базой для создаваемых элементов управления. =head1 MEMBERS =over =item C<[get,set]template> Документ C<Template::Document> который описывает элемент управления. См. C<IMPL::Web::View::TTControl>. =item C<[get,set]context> Контекст фабрики элементов управления, в этом контексте выполняет шаблон элемента управления при загрузке. Далее в этом контексте будет выполнен блок инициализации при создании первого элемента управления. =item C<[get,set]opts> Параметры контекста элемента управления (ссылка на хеш). Каждый элемент управления при создании получает свой контекст, который создает с данными параметрами и хранилищем переменных, дочерним к контексту фабрики. =item C<[get,set]nodeProperties> Ссылка на хеш со значениями свойств по умолчанию для создаваемого элемента управления. =item C<[get]instances> Количество созданных элементов управления данной фабрикой =item C<[override]MergeParameters($name,$nodeProps)> Превращает значения переданные методу C<new> фабрики в параметры для создания элемента управления. =over =item C<$name> Имя создаваемого узла (C<nodeName>). =item C<$nodeProps> Ссылка на шех со значениями свойств узла. Данные значения будут совмещены со значениями из свойства C<nodeProperties> =back =item C<[override]CreateObject(@params)> Создает экземпляр элемента управления стандартным образом. Учитывает количество экземпляров и если это первый, то производит дополнительную инициализацию контекста выполнив блок шаблона C<INIT>. =item C<[inherited]new($name,$nodeProps)> Создает элемент управления с указанным именем и набором свойств. =back =cut