Mercurial > pub > Impl
annotate Lib/IMPL/Web/View/TTFactory.pm @ 304:2ff513227cb4
*TTView: refactoring. Added control registry for the document.
| author | cin |
|---|---|
| date | Mon, 15 Apr 2013 07:44:50 +0400 |
| parents | aeeb57a12046 |
| children | b5d5793f348e |
| rev | line source |
|---|---|
| 181 | 1 package IMPL::Web::View::TTFactory; |
| 2 use strict; | |
| 3 | |
| 4 use Template::Context(); | |
| 5 | |
| 301 | 6 use Carp qw(carp); |
| 267 | 7 use IMPL::lang qw(:hash); |
| 181 | 8 use IMPL::Exception(); |
| 192 | 9 use Scalar::Util qw(weaken); |
| 181 | 10 |
| 11 | |
| 267 | 12 use IMPL::Const qw(:prop); |
| 13 use IMPL::declare { | |
| 298 | 14 require => { |
| 301 | 15 Loader => 'IMPL::Code::Loader', |
| 16 OpException => '-IMPL::InvalidOperationException', | |
| 17 ArgException => '-IMPL::InvalidArgumentException' | |
| 298 | 18 }, |
| 267 | 19 base => [ |
| 298 | 20 'IMPL::Object::Factory' => sub { |
| 301 | 21 shift->class || 'IMPL::Web::View::TTControl'; |
| 298 | 22 } |
| 267 | 23 ], |
| 24 props => [ | |
| 25 template => PROP_RW, | |
| 26 context => PROP_RW, | |
| 27 instances => PROP_RW, | |
| 300 | 28 baseLocation => PROP_RW, |
| 301 | 29 base => PROP_RW, |
| 30 require => PROP_RO, | |
| 31 blocks => PROP_RO, | |
| 32 initialized => PROP_RO | |
| 267 | 33 ] |
| 34 }; | |
| 181 | 35 |
| 36 sub CTOR { | |
| 301 | 37 my ($this,$template,$context,$baseLocation,$require) = @_; |
| 194 | 38 |
| 301 | 39 die ArgException->new("A template is required") unless $template; |
| 194 | 40 |
| 301 | 41 Loader->safe->Require($this->factory) |
| 42 if $this->factory and not ref $this->factory; | |
| 298 | 43 |
| 287 | 44 $context ||= new Template::Context(); |
| 194 | 45 |
| 46 $this->template($template); | |
| 47 $this->context($context); | |
| 300 | 48 $this->baseLocation($baseLocation); |
| 194 | 49 $this->instances(0); |
|
288
3a9cfea098dd
*TTView refactoring: removed RequireControl method, etc.
sergey
parents:
287
diff
changeset
|
50 $this->require($require); |
| 301 | 51 |
| 52 if (my $baseTplName = $template->extends) { | |
| 53 $baseTplName =~ s{^\./}{$baseLocation/}; | |
| 54 | |
| 55 my $base = &$require($baseTplName) | |
| 56 or die OpException->new("The specified base template isn't found"); | |
| 57 | |
| 58 $this->base($base); | |
| 59 | |
| 60 $this->blocks(hashMerge($base->blocks, $template->blocks)); | |
| 61 | |
| 62 # блок BASE должен меняться в процессе выполнения, в зависимости от | |
| 63 # шаблона, который рендерится, по мере перехода в BASE | |
| 64 | |
| 65 my @baseStack; | |
| 66 | |
| 67 $this->blocks->{BASE} = sub { | |
| 68 my $ctx = shift; | |
| 69 | |
| 70 die OpException->new("This tamplate doesn't have a base template") | |
| 71 unless $base; | |
| 72 | |
| 73 push @baseStack, $base; | |
| 74 my $block = $base->template->block; | |
| 75 | |
| 76 $base = $base->base; | |
| 77 | |
| 78 my $result = eval { | |
| 79 $ctx->process($block); | |
| 80 }; | |
| 81 my $e = $@; | |
| 82 | |
| 83 $base = pop @baseStack; | |
| 84 | |
| 85 die $e if $e; | |
| 86 return $result; | |
| 87 }; | |
| 88 } else { | |
| 89 $this->blocks( $template->blocks ); | |
| 90 } | |
| 91 | |
| 92 if(my $blocks = $this->blocks) { | |
| 93 while (my ($name,$block) = each %$blocks) { | |
| 94 $context->define_block($name,$block); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 $context->stash->update({ require => sub { | |
| 99 my ($module) = @_; | |
| 100 | |
| 101 $module =~ s/^\.\//$baseLocation\//; | |
| 102 return $require->($module); | |
| 103 }}); | |
| 181 | 104 } |
| 105 | |
| 106 sub MergeParameters { | |
| 301 | 107 my $this = shift; |
| 108 my $refProps = shift || {}; | |
| 109 | |
| 110 unless (ref($refProps) eq 'HASH') { | |
| 111 carp "Passing control name through the first parameter is deprecated"; | |
| 112 my $name = $refProps; | |
| 113 $refProps = shift; | |
| 114 $refProps->{name} ||= $name; | |
| 115 } | |
| 291 | 116 |
| 298 | 117 $refProps->{factory} = $this; |
| 300 | 118 my $ctx = $this->CloneContext(); |
| 301 | 119 |
| 300 | 120 return ($this->template, $ctx, $refProps); |
| 181 | 121 } |
| 122 | |
| 123 sub CreateObject { | |
| 194 | 124 my $this = shift; |
| 125 | |
| 301 | 126 $this->InitOnDemand(); |
| 194 | 127 |
| 128 my $instance = $this->SUPER::CreateObject(@_); | |
| 301 | 129 |
| 130 my $count = $this->instances; | |
| 194 | 131 $count++; |
| 132 $this->instances($count); | |
| 133 | |
| 134 return $instance; | |
| 181 | 135 } |
| 136 | |
| 301 | 137 sub InitOnDemand { |
| 138 my ($this) = @_; | |
| 139 | |
| 140 unless ($this->initialized) { | |
| 141 $this->initialized(1); | |
| 142 | |
| 143 $this->base->InitOnDemand() | |
| 144 if $this->base; | |
| 145 | |
| 146 if (my $init = $this->template->blocks->{INIT}) { | |
| 147 $this->context->process($init); | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 | |
| 300 | 152 sub CloneContext { |
| 153 my ($this) = @_; | |
| 154 | |
| 155 $this->context->localise(); | |
| 156 | |
| 157 my $args = { %{$this->context} }; | |
| 289 | 158 delete $args->{CONFIG}; |
| 159 | |
| 300 | 160 $this->context->delocalise(); |
| 161 | |
| 289 | 162 return Template::Context->new($args); |
| 163 } | |
| 164 | |
| 301 | 165 sub Render { |
| 166 my ($this, $args) = @_; | |
| 167 | |
| 168 return $this->new()->Render($args); | |
| 169 } | |
| 170 | |
| 181 | 171 sub save { |
| 194 | 172 die new IMPL::NotImplementedException("This class doesn't support serialization"); |
| 181 | 173 } |
| 174 | |
| 175 sub restore { | |
| 194 | 176 die new IMPL::NotImplementedException("This class doesn't support serialization"); |
| 181 | 177 } |
| 178 | |
| 179 1; | |
| 180 | |
| 181 __END__ | |
| 182 | |
| 183 =pod | |
| 184 | |
| 185 =head1 NAME | |
| 186 | |
| 187 C<IMPL::Web::View::TTFactory> - фабрика элементов управления | |
| 188 | |
| 189 =head1 SYNOPSIS | |
| 190 | |
| 191 =begin code | |
| 192 | |
| 193 my $factory = new IMPL::Web::View::TTFactory( | |
| 280 | 194 'IMPL::Web::View::TTControl', |
| 194 | 195 $doc, |
| 196 $context, | |
| 197 { | |
| 198 TRIM => 1 | |
| 199 }, | |
| 200 { | |
| 201 myprop => 'my value' | |
| 202 }, | |
| 181 | 203 ); |
| 204 | |
| 205 my $input1 = $factory->new('login', { class => "required" } ); | |
| 206 | |
| 207 my $propval = $input->nodeProperty('myprop'); # 'my value' | |
| 208 | |
| 209 =end code | |
| 210 | |
| 211 =begin text | |
| 212 | |
| 213 [% | |
| 194 | 214 this.appendChild( |
| 215 my.org.input.new('login', class = this.errors('login') ? "invalid" : "" ) | |
| 216 ); | |
| 181 | 217 %] |
| 218 | |
| 219 =end text | |
| 220 | |
| 221 =head1 DESCRIPTION | |
| 222 | |
| 223 C< Inherits L<IMPL::Object::Factory> > | |
| 224 | |
| 225 =head1 MEMBERS | |
| 226 | |
| 227 =over | |
| 228 | |
| 229 =item C<[get,set]template> | |
| 230 | |
| 231 Документ C<Template::Document> который описывает элемент управления. См. C<IMPL::Web::View::TTControl>. | |
| 232 | |
| 233 =item C<[get,set]context> | |
| 234 | |
| 235 Контекст фабрики элементов управления, в этом контексте выполняет шаблон элемента управления при загрузке. | |
| 236 Далее в этом контексте будет выполнен блок инициализации при создании первого элемента управления. | |
| 237 | |
| 238 =item C<[get,set]opts> | |
| 239 | |
| 240 Параметры контекста элемента управления (ссылка на хеш). Каждый элемент управления при создании получает свой контекст, | |
| 241 который создает с данными параметрами и хранилищем переменных, дочерним к контексту фабрики. | |
| 242 | |
| 243 =item C<[get,set]nodeProperties> | |
| 244 | |
| 245 Ссылка на хеш со значениями свойств по умолчанию для создаваемого элемента управления. | |
| 246 | |
| 247 =item C<[get]instances> | |
| 248 | |
| 249 Количество созданных элементов управления данной фабрикой | |
| 250 | |
| 251 =item C<[override]MergeParameters($name,$nodeProps)> | |
| 252 | |
| 253 Превращает значения переданные методу C<new> фабрики в параметры для создания элемента управления. | |
| 254 | |
| 255 =over | |
| 256 | |
| 257 =item C<$name> | |
| 258 | |
| 259 Имя создаваемого узла (C<nodeName>). | |
| 260 | |
| 261 =item C<$nodeProps> | |
| 262 | |
| 263 Ссылка на шех со значениями свойств узла. Данные значения будут совмещены со значениями из свойства C<nodeProperties> | |
| 264 | |
| 265 =back | |
| 266 | |
| 267 =item C<[override]CreateObject(@params)> | |
| 268 | |
| 269 Создает экземпляр элемента управления стандартным образом. Учитывает количество экземпляров и если это первый, | |
| 270 то производит дополнительную инициализацию контекста выполнив блок шаблона C<INIT>. | |
| 271 | |
| 191 | 272 =item C<[inherited]new($name,$nodeProps)> |
| 181 | 273 |
| 274 Создает элемент управления с указанным именем и набором свойств. | |
| 275 | |
| 276 =back | |
| 277 | |
| 278 =cut |
