Make active first-level nav items better distinguishable
This commit is contained in:
parent
1e79ba5c1c
commit
b3b80fdc31
|
@ -37,6 +37,13 @@ class NavigationItem implements IteratorAggregate
|
|||
*/
|
||||
protected $active;
|
||||
|
||||
/**
|
||||
* Whether this item is selected
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $selected;
|
||||
|
||||
/**
|
||||
* The CSS class used for the outer li element
|
||||
*
|
||||
|
@ -213,6 +220,39 @@ class NavigationItem implements IteratorAggregate
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this item is selected
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getSelected()
|
||||
{
|
||||
if ($this->selected === null) {
|
||||
$this->active = false;
|
||||
if ($this->getUrl() !== null && Icinga::app()->getRequest()->getUrl()->matches($this->getUrl())) {
|
||||
$this->setSelected();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this item is active
|
||||
*
|
||||
* If it's active and has a parent, the parent gets activated as well.
|
||||
*
|
||||
* @param bool $selected
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSelected($selected = true)
|
||||
{
|
||||
$this->selected = (bool) $selected;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CSS class used for the outer li element
|
||||
*
|
||||
|
|
|
@ -322,6 +322,10 @@ class NavigationRenderer implements RecursiveIterator, NavigationRendererInterfa
|
|||
$cssClasses[] = static::CSS_CLASS_ACTIVE;
|
||||
}
|
||||
|
||||
if ($item->getSelected()) {
|
||||
$cssClasses[] = static::CSS_CLASS_SELECTED;
|
||||
}
|
||||
|
||||
if ($cssClass = $item->getCssClass()) {
|
||||
$cssClasses[] = $cssClass;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,13 @@ interface NavigationRendererInterface
|
|||
*/
|
||||
const CSS_CLASS_ACTIVE = 'active';
|
||||
|
||||
/**
|
||||
* CSS class for selected items
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CSS_CLASS_SELECTED = 'selected';
|
||||
|
||||
/**
|
||||
* CSS class for dropdown items
|
||||
*
|
||||
|
|
|
@ -79,10 +79,16 @@
|
|||
|
||||
> a {
|
||||
padding: 0.5em 0.5em 0.5em .75em;
|
||||
}
|
||||
|
||||
&:focus, &:hover {
|
||||
color: @menu-highlight-color;
|
||||
}
|
||||
&.active:not(.selected) > a:focus,
|
||||
&.active:not(.selected) > a:hover {
|
||||
background-color: mix(#000, @menu-active-bg-color, 20);
|
||||
}
|
||||
|
||||
&:not(.selected) > a:hover,
|
||||
&:not(.selected) > a:focus {
|
||||
background-color: mix(#000, @menu-bg-color, 20);
|
||||
}
|
||||
|
||||
// Balance icon weight for non active menu items
|
||||
|
@ -102,9 +108,6 @@ ul:not(.nav-level-2) > .selected > a {
|
|||
background-color: @menu-highlight-color;
|
||||
color: @text-color-inverted;
|
||||
|
||||
&:focus {
|
||||
background-color: mix(#000, @menu-highlight-color, 20);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @text-color-inverted;
|
||||
|
@ -134,26 +137,19 @@ ul:not(.nav-level-2) > .selected > a {
|
|||
> a {
|
||||
color: @menu-2ndlvl-color;
|
||||
font-size: @font-size-small;
|
||||
padding: 0.364em 0.545em 0.364em .8em;
|
||||
padding: 0.364em 0.545em 0.364em (@icon-width + .75em);
|
||||
}
|
||||
|
||||
&:hover, &:focus {
|
||||
color: @menu-2ndlvl-highlight-color;
|
||||
}
|
||||
&:not(.selected):not(.active) > a:hover,
|
||||
&:not(.selected):not(.active) > a:focus {
|
||||
background-color: mix(#000, @menu-active-bg-color, 20);
|
||||
color: @menu-2ndlvl-highlight-color;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: @menu-highlight-color;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
background-color: @menu-highlight-color;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&.active > a:focus {
|
||||
background-color: mix(#000, @menu-highlight-color, 20);
|
||||
}
|
||||
|
||||
// Little caret on active level-2 item
|
||||
|
|
|
@ -52,11 +52,11 @@
|
|||
var $active = _this.$menu.find('li.active');
|
||||
if ($active.length) {
|
||||
$active.each(function() {
|
||||
_this.setActive($(this));
|
||||
_this.setActiveAndSelected($(this));
|
||||
});
|
||||
} else {
|
||||
// if no item is marked as active, try to select the menu from the current URL
|
||||
_this.setActiveByUrl($('#col1').data('icingaUrl'));
|
||||
_this.setActiveAndSelectedByUrl($('#col1').data('icingaUrl'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
|||
// restore selection to current active element
|
||||
if (this.active) {
|
||||
var $el = $(this.icinga.utils.getElementByDomPath(this.active));
|
||||
this.setActive($el);
|
||||
this.setActiveAndSelected($el);
|
||||
|
||||
/*
|
||||
* Recreate the html content of the menu item to force the browser to update the layout, or else
|
||||
|
@ -98,9 +98,9 @@
|
|||
if (href.match(/#/)) {
|
||||
// ...it may be a menu section without a dedicated link.
|
||||
// Switch the active menu item:
|
||||
_this.setActive($a);
|
||||
_this.setActiveAndSelected($a);
|
||||
} else {
|
||||
_this.setActive($(event.target));
|
||||
_this.setActiveAndSelected($(event.target));
|
||||
}
|
||||
// update target url of the menu container to the clicked link
|
||||
var $menu = $('#menu');
|
||||
|
@ -116,7 +116,7 @@
|
|||
*
|
||||
* @param url {String} The url to match
|
||||
*/
|
||||
Navigation.prototype.setActiveByUrl = function(url) {
|
||||
Navigation.prototype.setActiveAndSelectedByUrl = function(url) {
|
||||
var $menu = $('#menu');
|
||||
|
||||
if (! $menu.length) {
|
||||
|
@ -124,17 +124,17 @@
|
|||
}
|
||||
|
||||
// try to active the first item that has an exact URL match
|
||||
this.setActive($menu.find('[href="' + url + '"]'));
|
||||
this.setActiveAndSelected($menu.find('[href="' + url + '"]'));
|
||||
|
||||
// the url may point to the search field, which must be activated too
|
||||
if (! this.active) {
|
||||
this.setActive($menu.find('form[action="' + this.icinga.utils.parseUrl(url).path + '"]'));
|
||||
this.setActiveAndSelected($menu.find('form[action="' + this.icinga.utils.parseUrl(url).path + '"]'));
|
||||
}
|
||||
|
||||
// some urls may have custom filters which won't match any menu item, in that case search
|
||||
// for a menu item that points to the base action without any filters
|
||||
if (! this.active) {
|
||||
this.setActive($menu.find('[href="' + this.icinga.utils.parseUrl(url).path + '"]').first());
|
||||
this.setActiveAndSelected($menu.find('[href="' + this.icinga.utils.parseUrl(url).path + '"]').first());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -143,11 +143,12 @@
|
|||
*
|
||||
* @param url
|
||||
*/
|
||||
Navigation.prototype.trySetActiveByUrl = function(url) {
|
||||
Navigation.prototype.trySetActiveAndSelectedByUrl = function(url) {
|
||||
var active = this.active;
|
||||
this.setActiveByUrl(url);
|
||||
this.setActiveAndSelectedByUrl(url);
|
||||
|
||||
if (! this.active && active) {
|
||||
this.setActive($(this.icinga.utils.getElementByDomPath(active)));
|
||||
this.setActiveAndSelected($(this.icinga.utils.getElementByDomPath(active)));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -160,6 +161,15 @@
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all selected elements
|
||||
*/
|
||||
Navigation.prototype.clearSelected = function() {
|
||||
if (this.$menu) {
|
||||
this.$menu.find('.selected').removeClass('selected');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Select all menu items in the selector as active and unfold surrounding menus when necessary
|
||||
*
|
||||
|
@ -184,6 +194,11 @@
|
|||
}
|
||||
};
|
||||
|
||||
Navigation.prototype.setActiveAndSelected = function ($el) {
|
||||
this.setActive($el);
|
||||
this.setSelected($el);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the active menu element
|
||||
*
|
||||
|
@ -202,6 +217,15 @@
|
|||
// TODO: push to history
|
||||
};
|
||||
|
||||
Navigation.prototype.setSelected = function($el) {
|
||||
this.clearSelected();
|
||||
$el = $el.closest('li');
|
||||
|
||||
if ($el.length) {
|
||||
$el.addClass('selected');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the active element to nothing
|
||||
*/
|
||||
|
@ -210,6 +234,14 @@
|
|||
this.active = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the selected element to nothing
|
||||
*/
|
||||
Navigation.prototype.resetSelected = function() {
|
||||
this.clearSelected();
|
||||
this.selected = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the fly-out menu
|
||||
*
|
||||
|
@ -318,9 +350,10 @@
|
|||
);
|
||||
return;
|
||||
}
|
||||
this.setActive($(active));
|
||||
this.setActiveAndSelected($(active))
|
||||
} else {
|
||||
this.resetActive();
|
||||
this.resetSelected();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@
|
|||
var url = req.url;
|
||||
|
||||
if (req.$target[0].id === 'col1') {
|
||||
this.icinga.behaviors.navigation.trySetActiveByUrl(url);
|
||||
this.icinga.behaviors.navigation.trySetActiveAndSelectedByUrl(url);
|
||||
}
|
||||
|
||||
var $forms = $('[action="' + this.icinga.utils.parseUrl(url).path + '"]');
|
||||
|
|
|
@ -186,7 +186,7 @@
|
|||
var kill = this.cutContainer($('#col1'));
|
||||
this.pasteContainer($('#col1'), col2);
|
||||
this.fixControls();
|
||||
this.icinga.behaviors.navigation.trySetActiveByUrl($('#col1').data('icingaUrl'));
|
||||
this.icinga.behaviors.navigation.trySetActiveAndSelectedByUrl($('#col1').data('icingaUrl'));
|
||||
},
|
||||
|
||||
cutContainer: function ($col) {
|
||||
|
|
Loading…
Reference in New Issue