package WebGUI::Asset::Wobject::Navigation; #------------------------------------------------------------------- # WebGUI is Copyright 2001-2009 Plain Black Corporation. #------------------------------------------------------------------- # Please read the legal notices (docs/legal.txt) and the license # (docs/license.txt) that came with this distribution before using # this software. #------------------------------------------------------------------- # http://www.plainblack.com info@plainblack.com #------------------------------------------------------------------- use strict; use Tie::IxHash; use WebGUI::Asset::Wobject; use WebGUI::Form; use WebGUI::International; use WebGUI::SQL; use WebGUI::TabForm; use WebGUI::Utility; our @ISA = qw(WebGUI::Asset::Wobject); #------------------------------------------------------------------- sub definition { my $class = shift; my $session = shift; my $definition = shift; my $i18n = WebGUI::International->new($session,"Asset_Navigation"); push(@{$definition}, { assetName=>$i18n->get("assetName"), icon=>'navigation.gif', tableName=>'Navigation', className=>'WebGUI::Asset::Wobject::Navigation', properties=>{ templateId =>{ fieldType=>"template", defaultValue=>'PBtmpl0000000000000048' }, mimeType =>{ fieldType=>"mimeType", defaultValue=>'text/html' }, assetsToInclude=>{ fieldType=>'checkList', defaultValue=>"descendants" }, startType=>{ fieldType=>'selectBox', defaultValue=>"relativeToCurrentUrl" }, startPoint=>{ fieldType=>'text', defaultValue=>0 }, ancestorEndPoint=>{ fieldType=>'selectBox', defaultValue=>55 }, descendantEndPoint=>{ fieldType=>'selectBox', defaultValue=>55 }, showSystemPages=>{ fieldType=>'yesNo', defaultValue=>0 }, showHiddenPages=>{ fieldType=>'yesNo', defaultValue=>0 }, showUnprivilegedPages=>{ fieldType=>'yesNo', defaultValue=>0 }, reversePageLoop=>{ fieldType=>'yesNo', defaultValue=>0 }, } }); return $class->SUPER::definition($session, $definition); } #------------------------------------------------------------------- sub getEditForm { my $self = shift; my $tabform = $self->SUPER::getEditForm; my $i18n = WebGUI::International->new($self->session, "Asset_Navigation"); $tabform->getTab("display")->template( -value=>$self->getValue('templateId'), -namespace=>"Navigation", -label=>$i18n->get(1096), -hoverHelp=>$i18n->get('1096 description'), ); $tabform->getTab("display")->mimeType( -value=>$self->getValue('mimeType'), -name=>"mimeType", -label=>$i18n->get('mimeType'), -hoverHelp=>$i18n->get('mimeType description'), ); $tabform->hidden({ name=>"returnUrl", value=>$self->session->form->process("returnUrl") }); my ($descendantsChecked, $ancestorsChecked, $selfChecked, $pedigreeChecked, $siblingsChecked); my @assetsToInclude = split("\n",$self->getValue("assetsToInclude")); my $afterScript; foreach my $item (@assetsToInclude) { if ($item eq "self") { $selfChecked = 1; } elsif ($item eq "descendants") { $descendantsChecked = 1; $afterScript = "displayNavEndPoint = false;"; } elsif ($item eq "ancestors") { $ancestorsChecked = 1; } elsif ($item eq "siblings") { $siblingsChecked = 1; } elsif ($item eq "pedigree") { $pedigreeChecked = 1; } } $tabform->getTab("properties")->selectBox( -name=>"startType", -options=>{ specificUrl=>$i18n->get('Specific URL'), relativeToCurrentUrl=>$i18n->get('Relative To Current URL'), relativeToRoot=>$i18n->get('Relative To Root') }, -value=>[$self->getValue("startType")], -label=>$i18n->get("Start Point Type"), -hoverHelp=>$i18n->get("Start Point Type description"), -id=>"navStartType", -extras=>'onchange="changeStartPoint()"' ); $tabform->getTab("properties")->readOnly( -label=>$i18n->get("Start Point"), -hoverHelp=>$i18n->get("Start Point description"), -value=>'' ); my %options = (); tie %options, 'Tie::IxHash'; %options = ( '1'=>'../ (-1)', '2'=>'../../ (-2)', '3'=>'../../../ (-3)', '4'=>'../../../../ (-4)', '5'=>'../../../../../ (-5)', '55'=>$i18n->get('Infinity') ); $tabform->getTab("properties")->raw( ''.$i18n->get("Ancestor End Point").'' .WebGUI::Form::selectBox($self->session,{ name=>"ancestorEndPoint", value=>[$self->getValue("ancestorEndPoint")], options=>\%options }) .'' ); $tabform->getTab("properties")->readOnly( -label=>$i18n->get("Relatives To Include"), -hoverHelp=>$i18n->get("Relatives To Include description"), -value=>WebGUI::Form::checkbox($self->session,{ checked=>$ancestorsChecked, name=>"assetsToInclude", extras=>'onchange="toggleAncestorEndPoint()"', value=>"ancestors" }).$i18n->get('Ancestors').'
' .WebGUI::Form::checkbox($self->session,{ checked=>$selfChecked, name=>"assetsToInclude", value=>"self" }).$i18n->get('Self').'
' .WebGUI::Form::checkbox($self->session,{ checked=>$siblingsChecked, name=>"assetsToInclude", value=>"siblings" }).$i18n->get('Siblings').'
' .WebGUI::Form::checkbox($self->session,{ checked=>$descendantsChecked, name=>"assetsToInclude", value=>"descendants", extras=>'onchange="toggleDescendantEndPoint()"' }).$i18n->get('Descendants').'
' .WebGUI::Form::checkbox($self->session,{ checked=>$pedigreeChecked, name=>"assetsToInclude", value=>"pedigree" }).$i18n->get('Pedigree').'
' ); %options = (); tie %options, 'Tie::IxHash'; %options = ( '1'=>'./a/ (+1)', '2'=>'./a/b/ (+2)', '3'=>'./a/b/c/ (+3)', '4'=>'./a/b/c/d/ (+4)', '5'=>'./a/b/c/d/e/ (+5)', '55'=>$i18n->get('Infinity') ); $tabform->getTab("properties")->raw( ''.$i18n->get('Descendant End Point').'' .WebGUI::Form::selectBox($self->session,{ name=>"descendantEndPoint", value=>[$self->getValue("descendantEndPoint")], options=>\%options }) .'' ); $tabform->getTab("display")->yesNo( -name=>'showSystemPages', -label=>$i18n->get(30), -hoverHelp=>$i18n->get('30 description'), -value=>$self->getValue("showSystemPages") ); $tabform->getTab("display")->yesNo( -name=>'showHiddenPages', -label=>$i18n->get(31), -hoverHelp=>$i18n->get('31 description'), -value=>$self->getValue("showHiddenPages") ); $tabform->getTab("display")->yesNo( -name=>'showUnprivilegedPages', -label=>$i18n->get(32), -hoverHelp=>$i18n->get('32 description'), -value=>$self->getValue("showUnprivilegedPages") ); $tabform->getTab("display")->yesNo( -name=>'reversePageLoop', -label=>$i18n->get('reverse page loop'), -hoverHelp => $i18n->get('reverse page loop description'), -value=>$self->getValue('reversePageLoop'), ); my $start = $self->getValue("startPoint"); $tabform->getTab("properties")->raw(""); my $previewButton;# = qq{ # }; my $saveButton = ' '; $tabform->{_submit} = $previewButton." ".$saveButton; return $tabform; } #------------------------------------------------------------------- =head2 getToolbar ( ) Returns a toolbar with a set of icons that hyperlink to functions that delete, edit, promote, demote, cut, and copy. =cut sub getToolbar { my $self = shift; return unless $self->canEdit; if ($self->getToolbarState) { my $toolbar = ''; if ($self->canEditIfLocked) { my $userUiLevel = $self->session->user->profileField("uiLevel"); my $uiLevels = $self->session->config->get("assetToolbarUiLevel"); my $returnUrl = ''; if ($self->session->asset) { $returnUrl = ";proceed=goBackToPage;returnUrl=".$self->session->url->escape($self->session->asset->getUrl); } $toolbar = $self->session->icon->edit('func=edit'.$returnUrl,$self->get("url")) if ($userUiLevel >= $uiLevels->{"edit"}); } $self->session->style->setLink($self->session->url->extras('assetToolbar/assetToolbar.css'), {rel=>"stylesheet",type=>"text/css"}); $self->session->style->setLink($self->session->url->extras('yui/build/menu/assets/skins/sam/menu.css'), {rel=>"stylesheet",type=>"text/css"}); $self->session->style->setScript($self->session->url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>"text/javascript"}); $self->session->style->setScript($self->session->url->extras('yui/build/container/container_core-min.js'), {type=>"text/javascript"}); $self->session->style->setScript($self->session->url->extras('yui/build/menu/menu-min.js'), {type=>"text/javascript"}); $self->session->style->setScript($self->session->url->extras('assetToolbar/assetToolbar.js'), {type=>"text/javascript"}); my $i18n = WebGUI::International->new($self->session, "Asset"); return '
' . '' . $self->getName . '' . '
' . '
$toolbar
"; } return $self->SUPER::getToolbar; } #------------------------------------------------------------------- =head2 prepareView ( ) See WebGUI::Asset::prepareView() for details. =cut sub prepareView { my $self = shift; $self->SUPER::prepareView(); my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId")); $template->prepare($self->getMetaDataAsTemplateVariables); $self->{_viewTemplate} = $template; } #------------------------------------------------------------------- sub view { my $self = shift; # we've got to determine what our start point is based upon user conditions my $start; $self->session->asset(WebGUI::Asset->newByUrl($self->session)) unless ($self->session->asset); my $current = $self->session->asset; # no current asset is set unless (defined $current) { $current = WebGUI::Asset->getDefault($self->session); } if ($self->get("startType") eq "specificUrl") { $start = WebGUI::Asset->newByUrl($self->session,$self->get("startPoint")); } elsif ($self->get("startType") eq "relativeToRoot") { unless (($self->get("startPoint")+1) >= $current->getLineageLength) { $start = WebGUI::Asset->newByLineage($self->session,substr($current->get("lineage"),0, ($self->get("startPoint") + 1) * 6)); } } elsif ($self->get("startType") eq "relativeToCurrentUrl") { $start = WebGUI::Asset->newByLineage($self->session,substr($current->get("lineage"),0, ($current->getLineageLength + $self->get("startPoint")) * 6)); } $start = $current unless (defined $start); # if none of the above results in a start point, then the current page must be it my @includedRelationships = split("\n",$self->get("assetsToInclude")); my %rules; $rules{returnObjects} = 1; $rules{endingLineageLength} = $start->getLineageLength+$self->get("descendantEndPoint"); $rules{assetToPedigree} = $current if (isIn("pedigree",@includedRelationships)); $rules{ancestorLimit} = $self->get("ancestorEndPoint"); $rules{orderByClause} = 'rpad(asset.lineage, 255, 9) desc' if ($self->get('reversePageLoop')); my @interestingProperties = ('assetId', 'parentId', 'ownerUserId', 'synopsis', 'newWindow'); my $assets = $start->getLineage(\@includedRelationships,\%rules); my $var = {'page_loop' => []}; foreach my $property (@interestingProperties) { $var->{'currentPage.'.$property} = $current->get($property); } $var->{'currentPage.menuTitle'} = $current->getMenuTitle; $var->{'currentPage.title'} = $current->getTitle; $var->{'currentPage.isHome'} = ($current->getId eq $self->session->setting->get("defaultPage")); $var->{'currentPage.url'} = $current->getUrl; $var->{'currentPage.hasChild'} = $current->hasChildren; $var->{'currentPage.rank'} = $current->getRank; $var->{'currentPage.rankIs'.$current->getRank} = 1; my $currentLineage = $current->get("lineage"); my $lineageToSkip = "noskip"; my $absoluteDepthOfLastPage; my $absoluteDepthOfFirstPage; # Will set on first iteration of loop, below my %lastChildren; my $previousPageData = undef; my $eh = $self->session->errorHandler; foreach my $asset (@{$assets}) { # skip pages we shouldn't see my $pageLineage = $asset->get("lineage"); next if ($pageLineage =~ m/^$lineageToSkip/); if ($asset->get("isHidden") && !$self->get("showHiddenPages")) { $lineageToSkip = $pageLineage unless ($pageLineage eq "000001"); next; } if ($asset->get("isSystem") && !$self->get("showSystemPages")) { $lineageToSkip = $pageLineage unless ($pageLineage eq "000001"); next; } unless ($self->get("showUnprivilegedPages") || $asset->canView) { $lineageToSkip = $pageLineage unless ($pageLineage eq "000001"); next; } # Set absoluteDepthOfFirstPage after we have determined if the first page is viewable! # Otherwise, the indent loop calculation below will be off by 1 (or more) if ( !defined $absoluteDepthOfFirstPage ) { $absoluteDepthOfFirstPage = $asset->getLineageLength; } my $pageData = {}; my $pageProperties = $asset->get; while (my ($property, $propertyValue) = each %{ $pageProperties }) { $pageData->{"page.".$property} = $propertyValue; } $pageData->{'page.menuTitle'} = $asset->getMenuTitle; $pageData->{'page.title'} = $asset->getTitle; # build nav variables $pageData->{"page.rank"} = $asset->getRank; $pageData->{"page.absDepth"} = $asset->getLineageLength; $pageData->{"page.relDepth"} = $asset->getLineageLength - $absoluteDepthOfFirstPage; $pageData->{"page.isSystem"} = $asset->get("isSystem"); $pageData->{"page.isHidden"} = $asset->get("isHidden"); $pageData->{"page.isViewable"} = $asset->canView; $pageData->{'page.isContainer'} = $self->session->config->get("assets/".$asset->get("className")."/isContainer"); $pageData->{'page.isUtility'} = $self->session->config->get("assets/".$asset->get("className")."/category") eq "utilities"; $pageData->{"page.url"} = $asset->getUrl; my $indent = $asset->getLineageLength - $absoluteDepthOfFirstPage; $pageData->{"page.indent_loop"} = []; push(@{$pageData->{"page.indent_loop"}},{'indent'=>$_}) for(1..$indent); $pageData->{"page.indent"} = "   " x $indent; $pageData->{"page.isBranchRoot"} = ($pageData->{"page.absDepth"} == 1); $pageData->{"page.isTopOfBranch"} = ($pageData->{"page.absDepth"} == 2); $pageData->{"page.isChild"} = ($asset->get("parentId") eq $current->getId); $pageData->{"page.isParent"} = ($asset->getId eq $current->get("parentId")); $pageData->{"page.isCurrent"} = ($asset->getId eq $current->getId); $pageData->{"page.isDescendant"} = ( $pageLineage =~ m/^$currentLineage/ && !$pageData->{"page.isCurrent"}); $pageData->{"page.isAncestor"} = ( $currentLineage =~ m/^$pageLineage/ && !$pageData->{"page.isCurrent"}); my $currentBranchLineage = substr($currentLineage,0,12); $pageData->{"page.inBranchRoot"} = ($pageLineage =~ m/^$currentBranchLineage/); $pageData->{"page.isSibling"} = ( $asset->get("parentId") eq $current->get("parentId") && $asset->getId ne $current->getId ); $pageData->{"page.inBranch"} = ( $pageData->{"page.isCurrent"} || $pageData->{"page.isAncestor"} || $pageData->{"page.isSibling"} || $pageData->{"page.isDescendant"} ); $pageData->{"page.depthIs".$pageData->{"page.absDepth"}} = 1; $pageData->{"page.relativeDepthIs".$pageData->{"page.relDepth"}} = 1; my $depthDiff = ($absoluteDepthOfLastPage) ? ($absoluteDepthOfLastPage - $pageData->{'page.absDepth'}) : 0; $pageData->{"page.depthDiff"} = $depthDiff; $pageData->{"page.depthDiffIs".$depthDiff} = 1; if ($depthDiff > 0) { push(@{$pageData->{"page.depthDiff_loop"}},{}) for(1..$depthDiff); } $absoluteDepthOfLastPage = $pageData->{"page.absDepth"}; $pageData->{"page.hasChild"} = $asset->hasChildren; ++$var->{"currentPage.hasSibling"} if $pageData->{"page.isSibling"}; ++$var->{"currentPage.hasViewableSiblings"} if ($pageData->{"page.isSibling"} && $pageData->{"page.isViewable"}); ++$var->{"currentPage.hasViewableChildren"} if ($pageData->{"page.isChild"} && $pageData->{"page.isViewable"}); my $parent = $asset->getParent; if (defined $parent) { foreach my $property (@interestingProperties) { $pageData->{"page.parent.".$property} = $parent->get($property); } $pageData->{'page.parent.menuTitle'} = $parent->getMenuTitle; $pageData->{'page.parent.title'} = $parent->getTitle; $pageData->{"page.parent.url"} = $parent->getUrl; $pageData->{"page.parent.rank"} = $parent->getRank; $pageData->{"page.isRankedFirst"} = 1 unless exists $lastChildren{$parent->getId}; $lastChildren{$parent->getId} = $asset->getId; } $previousPageData->{"page.hasViewableChildren"} = ($previousPageData->{"page.assetId"} eq $pageData->{"page.parentId"}); push(@{$var->{page_loop}}, $pageData); $previousPageData = $pageData; } my $counter; for($counter=0 ; $counter < scalar( @{$var->{page_loop}} ) ; $counter++) { @{$var->{page_loop}}[$counter]->{"page.isRankedLast"} = 1 if ($lastChildren{@{$var->{page_loop}}[$counter]->{"page.parent.assetId"}} eq @{$var->{page_loop}}[$counter]->{"page.assetId"}); } return $self->processTemplate($var,undef,$self->{_viewTemplate}); } #------------------------------------------------------------------- sub www_goBackToPage { my $self = shift; $self->session->http->setRedirect($self->session->form->process("returnUrl")) if ($self->session->form->process("returnUrl")); return undef; } #------------------------------------------------------------------- =head2 www_view A web accessible version of the view method. The SUPER method is overridden so that we can serve other types aside from text/html. =cut sub www_view { my $self = shift; my $mimeType = $self->getValue('mimeType') || 'text/html'; if ($mimeType eq 'text/html') { return $self->SUPER::www_view(); } else { $self->prepareView(); $self->session->http->setMimeType($mimeType || 'text/html'); return $self->view(); } } 1;