Mercurial > pub > Impl
comparison Lib/IMPL/Web/Handler/TTView.pm @ 205:891c04080658
IMPL::Web::View fixed template selection, release candidate
author | sergey |
---|---|
date | Thu, 03 May 2012 01:00:02 +0400 |
parents | d63f9a92d6d4 |
children | c8fe3f84feba |
comparison
equal
deleted
inserted
replaced
204:d63f9a92d6d4 | 205:891c04080658 |
---|---|
2 use strict; | 2 use strict; |
3 | 3 |
4 use List::Util qw(first); | 4 use List::Util qw(first); |
5 use IMPL::lang qw(:declare :constants); | 5 use IMPL::lang qw(:declare :constants); |
6 use IMPL::declare { | 6 use IMPL::declare { |
7 require => { | |
8 Factory => 'IMPL::Object::Factory' | |
9 }, | |
7 base => { | 10 base => { |
8 'IMPL::Object' => undef, | 11 'IMPL::Object' => undef, |
9 'IMPL::Object::Autofill' => '@_', | 12 'IMPL::Object::Autofill' => '@_', |
10 'IMPL::Object::Serializable' => undef | 13 'IMPL::Object::Serializable' => undef |
11 } | 14 } |
30 sub Invoke { | 33 sub Invoke { |
31 my ($this,$action,$next) = @_; | 34 my ($this,$action,$next) = @_; |
32 | 35 |
33 my $result = $next ? $next->($action) : undef; | 36 my $result = $next ? $next->($action) : undef; |
34 | 37 |
38 my $vars = { | |
39 data => $result, | |
40 action => $action, | |
41 app => $action->application, | |
42 LoadFactory => sub { | |
43 my $class = shift; | |
44 | |
45 my $module = $class; | |
46 | |
47 $module =~ s/::/\//g; | |
48 $module .= ".pm"; | |
49 | |
50 require $module; | |
51 return Factory->new($class); | |
52 } | |
53 }; | |
54 | |
35 my $doc = $this->loader->document( | 55 my $doc = $this->loader->document( |
36 $this->SelectView($action,ref $result), | 56 $this->SelectView($action,ref $result), |
37 { | 57 $vars |
38 data => $result, | |
39 action => $action, | |
40 app => $action->application | |
41 } | |
42 ); | 58 ); |
43 | 59 |
44 my $hout = $action->response->streamBody; | 60 my $hout = $action->response->streamBody; |
45 | 61 |
46 print $hout $doc->Render(); | 62 print $hout $doc->Render($vars); |
47 } | 63 } |
48 | 64 |
49 sub SelectView { | 65 sub SelectView { |
50 my ($this,$action,$class) = @_; | 66 my ($this,$action,$class) = @_; |
51 | 67 |
52 my @path = split /\//, $action->query->path_info(), -1; | 68 my @path = split /\//, $action->query->path_info(), -1; |
53 | 69 |
70 shift @path; # remove always empty leading segment | |
71 | |
54 my $last = pop @path; | 72 my $last = pop @path; |
55 $last =~ s/\.\w+$//; | 73 $last =~ s/\.\w+$//; |
56 $last = $this->indexResource; | 74 $last ||= $this->indexResource; |
57 push @path,$last; | 75 push @path,$last; |
58 | 76 |
59 $this->BuildCache unless $this->_selectorsCache; | 77 $this->BuildCache unless $this->_selectorsCache; |
60 my $cache = $this->_selectorsCache; | 78 my $cache = $this->_selectorsCache; |
61 | 79 |
80 @path = reverse @path; | |
81 | |
62 foreach my $subclass ( $class ? (_GetHierarchy($class), '-default') : '-plain') { | 82 foreach my $subclass ( $class ? (_GetHierarchy($class), '-default') : '-plain') { |
63 my @results; | 83 my @results; |
64 push @results, { data => $this->_classTemplates->{$subclass} } if $this->_classTemplates->{$subclass}; | 84 push @results, { result => $this->_classTemplates->{$subclass}, level => 0 } if $this->_classTemplates->{$subclass}; |
65 my $alternatives = [ { selectors => $cache->{$subclass}, immediate => 1 } ]; | 85 if ($cache->{$subclass}) { |
66 $alternatives = $this->MatchAlternatives($_,$alternatives,\@results) foreach @path; | 86 my $alternatives = [ { selector => $cache->{$subclass}, immediate => 1 } ]; |
87 $alternatives = $this->MatchAlternatives($_,$alternatives,\@results) foreach @path; | |
88 } | |
67 | 89 |
68 if (@results) { | 90 if (@results) { |
69 return shift sort { $b->{level} <=> $a->{level} } @results; | 91 @results = sort { $b->{level} <=> $a->{level} } @results; |
92 return (shift @results)->{result}; | |
70 } | 93 } |
71 } | 94 } |
72 | 95 |
73 return $this->defaultDocument; | 96 return $this->defaultDocument; |
74 } | 97 } |
75 | 98 |
76 sub _GetHierarchy { | 99 sub _GetHierarchy { |
77 my ($class) = @_; | 100 my ($class) = @_; |
78 return unless $class; | 101 return unless $class; |
98 my @path = split(/\s+/,$path); | 121 my @path = split(/\s+/,$path); |
99 | 122 |
100 my $class; | 123 my $class; |
101 | 124 |
102 # if this selector has a class part | 125 # if this selector has a class part |
103 if ($path[$#path-1] =~ m/^\@(.*)/) { | 126 if ($path[$#path] =~ m/^\@(.*)/) { |
104 $class = $1; | 127 $class = $1; |
105 shift @path; | 128 pop @path; |
106 } else { | 129 } else { |
107 $class = '-default'; | 130 $class = '-default'; |
108 } | 131 } |
109 | 132 |
110 #if this selector has a path | 133 #if this selector has a path |
131 } | 154 } |
132 | 155 |
133 sub MatchAlternatives { | 156 sub MatchAlternatives { |
134 my ($this,$segment,$alternatives,$results) = @_; | 157 my ($this,$segment,$alternatives,$results) = @_; |
135 | 158 |
136 warn "alternatives: ", scalar @$alternatives,", segment: $segment"; | |
137 | |
138 my @next; | 159 my @next; |
139 | 160 |
140 foreach my $alt (@$alternatives) { | 161 foreach my $alt (@$alternatives) { |
141 while (my ($selector,$match) = each %{$alt->{selector}} ) { | 162 while (my ($selector,$match) = each %{$alt->{selector}} ) { |
142 warn $selector; | 163 |
143 | |
144 warn "\timmediate" if $alt->{immediate}; | |
145 warn "\thas children" if $match->{next}; | |
146 | 164 |
147 my $context = { | 165 my $context = { |
148 vars => \%{ $alt->{vars} || {} }, | 166 vars => \%{ $alt->{vars} || {} }, |
149 selector => $match->{next} | 167 selector => $match->{next} |
150 }; | 168 }; |
153 $context->{immediate} = 1; | 171 $context->{immediate} = 1; |
154 } | 172 } |
155 | 173 |
156 if (my ($name,$rx) = ($selector =~ m/^\{(?:(\w+)\:)?(.*)\}$/) ) { | 174 if (my ($name,$rx) = ($selector =~ m/^\{(?:(\w+)\:)?(.*)\}$/) ) { |
157 #this is a regexp | 175 #this is a regexp |
158 warn "\tregexp: [$name] $rx"; | |
159 | 176 |
160 if ( my @captures = ($segment =~ m/($rx)/) ) { | 177 if ( my @captures = ($segment =~ m/($rx)/) ) { |
161 $context->{success} = 1; | 178 $context->{success} = 1; |
162 | 179 |
163 warn "\t",join(',',@captures); | |
164 | |
165 if ($name) { | 180 if ($name) { |
166 $context->{vars}->{$name} = \@captures; | 181 $context->{vars}->{$name} = \@captures; |
167 } | 182 } |
168 } | 183 } |
169 } else { | 184 } else { |
173 } | 188 } |
174 } | 189 } |
175 | 190 |
176 # test if there were a match | 191 # test if there were a match |
177 if (delete $context->{success}) { | 192 if (delete $context->{success}) { |
178 warn "\tmatch"; | |
179 if (my $data = $match->{data}) { | 193 if (my $data = $match->{data}) { |
180 # interpolate data | 194 # interpolate data |
181 $data =~ s/{(\w+)(?:\:(\d+))?}/ | 195 $data =~ s/{(\w+)(?:\:(\d+))?}/ |
182 my ($name,$index) = ($1,$2 || 0); | 196 my ($name,$index) = ($1,$2 || 0); |
183 | 197 |
188 } | 202 } |
189 /gex; | 203 /gex; |
190 | 204 |
191 push @$results, { level => $match->{level}, result => $data }; | 205 push @$results, { level => $match->{level}, result => $data }; |
192 } | 206 } |
193 warn "\tnext" if $context->{selector}; | |
194 push @next, $context if $context->{selector}; | 207 push @next, $context if $context->{selector}; |
195 } else { | 208 } else { |
196 #repeat current alternative if it's not required to be immediate | 209 #repeat current alternative if it's not required to be immediate |
197 push @next, { | 210 push @next, { |
198 selector => { $selector, $match }, | 211 selector => { $selector, $match }, |
200 } unless $alt->{immediate}; | 213 } unless $alt->{immediate}; |
201 } | 214 } |
202 } | 215 } |
203 } | 216 } |
204 | 217 |
205 warn "end, next trip: ",scalar @next, " alternatives"; | |
206 | |
207 return \@next; | 218 return \@next; |
208 } | 219 } |
209 | 220 |
210 1; | 221 1; |
211 | 222 |