icingaweb2/public/js/icinga/behavior/navigation.js

216 lines
7.0 KiB
JavaScript
Raw Normal View History

/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
(function(Icinga, $) {
"use strict";
var activeMenuId;
Icinga.Behaviors = Icinga.Behaviors || {};
var Navigation = function (icinga) {
Icinga.EventListener.call(this, icinga);
this.on('click', '#menu a', this.linkClicked, this);
this.on('click', '#menu tr[href]', this.linkClicked, this);
this.on('mouseenter', 'li.dropdown', this.dropdownHover, this);
this.on('mouseleave', 'li.dropdown', this.dropdownLeave, this);
this.on('mouseenter', '#menu > nav > ul > li', this.menuTitleHovered, this);
this.on('mouseleave', '#sidebar', this.leaveSidebar, this);
this.on('rendered', this.onRendered, this);
};
Navigation.prototype = new Icinga.EventListener();
Navigation.prototype.onRendered = function(evt) {
var self = evt.data.self;
// get original source element of the rendered-event
var el = evt.target;
if (activeMenuId) {
2014-10-01 16:48:38 +02:00
// restore old menu state
$('#menu li.active', el).removeClass('active');
var $selectedMenu = $('#' + activeMenuId).addClass('active');
var $outerMenu = $selectedMenu.parent().closest('li');
if ($outerMenu.size()) {
$outerMenu.addClass('active');
}
/*
Recreate the html content of the menu item to force the browser to update the layout, or else
the link would only be visible as active after another click or page reload in Gecko and WebKit.
fixes #7897
*/
$selectedMenu.html($selectedMenu.html());
} else {
// store menu state
var $menus = $('#menu li.active', el);
if ($menus.size()) {
activeMenuId = $menus[0].id;
$menus.find('li.active').first().each(function () {
activeMenuId = this.id;
});
}
}
// restore hovered menu after auto-reload
if (self.hovered) {
var hovered = self.icinga.utils.getElementByDomPath(self.hovered);
if (hovered) {
self.hoverElement($(hovered));
}
}
};
Navigation.prototype.linkClicked = function(event) {
var $a = $(this);
var href = $a.attr('href');
var $li;
var self = event.data.self;
var icinga = self.icinga;
self.hovered = null;
if (href.match(/#/)) {
2014-09-10 14:21:15 +02:00
// ...it may be a menu section without a dedicated link.
// Switch the active menu item:
$li = $a.closest('li');
$('#menu .active').removeClass('active');
$li.addClass('active');
activeMenuId = $($li).attr('id');
if ($li.hasClass('hover')) {
$li.removeClass('hover');
2014-09-10 14:21:15 +02:00
}
if (href === '#') {
// Allow to access dropdown menu by keyboard
if ($a.hasClass('dropdown-toggle')) {
$a.closest('li').toggleClass('hover');
}
return;
}
} else {
activeMenuId = $(event.target).closest('li').attr('id');
}
// update target url of the menu container to the clicked link
var $menu = $('#menu');
var menuDataUrl = icinga.utils.parseUrl($menu.data('icinga-url'));
menuDataUrl = icinga.utils.addUrlParams(menuDataUrl.path, { url: href });
$menu.data('icinga-url', menuDataUrl);
};
Navigation.prototype.setActiveByUrl = function(url) {
this.resetActive();
this.setActive($('#menu [href="' + url + '"]'));
};
/**
* Change the active menu element
*
* @param $el {jQuery} A selector pointing to the active element
*/
Navigation.prototype.setActive = function($el) {
$el.closest('li').addClass('active');
$el.parents('li').addClass('active');
activeMenuId = $el.closest('li').attr('id');
};
Navigation.prototype.resetActive = function() {
$('#menu .active').removeClass('active');
activeMenuId = null;
};
2014-09-10 14:21:15 +02:00
Navigation.prototype.menuTitleHovered = function(event) {
var $li = $(this),
delay = 800,
self = event.data.self;
self.hovered = null;
2014-09-10 14:21:15 +02:00
if ($li.hasClass('active')) {
$li.siblings().removeClass('hover');
return;
}
if ($li.children('ul').children('li').length === 0) {
return;
}
if ($('#menu').scrollTop() > 0) {
return;
}
if ($('#layout').hasClass('hoveredmenu')) {
delay = 0;
}
setTimeout(function () {
try {
if (!$li.is('li:hover')) {
return;
}
if ($li.hasClass('active')) {
return;
}
} catch(e) { /* Bypass because if IE8 */ }
2014-09-10 14:21:15 +02:00
$li.siblings().each(function () {
var $sibling = $(this);
try {
if ($sibling.is('li:hover')) {
return;
}
} catch(e) { /* Bypass because if IE8 */ };
2014-09-10 14:21:15 +02:00
if ($sibling.hasClass('hover')) {
$sibling.removeClass('hover');
}
});
self.hoverElement($li);
}, delay);
};
Navigation.prototype.leaveSidebar = function (event) {
var $sidebar = $(this),
$li = $sidebar.find('li.hover'),
self = event.data.self;
if (! $li.length) {
$('#layout').removeClass('hoveredmenu');
return;
}
setTimeout(function () {
try {
if ($li.is('li:hover') || $sidebar.is('sidebar:hover')) {
return;
}
} catch(e) { /* Bypass because if IE8 */ };
2014-09-10 14:21:15 +02:00
$li.removeClass('hover');
$('#layout').removeClass('hoveredmenu');
}, 500);
self.hovered = null;
2014-09-10 14:21:15 +02:00
};
Navigation.prototype.hoverElement = function ($li) {
$('#layout').addClass('hoveredmenu');
$li.addClass('hover');
if ($li[0]) {
this.hovered = this.icinga.utils.getDomPath($li[0]);
} else {
this.hovered = null;
}
2014-09-10 14:21:15 +02:00
};
Navigation.prototype.dropdownHover = function () {
$(this).addClass('hover');
};
Navigation.prototype.dropdownLeave = function (event) {
var $li = $(this),
self = event.data.self;
setTimeout(function () {
// TODO: make this behave well together with keyboard navigation
try {
if (!$li.is('li:hover') /*&& ! $li.find('a:focus')*/) {
$li.removeClass('hover');
}
} catch(e) { /* Bypass because if IE8 */ }
2014-09-10 14:21:15 +02:00
}, 300);
self.hovered = null;
2014-09-10 14:21:15 +02:00
};
Icinga.Behaviors.Navigation = Navigation;
}) (Icinga, jQuery);