Mercurial > pub > Impl
comparison Lib/IMPL/Web/TT/Document.pm @ 194:4d0e1962161c
Replaced tabs with spaces
IMPL::Web::View - fixed document model, new features (control classes, document constructor parameters)
author | cin |
---|---|
date | Tue, 10 Apr 2012 20:08:29 +0400 |
parents | d1676be8afcc |
children |
comparison
equal
deleted
inserted
replaced
193:8e8401c0aea4 | 194:4d0e1962161c |
---|---|
28 our %CTOR = ( | 28 our %CTOR = ( |
29 'IMPL::DOM::Document' => sub { nodeName => 'document' } | 29 'IMPL::DOM::Document' => sub { nodeName => 'document' } |
30 ); | 30 ); |
31 | 31 |
32 sub CTOR { | 32 sub CTOR { |
33 my ($this,%args) = @_; | 33 my ($this,%args) = @_; |
34 | 34 |
35 $this->_controlClassMap({}); | 35 $this->_controlClassMap({}); |
36 $this->registerControlClass( Control => 'IMPL::Web::TT::Control' ); | 36 $this->registerControlClass( Control => 'IMPL::Web::TT::Control' ); |
37 $this->appendChild( $this->Create(body => 'IMPL::Web::TT::Collection') ); | 37 $this->appendChild( $this->Create(body => 'IMPL::Web::TT::Collection') ); |
38 $this->appendChild( $this->Create(head => 'IMPL::Web::TT::Collection') ); | 38 $this->appendChild( $this->Create(head => 'IMPL::Web::TT::Collection') ); |
39 $this->cache($args{cache}) if $args{cache}; | 39 $this->cache($args{cache}) if $args{cache}; |
40 $this->preprocess($args{preprocess}) if $args{preprocess}; | 40 $this->preprocess($args{preprocess}) if $args{preprocess}; |
41 } | 41 } |
42 | 42 |
43 sub CreateControl { | 43 sub CreateControl { |
44 my ($this,$name,$class,$args) = @_; | 44 my ($this,$name,$class,$args) = @_; |
45 | 45 |
46 $args = {} unless ref $args eq 'HASH'; | 46 $args = {} unless ref $args eq 'HASH'; |
47 | 47 |
48 if (my $info = $this->_controlClassMap->{$class}) { | 48 if (my $info = $this->_controlClassMap->{$class}) { |
49 my %nodeArgs = (%{$info->{args}},%$args); | 49 my %nodeArgs = (%{$info->{args}},%$args); |
50 $nodeArgs{controlClass} = $class; | 50 $nodeArgs{controlClass} = $class; |
51 | 51 |
52 return $this->Create($name,$info->{type},\%nodeArgs); | 52 return $this->Create($name,$info->{type},\%nodeArgs); |
53 } else { | 53 } else { |
54 die new IMPL::Exception('A control is\'t registered', $class, $name); | 54 die new IMPL::Exception('A control is\'t registered', $class, $name); |
55 } | 55 } |
56 } | 56 } |
57 | 57 |
58 sub provider { | 58 sub provider { |
59 my ($this,%args) = @_; | 59 my ($this,%args) = @_; |
60 | 60 |
77 new Template::Context( | 77 new Template::Context( |
78 VARIABLES => { | 78 VARIABLES => { |
79 document => $this, | 79 document => $this, |
80 this => $this, | 80 this => $this, |
81 render => sub { | 81 render => sub { |
82 $this->_process(@_); | 82 $this->_process(@_); |
83 }, | 83 }, |
84 encode => sub { | 84 encode => sub { |
85 Encode::encode('utf8',shift); | 85 Encode::encode('utf8',shift); |
86 }, | 86 }, |
87 dump => sub { | 87 dump => sub { |
88 Dumper(shift); | 88 Dumper(shift); |
89 }, | 89 }, |
90 as_list => sub { | 90 as_list => sub { |
91 [ map ref($_) eq 'ARRAY' ? @$_ : $_, @_ ] | 91 [ map ref($_) eq 'ARRAY' ? @$_ : $_, @_ ] |
92 } | 92 } |
93 }, | 93 }, |
94 RECURSION => 1, | 94 RECURSION => 1, |
95 LOAD_TEMPLATES => [$this->provider] | 95 LOAD_TEMPLATES => [$this->provider] |
96 ) | 96 ) |
97 ) | 97 ) |
98 } | 98 } |
99 } | 99 } |
100 | 100 |
101 sub resolveVar { | 101 sub resolveVar { |
102 my ($this,$var) = @_; | 102 my ($this,$var) = @_; |
103 | 103 |
104 return $this->context->stash->get($var); | 104 return $this->context->stash->get($var); |
105 } | 105 } |
106 | 106 |
107 sub registerControlClass { | 107 sub registerControlClass { |
108 my ($this, $controlClass, $type, $args) = @_; | 108 my ($this, $controlClass, $type, $args) = @_; |
109 | 109 |
110 $type ||= 'IMPL::Web::TT::Control'; | 110 $type ||= 'IMPL::Web::TT::Control'; |
111 | 111 |
112 die new IMPL::InvalidArgumentException("A controlClass must be a single word",$controlClass) unless $controlClass =~ /^\w+$/; | 112 die new IMPL::InvalidArgumentException("A controlClass must be a single word",$controlClass) unless $controlClass =~ /^\w+$/; |
113 | 113 |
114 eval "require $type; 1;" or die new IMPL::Exception("Failed to load a module",$type,"$@") unless eval { $type->can('new') }; | 114 eval "require $type; 1;" or die new IMPL::Exception("Failed to load a module",$type,"$@") unless eval { $type->can('new') }; |
115 | 115 |
116 die new IMPL::InvalidArgumentException("A type must be subclass of IMPL::DOM::Node",$type) unless $type->isa('IMPL::DOM::Node'); | 116 die new IMPL::InvalidArgumentException("A type must be subclass of IMPL::DOM::Node",$type) unless $type->isa('IMPL::DOM::Node'); |
117 | 117 |
118 # resolve template name to a real template | 118 # resolve template name to a real template |
119 $args->{template} = $this->context->template($args->{template}) if $args->{template}; | 119 $args->{template} = $this->context->template($args->{template}) if $args->{template}; |
120 | 120 |
121 $this->_controlClassMap->{$controlClass} = { | 121 $this->_controlClassMap->{$controlClass} = { |
122 controlClass => $controlClass, | 122 controlClass => $controlClass, |
123 type => $type, | 123 type => $type, |
124 args => ref $args eq 'HASH' ? $args : {} | 124 args => ref $args eq 'HASH' ? $args : {} |
125 }; | 125 }; |
126 } | 126 } |
127 | 127 |
128 sub require { | 128 sub require { |
129 my ($this,$template) = @_; | 129 my ($this,$template) = @_; |
130 | 130 |
131 my $doc = $this->context->template($template); | 131 my $doc = $this->context->template($template); |
132 | 132 |
133 die new IMPL::InvalidOperationException("A specified template isn't a document",$template) unless eval{ $doc -> isa('Template::Document') }; | 133 die new IMPL::InvalidOperationException("A specified template isn't a document",$template) unless eval{ $doc -> isa('Template::Document') }; |
134 | 134 |
135 my $controlClass = $doc->class; | 135 my $controlClass = $doc->class; |
136 my $type = $doc->nativeType; | 136 my $type = $doc->nativeType; |
137 my $controlTemplate; | 137 my $controlTemplate; |
138 my $out = ""; | 138 my $out = ""; |
139 | 139 |
140 die new IMPL::InvalidOperationException("A specified template isn't a control",$template) unless $controlClass; | 140 die new IMPL::InvalidOperationException("A specified template isn't a control",$template) unless $controlClass; |
141 | 141 |
142 if (not $this->isControlClass($controlClass)) { | 142 if (not $this->isControlClass($controlClass)) { |
143 if ($doc->template) { | 143 if ($doc->template) { |
144 $controlTemplate = $doc->blocks()->{$doc->template} || $this->context->template($doc->template); | 144 $controlTemplate = $doc->blocks()->{$doc->template} || $this->context->template($doc->template); |
145 $out = $this->context->include($doc); | 145 $out = $this->context->include($doc); |
146 } else { | 146 } else { |
147 $controlTemplate = $doc; | 147 $controlTemplate = $doc; |
148 } | 148 } |
149 $this->registerControlClass($controlClass,$type,{ template => $controlTemplate } ); | 149 $this->registerControlClass($controlClass,$type,{ template => $controlTemplate } ); |
150 } | 150 } |
151 | 151 |
152 return $out; | 152 return $out; |
153 } | 153 } |
154 | 154 |
155 sub isControlClass { | 155 sub isControlClass { |
156 my ($this,$name) = @_; | 156 my ($this,$name) = @_; |
157 return $this->_controlClassMap->{$name} ? 1 : 0; | 157 return $this->_controlClassMap->{$name} ? 1 : 0; |
158 } | 158 } |
159 | 159 |
160 sub _getControls { | 160 sub _getControls { |
161 my ($this) = @_; | 161 my ($this) = @_; |
162 | 162 |
163 my ($node) = $this->selectNodes('controls'); | 163 my ($node) = $this->selectNodes('controls'); |
164 return $node; | 164 return $node; |
165 } | 165 } |
166 | 166 |
167 sub _validatePresenter { | 167 sub _validatePresenter { |
168 my ($this,$value) = @_; | 168 my ($this,$value) = @_; |
169 | 169 |
170 die new IMPL::InvalidArgumentException("A view object is required") unless blessed($value) and $value->isa('Template::View'); | 170 die new IMPL::InvalidArgumentException("A view object is required") unless blessed($value) and $value->isa('Template::View'); |
171 } | 171 } |
172 | 172 |
173 sub LoadFile { | 173 sub LoadFile { |
174 my ($this,$src,$encoding,$includes,$vars) = @_; | 174 my ($this,$src,$encoding,$includes,$vars) = @_; |
175 | 175 |
181 | 181 |
182 $this->_context(undef); | 182 $this->_context(undef); |
183 $this->_provider(undef); | 183 $this->_provider(undef); |
184 | 184 |
185 if (not ref $src) { | 185 if (not ref $src) { |
186 my ($vol,$dir,$fileName) = File::Spec->splitpath($src); | 186 my ($vol,$dir,$fileName) = File::Spec->splitpath($src); |
187 unshift @$includes, File::Spec->catpath($vol,$dir,''); | 187 unshift @$includes, File::Spec->catpath($vol,$dir,''); |
188 $src = $fileName; | 188 $src = $fileName; |
189 } | 189 } |
190 | 190 |
191 $this->provider( | 191 $this->provider( |
192 ENCODING => $encoding, | 192 ENCODING => $encoding, |
193 INTERPOLATE => 1, | 193 INTERPOLATE => 1, |
198 COMPILE_DIR => $this->cache, | 198 COMPILE_DIR => $this->cache, |
199 INCLUDE_PATH => $includes | 199 INCLUDE_PATH => $includes |
200 ); | 200 ); |
201 | 201 |
202 if ($vars) { | 202 if ($vars) { |
203 while ( my ($var,$val) = each %$vars ) { | 203 while ( my ($var,$val) = each %$vars ) { |
204 $this->AddVar($var,$val); | 204 $this->AddVar($var,$val); |
205 } | 205 } |
206 } | 206 } |
207 | 207 |
208 $this->context->process($_) foreach $this->preprocess; | 208 $this->context->process($_) foreach $this->preprocess; |
209 | 209 |
210 my $template = $this->context->template($src); | 210 my $template = $this->context->template($src); |
211 $this->title($template->title); | 211 $this->title($template->title); |
212 if ( $template->template ) { | 212 if ( $template->template ) { |
213 $this->context->process($template); | 213 $this->context->process($template); |
214 $this->template($template->template); | 214 $this->template($template->template); |
215 } else { | 215 } else { |
216 $this->template($template); | 216 $this->template($template); |
217 } | 217 } |
218 | 218 |
219 } | 219 } |
220 | 220 |
221 sub AddVar { | 221 sub AddVar { |
222 my ($this,$name,$value) = @_; | 222 my ($this,$name,$value) = @_; |
223 | 223 |
224 $this->context->stash->set($name,$value); | 224 $this->context->stash->set($name,$value); |
225 } | 225 } |
226 | 226 |
227 sub Render { | 227 sub Render { |
228 my ($this) = @_; | 228 my ($this) = @_; |
229 | 229 |
230 return $this->context->process($this->template); | 230 return $this->context->process($this->template); |
231 } | 231 } |
232 | 232 |
233 # Формирует представление для произвольных объектов | 233 # Формирует представление для произвольных объектов |
234 sub _process { | 234 sub _process { |
235 my ($this,@items) = @_; | 235 my ($this,@items) = @_; |
236 | 236 |
237 my @result; | 237 my @result; |
238 | 238 |
239 foreach my $item (@items) { | 239 foreach my $item (@items) { |
240 if (blessed($item) and $item->isa('IMPL::Web::TT::Control')) { | 240 if (blessed($item) and $item->isa('IMPL::Web::TT::Control')) { |
241 push @result, $item->Render(); | 241 push @result, $item->Render(); |
242 } elsif(blessed($item)) { | 242 } elsif(blessed($item)) { |
243 if ($this->presenter) { | 243 if ($this->presenter) { |
244 push @result, $this->presenter->print($item); | 244 push @result, $this->presenter->print($item); |
245 } else { | 245 } else { |
246 push @result, $this->toString; | 246 push @result, $this->toString; |
247 } | 247 } |
248 } else { | 248 } else { |
249 push @result, $item; | 249 push @result, $item; |
250 } | 250 } |
251 } | 251 } |
252 | 252 |
253 return join '',@result; | 253 return join '',@result; |
254 } | 254 } |
255 | 255 |
256 our $AUTOLOAD; | 256 our $AUTOLOAD; |
257 sub AUTOLOAD { | 257 sub AUTOLOAD { |
258 my $this = shift; | 258 my $this = shift; |
259 my ($method) = ($AUTOLOAD =~ /(\w+)$/); | 259 my ($method) = ($AUTOLOAD =~ /(\w+)$/); |
260 | 260 |
261 if($method =~ /^create(\w+)/) { | 261 if($method =~ /^create(\w+)/) { |
262 my ($name,$args) = @_; | 262 my ($name,$args) = @_; |
263 return $this->CreateControl($name,$1,$args); | 263 return $this->CreateControl($name,$1,$args); |
264 } | 264 } |
265 | 265 |
266 my @result = $this->selectNodes($method); | 266 my @result = $this->selectNodes($method); |
267 | 267 |
268 return $result[0] if @result; | 268 return $result[0] if @result; |
269 carp "Looks like you have a mistake, the document doesn't have a such property or child: $method"; | 269 carp "Looks like you have a mistake, the document doesn't have a such property or child: $method"; |
270 return; | 270 return; |
271 } | 271 } |
272 | 272 |
273 sub Dispose { | 273 sub Dispose { |
274 my ($this) = @_; | 274 my ($this) = @_; |
275 | 275 |
358 [% CALL document.registerClass( 'Form' )%] | 358 [% CALL document.registerClass( 'Form' )%] |
359 | 359 |
360 [% table = document.сreateTable('env') %] | 360 [% table = document.сreateTable('env') %] |
361 | 361 |
362 [% FOEACH item in document.result %] | 362 [% FOEACH item in document.result %] |
363 [% table.rows.Add( item.get('name','value') ) %] | 363 [% table.rows.Add( item.get('name','value') ) %] |
364 [% END %] | 364 [% END %] |
365 | 365 |
366 [% form = document.createForm('login') %] | 366 [% form = document.createForm('login') %] |
367 [% form.template = 'LOGIN_FORM'%] | 367 [% form.template = 'LOGIN_FORM'%] |
368 | 368 |
369 [% FOREACH item IN document.childNodes %] | 369 [% FOREACH item IN document.childNodes %] |
370 [%render(item)%] | 370 [%render(item)%] |
371 [% END %] | 371 [% END %] |
372 | 372 |
373 [% BLOCK LOGIN_FORM %] | 373 [% BLOCK LOGIN_FORM %] |
374 <form method="POST" action='/login.pl'> | 374 <form method="POST" action='/login.pl'> |
375 user: [% render(this.item('name')) %] password: [% render(this.item('password')) %] <input type="submit"/> | 375 user: [% render(this.item('name')) %] password: [% render(this.item('password')) %] <input type="submit"/> |
376 </form> | 376 </form> |
377 [% END %] | 377 [% END %] |
378 | 378 |
379 =end code html | 379 =end code html |
380 | 380 |