diff -r bd595ad770fc -r 1c2f13fd785c web/enmi/Zend/View/Helper/Navigation/Menu.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/enmi/Zend/View/Helper/Navigation/Menu.php Thu Jan 20 19:30:54 2011 +0100 @@ -0,0 +1,647 @@ +setContainer($container); + } + + return $this; + } + + // Accessors: + + /** + * Sets CSS class to use for the first 'ul' element when rendering + * + * @param string $ulClass CSS class to set + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setUlClass($ulClass) + { + if (is_string($ulClass)) { + $this->_ulClass = $ulClass; + } + + return $this; + } + + /** + * Returns CSS class to use for the first 'ul' element when rendering + * + * @return string CSS class + */ + public function getUlClass() + { + return $this->_ulClass; + } + + /** + * Sets a flag indicating whether only active branch should be rendered + * + * @param bool $flag [optional] render only active + * branch. Default is true. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setOnlyActiveBranch($flag = true) + { + $this->_onlyActiveBranch = (bool) $flag; + return $this; + } + + /** + * Returns a flag indicating whether only active branch should be rendered + * + * By default, this value is false, meaning the entire menu will be + * be rendered. + * + * @return bool whether only active branch should be rendered + */ + public function getOnlyActiveBranch() + { + return $this->_onlyActiveBranch; + } + + /** + * Enables/disables rendering of parents when only rendering active branch + * + * See {@link setOnlyActiveBranch()} for more information. + * + * @param bool $flag [optional] render parents when + * rendering active branch. + * Default is true. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setRenderParents($flag = true) + { + $this->_renderParents = (bool) $flag; + return $this; + } + + /** + * Returns flag indicating whether parents should be rendered when rendering + * only the active branch + * + * By default, this value is true. + * + * @return bool whether parents should be rendered + */ + public function getRenderParents() + { + return $this->_renderParents; + } + + /** + * Sets which partial view script to use for rendering menu + * + * @param string|array $partial partial view script or null. If + * an array is given, it is + * expected to contain two values; + * the partial view script to use, + * and the module where the script + * can be found. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setPartial($partial) + { + if (null === $partial || is_string($partial) || is_array($partial)) { + $this->_partial = $partial; + } + + return $this; + } + + /** + * Returns partial view script to use for rendering menu + * + * @return string|array|null + */ + public function getPartial() + { + return $this->_partial; + } + + // Public methods: + + /** + * Returns an HTML string containing an 'a' element for the given page if + * the page's href is not empty, and a 'span' element if it is empty + * + * Overrides {@link Zend_View_Helper_Navigation_Abstract::htmlify()}. + * + * @param Zend_Navigation_Page $page page to generate HTML for + * @return string HTML string for the given page + */ + public function htmlify(Zend_Navigation_Page $page) + { + // get label and title for translating + $label = $page->getLabel(); + $title = $page->getTitle(); + + // translate label and title? + if ($this->getUseTranslator() && $t = $this->getTranslator()) { + if (is_string($label) && !empty($label)) { + $label = $t->translate($label); + } + if (is_string($title) && !empty($title)) { + $title = $t->translate($title); + } + } + + // get attribs for element + $attribs = array( + 'id' => $page->getId(), + 'title' => $title, + 'class' => $page->getClass() + ); + + // does page have a href? + if ($href = $page->getHref()) { + $element = 'a'; + $attribs['href'] = $href; + $attribs['target'] = $page->getTarget(); + } else { + $element = 'span'; + } + + return '<' . $element . $this->_htmlAttribs($attribs) . '>' + . $this->view->escape($label) + . ''; + } + + /** + * Normalizes given render options + * + * @param array $options [optional] options to normalize + * @return array normalized options + */ + protected function _normalizeOptions(array $options = array()) + { + if (isset($options['indent'])) { + $options['indent'] = $this->_getWhitespace($options['indent']); + } else { + $options['indent'] = $this->getIndent(); + } + + if (isset($options['ulClass']) && $options['ulClass'] !== null) { + $options['ulClass'] = (string) $options['ulClass']; + } else { + $options['ulClass'] = $this->getUlClass(); + } + + if (array_key_exists('minDepth', $options)) { + if (null !== $options['minDepth']) { + $options['minDepth'] = (int) $options['minDepth']; + } + } else { + $options['minDepth'] = $this->getMinDepth(); + } + + if ($options['minDepth'] < 0 || $options['minDepth'] === null) { + $options['minDepth'] = 0; + } + + if (array_key_exists('maxDepth', $options)) { + if (null !== $options['maxDepth']) { + $options['maxDepth'] = (int) $options['maxDepth']; + } + } else { + $options['maxDepth'] = $this->getMaxDepth(); + } + + if (!isset($options['onlyActiveBranch'])) { + $options['onlyActiveBranch'] = $this->getOnlyActiveBranch(); + } + + if (!isset($options['renderParents'])) { + $options['renderParents'] = $this->getRenderParents(); + } + + return $options; + } + + // Render methods: + + /** + * Renders the deepest active menu within [$minDepth, $maxDeth], (called + * from {@link renderMenu()}) + * + * @param Zend_Navigation_Container $container container to render + * @param array $active active page and depth + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @return string rendered menu + */ + protected function _renderDeepestMenu(Zend_Navigation_Container $container, + $ulClass, + $indent, + $minDepth, + $maxDepth) + { + if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) { + return ''; + } + + // special case if active page is one below minDepth + if ($active['depth'] < $minDepth) { + if (!$active['page']->hasPages()) { + return ''; + } + } else if (!$active['page']->hasPages()) { + // found pages has no children; render siblings + $active['page'] = $active['page']->getParent(); + } else if (is_int($maxDepth) && $active['depth'] +1 > $maxDepth) { + // children are below max depth; render siblings + $active['page'] = $active['page']->getParent(); + } + + $ulClass = $ulClass ? ' class="' . $ulClass . '"' : ''; + $html = $indent . '' . self::EOL; + + foreach ($active['page'] as $subPage) { + if (!$this->accept($subPage)) { + continue; + } + $liClass = $subPage->isActive(true) ? ' class="active"' : ''; + $html .= $indent . ' ' . self::EOL; + $html .= $indent . ' ' . $this->htmlify($subPage) . self::EOL; + $html .= $indent . ' ' . self::EOL; + } + + $html .= $indent . ''; + + return $html; + } + + /** + * Renders a normal menu (called from {@link renderMenu()}) + * + * @param Zend_Navigation_Container $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param bool $onlyActive render only active branch? + * @return string + */ + protected function _renderMenu(Zend_Navigation_Container $container, + $ulClass, + $indent, + $minDepth, + $maxDepth, + $onlyActive) + { + $html = ''; + + // find deepest active + if ($found = $this->findActive($container, $minDepth, $maxDepth)) { + $foundPage = $found['page']; + $foundDepth = $found['depth']; + } else { + $foundPage = null; + } + + // create iterator + $iterator = new RecursiveIteratorIterator($container, + RecursiveIteratorIterator::SELF_FIRST); + if (is_int($maxDepth)) { + $iterator->setMaxDepth($maxDepth); + } + + // iterate container + $prevDepth = -1; + foreach ($iterator as $page) { + $depth = $iterator->getDepth(); + $isActive = $page->isActive(true); + if ($depth < $minDepth || !$this->accept($page)) { + // page is below minDepth or not accepted by acl/visibilty + continue; + } else if ($onlyActive && !$isActive) { + // page is not active itself, but might be in the active branch + $accept = false; + if ($foundPage) { + if ($foundPage->hasPage($page)) { + // accept if page is a direct child of the active page + $accept = true; + } else if ($foundPage->getParent()->hasPage($page)) { + // page is a sibling of the active page... + if (!$foundPage->hasPages() || + is_int($maxDepth) && $foundDepth + 1 > $maxDepth) { + // accept if active page has no children, or the + // children are too deep to be rendered + $accept = true; + } + } + } + + if (!$accept) { + continue; + } + } + + // make sure indentation is correct + $depth -= $minDepth; + $myIndent = $indent . str_repeat(' ', $depth); + + if ($depth > $prevDepth) { + // start new ul tag + if ($ulClass && $depth == 0) { + $ulClass = ' class="' . $ulClass . '"'; + } else { + $ulClass = ''; + } + $html .= $myIndent . '' . self::EOL; + } else if ($prevDepth > $depth) { + // close li/ul tags until we're at current depth + for ($i = $prevDepth; $i > $depth; $i--) { + $ind = $indent . str_repeat(' ', $i); + $html .= $ind . ' ' . self::EOL; + $html .= $ind . '' . self::EOL; + } + // close previous li tag + $html .= $myIndent . ' ' . self::EOL; + } else { + // close previous li tag + $html .= $myIndent . ' ' . self::EOL; + } + + // render li tag and page + $liClass = $isActive ? ' class="active"' : ''; + $html .= $myIndent . ' ' . self::EOL + . $myIndent . ' ' . $this->htmlify($page) . self::EOL; + + // store as previous depth for next iteration + $prevDepth = $depth; + } + + if ($html) { + // done iterating container; close open ul/li tags + for ($i = $prevDepth+1; $i > 0; $i--) { + $myIndent = $indent . str_repeat(' ', $i-1); + $html .= $myIndent . ' ' . self::EOL + . $myIndent . '' . self::EOL; + } + $html = rtrim($html, self::EOL); + } + + return $html; + } + + /** + * Renders helper + * + * Renders a HTML 'ul' for the given $container. If $container is not given, + * the container registered in the helper will be used. + * + * Available $options: + * + * + * @param Zend_Navigation_Container $container [optional] container to + * create menu from. Default + * is to use the container + * retrieved from + * {@link getContainer()}. + * @param array $options [optional] options for + * controlling rendering + * @return string rendered menu + */ + public function renderMenu(Zend_Navigation_Container $container = null, + array $options = array()) + { + if (null === $container) { + $container = $this->getContainer(); + } + + $options = $this->_normalizeOptions($options); + + if ($options['onlyActiveBranch'] && !$options['renderParents']) { + $html = $this->_renderDeepestMenu($container, + $options['ulClass'], + $options['indent'], + $options['minDepth'], + $options['maxDepth']); + } else { + $html = $this->_renderMenu($container, + $options['ulClass'], + $options['indent'], + $options['minDepth'], + $options['maxDepth'], + $options['onlyActiveBranch']); + } + + return $html; + } + + /** + * Renders the inner-most sub menu for the active page in the $container + * + * This is a convenience method which is equivalent to the following call: + * + * renderMenu($container, array( + * 'indent' => $indent, + * 'ulClass' => $ulClass, + * 'minDepth' => null, + * 'maxDepth' => null, + * 'onlyActiveBranch' => true, + * 'renderParents' => false + * )); + * + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to render + * the container registered in + * the helper. + * @param string $ulClass [optional] CSS class to + * use for UL element. Default + * is to use the value from + * {@link getUlClass()}. + * @param string|int $indent [optional] indentation as + * a string or number of + * spaces. Default is to use + * the value retrieved from + * {@link getIndent()}. + * @return string rendered content + */ + public function renderSubMenu(Zend_Navigation_Container $container = null, + $ulClass = null, + $indent = null) + { + return $this->renderMenu($container, array( + 'indent' => $indent, + 'ulClass' => $ulClass, + 'minDepth' => null, + 'maxDepth' => null, + 'onlyActiveBranch' => true, + 'renderParents' => false + )); + } + + /** + * Renders the given $container by invoking the partial view helper + * + * The container will simply be passed on as a model to the view script + * as-is, and will be available in the partial script as 'container', e.g. + * echo 'Number of pages: ', count($this->container);. + * + * @param Zend_Navigation_Container $container [optional] container to + * pass to view script. Default + * is to use the container + * registered in the helper. + * @param string|array $partial [optional] partial view + * script to use. Default is to + * use the partial registered + * in the helper. If an array + * is given, it is expected to + * contain two values; the + * partial view script to use, + * and the module where the + * script can be found. + * @return string helper output + */ + public function renderPartial(Zend_Navigation_Container $container = null, + $partial = null) + { + if (null === $container) { + $container = $this->getContainer(); + } + + if (null === $partial) { + $partial = $this->getPartial(); + } + + if (empty($partial)) { + require_once 'Zend/View/Exception.php'; + $e = new Zend_View_Exception( + 'Unable to render menu: No partial view script provided' + ); + $e->setView($this->view); + throw $e; + } + + $model = array( + 'container' => $container + ); + + if (is_array($partial)) { + if (count($partial) != 2) { + require_once 'Zend/View/Exception.php'; + $e = new Zend_View_Exception( + 'Unable to render menu: A view partial supplied as ' + . 'an array must contain two values: partial view ' + . 'script and module where script can be found' + ); + $e->setView($this->view); + throw $e; + } + + return $this->view->partial($partial[0], $partial[1], $model); + } + + return $this->view->partial($partial, null, $model); + } + + // Zend_View_Helper_Navigation_Helper: + + /** + * Renders menu + * + * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. + * + * If a partial view is registered in the helper, the menu will be rendered + * using the given partial script. If no partial is registered, the menu + * will be rendered as an 'ul' element by the helper's internal method. + * + * @see renderPartial() + * @see renderMenu() + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + */ + public function render(Zend_Navigation_Container $container = null) + { + if ($partial = $this->getPartial()) { + return $this->renderPartial($container, $partial); + } else { + return $this->renderMenu($container); + } + } +}