view Lib/IMPL/Web/View/TTControl.pm @ 250:129e48bb5afb

DOM refactoring ObjectToDOM methods are virtual QueryToDOM uses inflators Fixed transform for the complex values in the ObjectToDOM QueryToDOM doesn't allow to use complex values (HASHes) as values for nodes (overpost problem)
author sergey
date Wed, 07 Nov 2012 04:17:53 +0400
parents f48a1a9f4fa2
children 6b6d4b2275a1
line wrap: on
line source

package IMPL::Web::View::TTControl;
use strict;

use IMPL::Const qw(:prop);
use IMPL::lang qw(:hash);
use Scalar::Util qw(blessed);
use IMPL::declare {
	require => {
        TTContext => 'Template::Context',
        Exception => 'IMPL::Exception',
        ArgumentException => '-IMPL::InvalidArgumentException',
        OperationException => '-IMPL::InvalidOperationException'
	},
	base => [
	   'IMPL::Object' => undef
	],
	props => [
	   id => PROP_RO,
	   attributes => PROP_RW,
	   name => PROP_RO,
	   context => PROP_RO,
	   template => PROP_RO
	]
};


{
    my $nextId = 1;
    sub _GetNextId {
        return $nextId++;
    }
}

our $AutoloadRegex = qr/^[a-z]/;
our @REFLECT_META = qw(title layout);

sub CTOR {
    my ($this,$name,$template,$context,$refProps) = @_;
    
    $name ||= "control";
    
    $this->template( $template ) or die new IMPL::ArgumentException("A template is required");
    $this->context( $context ) or die new IMPL::ArgumentException("A context is required");
    
    $this->id($name . "-" . _GetNextId()) unless $this->id;
    
    $this->name($name);
    $this->attributes({});
    
    my %attrs;
    
    foreach my $meta ( @REFLECT_META ) {
        next if $meta =~ /^_/;
        if( my $value = $template->$meta() ) {
            $attrs{$meta} = $value;
        }
    }
    
    hashApply(\%attrs,$refProps) if ref $refProps eq 'HASH';
    
    while (my($key,$value) = each %attrs) {
        $this->SetAttribute($key,$value);
    }
}

sub InitInstance {
    my ($this,$args) = @_;
    
    $args ||= {};
    
    if ( my $ctor = $this->template->blocks->{CTOR} ) {
        $this->context->include($ctor, { %$args, this => $this, template => $this->template } );
    }
}

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 GetRenderBlock {
    $_[0]->template->blocks->{RENDER} || $_[0]->template;
}

sub Render {
    my ($this,$args) = @_;
    
    $args = {} unless ref $args eq 'HASH';
    
    if(my $body = $this->GetRenderBlock ) {
        return $this->context->include( $body, { %$args, this => $this, template => $this->template } );
    } else {
        return "";
    }    
}

sub AUTOLOAD {
    our $AUTOLOAD;
    
    my $method = ($AUTOLOAD =~ m/(\w+)$/)[0];
    
    return if $method eq 'DESTROY';
    
    if ($method =~ /$AutoloadRegex/) {
        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");
    }
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::View::TTControl>

=head1 SYNPOSIS

=head1 DESCRIPTION

=head2 BLOCKS

=head3 INIT

Данный блок шаблона управления выполняется один раз при создании первого экземпляра элемента управления,
может использоваться для формирования заголовочной части документа, скрипта подключающего ajax модули
при необходимости и т.п.

=head3 CTOR

данный блок выполняется каждый раз при создании нового экземпляра элемента управления, при этом переменная C<this>
указывает на эземпляр элемента упарвления. Данный блок можно использовать для инициализации свойств элемента
управления.

=head3 RENDER

Данный блок выполняется при вызове метода C<Render()>, вывод данного блока и есть результат отображения элемента управления.
Если в шаблоне нет блока C<RENDER>, то сам шаблон считается таковым. 

=head2 TEMPLATE VARS

Каждый шаблон имеет собственное пространство имен, унаследованное от пространства имен фабрики элементов (которая в свою очередь наследует контекст документа).
В шаблоне могут определяться новые переменные, которые разделяются между блоками. Также доступны стандартные переменные

=over

=item * C<this> ссылка на объект элемента управления

=item * C<component> ссылка на текущий шаблон, устанавливается автоматически в методе C<Template::Context::process>.

=item * C<template> ссылка на шаблон элемента управления, для совместимости с C<TT>

=back

=head1 MEMBERS

=over

=item * C<[get]context>

Контекст элемента управления, хранит пременные шаблона. Наследуется от контекста фабрики элементов управления, который
наследуется от контекста документа.

=item * C<[get,set]template>

C<Template::Document> Шаблон элемента управления.

=item * C<AUTOLOAD>

Для удобства работы с шаблоном, элементы управления предоставляю доступ к своим свойствам через метод C<AUTOLOAD>.

=back


C<lang ru>

=cut