From b07ffd49876e126d789fb5b2b2f2a7240c29fe60 Mon Sep 17 00:00:00 2001 From: Florian Strohmaier Date: Wed, 21 Nov 2018 13:59:54 +0100 Subject: [PATCH] JS: Implement collapsible-container behavior --- application/layouts/scripts/layout.phtml | 2 +- library/Icinga/Web/JavaScript.php | 1 + public/css/icinga/main.less | 72 ++++++++++---- .../icinga/behavior/collapsibleContainer.js | 96 +++++++++++++++++++ 4 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 public/js/icinga/behavior/collapsibleContainer.js diff --git a/application/layouts/scripts/layout.phtml b/application/layouts/scripts/layout.phtml index 549a842a3..2fbf412cc 100644 --- a/application/layouts/scripts/layout.phtml +++ b/application/layouts/scripts/layout.phtml @@ -76,7 +76,7 @@ $innerLayoutScript = $this->layout()->innerLayout . '.phtml'; } }()); - diff --git a/library/Icinga/Web/JavaScript.php b/library/Icinga/Web/JavaScript.php index a26a863c3..cb80ff647 100644 --- a/library/Icinga/Web/JavaScript.php +++ b/library/Icinga/Web/JavaScript.php @@ -24,6 +24,7 @@ class JavaScript 'js/icinga/timezone.js', 'js/icinga/behavior/application-state.js', 'js/icinga/behavior/autofocus.js', + 'js/icinga/behavior/collapsibleContainer.js', 'js/icinga/behavior/detach.js', 'js/icinga/behavior/tooltip.js', 'js/icinga/behavior/sparkline.js', diff --git a/public/css/icinga/main.less b/public/css/icinga/main.less index 05db9d06a..d5a70b1d2 100644 --- a/public/css/icinga/main.less +++ b/public/css/icinga/main.less @@ -161,13 +161,6 @@ a:hover > .icon-cancel { background-color: @tr-hover-color; cursor: pointer; } - - caption { - border-top: 1px solid @gray-light; - caption-side: bottom; - font-style: italic; - text-align: right; - } } .name-value-table { @@ -235,27 +228,68 @@ a:hover > .icon-cancel { } // Collapsible Control +.collapsible-table-container { + &.collapsed.has-collapsible .collapsible { + overflow: hidden; + max-height: 8em; + } +} -.collapsible-container { +.collapsible-container, +.collapsible-table-container { + &.collapsed:not(.has-collapsible), + &.collapsed.has-collapsible .collapsible { + overflow: hidden; + max-height: 96px; + } + + &.collapsed:not(.has-collapsible) { + .collapsible-control { + bottom: 4px; + } + } +} + +.collapsible-container, +.collapsible-table-container { position: relative; - .icon-angle-double-down { - display: none; + .table-wrapper { + overflow: hidden; } - &.collapsed .icon-angle-double-up { - display: none; + .collapsed .table-wrapper { + overflow: hidden; + max-height: 12em; } +} - &.collapsed .icon-angle-double-down { - display: inline-block; - } +.collapsible-control > i:before { + margin-right: 0; } #collapsible-control-ghost { display: none; } +.collapsible-control > .icon-angle-double-down { + display: none; +} + +.collapsible-control > .icon-angle-double-up { + display: block; +} + +.collapsed { + .collapsible-control > .icon-angle-double-up { + display: none; + } + + .collapsible-control > .icon-angle-double-down { + display: block; + } +} + .collapsible-control { .rounded-corners(50%); @@ -263,10 +297,12 @@ a:hover > .icon-cancel { color: @gray; width: 2em; height: 2em; + z-index: 1; position: absolute; border: none; - z-index: 1; + bottom: -1em; + right: .25em; -webkit-box-shadow: 0 0 1/3em rgba(0,0,0,.3); - -moz-box-shadow: 0 0 1/3em rgba(0,0,0,.3); - box-shadow: 0 0 1/3em rgba(0,0,0,.3); + -moz-box-shadow: 0 0 1/3em rgba(0,0,0,.3); + box-shadow: 0 0 1/3em rgba(0,0,0,.3); } diff --git a/public/js/icinga/behavior/collapsibleContainer.js b/public/js/icinga/behavior/collapsibleContainer.js new file mode 100644 index 000000000..e9c142a76 --- /dev/null +++ b/public/js/icinga/behavior/collapsibleContainer.js @@ -0,0 +1,96 @@ +/*! Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */ + +;(function(Icinga, $) { + + 'use strict'; + + var expandedContainers = []; + var maxLength = 32; + var defaultNumOfRows = 2; + var defaultHeight = 36; + + function CollapsibleContainer(icinga) { + Icinga.EventListener.call(this, icinga); + + this.on('rendered', '#col2', this.onRendered, this); + this.on('click', '.collapsible-container .collapsible-control, .collapsible-table-container .collapsible-control', this.onControlClicked, this); + } + + CollapsibleContainer.prototype = new Icinga.EventListener(); + + CollapsibleContainer.prototype.onRendered = function(event) { + $(event.target).find('.collapsible-container').each(function() { + var $this = $(this); + + if ($this.find('.collapsible').length > 0) { + $this.addClass('has-collapsible'); + if ($this.find('.collapsible').innerHeight() > ($this.attr('data-height') || defaultHeight)) { + $this.append($('#collapsible-control-ghost').clone().removeAttr('id')); + } + } else { + if ($this.innerHeight() > ($this.attr('data-height') || defaultHeight)) { + $this.append($('#collapsible-control-ghost').clone().removeAttr('id')); + } + } + updateCollapsedState($this); + }); + + $(event.target).find('.collapsible-table-container').each(function() { + var $this = $(this); + + if ($this.find('.collapsible').length > 0) { + $this.addClass('has-collapsible'); + if ($this.find('tr').length > ($this.attr('data-numofrows') || defaultNumOfRows)) { + $this.append($('#collapsible-control-ghost').clone().removeAttr('id')); + } + + if ($this.find('li').length > ($this.attr('data-numofrows') || defaultNumOfRows)) { + $this.append($('#collapsible-control-ghost').clone().removeAttr('id')); + } + } + updateCollapsedState($this); + }); + }; + + CollapsibleContainer.prototype.onControlClicked = function(event) { + var $target = $(event.target); + var $c = $target.closest('.collapsible-container, .collapsible-table-container'); + + if ($c.hasClass('collapsed')) { + if (expandedContainers.length > maxLength - 1) { + expandedContainers.shift(); + } + expandedContainers.push($c.attr('id')); + } else { + expandedContainers.splice(expandedContainers.indexOf($c.attr('id')), 1); + } + + updateCollapsedState($c); + }; + + function updateCollapsedState($container, listener) { + var $collapsible; + if ($container.hasClass('has-collapsible')) { + $collapsible = $container.find('.collapsible'); + } else { + $collapsible = $container; + } + if (expandedContainers.indexOf($container.attr('id')) > -1) { + $container.removeClass('collapsed'); + $collapsible.css({ maxHeight: 'none' }); + } else { + $container.addClass('collapsed'); + if ($container.hasClass('collapsible-container')) { + $collapsible.css({ maxHeight: $container.data('height') || defaultHeight }); + } + if ($container.hasClass('collapsible-table-container')) { + $collapsible.css({ maxHeight: ($container.data('numofrows') || defaultNumOfRows) * $container.find('tr').height() }); + } + } + } + + Icinga.Behaviors = Icinga.Behaviors || {}; + + Icinga.Behaviors.collapsibleContainer = CollapsibleContainer; + +})(Icinga, jQuery);