Mercurial > pub > Impl
diff Lib/DOM/Providers/Page.pm @ 0:03e58a454b20
Создан репозитарий
author | Sergey |
---|---|
date | Tue, 14 Jul 2009 12:54:37 +0400 |
parents | |
children | 16ada169ca75 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/DOM/Providers/Page.pm Tue Jul 14 12:54:37 2009 +0400 @@ -0,0 +1,258 @@ +use strict; + +package DOM::Providers::Page; +use Template::Provider; +#use PerfCounter; +use DOM::Page; +use Common; +use Encode; + +our @ISA= qw(Object Exporter); + +our $UseIndexPage; #optional +our $PagesPath; #required +our $IncludesPath; #optional +our $CacheSize; #optional +our $CachePath; #optional +our $Encoding; #optional +our $AllowExtPath; #optional +our $PageResolver; #optional + + +BEGIN { + DeclareProperty('PageResolver'); + DeclareProperty('PagesBase'); + DeclareProperty('IndexPage'); + DeclareProperty('TemplatesProvider'); + DeclareProperty('PageEnc'); +} + +sub as_list { + return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ ); +} + +sub GetProviderInfo { + return { + Name => 'Page', + Host => 'DOM::Site', + Methods => { + LoadPage => \&SiteLoadPage, + ReleasePage => \&SiteReleasePage, + } + } +} + +sub CTOR { + my ($this,%args) = @_; + + $this->{$PageResolver} = $args{'PageResolver'}; + $this->{$PagesBase} = $args{'TemplatesPath'}; + $this->{$IndexPage} = $args{'IndexPage'} || 'index.html'; + $this->{$PageEnc} = $args{'Encoding'}; + $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); +} + +sub ResolveId { + my ($this,$pageId) = @_; + + if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'ResolveId')) { + return $this->{$PageResolver}->ResolveId($pageId); + } else { + return grep { $_ } split /\//,$pageId; + } +} + +sub MakePageId { + my ($this,$raPath) = @_; + + if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'MakeId')) { + return $this->{$PageResolver}->MakeId($raPath); + } else { + return join '/',@$raPath; + } +} + +sub PageIdToURL { + my ($this,$pageId) = @_; + + if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'PageIdToURL')) { + return $this->{$PageResolver}->PageIdToURL($pageId); + } else { + return '/'.$pageId; + } +} + +sub SiteLoadPage { + my ($this,$site,$pageId) = @_; + + return $site->RegisterObject('Page', $this->LoadPage($pageId, Site => $site)); +} +sub LoadPage { + my ($this,$pageId,%args) = @_; + + #StartTimeCounter('LoadPageTime'); + + my @pathPage = $this->ResolveId($pageId); + + my $pageNode = $this->LoadNode(\@pathPage); + + pop @pathPage; + + my @pathNode; + + # ïîñêîëüêó ïóòü óêàçàí îòíîñèòåëüíî êîðíåâîãî êîíòåéíåðà, òî íóæíî åãî äîáàâèòü â íà÷àëî + my @NavChain = map { push @pathNode, $_; $this->LoadNode(\@pathNode); } ('.',@pathPage); + + if ($pageNode->{'Type'} eq 'Section') { + push @NavChain,$pageNode; + $pageNode = $this->LoadNode($pageNode->{'pathIndexPage'}); + } + + # ôîðìèðóåì ìåíþ ñòðàíèöû + my %PageMenus; + foreach my $MenuSet (map { $_->{'Menus'}} @NavChain, $pageNode->{'Menus'} ) { + foreach my $menuName (keys %$MenuSet) { + if ($PageMenus{$menuName}) { + $PageMenus{$menuName}->Merge($MenuSet->{$menuName}); + } else { + $PageMenus{$menuName} = $MenuSet->{$menuName}; + } + } + } + + # ôîðìèðóåì êëþ÷åâûå ñëîâà è ñâîéñòâà + my @keywords; + my %Props; + foreach my $PropSet ( (map { $_->{'Props'}} @NavChain), $pageNode->{'Props'} ) { + if(ref $PropSet->{'Keywords'} eq 'ARRAY') { + push @keywords, @{$PropSet->{'Keywords'}}; + } elsif (not ref $PropSet->{'Keywords'} and exists $PropSet->{'Keywords'}) { + push @keywords, $PropSet->{'Keywords'}; + } + + while (my ($prop,$value) = each %$PropSet) { + next if $prop eq 'Keywords'; + $Props{$prop} = $value; + } + } + + #StopTimeCounter('LoadPageTime'); + # çàãðóæàåì øàáëîí + + #StartTimeCounter('FetchTime'); + my ($Template,$error) = $this->{$TemplatesProvider}->fetch($pageNode->{'TemplateFileName'}); + die new Exception("Failed to load page $pageId",$Template ? $Template->as_string : 'Failed to parse') if $error; + #StopTimeCounter('FetchTime'); + + my $page = new DOM::Page(TemplatesProvider => $this->{$TemplatesProvider}, Properties => \%Props, Menus => \%PageMenus, NavChain => \@NavChain, Template => $Template, %args); + $page->Properties->{url} = $this->PageIdToURL($pageId); + return $page; +} + +sub LoadNode { + my ($this,$refNodePath) = @_; + + my $fileNameNode = $this->{$PagesBase} . join('/',grep $_, @$refNodePath); + my $fileNameMenus; + my $fileNameProps; + + my %Node; + + if ( -d $fileNameNode ) { + $Node{'Type'} = 'Section'; + $fileNameMenus = $fileNameNode . '/.menu.pl'; + $fileNameProps = $fileNameNode . '/.prop.pl'; + } elsif ( -e $fileNameNode ) { + $Node{'Type'} = 'Page'; + $Node{'TemplateFileName'} = join('/',@$refNodePath);; + $fileNameMenus = $fileNameNode . '.menu.pl'; + $fileNameProps = $fileNameNode . '.prop.pl'; + } else { + die new Exception("Page not found: $fileNameNode"); + } + + if ( -f $fileNameProps ) { + local ${^ENCODING}; + my $dummy = ''; + open my $hnull,'>>',\$dummy; + local (*STDOUT,*STDIN) = ($hnull,$hnull); + $Node{'Props'} = do $fileNameProps or warn "can't parse $fileNameProps: $@"; + } + + if ( -f $fileNameMenus ) { + local ${^ENCODING}; + my $dummy = ''; + open my $hnull,'>>',\$dummy; + local (*STDOUT,*STDIN) = ($hnull,$hnull); + $Node{'Menus'} = do $fileNameMenus or warn "can't parse $fileNameMenus: $@"; + } + + if ($Node{'Menus'}) { + my %Menus; + foreach my $menu (keys %{$Node{'Menus'}}) { + $Menus{$menu} = new DOM::PageMenu( DATA => $Node{'Menus'}->{$menu} ); + } + $Node{'Menus'} = \%Menus; + } + + $Node{'pathIndexPage'} = [@$refNodePath, $Node{'Props'}->{'IndexPage'} || $this->{$IndexPage}] if $Node{'Type'} eq 'Section'; + + return \%Node; +} + +sub SiteReleasePage { + my ($this,$site) = @_; + + my $page = $site->Objects()->{'Page'}; + $page->Release() if $page; + + return 1; +} + +sub construct { + my $self = shift; + + return new DOM::Providers::Page(TemplatesPath => $PagesPath, IncludePath => $IncludesPath, IndexPage => $UseIndexPage, CachePath => $CachePath, CacheSize => $CacheSize, Encoding => $Encoding); +} + +sub DecodeData { + my ($Encoding, $data) = @_; + + if (ref $data) { + if (ref $data eq 'SCALAR') { + my $decoded = Encode::decode($Encoding,$$data,Encode::LEAVE_SRC); + return \$decoded; + } elsif (UNIVERSAL::isa($data, 'HASH')) { + return {map {Encode::decode($Encoding,$_,Encode::LEAVE_SRC),DecodeData($Encoding,$data->{$_})} keys %$data }; + } elsif (UNIVERSAL::isa($data, 'ARRAY')) { + return [map {DecodeData($Encoding,$_)} @$data]; + } elsif (ref $data eq 'REF') { + my $decoded = DecodeData($Encoding,$$data); + return \$decoded; + } else { + die new Exception('Cant decode data type', ref $data); + } + } else { + return Encode::decode($Encoding,$data,Encode::LEAVE_SRC); + } +} + +1; + +=pod +Õðàíèëèùå øàáëîíîâ íà îñíîâå ôàéëîâîé ñèñòåìû. + +Õðàíèëèùå ñîñòîèò èç ðàçäåëîâ, êàæäûé ðàçäåë èìååò íàáîð ñâîéñòâ è ìåíþ +Ñïåöèàëüíû ñâîéñòâà ðàçäåëîâ + Keywords Êëþ÷åâûå ñëîâà + Name Íàçâàíèå + IndexPage ñòðàíèöà ïî óìîë÷àíèþ + + ðàçäåëàõ íàõîäÿòñÿ ñòðàíèöû, êàæäàÿ ñòðàíèöà èìååò íàáîð ñâîéñòâ è ìåíþ + +Ïðè çàãðóçêå ñòðàíèöû ïîëíîñòüþ çàãðóæàþòñÿ âñå ðîäèòåëüñêèå êîíòåéíåðû, +Ïðè ýòîì îäíîèìåííûå ìåíþ ñëèâàþòñÿ, +Ñâîéñòâà keywords îáúåúåäèíÿþòñÿ, +Åñëè èìÿ ñòðàíèöû íå çàäàíî, òî èñïîëüçóåòñÿ èìÿ ðàçäåëà + +=cut \ No newline at end of file