Merge pull request #4697 from Icinga/feature/redesigned-user-menu-new
Feature/redesigned user menu
This commit is contained in:
commit
74022ae4e0
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Web\Navigation\ConfigMenu;
|
||||
use Icinga\Web\Widget\SearchDashboard;
|
||||
|
||||
$searchDashboard = new SearchDashboard();
|
||||
|
@ -14,3 +15,6 @@ if ($searchDashboard->search('dummy')->getPane('search')->hasDashlets()): ?>
|
|||
</form>
|
||||
<?php endif; ?>
|
||||
<?= $menuRenderer->setCssClass('primary-nav')->setElementTag('nav')->setHeading(t('Navigation')); ?>
|
||||
<nav class="config-menu">
|
||||
<?= new ConfigMenu() ?>
|
||||
</nav>
|
||||
|
|
|
@ -33,6 +33,7 @@ class Menu extends Navigation
|
|||
'priority' => 10
|
||||
]);
|
||||
$this->addItem('system', [
|
||||
'cssClass' => 'system-nav-item',
|
||||
'label' => t('System'),
|
||||
'icon' => 'services',
|
||||
'priority' => 700,
|
||||
|
@ -74,6 +75,7 @@ class Menu extends Navigation
|
|||
]
|
||||
]);
|
||||
$this->addItem('configuration', [
|
||||
'cssClass' => 'configuration-nav-item',
|
||||
'label' => t('Configuration'),
|
||||
'icon' => 'wrench',
|
||||
'permission' => 'config/*',
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Navigation;
|
||||
|
||||
use Icinga\Application\Hook\HealthHook;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Authentication\Auth;
|
||||
use ipl\Html\Attributes;
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\Text;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\Icon;
|
||||
use ipl\Web\Widget\StateBadge;
|
||||
|
||||
class ConfigMenu extends BaseHtmlElement
|
||||
{
|
||||
const STATE_OK = 'ok';
|
||||
const STATE_CRITICAL = 'critical';
|
||||
const STATE_WARNING = 'warning';
|
||||
const STATE_PENDING = 'pending';
|
||||
const STATE_UNKNOWN = 'unknown';
|
||||
|
||||
protected $tag = 'ul';
|
||||
|
||||
protected $defaultAttributes = ['class' => 'nav'];
|
||||
|
||||
protected $children;
|
||||
|
||||
protected $selected;
|
||||
|
||||
protected $cogItemActive = false;
|
||||
|
||||
protected $state;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = [
|
||||
'system' => [
|
||||
'title' => t('System'),
|
||||
'items' => [
|
||||
'about' => [
|
||||
'label' => t('About'),
|
||||
'url' => 'about'
|
||||
],
|
||||
'health' => [
|
||||
'label' => t('Health'),
|
||||
'url' => 'health',
|
||||
],
|
||||
'announcements' => [
|
||||
'label' => t('Announcements'),
|
||||
'url' => 'announcements'
|
||||
],
|
||||
'sessions' => [
|
||||
'label' => t('User Sessions'),
|
||||
'permission' => 'application/sessions',
|
||||
'url' => 'manage-user-devices'
|
||||
]
|
||||
]
|
||||
],
|
||||
'configuration' => [
|
||||
'title' => t('Configuration'),
|
||||
'permission' => 'config/*',
|
||||
'items' => [
|
||||
'application' => [
|
||||
'label' => t('Application'),
|
||||
'url' => 'config/general'
|
||||
],
|
||||
'authentication' => [
|
||||
'label' => t('Access Control'),
|
||||
'permission' => 'config/access-control/*',
|
||||
'url' => 'role/list'
|
||||
],
|
||||
'navigation' => [
|
||||
'label' => t('Shared Navigation'),
|
||||
'permission' => 'config/navigation',
|
||||
'url' => 'navigation'
|
||||
],
|
||||
'modules' => [
|
||||
'label' => t('Modules'),
|
||||
'permission' => 'config/modules',
|
||||
'url' => 'config/modules'
|
||||
]
|
||||
]
|
||||
],
|
||||
'logout' => [
|
||||
'items' => [
|
||||
'logout' => [
|
||||
'label' => t('Logout'),
|
||||
'atts' => [
|
||||
'target' => '_self',
|
||||
'class' => 'nav-item-logout'
|
||||
],
|
||||
'url' => 'authentication/logout'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
protected function assembleUserMenuItem(BaseHtmlElement $userMenuItem)
|
||||
{
|
||||
$username = Auth::getInstance()->getUser()->getUsername();
|
||||
|
||||
$userMenuItem->add(
|
||||
new HtmlElement(
|
||||
'a',
|
||||
Attributes::create(['href' => Url::fromPath('account')]),
|
||||
new HtmlElement(
|
||||
'i',
|
||||
Attributes::create(['class' => 'user-ball']),
|
||||
Text::create($username[0])
|
||||
),
|
||||
Text::create($username)
|
||||
)
|
||||
);
|
||||
|
||||
if (Icinga::app()->getRequest()->getUrl()->matches('account')) {
|
||||
$userMenuItem->addAttributes(['class' => 'selected active']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function assembleCogMenuItem($cogMenuItem)
|
||||
{
|
||||
$cogMenuItem->add([
|
||||
HtmlElement::create(
|
||||
'button',
|
||||
null,
|
||||
[
|
||||
new Icon('cog'),
|
||||
$this->createHealthBadge(),
|
||||
]
|
||||
),
|
||||
$this->createLevel2Menu()
|
||||
]);
|
||||
|
||||
if ($this->cogItemActive) {
|
||||
$cogMenuItem->addAttributes([ 'class' => 'active' ]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function assembleLevel2Nav(BaseHtmlElement $level2Nav)
|
||||
{
|
||||
$navContent = HtmlElement::create('div', ['class' => 'flyout-content']);
|
||||
foreach ($this->children as $c) {
|
||||
if (isset($c['permission']) && ! Auth::getInstance()->hasPermission($c['permission'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($c['title'])) {
|
||||
$navContent->add(HtmlElement::create(
|
||||
'h3',
|
||||
null,
|
||||
$c['title']
|
||||
));
|
||||
}
|
||||
|
||||
$ul = HtmlElement::create('ul', ['class' => 'nav']);
|
||||
foreach ($c['items'] as $key => $item) {
|
||||
$ul->add($this->createLevel2MenuItem($item, $key));
|
||||
}
|
||||
|
||||
$navContent->add($ul);
|
||||
}
|
||||
|
||||
$level2Nav->add($navContent);
|
||||
}
|
||||
|
||||
protected function getHealthCount()
|
||||
{
|
||||
$count = 0;
|
||||
$title = null;
|
||||
$worstState = null;
|
||||
foreach (HealthHook::collectHealthData()->select() as $result) {
|
||||
if ($worstState === null || $result->state > $worstState) {
|
||||
$worstState = $result->state;
|
||||
$title = $result->message;
|
||||
$count = 1;
|
||||
} elseif ($worstState === $result->state) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($worstState) {
|
||||
case HealthHook::STATE_OK:
|
||||
$count = 0;
|
||||
break;
|
||||
case HealthHook::STATE_WARNING:
|
||||
$this->state = self::STATE_WARNING;
|
||||
break;
|
||||
case HealthHook::STATE_CRITICAL:
|
||||
$this->state = self::STATE_CRITICAL;
|
||||
break;
|
||||
case HealthHook::STATE_UNKNOWN:
|
||||
$this->state = self::STATE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->title = $title;
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
protected function isSelectedItem($item)
|
||||
{
|
||||
if ($item !== null && Icinga::app()->getRequest()->getUrl()->matches($item['url'])) {
|
||||
$this->selected = $item;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function createHealthBadge()
|
||||
{
|
||||
$stateBadge = null;
|
||||
if ($this->getHealthCount() > 0) {
|
||||
$stateBadge = new StateBadge($this->getHealthCount(), $this->state);
|
||||
$stateBadge->addAttributes(['class' => 'disabled']);
|
||||
}
|
||||
|
||||
return $stateBadge;
|
||||
}
|
||||
|
||||
protected function createLevel2Menu()
|
||||
{
|
||||
$level2Nav = HtmlElement::create(
|
||||
'div',
|
||||
Attributes::create(['class' => 'nav-level-1 flyout'])
|
||||
);
|
||||
|
||||
$this->assembleLevel2Nav($level2Nav);
|
||||
|
||||
return $level2Nav;
|
||||
}
|
||||
|
||||
protected function createLevel2MenuItem($item, $key)
|
||||
{
|
||||
if (isset($item['permission']) && ! Auth::getInstance()->hasPermission($item['permission'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$healthBadge = null;
|
||||
$class = null;
|
||||
if ($key === 'health') {
|
||||
$class = 'badge-nav-item';
|
||||
$healthBadge = $this->createHealthBadge();
|
||||
}
|
||||
|
||||
$li = HtmlElement::create(
|
||||
'li',
|
||||
isset($item['atts']) ? $item['atts'] : [],
|
||||
[
|
||||
HtmlElement::create(
|
||||
'a',
|
||||
Attributes::create(['href' => $item['url']]),
|
||||
[
|
||||
$item['label'],
|
||||
isset($healthBadge) ? $healthBadge : ''
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
$li->addAttributes(['class' => $class]);
|
||||
|
||||
if ($this->isSelectedItem($item)) {
|
||||
$li->addAttributes(['class' => 'selected']);
|
||||
$this->cogItemActive = true;
|
||||
}
|
||||
|
||||
return $li;
|
||||
}
|
||||
|
||||
protected function createUserMenuItem()
|
||||
{
|
||||
$userMenuItem = HtmlElement::create('li', ['class' => 'user-nav-item']);
|
||||
|
||||
$this->assembleUserMenuItem($userMenuItem);
|
||||
|
||||
return $userMenuItem;
|
||||
}
|
||||
|
||||
protected function createCogMenuItem()
|
||||
{
|
||||
$cogMenuItem = HtmlElement::create('li', ['class' => 'config-nav-item']);
|
||||
|
||||
$this->assembleCogMenuItem($cogMenuItem);
|
||||
|
||||
return $cogMenuItem;
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$this->add([
|
||||
$this->createUserMenuItem(),
|
||||
$this->createCogMenuItem()
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -97,7 +97,13 @@ abstract class BadgeNavigationItemRenderer extends NavigationItemRenderer
|
|||
if ($item === null) {
|
||||
$item = $this->getItem();
|
||||
}
|
||||
$item->setCssClass('badge-nav-item');
|
||||
|
||||
$cssClass = '';
|
||||
if ($item->getCssClass() !== null) {
|
||||
$cssClass = ' ' . $item->getCssClass();
|
||||
}
|
||||
|
||||
$item->setCssClass('badge-nav-item' . $cssClass);
|
||||
$this->setEscapeLabel(false);
|
||||
$label = $this->view()->escape($item->getLabel());
|
||||
$item->setLabel($this->renderBadge() . $label);
|
||||
|
|
|
@ -56,6 +56,7 @@ class StyleSheet
|
|||
'css/vendor/normalize.css',
|
||||
'css/icinga/base.less',
|
||||
'css/icinga/badges.less',
|
||||
'css/icinga/configmenu.less',
|
||||
'css/icinga/mixins.less',
|
||||
'css/icinga/grid.less',
|
||||
'css/icinga/nav.less',
|
||||
|
|
|
@ -289,18 +289,6 @@ $section = $this->menuSection(N_('Reporting'), array(
|
|||
'priority' => 100
|
||||
));
|
||||
|
||||
/*
|
||||
* System Section
|
||||
*/
|
||||
$section = $this->menuSection(N_('System'));
|
||||
$section->add(N_('Monitoring Health'), array(
|
||||
'icon' => 'check',
|
||||
'description' => $this->translate('Open monitoring health'),
|
||||
'url' => 'monitoring/health/info',
|
||||
'priority' => 720,
|
||||
'renderer' => 'BackendAvailabilityNavigationItemRenderer'
|
||||
));
|
||||
|
||||
/*
|
||||
* Current Incidents
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
#menu {
|
||||
margin-bottom: 3em;
|
||||
}
|
||||
|
||||
.sidebar-collapsed #menu {
|
||||
margin-bottom: 8em;
|
||||
}
|
||||
|
||||
#menu .config-menu {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: @menu-bg-color;
|
||||
margin-top: auto;
|
||||
|
||||
> ul {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0;
|
||||
|
||||
> li {
|
||||
> a {
|
||||
padding: 0.5em 0.5em 0.5em 0.75em;
|
||||
line-height: 2.167em;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
|
||||
}
|
||||
|
||||
&:hover .nav-level-1 {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
li.active a:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user-nav-item {
|
||||
width: 100%;
|
||||
overflow: hidden; // necessary for .text-ellipsis of <a>
|
||||
|
||||
> a {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&:not(.active):hover a,
|
||||
&:not(.active) a:focus {
|
||||
background: @menu-hover-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
.config-nav-item {
|
||||
line-height: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
> button {
|
||||
background: none;
|
||||
border: none;
|
||||
display: block;
|
||||
.rounded-corners();
|
||||
|
||||
> .state-badge {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.icon {
|
||||
opacity: .8;
|
||||
font-size: 1.25em;
|
||||
|
||||
&:before {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover > button {
|
||||
background: fade(@menu-hover-bg-color, 25);
|
||||
|
||||
> .state-badge {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
button:focus {
|
||||
background: fade(@menu-hover-bg-color, 25);
|
||||
}
|
||||
|
||||
&.active > button {
|
||||
color: @text-color-inverted;
|
||||
background: @icinga-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.state-badge {
|
||||
line-height: 1.2;
|
||||
padding: .25em;
|
||||
font-family: @font-family-wide;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-level-1 li {
|
||||
&.badge-nav-item > a {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
width: 100%;
|
||||
|
||||
.state-badge {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item-logout {
|
||||
color: @color-critical;
|
||||
border-top: 1px solid @gray-lighter;
|
||||
}
|
||||
|
||||
.user-ball {
|
||||
.ball();
|
||||
.ball-size-l();
|
||||
.ball-solid(@icinga-blue);
|
||||
|
||||
// icingadb-web/public/css/common.less: .user-ball
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
|
||||
// compensate border vertically and add space to the right;
|
||||
margin: -1px .2em -2px 0;
|
||||
border: 1px solid @text-color-inverted;
|
||||
font-style: normal;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
#layout:not(.sidebar-collapsed) #menu .config-menu {
|
||||
.user-nav-item {
|
||||
> a {
|
||||
padding-right: 4.75em;
|
||||
}
|
||||
|
||||
&.active.selected + .config-nav-item {
|
||||
> button {
|
||||
color: @text-color-inverted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-nav-item {
|
||||
position: absolute;
|
||||
right: 2.5em;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
|
||||
.state-badge {
|
||||
left: -1em;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.flyout {
|
||||
bottom: 100%;
|
||||
right: -2em;
|
||||
width: 15em;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-collapsed #menu .config-menu {
|
||||
ul {
|
||||
flex-direction: column;
|
||||
|
||||
.user-ball {
|
||||
margin-left: .25em * 1.5/2;
|
||||
margin-right: .5em + .25em * 1.5/2;
|
||||
width: 2em * 1.5/2 ;
|
||||
height: 2em * 1.5/2;
|
||||
font-size: 2/1.5em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.config-nav-item {
|
||||
padding-right: 0;
|
||||
margin-bottom: 3em;
|
||||
|
||||
.icon {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: 3em;
|
||||
margin: .125em .5em;
|
||||
padding: .5em .75em;
|
||||
|
||||
.state-badge {
|
||||
right: -.25em;
|
||||
bottom: -.25em;
|
||||
font-size: .75em;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 4em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flyout {
|
||||
bottom: 0;
|
||||
left: 100%;
|
||||
width: 14em;
|
||||
|
||||
&:before {
|
||||
left: -.6em;
|
||||
bottom: 1em;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flyout {
|
||||
display: none;
|
||||
position: absolute;
|
||||
border: 1px solid @gray-lighter;
|
||||
background: @body-bg-color;
|
||||
box-shadow: 0 0 1em 0 rgba(0,0,0,.25);
|
||||
z-index: 1;
|
||||
.rounded-corners();
|
||||
|
||||
a {
|
||||
font-size: 11/12em;
|
||||
padding: 0.364em 0.545em 0.364em 2em;
|
||||
line-height: 2;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background: @menu-2ndlvl-highlight-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 10/12em;
|
||||
color: @text-color-light;
|
||||
letter-spacing: .1px;
|
||||
padding: 0.364em 0.545em 0.364em 0.545em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flyout-content {
|
||||
overflow: auto;
|
||||
// Partially escape to have ems calculated
|
||||
max-height: calc(~"100vh - " 50/12em);
|
||||
padding: .5em 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// Caret
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
background: @body-bg-color;
|
||||
border-bottom: 1px solid @gray-lighter;
|
||||
border-right: 1px solid @gray-lighter;
|
||||
height: 1.1em;
|
||||
width: 1.1em;
|
||||
bottom: -.6em;
|
||||
right: 2.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent flyout to vanish on autorefresh
|
||||
#layout.config-flyout-open .config-nav-item {
|
||||
.flyout {
|
||||
display: block;
|
||||
}
|
||||
|
||||
> button > .state-badge {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#layout.minimal-layout .config-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#layout.minimal-layout #menu {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#layout:not(.minimal-layout) #menu .primary-nav {
|
||||
.user-nav-item,
|
||||
.configuration-nav-item,
|
||||
.system-nav-item {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -2,12 +2,20 @@
|
|||
|
||||
#footer {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
left: 12em;
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#layout.minimal-layout #footer {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sidebar-collapsed #footer {
|
||||
left: 3em;
|
||||
}
|
||||
|
||||
#guest-error {
|
||||
background-color: @icinga-blue;
|
||||
height: 100%;
|
||||
|
@ -208,10 +216,6 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
#layout:not(.minimal-layout) #notifications {
|
||||
padding-left: 12em;
|
||||
}
|
||||
|
||||
#notifications > li {
|
||||
color: @text-color;
|
||||
display: block;
|
||||
|
|
|
@ -17,15 +17,6 @@
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#layout:not(.minimal-layout) #menu {
|
||||
// Space for the #toggle-sidebar button
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
padding-bottom: 2.25em;
|
||||
}
|
||||
}
|
||||
|
||||
#menu .nav-item {
|
||||
vertical-align: middle;
|
||||
|
||||
|
@ -480,9 +471,10 @@ input[type=text].search-input {
|
|||
padding: 0;
|
||||
color: @text-color-light;
|
||||
position: absolute;
|
||||
bottom: 0.2em;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
line-height: 2;
|
||||
|
||||
i {
|
||||
background-color: @body-bg-color;
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
color: @text-color-on-icinga-blue;
|
||||
line-height: 1.5em;
|
||||
padding: 0.5em 1em 0.5em 3em;
|
||||
margin-left: 12em;
|
||||
|
||||
position: relative;
|
||||
|
||||
|
|
|
@ -11,10 +11,16 @@
|
|||
this.on('click', '#menu a', this.linkClicked, this);
|
||||
this.on('click', '#menu tr[href]', this.linkClicked, this);
|
||||
this.on('rendered', '#menu', this.onRendered, this);
|
||||
this.on('mouseenter', '#menu .nav-level-1 > .nav-item', this.showFlyoutMenu, this);
|
||||
this.on('mouseleave', '#menu', this.hideFlyoutMenu, this);
|
||||
this.on('mouseenter', '#menu .primary-nav .nav-level-1 > .nav-item', this.showFlyoutMenu, this);
|
||||
this.on('mouseleave', '#menu .primary-nav', this.hideFlyoutMenu, this);
|
||||
this.on('click', '#toggle-sidebar', this.toggleSidebar, this);
|
||||
|
||||
this.on('click', '#menu .config-nav-item button', this.toggleConfigFlyout, this);
|
||||
this.on('mouseenter', '#menu .config-menu .config-nav-item', this.showConfigFlyout, this);
|
||||
this.on('mouseleave', '#menu .config-menu .config-nav-item', this.hideConfigFlyout, this);
|
||||
|
||||
this.on('keydown', '#menu .config-menu .config-nav-item', this.onKeyDown, this);
|
||||
|
||||
/**
|
||||
* The DOM-Path of the active item
|
||||
*
|
||||
|
@ -121,6 +127,7 @@
|
|||
} else {
|
||||
_this.setActiveAndSelected($(event.target));
|
||||
}
|
||||
|
||||
// update target url of the menu container to the clicked link
|
||||
var $menu = $('#menu');
|
||||
var menuDataUrl = icinga.utils.parseUrl($menu.data('icinga-url'));
|
||||
|
@ -322,7 +329,8 @@
|
|||
*/
|
||||
Navigation.prototype.hideFlyoutMenu = function(e) {
|
||||
var $layout = $('#layout');
|
||||
var $hovered = $('#menu').find('.nav-level-1 > .nav-item.hover');
|
||||
var $nav = $(e.currentTarget);
|
||||
var $hovered = $nav.find('.nav-level-1 > .nav-item.hover');
|
||||
|
||||
if (! $hovered.length) {
|
||||
$layout.removeClass('menu-hovered');
|
||||
|
@ -332,7 +340,7 @@
|
|||
|
||||
setTimeout(function() {
|
||||
try {
|
||||
if ($hovered.is(':hover') || $('#menu').is(':hover')) {
|
||||
if ($hovered.is(':hover') || $nav.is(':hover')) {
|
||||
return;
|
||||
}
|
||||
} catch(e) { /* Bypass because if IE8 */ };
|
||||
|
@ -354,6 +362,55 @@
|
|||
$(window).trigger('resize');
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle config flyout visibility
|
||||
*
|
||||
* @param {Object} e Event
|
||||
*/
|
||||
Navigation.prototype.toggleConfigFlyout = function(e) {
|
||||
var _this = e.data.self;
|
||||
if ($('#layout').is('.config-flyout-open')) {
|
||||
_this.hideConfigFlyout(e);
|
||||
} else {
|
||||
_this.showConfigFlyout(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide config flyout
|
||||
*
|
||||
* @param {Object} e Event
|
||||
*/
|
||||
Navigation.prototype.hideConfigFlyout = function(e) {
|
||||
$('#layout').removeClass('config-flyout-open');
|
||||
if (e.target) {
|
||||
delete $(e.target).closest('.container')[0].dataset.suspendAutorefresh;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show config flyout
|
||||
*
|
||||
* @param {Object} e Event
|
||||
*/
|
||||
Navigation.prototype.showConfigFlyout = function(e) {
|
||||
$('#layout').addClass('config-flyout-open');
|
||||
$(e.target).closest('.container')[0].dataset.suspendAutorefresh = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide, config flyout when "Enter" key is pressed to follow `.flyout` nav item link
|
||||
*
|
||||
* @param {Object} e Event
|
||||
*/
|
||||
Navigation.prototype.onKeyDown = function(e) {
|
||||
var _this = e.data.self;
|
||||
|
||||
if (e.key == 'Enter' && $(document.activeElement).is('.flyout a')) {
|
||||
_this.hideConfigFlyout(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the history changes
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue