Mercurial > pub > Impl
comparison Lib/DOM/Providers/Page.pm @ 0:03e58a454b20
Создан репозитарий
author | Sergey |
---|---|
date | Tue, 14 Jul 2009 12:54:37 +0400 |
parents | |
children | 16ada169ca75 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:03e58a454b20 |
---|---|
1 use strict; | |
2 | |
3 package DOM::Providers::Page; | |
4 use Template::Provider; | |
5 #use PerfCounter; | |
6 use DOM::Page; | |
7 use Common; | |
8 use Encode; | |
9 | |
10 our @ISA= qw(Object Exporter); | |
11 | |
12 our $UseIndexPage; #optional | |
13 our $PagesPath; #required | |
14 our $IncludesPath; #optional | |
15 our $CacheSize; #optional | |
16 our $CachePath; #optional | |
17 our $Encoding; #optional | |
18 our $AllowExtPath; #optional | |
19 our $PageResolver; #optional | |
20 | |
21 | |
22 BEGIN { | |
23 DeclareProperty('PageResolver'); | |
24 DeclareProperty('PagesBase'); | |
25 DeclareProperty('IndexPage'); | |
26 DeclareProperty('TemplatesProvider'); | |
27 DeclareProperty('PageEnc'); | |
28 } | |
29 | |
30 sub as_list { | |
31 return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ ); | |
32 } | |
33 | |
34 sub GetProviderInfo { | |
35 return { | |
36 Name => 'Page', | |
37 Host => 'DOM::Site', | |
38 Methods => { | |
39 LoadPage => \&SiteLoadPage, | |
40 ReleasePage => \&SiteReleasePage, | |
41 } | |
42 } | |
43 } | |
44 | |
45 sub CTOR { | |
46 my ($this,%args) = @_; | |
47 | |
48 $this->{$PageResolver} = $args{'PageResolver'}; | |
49 $this->{$PagesBase} = $args{'TemplatesPath'}; | |
50 $this->{$IndexPage} = $args{'IndexPage'} || 'index.html'; | |
51 $this->{$PageEnc} = $args{'Encoding'}; | |
52 $this->{$TemplatesProvider} = new Template::Provider( INCLUDE_PATH => [$this->{$PagesBase}, as_list($args{'IncludePath'}) ], COMPILE_DIR => $args{'CachePath'}, CACHE_SIZE => $args{'CacheSize'}, ENCODING => $args{'Encoding'}, ABSOLUTE => $AllowExtPath, RELATIVE => $AllowExtPath, INTERPOLATE => 1, PRE_CHOMP => 3); | |
53 } | |
54 | |
55 sub ResolveId { | |
56 my ($this,$pageId) = @_; | |
57 | |
58 if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'ResolveId')) { | |
59 return $this->{$PageResolver}->ResolveId($pageId); | |
60 } else { | |
61 return grep { $_ } split /\//,$pageId; | |
62 } | |
63 } | |
64 | |
65 sub MakePageId { | |
66 my ($this,$raPath) = @_; | |
67 | |
68 if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'MakeId')) { | |
69 return $this->{$PageResolver}->MakeId($raPath); | |
70 } else { | |
71 return join '/',@$raPath; | |
72 } | |
73 } | |
74 | |
75 sub PageIdToURL { | |
76 my ($this,$pageId) = @_; | |
77 | |
78 if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'PageIdToURL')) { | |
79 return $this->{$PageResolver}->PageIdToURL($pageId); | |
80 } else { | |
81 return '/'.$pageId; | |
82 } | |
83 } | |
84 | |
85 sub SiteLoadPage { | |
86 my ($this,$site,$pageId) = @_; | |
87 | |
88 return $site->RegisterObject('Page', $this->LoadPage($pageId, Site => $site)); | |
89 } | |
90 sub LoadPage { | |
91 my ($this,$pageId,%args) = @_; | |
92 | |
93 #StartTimeCounter('LoadPageTime'); | |
94 | |
95 my @pathPage = $this->ResolveId($pageId); | |
96 | |
97 my $pageNode = $this->LoadNode(\@pathPage); | |
98 | |
99 pop @pathPage; | |
100 | |
101 my @pathNode; | |
102 | |
103 # ïîñêîëüêó ïóòü óêàçàí îòíîñèòåëüíî êîðíåâîãî êîíòåéíåðà, òî íóæíî åãî äîáàâèòü â íà÷àëî | |
104 my @NavChain = map { push @pathNode, $_; $this->LoadNode(\@pathNode); } ('.',@pathPage); | |
105 | |
106 if ($pageNode->{'Type'} eq 'Section') { | |
107 push @NavChain,$pageNode; | |
108 $pageNode = $this->LoadNode($pageNode->{'pathIndexPage'}); | |
109 } | |
110 | |
111 # ôîðìèðóåì ìåíþ ñòðàíèöû | |
112 my %PageMenus; | |
113 foreach my $MenuSet (map { $_->{'Menus'}} @NavChain, $pageNode->{'Menus'} ) { | |
114 foreach my $menuName (keys %$MenuSet) { | |
115 if ($PageMenus{$menuName}) { | |
116 $PageMenus{$menuName}->Merge($MenuSet->{$menuName}); | |
117 } else { | |
118 $PageMenus{$menuName} = $MenuSet->{$menuName}; | |
119 } | |
120 } | |
121 } | |
122 | |
123 # ôîðìèðóåì êëþ÷åâûå ñëîâà è ñâîéñòâà | |
124 my @keywords; | |
125 my %Props; | |
126 foreach my $PropSet ( (map { $_->{'Props'}} @NavChain), $pageNode->{'Props'} ) { | |
127 if(ref $PropSet->{'Keywords'} eq 'ARRAY') { | |
128 push @keywords, @{$PropSet->{'Keywords'}}; | |
129 } elsif (not ref $PropSet->{'Keywords'} and exists $PropSet->{'Keywords'}) { | |
130 push @keywords, $PropSet->{'Keywords'}; | |
131 } | |
132 | |
133 while (my ($prop,$value) = each %$PropSet) { | |
134 next if $prop eq 'Keywords'; | |
135 $Props{$prop} = $value; | |
136 } | |
137 } | |
138 | |
139 #StopTimeCounter('LoadPageTime'); | |
140 # çàãðóæàåì øàáëîí | |
141 | |
142 #StartTimeCounter('FetchTime'); | |
143 my ($Template,$error) = $this->{$TemplatesProvider}->fetch($pageNode->{'TemplateFileName'}); | |
144 die new Exception("Failed to load page $pageId",$Template ? $Template->as_string : 'Failed to parse') if $error; | |
145 #StopTimeCounter('FetchTime'); | |
146 | |
147 my $page = new DOM::Page(TemplatesProvider => $this->{$TemplatesProvider}, Properties => \%Props, Menus => \%PageMenus, NavChain => \@NavChain, Template => $Template, %args); | |
148 $page->Properties->{url} = $this->PageIdToURL($pageId); | |
149 return $page; | |
150 } | |
151 | |
152 sub LoadNode { | |
153 my ($this,$refNodePath) = @_; | |
154 | |
155 my $fileNameNode = $this->{$PagesBase} . join('/',grep $_, @$refNodePath); | |
156 my $fileNameMenus; | |
157 my $fileNameProps; | |
158 | |
159 my %Node; | |
160 | |
161 if ( -d $fileNameNode ) { | |
162 $Node{'Type'} = 'Section'; | |
163 $fileNameMenus = $fileNameNode . '/.menu.pl'; | |
164 $fileNameProps = $fileNameNode . '/.prop.pl'; | |
165 } elsif ( -e $fileNameNode ) { | |
166 $Node{'Type'} = 'Page'; | |
167 $Node{'TemplateFileName'} = join('/',@$refNodePath);; | |
168 $fileNameMenus = $fileNameNode . '.menu.pl'; | |
169 $fileNameProps = $fileNameNode . '.prop.pl'; | |
170 } else { | |
171 die new Exception("Page not found: $fileNameNode"); | |
172 } | |
173 | |
174 if ( -f $fileNameProps ) { | |
175 local ${^ENCODING}; | |
176 my $dummy = ''; | |
177 open my $hnull,'>>',\$dummy; | |
178 local (*STDOUT,*STDIN) = ($hnull,$hnull); | |
179 $Node{'Props'} = do $fileNameProps or warn "can't parse $fileNameProps: $@"; | |
180 } | |
181 | |
182 if ( -f $fileNameMenus ) { | |
183 local ${^ENCODING}; | |
184 my $dummy = ''; | |
185 open my $hnull,'>>',\$dummy; | |
186 local (*STDOUT,*STDIN) = ($hnull,$hnull); | |
187 $Node{'Menus'} = do $fileNameMenus or warn "can't parse $fileNameMenus: $@"; | |
188 } | |
189 | |
190 if ($Node{'Menus'}) { | |
191 my %Menus; | |
192 foreach my $menu (keys %{$Node{'Menus'}}) { | |
193 $Menus{$menu} = new DOM::PageMenu( DATA => $Node{'Menus'}->{$menu} ); | |
194 } | |
195 $Node{'Menus'} = \%Menus; | |
196 } | |
197 | |
198 $Node{'pathIndexPage'} = [@$refNodePath, $Node{'Props'}->{'IndexPage'} || $this->{$IndexPage}] if $Node{'Type'} eq 'Section'; | |
199 | |
200 return \%Node; | |
201 } | |
202 | |
203 sub SiteReleasePage { | |
204 my ($this,$site) = @_; | |
205 | |
206 my $page = $site->Objects()->{'Page'}; | |
207 $page->Release() if $page; | |
208 | |
209 return 1; | |
210 } | |
211 | |
212 sub construct { | |
213 my $self = shift; | |
214 | |
215 return new DOM::Providers::Page(TemplatesPath => $PagesPath, IncludePath => $IncludesPath, IndexPage => $UseIndexPage, CachePath => $CachePath, CacheSize => $CacheSize, Encoding => $Encoding); | |
216 } | |
217 | |
218 sub DecodeData { | |
219 my ($Encoding, $data) = @_; | |
220 | |
221 if (ref $data) { | |
222 if (ref $data eq 'SCALAR') { | |
223 my $decoded = Encode::decode($Encoding,$$data,Encode::LEAVE_SRC); | |
224 return \$decoded; | |
225 } elsif (UNIVERSAL::isa($data, 'HASH')) { | |
226 return {map {Encode::decode($Encoding,$_,Encode::LEAVE_SRC),DecodeData($Encoding,$data->{$_})} keys %$data }; | |
227 } elsif (UNIVERSAL::isa($data, 'ARRAY')) { | |
228 return [map {DecodeData($Encoding,$_)} @$data]; | |
229 } elsif (ref $data eq 'REF') { | |
230 my $decoded = DecodeData($Encoding,$$data); | |
231 return \$decoded; | |
232 } else { | |
233 die new Exception('Cant decode data type', ref $data); | |
234 } | |
235 } else { | |
236 return Encode::decode($Encoding,$data,Encode::LEAVE_SRC); | |
237 } | |
238 } | |
239 | |
240 1; | |
241 | |
242 =pod | |
243 Õðàíèëèùå øàáëîíîâ íà îñíîâå ôàéëîâîé ñèñòåìû. | |
244 | |
245 Õðàíèëèùå ñîñòîèò èç ðàçäåëîâ, êàæäûé ðàçäåë èìååò íàáîð ñâîéñòâ è ìåíþ | |
246 Ñïåöèàëüíû ñâîéñòâà ðàçäåëîâ | |
247 Keywords Êëþ÷åâûå ñëîâà | |
248 Name Íàçâàíèå | |
249 IndexPage ñòðàíèöà ïî óìîë÷àíèþ | |
250 | |
251 Â ðàçäåëàõ íàõîäÿòñÿ ñòðàíèöû, êàæäàÿ ñòðàíèöà èìååò íàáîð ñâîéñòâ è ìåíþ | |
252 | |
253 Ïðè çàãðóçêå ñòðàíèöû ïîëíîñòüþ çàãðóæàþòñÿ âñå ðîäèòåëüñêèå êîíòåéíåðû, | |
254 Ïðè ýòîì îäíîèìåííûå ìåíþ ñëèâàþòñÿ, | |
255 Ñâîéñòâà keywords îáúåúåäèíÿþòñÿ, | |
256 Åñëè èìÿ ñòðàíèöû íå çàäàíî, òî èñïîëüçóåòñÿ èìÿ ðàçäåëà | |
257 | |
258 =cut |