diff options
Diffstat (limited to 'library/Icinga/Web/Widget/Tabs.php')
-rw-r--r-- | library/Icinga/Web/Widget/Tabs.php | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php new file mode 100644 index 0000000..9efa423 --- /dev/null +++ b/library/Icinga/Web/Widget/Tabs.php @@ -0,0 +1,453 @@ +<?php +/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Web\Widget; + +use Exception; +use Icinga\Exception\Http\HttpNotFoundException; +use Icinga\Exception\ProgrammingError; +use Icinga\Web\Url; +use Icinga\Web\Widget\Tabextension\Tabextension; +use Icinga\Application\Icinga; +use Countable; + +/** + * Navigation tab widget + */ +class Tabs extends AbstractWidget implements Countable +{ + /** + * Template used for the base tabs + * + * @var string + */ + private $baseTpl = <<< 'EOT' +<ul class="tabs primary-nav nav"> + {TABS} + {DROPDOWN} + {REFRESH} + {CLOSE} +</ul> +EOT; + + /** + * Template used for the tabs dropdown + * + * @var string + */ + private $dropdownTpl = <<< 'EOT' +<li class="dropdown-nav-item"> + <a href="#" class="dropdown-toggle" title="{TITLE}" aria-label="{TITLE}"> + <i aria-hidden="true" class="icon-down-open"></i> + </a> + <ul class="nav"> + {TABS} + </ul> +</li> +EOT; + + /** + * Template used for the close-button + * + * @var string + */ + private $closeTpl = <<< 'EOT' +<li class="close-container-btn"> + <a href="#" title="{TITLE}" aria-label="{TITLE}" class="close-container-control"> + <i aria-hidden="true" class="icon-cancel"></i> + </a> +</li> +EOT; + + /** + * Template used for the refresh icon + * + * @var string + */ + private $refreshTpl = <<< 'EOT' +<li> + <a class="refresh-container-control spinner" href="{URL}" title="{TITLE}" aria-label="{LABEL}"> + <i aria-hidden="true" class="icon-cw"></i> + </a> +</li> +EOT; + + /** + * This is where single tabs added to this container will be stored + * + * @var array + */ + private $tabs = array(); + + /** + * The name of the currently activated tab + * + * @var string + */ + private $active; + + /** + * Array of tab names which should be displayed in a dropdown + * + * @var array + */ + private $dropdownTabs = array(); + + /** + * Whether only the close-button should by rendered for this tab + * + * @var bool + */ + private $closeButtonOnly = false; + + /** + * Whether the tabs should contain a close-button + * + * @var bool + */ + private $closeTab = true; + + /** + * CSS class name(s) for the <ul> element + * + * @var string + */ + private $tab_class; + + /** + * Set whether the current tab is closable + */ + public function hideCloseButton() + { + $this->closeTab = false; + } + + /** + * Activate the tab with the given name + * + * If another tab is currently active it will be deactivated + * + * @param string $name Name of the tab going to be activated + * + * @return $this + * + * @throws HttpNotFoundException When the tab w/ the given name does not exist + * + */ + public function activate($name) + { + if (! $this->has($name)) { + throw new HttpNotFoundException('Can\'t activate tab %s. Tab does not exist', $name); + } + + if ($this->active !== null) { + $this->tabs[$this->active]->setActive(false); + } + $this->get($name)->setActive(); + $this->active = $name; + + return $this; + } + + /** + * Return the name of the active tab + * + * @return string + */ + public function getActiveName() + { + return $this->active; + } + + /** + * Set the CSS class name(s) for the <ul> element + * + * @param string $name CSS class name(s) + * + * @return $this + */ + public function setClass($name) + { + $this->tab_class = $name; + return $this; + } + + /** + * Whether the given tab name exists + * + * @param string $name Tab name + * + * @return bool + */ + public function has($name) + { + return array_key_exists($name, $this->tabs); + } + + /** + * Whether the given tab name exists + * + * @param string $name The tab you're interested in + * + * @return Tab + * + * @throws ProgrammingError When the given tab name doesn't exist + */ + public function get($name) + { + if (!$this->has($name)) { + return null; + } + return $this->tabs[$name]; + } + + /** + * Add a new tab + * + * A unique tab name is required, the Tab itself can either be an array + * with tab properties or an instance of an existing Tab + * + * @param string $name The new tab name + * @param array|Tab $tab The tab itself of its properties + * + * @return $this + * + * @throws ProgrammingError When the tab name already exists + */ + public function add($name, $tab) + { + if ($this->has($name)) { + throw new ProgrammingError( + 'Cannot add a tab named "%s" twice"', + $name + ); + } + return $this->set($name, $tab); + } + + /** + * Set a tab + * + * A unique tab name is required, will be replaced in case it already + * exists. The tab can either be an array with tab properties or an instance + * of an existing Tab + * + * @param string $name The new tab name + * @param array|Tab $tab The tab itself of its properties + * + * @return $this + */ + public function set($name, $tab) + { + if ($tab instanceof Tab) { + $this->tabs[$name] = $tab; + } else { + $this->tabs[$name] = new Tab($tab + array('name' => $name)); + } + return $this; + } + + /** + * Remove a tab + * + * @param string $name + * + * @return $this + */ + public function remove($name) + { + if ($this->has($name)) { + unset($this->tabs[$name]); + if (($dropdownIndex = array_search($name, $this->dropdownTabs, true)) !== false) { + array_splice($this->dropdownTabs, $dropdownIndex, 1); + } + } + + return $this; + } + + /** + * Add a tab to the dropdown on the right side of the tab-bar. + * + * @param $name + * @param $tab + */ + public function addAsDropdown($name, $tab) + { + $this->set($name, $tab); + $this->dropdownTabs[] = $name; + $this->dropdownTabs = array_unique($this->dropdownTabs); + } + + /** + * Render the dropdown area with its tabs and return the resulting HTML + * + * @return mixed|string + */ + private function renderDropdownTabs() + { + if (empty($this->dropdownTabs)) { + return ''; + } + $tabs = ''; + foreach ($this->dropdownTabs as $tabname) { + $tab = $this->get($tabname); + if ($tab === null) { + continue; + } + $tabs .= $tab; + } + return str_replace(array('{TABS}', '{TITLE}'), array($tabs, t('Dropdown menu')), $this->dropdownTpl); + } + + /** + * Render all tabs, except the ones in dropdown area and return the resulting HTML + * + * @return string + */ + private function renderTabs() + { + $tabs = ''; + foreach ($this->tabs as $name => $tab) { + // ignore tabs added to dropdown + if (in_array($name, $this->dropdownTabs)) { + continue; + } + $tabs .= $tab; + } + return $tabs; + } + + private function renderCloseTab() + { + return str_replace('{TITLE}', t('Close container'), $this->closeTpl); + } + + private function renderRefreshTab() + { + $url = Url::fromRequest(); + $tab = $this->get($this->getActiveName()); + + if ($tab !== null) { + $label = $this->view()->escape( + $tab->getLabel() + ); + } + + if (! empty($label)) { + $caption = $label; + } else { + $caption = t('Content'); + } + + $label = sprintf(t('Refresh the %s'), $caption); + $title = $label; + + $tpl = str_replace( + array( + '{URL}', + '{TITLE}', + '{LABEL}' + ), + array( + $this->view()->escape($url->getAbsoluteUrl()), + $title, + $label + ), + $this->refreshTpl + ); + + return $tpl; + } + + /** + * Render to HTML + * + * @see Widget::render + */ + public function render() + { + if (empty($this->tabs) || true === $this->closeButtonOnly) { + $tabs = ''; + $drop = ''; + } else { + $tabs = $this->renderTabs(); + $drop = $this->renderDropdownTabs(); + } + $close = $this->closeTab ? $this->renderCloseTab() : ''; + $refresh = $this->renderRefreshTab(); + + return str_replace( + array( + '{TABS}', + '{DROPDOWN}', + '{REFRESH}', + '{CLOSE}' + ), + array( + $tabs, + $drop, + $refresh, + $close + ), + $this->baseTpl + ); + } + + public function __toString() + { + try { + $html = $this->render(); + } catch (Exception $e) { + return htmlspecialchars($e->getMessage()); + } + return $html; + } + + /** + * Return the number of tabs + * + * @return int + * + * @see Countable + */ + public function count(): int + { + return count($this->tabs); + } + + /** + * Return all tabs contained in this tab panel + * + * @return array + */ + public function getTabs() + { + return $this->tabs; + } + + /** + * Whether to hide all elements except of the close button + * + * @param bool $value + * @return Tabs fluent interface + */ + public function showOnlyCloseButton($value = true) + { + $this->closeButtonOnly = $value; + return $this; + } + + /** + * Apply a Tabextension on this tabs object + * + * @param Tabextension $tabextension + * + * @return $this + */ + public function extend(Tabextension $tabextension) + { + $tabextension->apply($this); + return $this; + } +} |