Mercurial > pub > Impl
diff Lib/IMPL/Web/View/TTControl.pm @ 352:675cd1829255
working on TTView: added control classes support
author | cin |
---|---|
date | Thu, 10 Oct 2013 19:51:19 +0400 |
parents | f05634287ac7 |
children | feeb3bc4a818 |
line wrap: on
line diff
--- a/Lib/IMPL/Web/View/TTControl.pm Tue Oct 08 17:40:35 2013 +0400 +++ b/Lib/IMPL/Web/View/TTControl.pm Thu Oct 10 19:51:19 2013 +0400 @@ -3,24 +3,22 @@ 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' + Exception => 'IMPL::Exception', + ArgException => '-IMPL::InvalidArgumentException' }, base => [ 'IMPL::Object' => undef ], props => [ - id => PROP_RO, - attributes => PROP_RW, - context => PROP_RO, - template => PROP_RO, - parents => PROP_RO + context => PROP_RO, + template => PROP_RO, + _stash => PROP_RO, + id => { + get => sub { shift->_stash->get('id') }, + set => sub { shift->_stash->set('id',shift) } + } ] }; @@ -34,128 +32,45 @@ 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); - } - } + my ($this,$context,$template) = @_; - $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; - } + $this->context($context) + or die ArgException->new(context => 'A context is required'); + $this->template($template) + or die ArgException->new(template => 'A template is required'); + + $this->_stash($context->stash); } 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 - ); + my ($this,$args) = @_; + return $this->context->include($this->template,$args); } -sub HasBlock { - my ($this,$block) = @_; - - $this->GetTemplate ? 1 : 0; +our $AUTOLOAD; +sub AUTOLOAD { + my ($prop) = ($AUTOLOAD =~ m/(\w+)$/); + + die Exception->new("Control doesn't have method '$prop'") unless $prop=~/$AUTOLOAD_REGEX/; + + no strict 'refs'; + + my $method = sub { + if (@_ == 1) { + return shift->_stash->get($prop); + } elsif (@_ == 2) { + return shift->_stash->set($prop,shift); + } else { + return shift->_stash->get([$prop,[@_]]); + } + }; + + *{$AUTOLOAD} = $method; + + goto &$method; } -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; @@ -165,117 +80,32 @@ =head1 NAME -C<IMPL::Web::View::TTControl> +C<IMPL::Web::View::TTControl> расширяет функциональность шаблонов =head1 SYNPOSIS -=begin text +=begin code + +package My::View::Menu; +use IMPL::declare { + base => [ + 'IMPL::Web::View::TTControl' => '@_' + ] +}; -[% - 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> +sub Render { + my ($this,$args) = @_; + + $this->PrepareItems($args); + + return $this->next::method($args); +} -=end text +sub PrepareItems + +=end code =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 \ No newline at end of file