<?php /* Snippet name: Wayfinder Short Desc: builds site navigation Version: beta Authors: Ryan Thrash (vertexworks.com) Kyle Jaebker (muddydogpaws.com) */ class Wayfinder { var $id = 0; var $level = 0; var $ph = FALSE; var $debug; var $ignoreHidden = FALSE; var $hideSubMenus = FALSE; var $textOfLinks = 'menutitle'; var $titleOfLinks = 'pagetitle'; var $templates = array(); var $parentTree = array(); var $wfDocs = array(); var $css = array(); var $cssTpl = FALSE; var $jsTpl = FALSE; var $rowPlaceHolders = array('[+wf.link+]','[+wf.title+]','[+wf.linktext+]','[+wf.wrapper+]','[+wf.classes+]'); var $outerPlaceHolders = array('[+wf.wrapper+]','[+wf.classes+]'); var $ie = "\n"; var $customCss;//hack customCss which TV do we have to look at var $debugOutput = '<h2>WayFinder Debug Output:</h2>'; //remove any docs specified with hidemenu function filterHidden($var) { return (!$var['hidemenu']==1); } function endKey(&$array){ end($array); return key($array); } //generate the menu function buildMenu($parentId,$curLevel = 1) { global $modx; $output = ''; $getFields = 'id,menutitle,pagetitle,menuindex,published,hidemenu,parent,isfolder,description,alias,longtitle'; $resource = $modx->getActiveChildren($parentId,'menuindex','ASC',$getFields); if (!$this->ignoreHidden) { $resource = array_filter($resource, array($this, "filterHidden")); } $firstItem = 1; if (is_array($resource) && !empty($resource)) { $numItems = $this->endKey($resource); foreach ($resource as $n => $v) { $v['link'] = $modx->makeUrl($v['id']); $v['level'] = $curLevel; $v['first'] = $firstItem; //hack for specific css if(!empty($this->customCss)){// $mycss = $modx->getTemplateVar($this->customCss,$fields='id',$v['id']); //print_r($mycss); if(!empty($mycss['value'])) { $v['specific'] = $mycss['value']; } } //endhack $firstItem = 0; if ($n == $numItems) { $v['last'] = 1; } else { $v['last'] = 0; } $useTextField = (empty($v[$this->textOfLinks])) ? 'pagetitle' : "$this->textOfLinks"; $v['linktext'] = $v[$useTextField]; $v['title'] = $v[$this->titleOfLinks]; if ($v['isfolder'] && ($curLevel < $this->level || $this->level == 0) && (!$this->hideSubMenus || in_array($v['id'],$this->parentTree))) { $oldLevel = $curLevel; $subMenu = $this->ie . $this->buildMenu($v['id'],++$curLevel) . $this->ie; $curLevel = $oldLevel; } else { $subMenu = ''; } $output .= $this->renderRow($v,$subMenu); } if (!empty($this->templates['innerTpl']) && $curLevel > 1) { $useChunk = $this->templates['innerTpl']; $usedTemplate = 'innerTpl'; } else { $useChunk = $this->templates['outerTpl']; $usedTemplate = 'outerTpl'; } if ($curLevel > 1) { $wrapperClass = 'innercls'; } else { $wrapperClass = 'outercls'; } $useClass = $this->setItemClass($wrapperClass); $phArray = array($output,$useClass); $output = str_replace($this->outerPlaceHolders,$phArray,$useChunk); if ($this->debug) { $numDocs = $numItems + 1; $this->debugOutput .= '<strong>Nesting Complete</strong> - Previous ' . $numDocs . ' level ' . $curLevel . ' items inserted into ' . $usedTemplate . ' with class ' . $useClass . '<br/>'; } } return $output; } //render each rows output function renderRow(&$resource,$subMenu) { global $modx; $output = ''; if ($resource['isfolder'] && !empty($this->templates['parentRowTpl'])) { $usedTemplate = 'parentRowTpl'; } elseif ($resource['id'] == $modx->documentObject['id'] && !empty($this->templates['innerHereTpl']) && $resource['level'] > 1) { $usedTemplate = 'innerHereTpl'; } elseif ($resource['id'] == $modx->documentObject['id'] && !empty($this->templates['hereTpl'])) { $usedTemplate = 'hereTpl'; } elseif ($resource['level'] > 1 && !empty($this->templates['innerRowTpl'])) { $usedTemplate = 'innerRowTpl'; } else { $usedTemplate = 'rowTpl'; } $useChunk = $this->templates[$usedTemplate]; $useSub = $subMenu; $useClass = $this->setItemClass('rowcls',$resource['id'],$resource['first'],$resource['last'],$resource['level'],$resource['isfolder'],$resource['specific']); $phArray = array($resource['link'],$resource['title'],$resource['linktext'],$useSub,$useClass); $output .= str_replace($this->rowPlaceHolders,$phArray,$useChunk); if ($this->debug) { $this->debugOutput .= '<strong>Item Processed: (' . $resource['id'] . ') ' . $resource['pagetitle'] . '</strong><br/> template: ' . $usedTemplate . ' | class: ' . $useClass . '<br/> level: ' . $resource['level'] . ' | First/Last: ' . $resource['first'] . '/' . $resource['last'] . '<br/>'; } return $output . $this->ie; } //debugging to check for valid chunks function checkChunks() { global $modx; foreach ($this->templates as $n => $v) { $chunkcheck = $modx->getChunk($v); if (empty($v) || !$chunkcheck) { if ($n === 'outerTpl') { $this->templates[$n] = '<ul[+wf.classes+]>[+wf.wrapper+]</ul>'; } elseif ($n === 'rowTpl') { $this->templates[$n] = '<li[+wf.classes+]><a href="[+wf.link+]" title="[+wf.title+]">[+wf.linktext+]</a>[+wf.wrapper+]</li>'; } else { $this->templates[$n] = ''; } if ($this->debug) { $this->debugOutput .= '<p>No chunk found for <strong>' . $n . '</strong> using default.</p>'; } } else { $this->templates[$n] = $chunkcheck; } } } //determine "you are here" function isHere($did) { return in_array($did,$this->parentTree); } //determine style class for current item being processed //added 1param to the function for customCss hack function setItemClass($classType, $docId = 0, $first = 0, $last = 0, $level = 0, $isFolder = 0, $specificCss ='') { global $modx; $returnClass = ''; $hasClass = 0; if ($classType === 'outercls' && !empty($this->css['outer'])) { //Set outer class if specified $returnClass .= $this->css['outer']; $hasClass = 1; } elseif ($classType === 'innercls' && !empty($this->css['inner'])) { //Set inner class if specified $returnClass .= $this->css['inner']; $hasClass = 1; } elseif ($classType === 'rowcls') { //Set row class if specified if (!empty($this->css['row'])) { $returnClass .= $this->css['row']; $hasClass = 1; } //Set first class if specified if ($first && !empty($this->css['first'])) { $returnClass .= $hasClass ? ' ' . $this->css['first'] : $this->css['first']; $hasClass = 1; } //Set last class if specified if ($last && !empty($this->css['last'])) { $returnClass .= $hasClass ? ' ' . $this->css['last'] : $this->css['last']; $hasClass = 1; } //Set level class if specified if (!empty($this->css['level'])) { $returnClass .= $hasClass ? ' ' . $this->css['level'] . $level : $this->css['level'] . $level; $hasClass = 1; } //Set parentFolder class if specified if ($isFolder && !empty($this->css['parent']) && $level < $this->level) { $returnClass .= $hasClass ? ' ' . $this->css['parent'] : $this->css['parent']; $hasClass = 1; } //Set here class if specified if (!empty($this->css['here']) && $this->isHere($docId)) { $returnClass .= $hasClass ? ' ' . $this->css['here'] : $this->css['here']; $hasClass = 1; } //hack customCss //Set specific class if exists if (!empty($specificCss)) { $returnClass .= $hasClass ? ' ' . $specificCss : $specificCss; $hasClass = 1; } } if ($hasClass) { $returnClass = ' class="' . $returnClass . '"'; } return $returnClass; } //Add the specified css & javascript chunks to the page function regJsCss() { global $modx; if ($this->debug) { $this->debugOutput .= '<h3>Processing Css/Js Chunks</h3>'; } if ($this->cssTpl) { $cssChunk = $modx->getChunk($this->cssTpl); if ($cssChunk) { $modx->regClientCSS($cssChunk); if ($this->debug) {$this->debugOutput .= '<p>The CSS chunk ' . $this->cssTpl . ' was added to the page.</p>';} } else { if ($this->debug) {$this->debugOutput .= '<p>The CSS chunk ' . $this->cssTpl . ' was not found.</p>';} } } if ($this->jsTpl) { $jsChunk = $modx->getChunk($this->jsTpl); if ($jsChunk) { $modx->regClientStartupScript($jsChunk); if ($this->debug) {$this->debugOutput .= '<p>The JS chunk ' . $this->jsTpl . ' was added to the page.</p>';} } else { if ($this->debug) {$this->debugOutput .= '<p>The JS chunk ' . $this->jsTpl . ' was not found.</p>';} } } } function ultimateParent($id,$top) { // From UltimateParent - snippet for MODx 0.9x // March 2006 - [email protected] global $modx; if($id==$top || $id==0) { return $id; } $pid = $modx->getParent($id,1,'id'); if($pid['id'] == $top) { return $id; } while ($pid['id'] != $top && $pid['id'] != "") { $id = $pid['id']; $pid = $modx->getParent($id,1,'id'); if($pid['id'] == $top) { return $id; } } return 0; // if all else fails } } ?>
<?php /* :::::::::::::::::::::::::::::::::::::::: Snippet name: Wayfinder Short Desc: builds site navigation Version: beta Authors: Ryan Thrash (vertexworks.com) Kyle Jaebker (muddydogpaws.com) Date: August 2, 2006 Changelog: August 2, 2006 - Initial Public Beta released :::::::::::::::::::::::::::::::::::::::: Description: Totally refactored from original DropMenu nav builder to make it easier to create custom navigation by using chunks as output templates. By using templates, many of the paramaters are no longer needed for flexible output including tables, unordered- or ordered-lists (ULs or OLs), definition lists (DLs) or in any other format you desire. :::::::::::::::::::::::::::::::::::::::: Example Usage: [[Wayfinder? &startId=`0`]] :::::::::::::::::::::::::::::::::::::::: */ include_once("assets/snippets/wayfinder/wayfinder.inc.php"); if (class_exists('Wayfinder')) { $wf = new Wayfinder(); } else { return 'error: Wayfinder class not found'; } //parameter overrides if (isset($startUltimateParent)) { $topDoc = isset($topDoc)? $topDoc: 0; $wf->id = $wf->ultimateParent($modx->documentIdentifier,$topDoc); } else { $wf->id = isset($startId)? $startId: $modx->documentIdentifier; } $wf->level = isset($level)? $level: 0; $wf->ph = isset($ph)? $ph: FALSE; $wf->debug = isset($debug)? TRUE: FALSE; $wf->ignoreHidden = isset($ignoreHidden)? $ignoreHidden: FALSE; $wf->hideSubMenus = isset($hideSubMenus)? $hideSubMenus: FALSE; isset($removeNewLines)? $wf->ie = '': $wf->ie = "\n"; //Include javascript & css chunks $wf->cssTpl = isset($cssTpl)? $cssTpl : FALSE; $wf->jsTpl = isset($jsTpl)? $jsTpl : FALSE; //get user class definitions $wf->css['first'] = isset($firstClass)? $firstClass: ''; $wf->css['last'] = isset($lastClass)? $lastClass: 'last'; $wf->css['here'] = isset($hereClass)? $hereClass: 'active'; $wf->css['parent'] = isset($parentClass)? $parentClass: ''; $wf->css['row'] = isset($rowClass)? $rowClass: ''; $wf->css['outer'] = isset($outerClass)? $outerClass: ''; $wf->css['inner'] = isset($innerClass)? $innerClass: ''; $wf->css['level'] = isset($levelClass)? $levelClass: ''; //hack to add custom css //specify the name of TV from which we get the values $wf->customCss = isset($customCss) ? "$customCss" : ''; //get fields to output $wf->textOfLinks = (isset($textOfLinks)) ? $textOfLinks : 'menutitle'; $wf->titleOfLinks = (isset($titleOfLinks)) ? $titleOfLinks : 'pagetitle'; //get user templates $wf->templates['outerTpl'] = isset($outerTpl) ? $outerTpl : ''; $wf->templates['rowTpl'] = isset($rowTpl) ? $rowTpl : ''; $wf->templates['parentRowTpl'] = isset($parentRowTpl) ? $parentRowTpl : ''; $wf->templates['hereTpl'] = isset($hereTpl) ? $hereTpl : ''; $wf->templates['innerTpl'] = isset($innerTpl) ? $innerTpl : ''; $wf->templates['innerRowTpl'] = isset($innerRowTpl) ? $innerRowTpl : ''; $wf->templates['innerHereTpl'] = isset($innerHereTpl) ? $innerHereTpl : ''; //setup here checking array $wf->parentTree = $modx->getParentIds($modx->documentIdentifier); $wf->parentTree[] = $modx->documentIdentifier; if ($wf->debug) { $wf->debugOutput .= '<p>Starting Menu from Docid: ' . $wf->id . '<br/>'; $wf->debugOutput .= 'Docids for \'Here\' class checking: ' . implode(', ',$wf->parentTree) . '</p>'; $wf->debugOutput .= '<h3>Chunk Checks</h3>'; } $wf->checkChunks(); if ($wf->cssTpl || $wf->jsTpl) { $wf->regJsCss(); } if ($wf->debug) { $wf->debugOutput .= '<h3>Document Processing</h3>'; } $output = $wf->buildMenu($wf->id); if ($wf->debug) { $output = $output . $wf->debugOutput; } if ($ph) { $modx->setPlaceholder($ph,$output); } else { return $output; }
This discussion is closed to further replies. Keep calm and carry on.