diff options
Diffstat (limited to 'library/Icinga/Web/Navigation/Renderer/NavigationRenderer.php')
-rw-r--r-- | library/Icinga/Web/Navigation/Renderer/NavigationRenderer.php | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/library/Icinga/Web/Navigation/Renderer/NavigationRenderer.php b/library/Icinga/Web/Navigation/Renderer/NavigationRenderer.php new file mode 100644 index 0000000..00c0f9a --- /dev/null +++ b/library/Icinga/Web/Navigation/Renderer/NavigationRenderer.php @@ -0,0 +1,356 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Web\Navigation\Renderer; + +use ArrayIterator; +use Exception; +use RecursiveIterator; +use Icinga\Application\Icinga; +use Icinga\Exception\IcingaException; +use Icinga\Web\Navigation\Navigation; +use Icinga\Web\Navigation\NavigationItem; +use Icinga\Web\View; + +/** + * Renderer for single level navigation + */ +class NavigationRenderer implements RecursiveIterator, NavigationRendererInterface +{ + /** + * The tag used for the outer element + * + * @var string + */ + protected $elementTag; + + /** + * The CSS class used for the outer element + * + * @var string + */ + protected $cssClass; + + /** + * The navigation's heading text + * + * @var string + */ + protected $heading; + + /** + * The content rendered so far + * + * @var array + */ + protected $content; + + /** + * Whether to skip rendering the outer element + * + * @var bool + */ + protected $skipOuterElement; + + /** + * The navigation's iterator + * + * @var ArrayIterator + */ + protected $iterator; + + /** + * The navigation + * + * @var Navigation + */ + protected $navigation; + + /** + * View + * + * @var View + */ + protected $view; + + /** + * Create a new NavigationRenderer + * + * @param Navigation $navigation + * @param bool $skipOuterElement + */ + public function __construct(Navigation $navigation, $skipOuterElement = false) + { + $this->skipOuterElement = $skipOuterElement; + $this->iterator = $navigation->getIterator(); + $this->navigation = $navigation; + $this->content = array(); + } + + /** + * {@inheritdoc} + */ + public function setElementTag($tag) + { + $this->elementTag = $tag; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getElementTag() + { + return $this->elementTag ?: static::OUTER_ELEMENT_TAG; + } + + /** + * {@inheritdoc} + */ + public function setCssClass($class) + { + $this->cssClass = $class; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCssClass() + { + return $this->cssClass; + } + + /** + * {@inheritdoc} + */ + public function setHeading($heading) + { + $this->heading = $heading; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getHeading() + { + return $this->heading; + } + + /** + * Return the view + * + * @return View + */ + public function view() + { + if ($this->view === null) { + $this->setView(Icinga::app()->getViewRenderer()->view); + } + + return $this->view; + } + + /** + * Set the view + * + * @param View $view + * + * @return $this + */ + public function setView(View $view) + { + $this->view = $view; + return $this; + } + + public function getChildren(): NavigationRenderer + { + return new static($this->current()->getChildren(), $this->skipOuterElement); + } + + public function hasChildren(): bool + { + return $this->current()->hasChildren(); + } + + public function current(): NavigationItem + { + return $this->iterator->current(); + } + + public function key(): int + { + return $this->iterator->key(); + } + + public function next(): void + { + $this->iterator->next(); + } + + public function rewind(): void + { + $this->iterator->rewind(); + if (! $this->skipOuterElement) { + $this->content[] = $this->beginMarkup(); + } + } + + public function valid(): bool + { + $valid = $this->iterator->valid(); + if (! $this->skipOuterElement && !$valid) { + $this->content[] = $this->endMarkup(); + } + + return $valid; + } + + /** + * Return the opening markup for the navigation + * + * @return string + */ + public function beginMarkup() + { + $content = array(); + $content[] = sprintf( + '<%s%s role="navigation">', + $this->getElementTag(), + $this->getCssClass() !== null ? ' class="' . $this->getCssClass() . '"' : '' + ); + if (($heading = $this->getHeading()) !== null) { + $content[] = sprintf( + '<h%1$d id="navigation" class="sr-only" tabindex="-1">%2$s</h%1$d>', + static::HEADING_RANK, + $this->view()->escape($heading) + ); + } + $content[] = $this->beginChildrenMarkup(); + return join("\n", $content); + } + + /** + * Return the closing markup for the navigation + * + * @return string + */ + public function endMarkup() + { + $content = array(); + $content[] = $this->endChildrenMarkup(); + $content[] = '</' . $this->getElementTag() . '>'; + return join("\n", $content); + } + + /** + * Return the opening markup for multiple navigation items + * + * @param int $level + * + * @return string + */ + public function beginChildrenMarkup($level = 1) + { + $cssClass = array(static::CSS_CLASS_NAV); + if ($this->navigation->getLayout() === Navigation::LAYOUT_TABS) { + $cssClass[] = static::CSS_CLASS_NAV_TABS; + } elseif ($this->navigation->getLayout() === Navigation::LAYOUT_DROPDOWN) { + $cssClass[] = static::CSS_CLASS_NAV_DROPDOWN; + } + + $cssClass[] = 'nav-level-' . $level; + + return '<ul class="' . join(' ', $cssClass) . '">'; + } + + /** + * Return the closing markup for multiple navigation items + * + * @return string + */ + public function endChildrenMarkup() + { + return '</ul>'; + } + + /** + * Return the opening markup for the given navigation item + * + * @param NavigationItem $item + * + * @return string + */ + public function beginItemMarkup(NavigationItem $item) + { + $cssClasses = array(static::CSS_CLASS_ITEM); + + if ($item->hasChildren() && $item->getChildren()->getLayout() === Navigation::LAYOUT_DROPDOWN) { + $cssClasses[] = static::CSS_CLASS_DROPDOWN; + $item + ->setAttribute('class', static::CSS_CLASS_DROPDOWN_TOGGLE) + ->setIcon(static::DROPDOWN_TOGGLE_ICON) + ->setUrl('#'); + } + + if ($item->getActive()) { + $cssClasses[] = static::CSS_CLASS_ACTIVE; + } + + if ($item->getSelected()) { + $cssClasses[] = static::CSS_CLASS_SELECTED; + } + + if ($cssClass = $item->getCssClass()) { + $cssClasses[] = $cssClass; + } + + $content = sprintf( + '<li class="%s">', + join(' ', $cssClasses) + ); + return $content; + } + + /** + * Return the closing markup for a navigation item + * + * @return string + */ + public function endItemMarkup() + { + return '</li>'; + } + + /** + * {@inheritdoc} + */ + public function render() + { + foreach ($this as $item) { + /** @var NavigationItem $item */ + if ($item->shouldRender()) { + $content = $item->render(); + $this->content[] = $this->beginItemMarkup($item); + $this->content[] = $content; + $this->content[] = $this->endItemMarkup(); + } + } + + return join("\n", $this->content); + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + try { + return $this->render(); + } catch (Exception $e) { + return IcingaException::describe($e); + } + } +} |