diff --git a/application/controllers/LayoutController.php b/application/controllers/LayoutController.php index 929c64109..2d1abfb72 100644 --- a/application/controllers/LayoutController.php +++ b/application/controllers/LayoutController.php @@ -2,6 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} +use Icinga\Web\MenuRenderer; use Icinga\Web\Controller\ActionController; use Icinga\Web\Hook; use Icinga\Web\Menu; @@ -17,9 +18,7 @@ class LayoutController extends ActionController */ public function menuAction() { - $this->view->url = Url::fromRequest()->getRelativeUrl(); - $this->view->items = Menu::fromConfig()->getChildren(); - $this->view->sub = false; + $this->view->menuRenderer = new MenuRenderer(Menu::fromConfig()->order(), Url::fromRequest()->getRelativeUrl()); } /** diff --git a/application/layouts/scripts/parts/menu.phtml b/application/layouts/scripts/parts/menu.phtml deleted file mode 100644 index 7a4f84ef3..000000000 --- a/application/layouts/scripts/parts/menu.phtml +++ /dev/null @@ -1,33 +0,0 @@ -level) { - $this->level = 0; -} -?> -level === 0 ? ' role="navigation"' : '' ?>> -items as $item) { - - printf( - ' %s%s', - $this->href($this->url) === $this->href($item->getUrl()) ? ' class="active"' : '', - $item->getUrl() ? $this->href($item->getUrl()) : '#', - $item->getIcon() ? $this->img( - $item->getIcon(), - array('class' => 'icon') - ) . ' ' : '', - $this->escape($item->getTitle()) - ); - - if ($item->hasChildren()) { - echo $this->partial( - 'parts/menu.phtml', - array('items' => $item->getChildren(), 'url' => $this->url, 'level' => $this->level + 1) - ); - } - - echo "\n"; -} - -?> - diff --git a/application/layouts/scripts/parts/navigation.phtml b/application/layouts/scripts/parts/navigation.phtml index 106296173..c689db54a 100644 --- a/application/layouts/scripts/parts/navigation.phtml +++ b/application/layouts/scripts/parts/navigation.phtml @@ -2,22 +2,17 @@ use Icinga\Web\Url; use Icinga\Web\Menu; +use Icinga\Web\MenuRenderer; // Don't render a menu for unauthenticated users unless menu is auth aware if (! $this->auth()->isAuthenticated()) { return; } -// Current url -$url = Url::fromRequest()->getRelativeUrl(); -$menu = Menu::fromConfig(); ?> diff --git a/application/views/scripts/layout/menu.phtml b/application/views/scripts/layout/menu.phtml index 889076fc4..4e825777c 100644 --- a/application/views/scripts/layout/menu.phtml +++ b/application/views/scripts/layout/menu.phtml @@ -1,39 +1 @@ - + \ No newline at end of file diff --git a/library/Icinga/Web/MenuRenderer.php b/library/Icinga/Web/MenuRenderer.php new file mode 100644 index 000000000..950543fcd --- /dev/null +++ b/library/Icinga/Web/MenuRenderer.php @@ -0,0 +1,151 @@ +url = $url; + parent::__construct($menu, RecursiveIteratorIterator::CHILD_FIRST); + } + + /** + * Register the outer ul opening html-tag + */ + public function beginIteration() + { + $this->tags[] = ''; + } + + /** + * Register a inner ul opening html-tag + */ + public function beginChildren() + { + // The iterator runs in mode CHILD_FIRST so we need to remember + // where to insert the parent's opening html tag once its rendered + $parent = $this->getSubIterator(0)->current(); + $this->tags[$parent->getId() . '_begin'] = null; + + $this->tags[] = ''; + + // Remember the position of the parent's closing html-tag + $parent = $this->getSubIterator(0)->current(); + $this->tags[$parent->getId() . '_end'] = null; + } + + /** + * Render the given child + * + * @param Menu $child The menu's child to render + * + * @return string The child rendered as html + */ + public function renderChild(Menu $child) + { + return sprintf( + '%s%s', + $child->getUrl() ? Url::fromPath($child->getUrl()) : '#', + $child->getIcon() ? ' ' : '', + htmlspecialchars($child->getTitle()) + ); + } + + /** + * Return the menu rendered as html + * + * @return string + */ + public function render() + { + $passedActiveChild = false; + foreach ($this as $child) { + $childIsActive = $this->isActive($child); + if ($childIsActive && $this->getDepth() > 0) { + $passedActiveChild = true; + } + + if ($childIsActive || ($passedActiveChild && $this->getDepth() === 0)) { + $passedActiveChild &= $this->getDepth() !== 0; + $openTag = '
  • '; + } else { + $openTag = '
  • '; + } + $content = $this->renderChild($child); + $closingTag = '
  • '; + + if (array_key_exists($child->getId() . '_begin', $this->tags)) { + $this->tags[$child->getId() . '_begin'] = $openTag . $content; + $this->tags[$child->getId() . '_end'] = $closingTag; + } else { + $this->tags[] = $openTag . $content . $closingTag; + } + } + + return implode("\n", $this->tags); + } + + /** + * @see MenuRenderer::render() + */ + public function __toString() + { + return $this->render(); + } + + /** + * Return whether the current request url references the child's url + * + * @param Menu $child The menu's child to check + * + * @return bool + */ + protected function isActive(Menu $child) + { + return html_entity_decode(rawurldecode($this->url)) === html_entity_decode(rawurldecode($child->getUrl())); + } +}