File indexing completed on 2025-03-02 05:29:58
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_View 0017 * @subpackage Helper 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_View_Helper_Navigation_HelperAbstract 0025 */ 0026 // require_once 'Zend/View/Helper/Navigation/HelperAbstract.php'; 0027 0028 /** 0029 * Helper for rendering menus from navigation containers 0030 * 0031 * @category Zend 0032 * @package Zend_View 0033 * @subpackage Helper 0034 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0035 * @license http://framework.zend.com/license/new-bsd New BSD License 0036 */ 0037 class Zend_View_Helper_Navigation_Menu 0038 extends Zend_View_Helper_Navigation_HelperAbstract 0039 { 0040 /** 0041 * CSS class to use for the ul element 0042 * 0043 * @var string 0044 */ 0045 protected $_ulClass = 'navigation'; 0046 0047 /** 0048 * Unique identifier (id) for the ul element 0049 * 0050 * @var string 0051 */ 0052 protected $_ulId = null; 0053 0054 /** 0055 * CSS class to use for the active elements 0056 * 0057 * @var string 0058 */ 0059 protected $_activeClass = 'active'; 0060 0061 /** 0062 * CSS class to use for the parent li element 0063 * 0064 * @var string 0065 */ 0066 protected $_parentClass = 'menu-parent'; 0067 0068 /** 0069 * Whether parent li elements should be rendered with parent class 0070 * 0071 * @var bool 0072 */ 0073 protected $_renderParentClass = false; 0074 0075 /** 0076 * Whether only active branch should be rendered 0077 * 0078 * @var bool 0079 */ 0080 protected $_onlyActiveBranch = false; 0081 0082 /** 0083 * Whether parents should be rendered when only rendering active branch 0084 * 0085 * @var bool 0086 */ 0087 protected $_renderParents = true; 0088 0089 /** 0090 * Partial view script to use for rendering menu 0091 * 0092 * @var string|array 0093 */ 0094 protected $_partial = null; 0095 0096 /** 0097 * Expand all sibling nodes of active branch nodes 0098 * 0099 * @var bool 0100 */ 0101 protected $_expandSiblingNodesOfActiveBranch = false; 0102 0103 /** 0104 * Adds CSS class from page to li element 0105 * 0106 * @var bool 0107 */ 0108 protected $_addPageClassToLi = false; 0109 0110 /** 0111 * Inner indentation string 0112 * 0113 * @var string 0114 */ 0115 protected $_innerIndent = ' '; 0116 0117 /** 0118 * View helper entry point: 0119 * Retrieves helper and optionally sets container to operate on 0120 * 0121 * @param Zend_Navigation_Container $container [optional] container to 0122 * operate on 0123 * @return Zend_View_Helper_Navigation_Menu fluent interface, 0124 * returns self 0125 */ 0126 public function menu(Zend_Navigation_Container $container = null) 0127 { 0128 if (null !== $container) { 0129 $this->setContainer($container); 0130 } 0131 0132 return $this; 0133 } 0134 0135 // Accessors: 0136 0137 /** 0138 * Sets CSS class to use for the first 'ul' element when rendering 0139 * 0140 * @param string $ulClass CSS class to set 0141 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0142 */ 0143 public function setUlClass($ulClass) 0144 { 0145 if (is_string($ulClass)) { 0146 $this->_ulClass = $ulClass; 0147 } 0148 0149 return $this; 0150 } 0151 0152 /** 0153 * Returns CSS class to use for the first 'ul' element when rendering 0154 * 0155 * @return string CSS class 0156 */ 0157 public function getUlClass() 0158 { 0159 return $this->_ulClass; 0160 } 0161 0162 /** 0163 * Sets unique identifier (id) to use for the first 'ul' element when 0164 * rendering 0165 * 0166 * @param string|null $ulId Unique identifier (id) to set 0167 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0168 */ 0169 public function setUlId($ulId) 0170 { 0171 if (is_string($ulId)) { 0172 $this->_ulId = $ulId; 0173 } 0174 0175 return $this; 0176 } 0177 0178 /** 0179 * Returns unique identifier (id) to use for the first 'ul' element when 0180 * rendering 0181 * 0182 * @return string|null Unique identifier (id); Default is 'null' 0183 */ 0184 public function getUlId() 0185 { 0186 return $this->_ulId; 0187 } 0188 0189 /** 0190 * Sets CSS class to use for the active elements when rendering 0191 * 0192 * @param string $activeClass CSS class to set 0193 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0194 */ 0195 public function setActiveClass($activeClass) 0196 { 0197 if (is_string($activeClass)) { 0198 $this->_activeClass = $activeClass; 0199 } 0200 0201 return $this; 0202 } 0203 0204 /** 0205 * Returns CSS class to use for the active elements when rendering 0206 * 0207 * @return string CSS class 0208 */ 0209 public function getActiveClass() 0210 { 0211 return $this->_activeClass; 0212 } 0213 0214 /** 0215 * Sets CSS class to use for the parent li elements when rendering 0216 * 0217 * @param string $parentClass CSS class to set to parents 0218 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0219 */ 0220 public function setParentClass($parentClass) 0221 { 0222 if (is_string($parentClass)) { 0223 $this->_parentClass = $parentClass; 0224 } 0225 0226 return $this; 0227 } 0228 0229 /** 0230 * Returns CSS class to use for the parent lie elements when rendering 0231 * 0232 * @return string CSS class 0233 */ 0234 public function getParentClass() 0235 { 0236 return $this->_parentClass; 0237 } 0238 0239 /** 0240 * Enables/disables rendering of parent class to the li element 0241 * 0242 * @param bool $flag [optional] render with parent 0243 * class. Default is true. 0244 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0245 */ 0246 public function setRenderParentClass($flag = true) 0247 { 0248 $this->_renderParentClass = (bool) $flag; 0249 return $this; 0250 } 0251 0252 /** 0253 * Returns flag indicating whether parent class should be rendered to the li 0254 * element 0255 * 0256 * @return bool whether parent class should be rendered 0257 */ 0258 public function getRenderParentClass() 0259 { 0260 return $this->_renderParentClass; 0261 } 0262 0263 /** 0264 * Sets a flag indicating whether only active branch should be rendered 0265 * 0266 * @param bool $flag [optional] render only active 0267 * branch. Default is true. 0268 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0269 */ 0270 public function setOnlyActiveBranch($flag = true) 0271 { 0272 $this->_onlyActiveBranch = (bool) $flag; 0273 return $this; 0274 } 0275 0276 /** 0277 * Returns a flag indicating whether only active branch should be rendered 0278 * 0279 * By default, this value is false, meaning the entire menu will be 0280 * be rendered. 0281 * 0282 * @return bool whether only active branch should be rendered 0283 */ 0284 public function getOnlyActiveBranch() 0285 { 0286 return $this->_onlyActiveBranch; 0287 } 0288 0289 /** 0290 * Sets a flag indicating whether to expand all sibling nodes of the active branch 0291 * 0292 * @param bool $flag [optional] expand all siblings of 0293 * nodes in the active branch. Default is true. 0294 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0295 */ 0296 public function setExpandSiblingNodesOfActiveBranch($flag = true) 0297 { 0298 $this->_expandSiblingNodesOfActiveBranch = (bool) $flag; 0299 return $this; 0300 } 0301 0302 /** 0303 * Returns a flag indicating whether to expand all sibling nodes of the active branch 0304 * 0305 * By default, this value is false, meaning the entire menu will be 0306 * be rendered. 0307 * 0308 * @return bool whether siblings of nodes in the active branch should be expanded 0309 */ 0310 public function getExpandSiblingNodesOfActiveBranch() 0311 { 0312 return $this->_expandSiblingNodesOfActiveBranch; 0313 } 0314 0315 /** 0316 * Enables/disables rendering of parents when only rendering active branch 0317 * 0318 * See {@link setOnlyActiveBranch()} for more information. 0319 * 0320 * @param bool $flag [optional] render parents when 0321 * rendering active branch. 0322 * Default is true. 0323 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0324 */ 0325 public function setRenderParents($flag = true) 0326 { 0327 $this->_renderParents = (bool) $flag; 0328 return $this; 0329 } 0330 0331 /** 0332 * Returns flag indicating whether parents should be rendered when rendering 0333 * only the active branch 0334 * 0335 * By default, this value is true. 0336 * 0337 * @return bool whether parents should be rendered 0338 */ 0339 public function getRenderParents() 0340 { 0341 return $this->_renderParents; 0342 } 0343 0344 /** 0345 * Sets which partial view script to use for rendering menu 0346 * 0347 * @param string|array $partial partial view script or null. If 0348 * an array is given, it is 0349 * expected to contain two values; 0350 * the partial view script to use, 0351 * and the module where the script 0352 * can be found. 0353 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0354 */ 0355 public function setPartial($partial) 0356 { 0357 if (null === $partial || is_string($partial) || is_array($partial)) { 0358 $this->_partial = $partial; 0359 } 0360 0361 return $this; 0362 } 0363 0364 /** 0365 * Returns partial view script to use for rendering menu 0366 * 0367 * @return string|array|null 0368 */ 0369 public function getPartial() 0370 { 0371 return $this->_partial; 0372 } 0373 0374 /** 0375 * Adds CSS class from page to li element 0376 * 0377 * Before: 0378 * <code> 0379 * <li> 0380 * <a href="#" class="foo">Bar</a> 0381 * </li> 0382 * </code> 0383 * 0384 * After: 0385 * <code> 0386 * <li class="foo"> 0387 * <a href="#">Bar</a> 0388 * </li> 0389 * </code> 0390 * 0391 * @param bool $flag [optional] adds CSS class from 0392 * page to li element 0393 * 0394 * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self 0395 */ 0396 public function addPageClassToLi($flag = true) 0397 { 0398 $this->_addPageClassToLi = (bool) $flag; 0399 0400 return $this; 0401 } 0402 0403 /** 0404 * Returns a flag indicating whether the CSS class from page to be added to 0405 * li element 0406 * 0407 * @return bool 0408 */ 0409 public function getAddPageClassToLi() 0410 { 0411 return $this->_addPageClassToLi; 0412 } 0413 0414 /** 0415 * Set the inner indentation string for using in {@link render()}, optionally 0416 * a number of spaces to indent with 0417 * 0418 * @param string|int $indent indentation string or 0419 * number of spaces 0420 * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, 0421 * returns self 0422 */ 0423 public function setInnerIndent($indent) 0424 { 0425 $this->_innerIndent = $this->_getWhitespace($indent); 0426 0427 return $this; 0428 } 0429 0430 /** 0431 * Returns inner indentation (format output is respected) 0432 * 0433 * @see getFormatOutput() 0434 * 0435 * @return string indentation string or an empty string 0436 */ 0437 public function getInnerIndent() 0438 { 0439 if (false === $this->getFormatOutput()) { 0440 return ''; 0441 } 0442 0443 return $this->_innerIndent; 0444 } 0445 0446 // Public methods: 0447 0448 /** 0449 * Returns an HTML string containing an 'a' element for the given page if 0450 * the page's href is not empty, and a 'span' element if it is empty 0451 * 0452 * Overrides {@link Zend_View_Helper_Navigation_Abstract::htmlify()}. 0453 * 0454 * @param Zend_Navigation_Page $page page to generate HTML for 0455 * @return string HTML string for the given page 0456 */ 0457 public function htmlify(Zend_Navigation_Page $page) 0458 { 0459 // get label and title for translating 0460 $label = $page->getLabel(); 0461 $title = $page->getTitle(); 0462 0463 // translate label and title? 0464 if ($this->getUseTranslator() && $t = $this->getTranslator()) { 0465 if (is_string($label) && !empty($label)) { 0466 $label = $t->translate($label); 0467 } 0468 if (is_string($title) && !empty($title)) { 0469 $title = $t->translate($title); 0470 } 0471 } 0472 0473 // get attribs for element 0474 $attribs = array( 0475 'id' => $page->getId(), 0476 'title' => $title, 0477 ); 0478 0479 if (false === $this->getAddPageClassToLi()) { 0480 $attribs['class'] = $page->getClass(); 0481 } 0482 0483 // does page have a href? 0484 if ($href = $page->getHref()) { 0485 $element = 'a'; 0486 $attribs['href'] = $href; 0487 $attribs['target'] = $page->getTarget(); 0488 $attribs['accesskey'] = $page->getAccessKey(); 0489 } else { 0490 $element = 'span'; 0491 } 0492 0493 // Add custom HTML attributes 0494 $attribs = array_merge($attribs, $page->getCustomHtmlAttribs()); 0495 0496 return '<' . $element . $this->_htmlAttribs($attribs) . '>' 0497 . $this->view->escape($label) 0498 . '</' . $element . '>'; 0499 } 0500 0501 /** 0502 * Normalizes given render options 0503 * 0504 * @param array $options [optional] options to normalize 0505 * @return array normalized options 0506 */ 0507 protected function _normalizeOptions(array $options = array()) 0508 { 0509 // Ident 0510 if (isset($options['indent'])) { 0511 $options['indent'] = $this->_getWhitespace($options['indent']); 0512 } else { 0513 $options['indent'] = $this->getIndent(); 0514 } 0515 0516 // Inner ident 0517 if (isset($options['innerIndent'])) { 0518 $options['innerIndent'] = 0519 $this->_getWhitespace($options['innerIndent']); 0520 } else { 0521 $options['innerIndent'] = $this->getInnerIndent(); 0522 } 0523 0524 // UL class 0525 if (isset($options['ulClass']) && $options['ulClass'] !== null) { 0526 $options['ulClass'] = (string) $options['ulClass']; 0527 } else { 0528 $options['ulClass'] = $this->getUlClass(); 0529 } 0530 0531 // UL id 0532 if (isset($options['ulId']) && $options['ulId'] !== null) { 0533 $options['ulId'] = (string) $options['ulId']; 0534 } else { 0535 $options['ulId'] = $this->getUlId(); 0536 } 0537 0538 // Active class 0539 if (isset($options['activeClass']) && $options['activeClass'] !== null 0540 ) { 0541 $options['activeClass'] = (string) $options['activeClass']; 0542 } else { 0543 $options['activeClass'] = $this->getActiveClass(); 0544 } 0545 0546 // Parent class 0547 if (isset($options['parentClass']) && $options['parentClass'] !== null) { 0548 $options['parentClass'] = (string) $options['parentClass']; 0549 } else { 0550 $options['parentClass'] = $this->getParentClass(); 0551 } 0552 0553 // Minimum depth 0554 if (array_key_exists('minDepth', $options)) { 0555 if (null !== $options['minDepth']) { 0556 $options['minDepth'] = (int) $options['minDepth']; 0557 } 0558 } else { 0559 $options['minDepth'] = $this->getMinDepth(); 0560 } 0561 0562 if ($options['minDepth'] < 0 || $options['minDepth'] === null) { 0563 $options['minDepth'] = 0; 0564 } 0565 0566 // Maximum depth 0567 if (array_key_exists('maxDepth', $options)) { 0568 if (null !== $options['maxDepth']) { 0569 $options['maxDepth'] = (int) $options['maxDepth']; 0570 } 0571 } else { 0572 $options['maxDepth'] = $this->getMaxDepth(); 0573 } 0574 0575 // Only active branch 0576 if (!isset($options['onlyActiveBranch'])) { 0577 $options['onlyActiveBranch'] = $this->getOnlyActiveBranch(); 0578 } 0579 0580 // Expand sibling nodes of active branch 0581 if (!isset($options['expandSiblingNodesOfActiveBranch'])) { 0582 $options['expandSiblingNodesOfActiveBranch'] = $this->getExpandSiblingNodesOfActiveBranch(); 0583 } 0584 0585 // Render parents? 0586 if (!isset($options['renderParents'])) { 0587 $options['renderParents'] = $this->getRenderParents(); 0588 } 0589 0590 // Render parent class? 0591 if (!isset($options['renderParentClass'])) { 0592 $options['renderParentClass'] = $this->getRenderParentClass(); 0593 } 0594 0595 // Add page CSS class to LI element 0596 if (!isset($options['addPageClassToLi'])) { 0597 $options['addPageClassToLi'] = $this->getAddPageClassToLi(); 0598 } 0599 0600 return $options; 0601 } 0602 0603 // Render methods: 0604 0605 /** 0606 * Renders the deepest active menu within [$minDepth, $maxDeth], (called 0607 * from {@link renderMenu()}) 0608 * 0609 * @param Zend_Navigation_Container $container container to render 0610 * @param string $ulClass CSS class for first UL 0611 * @param string $indent initial indentation 0612 * @param string $innerIndent inner indentation 0613 * @param int|null $minDepth minimum depth 0614 * @param int|null $maxDepth maximum depth 0615 * @param string|null $ulId unique identifier (id) 0616 * for first UL 0617 * @param bool $addPageClassToLi adds CSS class from 0618 * page to li element 0619 * @param string|null $activeClass CSS class for active 0620 * element 0621 * @param string $parentClass CSS class for parent 0622 * li's 0623 * @param bool $renderParentClass Render parent class? 0624 * @return string rendered menu (HTML) 0625 */ 0626 protected function _renderDeepestMenu(Zend_Navigation_Container $container, 0627 $ulClass, 0628 $indent, 0629 $innerIndent, 0630 $minDepth, 0631 $maxDepth, 0632 $ulId, 0633 $addPageClassToLi, 0634 $activeClass, 0635 $parentClass, 0636 $renderParentClass) 0637 { 0638 if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) { 0639 return ''; 0640 } 0641 0642 // special case if active page is one below minDepth 0643 if ($active['depth'] < $minDepth) { 0644 if (!$active['page']->hasPages()) { 0645 return ''; 0646 } 0647 } else if (!$active['page']->hasPages()) { 0648 // found pages has no children; render siblings 0649 $active['page'] = $active['page']->getParent(); 0650 } else if (is_int($maxDepth) && $active['depth'] + 1 > $maxDepth) { 0651 // children are below max depth; render siblings 0652 $active['page'] = $active['page']->getParent(); 0653 } 0654 0655 $attribs = array( 0656 'class' => $ulClass, 0657 'id' => $ulId, 0658 ); 0659 0660 // We don't need a prefix for the menu ID (backup) 0661 $skipValue = $this->_skipPrefixForId; 0662 $this->skipPrefixForId(); 0663 0664 $html = $indent . '<ul' 0665 . $this->_htmlAttribs($attribs) 0666 . '>' 0667 . $this->getEOL(); 0668 0669 // Reset prefix for IDs 0670 $this->_skipPrefixForId = $skipValue; 0671 0672 foreach ($active['page'] as $subPage) { 0673 if (!$this->accept($subPage)) { 0674 continue; 0675 } 0676 0677 $liClass = ''; 0678 if ($subPage->isActive(true) && $addPageClassToLi) { 0679 $liClass = $this->_htmlAttribs( 0680 array('class' => $activeClass . ' ' . $subPage->getClass()) 0681 ); 0682 } else if ($subPage->isActive(true)) { 0683 $liClass = $this->_htmlAttribs(array('class' => $activeClass)); 0684 } else if ($addPageClassToLi) { 0685 $liClass = $this->_htmlAttribs( 0686 array('class' => $subPage->getClass()) 0687 ); 0688 } 0689 $html .= $indent . $innerIndent . '<li' . $liClass . '>' . $this->getEOL(); 0690 $html .= $indent . str_repeat($innerIndent, 2) . $this->htmlify($subPage) 0691 . $this->getEOL(); 0692 $html .= $indent . $innerIndent . '</li>' . $this->getEOL(); 0693 } 0694 0695 $html .= $indent . '</ul>'; 0696 0697 return $html; 0698 } 0699 0700 /** 0701 * Renders a normal menu (called from {@link renderMenu()}) 0702 * 0703 * @param Zend_Navigation_Container $container container to render 0704 * @param string $ulClass CSS class for first UL 0705 * @param string $indent initial indentation 0706 * @param string $innerIndent inner indentation 0707 * @param int|null $minDepth minimum depth 0708 * @param int|null $maxDepth maximum depth 0709 * @param bool $onlyActive render only active branch? 0710 * @param bool $expandSibs render siblings of active 0711 * branch nodes? 0712 * @param string|null $ulId unique identifier (id) 0713 * for first UL 0714 * @param bool $addPageClassToLi adds CSS class from 0715 * page to li element 0716 * @param string|null $activeClass CSS class for active 0717 * element 0718 * @param string $parentClass CSS class for parent 0719 * li's 0720 * @param bool $renderParentClass Render parent class? 0721 * @return string rendered menu (HTML) 0722 */ 0723 protected function _renderMenu(Zend_Navigation_Container $container, 0724 $ulClass, 0725 $indent, 0726 $innerIndent, 0727 $minDepth, 0728 $maxDepth, 0729 $onlyActive, 0730 $expandSibs, 0731 $ulId, 0732 $addPageClassToLi, 0733 $activeClass, 0734 $parentClass, 0735 $renderParentClass) 0736 { 0737 $html = ''; 0738 0739 // find deepest active 0740 if ($found = $this->findActive($container, $minDepth, $maxDepth)) { 0741 $foundPage = $found['page']; 0742 $foundDepth = $found['depth']; 0743 } else { 0744 $foundPage = null; 0745 } 0746 0747 // create iterator 0748 $iterator = new RecursiveIteratorIterator($container, 0749 RecursiveIteratorIterator::SELF_FIRST); 0750 if (is_int($maxDepth)) { 0751 $iterator->setMaxDepth($maxDepth); 0752 } 0753 0754 // iterate container 0755 $prevDepth = -1; 0756 foreach ($iterator as $page) { 0757 $depth = $iterator->getDepth(); 0758 $isActive = $page->isActive(true); 0759 if ($depth < $minDepth || !$this->accept($page)) { 0760 // page is below minDepth or not accepted by acl/visibilty 0761 continue; 0762 } else if ($expandSibs && $depth > $minDepth) { 0763 // page is not active itself, but might be in the active branch 0764 $accept = false; 0765 if ($foundPage) { 0766 if ($foundPage->hasPage($page)) { 0767 // accept if page is a direct child of the active page 0768 $accept = true; 0769 } else if ($page->getParent()->isActive(true)) { 0770 // page is a sibling of the active branch... 0771 $accept = true; 0772 } 0773 } 0774 if (!$isActive && !$accept) { 0775 continue; 0776 } 0777 } else if ($onlyActive && !$isActive) { 0778 // page is not active itself, but might be in the active branch 0779 $accept = false; 0780 if ($foundPage) { 0781 if ($foundPage->hasPage($page)) { 0782 // accept if page is a direct child of the active page 0783 $accept = true; 0784 } else if ($foundPage->getParent()->hasPage($page)) { 0785 // page is a sibling of the active page... 0786 if (!$foundPage->hasPages() || 0787 is_int($maxDepth) && $foundDepth + 1 > $maxDepth) { 0788 // accept if active page has no children, or the 0789 // children are too deep to be rendered 0790 $accept = true; 0791 } 0792 } 0793 } 0794 0795 if (!$accept) { 0796 continue; 0797 } 0798 } 0799 0800 // make sure indentation is correct 0801 $depth -= $minDepth; 0802 $myIndent = $indent . str_repeat($innerIndent, $depth * 2); 0803 0804 if ($depth > $prevDepth) { 0805 $attribs = array(); 0806 0807 // start new ul tag 0808 if (0 == $depth) { 0809 $attribs = array( 0810 'class' => $ulClass, 0811 'id' => $ulId, 0812 ); 0813 } 0814 0815 // We don't need a prefix for the menu ID (backup) 0816 $skipValue = $this->_skipPrefixForId; 0817 $this->skipPrefixForId(); 0818 0819 $html .= $myIndent . '<ul' 0820 . $this->_htmlAttribs($attribs) 0821 . '>' 0822 . $this->getEOL(); 0823 0824 // Reset prefix for IDs 0825 $this->_skipPrefixForId = $skipValue; 0826 } else if ($prevDepth > $depth) { 0827 // close li/ul tags until we're at current depth 0828 for ($i = $prevDepth; $i > $depth; $i--) { 0829 $ind = $indent . str_repeat($innerIndent, $i * 2); 0830 $html .= $ind . $innerIndent . '</li>' . $this->getEOL(); 0831 $html .= $ind . '</ul>' . $this->getEOL(); 0832 } 0833 // close previous li tag 0834 $html .= $myIndent . $innerIndent . '</li>' . $this->getEOL(); 0835 } else { 0836 // close previous li tag 0837 $html .= $myIndent . $innerIndent . '</li>' . $this->getEOL(); 0838 } 0839 0840 // render li tag and page 0841 $liClasses = array(); 0842 // Is page active? 0843 if ($isActive) { 0844 $liClasses[] = $activeClass; 0845 } 0846 // Add CSS class from page to LI? 0847 if ($addPageClassToLi) { 0848 $liClasses[] = $page->getClass(); 0849 } 0850 // Add CSS class for parents to LI? 0851 if ($renderParentClass && $page->hasChildren()) { 0852 // Check max depth 0853 if ((is_int($maxDepth) && ($depth + 1 < $maxDepth)) 0854 || !is_int($maxDepth) 0855 ) { 0856 $liClasses[] = $parentClass; 0857 } 0858 } 0859 0860 $html .= $myIndent . $innerIndent . '<li' 0861 . $this->_htmlAttribs(array('class' => implode(' ', $liClasses))) 0862 . '>' . $this->getEOL() 0863 . $myIndent . str_repeat($innerIndent, 2) 0864 . $this->htmlify($page) 0865 . $this->getEOL(); 0866 0867 // store as previous depth for next iteration 0868 $prevDepth = $depth; 0869 } 0870 0871 if ($html) { 0872 // done iterating container; close open ul/li tags 0873 for ($i = $prevDepth+1; $i > 0; $i--) { 0874 $myIndent = $indent . str_repeat($innerIndent . $innerIndent, $i - 1); 0875 $html .= $myIndent . $innerIndent . '</li>' . $this->getEOL() 0876 . $myIndent . '</ul>' . $this->getEOL(); 0877 } 0878 $html = rtrim($html, $this->getEOL()); 0879 } 0880 0881 return $html; 0882 } 0883 0884 /** 0885 * Renders helper 0886 * 0887 * Renders a HTML 'ul' for the given $container. If $container is not given, 0888 * the container registered in the helper will be used. 0889 * 0890 * Available $options: 0891 * 0892 * 0893 * @param Zend_Navigation_Container $container [optional] container to 0894 * create menu from. Default 0895 * is to use the container 0896 * retrieved from 0897 * {@link getContainer()}. 0898 * @param array $options [optional] options for 0899 * controlling rendering 0900 * @return string rendered menu 0901 */ 0902 public function renderMenu(Zend_Navigation_Container $container = null, 0903 array $options = array()) 0904 { 0905 if (null === $container) { 0906 $container = $this->getContainer(); 0907 } 0908 0909 $options = $this->_normalizeOptions($options); 0910 0911 if ($options['onlyActiveBranch'] && !$options['renderParents']) { 0912 $html = $this->_renderDeepestMenu( 0913 $container, 0914 $options['ulClass'], 0915 $options['indent'], 0916 $options['innerIndent'], 0917 $options['minDepth'], 0918 $options['maxDepth'], 0919 $options['ulId'], 0920 $options['addPageClassToLi'], 0921 $options['activeClass'], 0922 $options['parentClass'], 0923 $options['renderParentClass'] 0924 ); 0925 } else { 0926 $html = $this->_renderMenu( 0927 $container, 0928 $options['ulClass'], 0929 $options['indent'], 0930 $options['innerIndent'], 0931 $options['minDepth'], 0932 $options['maxDepth'], 0933 $options['onlyActiveBranch'], 0934 $options['expandSiblingNodesOfActiveBranch'], 0935 $options['ulId'], 0936 $options['addPageClassToLi'], 0937 $options['activeClass'], 0938 $options['parentClass'], 0939 $options['renderParentClass'] 0940 ); 0941 } 0942 0943 return $html; 0944 } 0945 0946 /** 0947 * Renders the inner-most sub menu for the active page in the $container 0948 * 0949 * This is a convenience method which is equivalent to the following call: 0950 * <code> 0951 * renderMenu($container, array( 0952 * 'indent' => $indent, 0953 * 'ulClass' => $ulClass, 0954 * 'minDepth' => null, 0955 * 'maxDepth' => null, 0956 * 'onlyActiveBranch' => true, 0957 * 'renderParents' => false 0958 * )); 0959 * </code> 0960 * 0961 * @param Zend_Navigation_Container $container [optional] container to 0962 * render. Default is to render 0963 * the container registered in 0964 * the helper. 0965 * @param string|null $ulClass [optional] CSS class to 0966 * use for UL element. Default 0967 * is to use the value from 0968 * {@link getUlClass()}. 0969 * @param string|int $indent [optional] indentation as 0970 * a string or number of 0971 * spaces. Default is to use 0972 * the value retrieved from 0973 * {@link getIndent()}. 0974 * @param string|null $ulId [optional] Unique identifier 0975 * (id) use for UL element 0976 * @param bool $addPageClassToLi adds CSS class from 0977 * page to li element 0978 * @param string|int $innerIndent [optional] inner 0979 * indentation as a string 0980 * or number of spaces. 0981 * Default is to use the 0982 * {@link getInnerIndent()}. 0983 * @return string rendered content 0984 */ 0985 public function renderSubMenu(Zend_Navigation_Container $container = null, 0986 $ulClass = null, 0987 $indent = null, 0988 $ulId = null, 0989 $addPageClassToLi = false, 0990 $innerIndent = null) 0991 { 0992 return $this->renderMenu($container, array( 0993 'indent' => $indent, 0994 'innerIndent' => $innerIndent, 0995 'ulClass' => $ulClass, 0996 'minDepth' => null, 0997 'maxDepth' => null, 0998 'onlyActiveBranch' => true, 0999 'renderParents' => false, 1000 'ulId' => $ulId, 1001 'addPageClassToLi' => $addPageClassToLi, 1002 )); 1003 } 1004 1005 /** 1006 * Renders the given $container by invoking the partial view helper 1007 * 1008 * The container will simply be passed on as a model to the view script 1009 * as-is, and will be available in the partial script as 'container', e.g. 1010 * <code>echo 'Number of pages: ', count($this->container);</code>. 1011 * 1012 * @param Zend_Navigation_Container $container [optional] container to 1013 * pass to view script. Default 1014 * is to use the container 1015 * registered in the helper. 1016 * @param string|array $partial [optional] partial view 1017 * script to use. Default is to 1018 * use the partial registered 1019 * in the helper. If an array 1020 * is given, it is expected to 1021 * contain two values; the 1022 * partial view script to use, 1023 * and the module where the 1024 * script can be found. 1025 * @return string helper output 1026 * 1027 * @throws Zend_View_Exception When no partial script is set 1028 */ 1029 public function renderPartial(Zend_Navigation_Container $container = null, 1030 $partial = null) 1031 { 1032 if (null === $container) { 1033 $container = $this->getContainer(); 1034 } 1035 1036 if (null === $partial) { 1037 $partial = $this->getPartial(); 1038 } 1039 1040 if (empty($partial)) { 1041 // require_once 'Zend/View/Exception.php'; 1042 $e = new Zend_View_Exception( 1043 'Unable to render menu: No partial view script provided' 1044 ); 1045 $e->setView($this->view); 1046 throw $e; 1047 } 1048 1049 $model = array( 1050 'container' => $container 1051 ); 1052 1053 if (is_array($partial)) { 1054 if (count($partial) != 2) { 1055 // require_once 'Zend/View/Exception.php'; 1056 $e = new Zend_View_Exception( 1057 'Unable to render menu: A view partial supplied as ' 1058 . 'an array must contain two values: partial view ' 1059 . 'script and module where script can be found' 1060 ); 1061 $e->setView($this->view); 1062 throw $e; 1063 } 1064 1065 return $this->view->partial($partial[0], $partial[1], $model); 1066 } 1067 1068 return $this->view->partial($partial, null, $model); 1069 } 1070 1071 // Zend_View_Helper_Navigation_Helper: 1072 1073 /** 1074 * Renders menu 1075 * 1076 * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. 1077 * 1078 * If a partial view is registered in the helper, the menu will be rendered 1079 * using the given partial script. If no partial is registered, the menu 1080 * will be rendered as an 'ul' element by the helper's internal method. 1081 * 1082 * @see renderPartial() 1083 * @see renderMenu() 1084 * 1085 * @param Zend_Navigation_Container $container [optional] container to 1086 * render. Default is to 1087 * render the container 1088 * registered in the helper. 1089 * @return string helper output 1090 */ 1091 public function render(Zend_Navigation_Container $container = null) 1092 { 1093 if ($partial = $this->getPartial()) { 1094 return $this->renderPartial($container, $partial); 1095 } else { 1096 return $this->renderMenu($container); 1097 } 1098 } 1099 }