From 0845edce1af349b2229efa01fdadc47fbc3d1a1a Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 5 Nov 2015 12:39:42 +0530 Subject: [PATCH] CLOUDSTACK-9020: Implement collapsible columns and threshold colorings Implements following in listView that generates tabular views; - Collapsible columns in case of multi-header groupable columns - Implements threshold coloring of cells in table - Implements option to render a table that is scrollable in both x-y directions - Support to only display status icon instead of label if compact is set to true - Fixes quick-view alignment issue on Safari - If a column was previously sorted, sorts after adding new rows - If a supercolumn was collapsed, hides cell after adding new rows Signed-off-by: Rohit Yadav --- ui/scripts/ui/widgets/listView.js | 204 +++++++++++++++++++++++++++--- 1 file changed, 186 insertions(+), 18 deletions(-) diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index c3c6930752e..c0740aa6a6a 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -765,10 +765,12 @@ var createHeader = function(preFilter, fields, $table, actions, options) { if (!options) options = {}; - var $thead = $('').prependTo($table).append($('')); + var $tr = $(''); + var $thead = $('').prependTo($table).append($tr); var reorder = options.reorder; var detailView = options.detailView; var multiSelect = options.multiSelect; + var groupableColumns = options.groupableColumns; var viewArgs = $table.closest('.list-view').data('view-args'); var uiCustom = viewArgs.uiCustom; var hiddenFields = []; @@ -776,8 +778,110 @@ if (preFilter != null) hiddenFields = preFilter(); + var addColumnToTr = function($tr, key, colspan, label, needsCollapsibleColumn) { + var trText = _l(label); + var $th = $('').addClass(key).attr('colspan', colspan).appendTo($tr); + if ($th.index()) $th.addClass('reduced-hide'); + $th.css({'border-right': '1px solid #C6C3C3', 'border-left': '1px solid #C6C3C3'}); + if (needsCollapsibleColumn) { + var karetLeft = $('').css({'margin-right': '10px'}); + karetLeft.attr('title', trText); + karetLeft.appendTo($th); + $('').html('«').css({'font-size': '15px', 'float': 'right'}).appendTo(karetLeft); + $('').html(trText).appendTo(karetLeft); + + $th.click(function(event) { + event.stopPropagation(); + var $th = $(this); + var startIndex = 0; + $th.prevAll('th').each(function() { + startIndex += parseInt($(this).attr('colspan')); + }); + var endIndex = startIndex + parseInt($th.attr('colspan')); + // Hide Column group + $th.hide(); + $th.closest('table').find('tbody td').filter(function() { + return $(this).index() >= startIndex && $(this).index() < endIndex; + }).hide(); + $th.closest('table').find('thead tr:last th').filter(function() { + return $(this).index() >= startIndex && $(this).index() < endIndex; + }).hide(); + // Show collapsible column with blank cells + $th.next('th').show(); + $th.closest('table').find('tbody td').filter(function() { + return $(this).index() == endIndex; + }).show(); + $th.closest('table').find('thead tr:last th').filter(function() { + return $(this).index() == endIndex; + }).show(); + // Refresh list view + $tr.closest('.list-view').find('.no-split').dataTable('refresh'); + }); + + var karetRight = addColumnToTr($tr, 'collapsible-column', 1, ''); + $('').html(trText.substring(0,3)).appendTo(karetRight); + $('').css({'font-size': '15px'}).html(' »').appendTo(karetRight); + karetRight.attr('title', trText); + karetRight.css({'border-right': '1px solid #C6C3C3', 'border-left': '1px solid #C6C3C3', 'min-width': '10px', 'width': '10px', 'max-width': '45px', 'padding': '2px'}); + karetRight.hide(); + karetRight.click(function(event) { + event.stopPropagation(); + var prevTh = $(this).prev('th'); + var startIndex = 0; + prevTh.prevAll('th').each(function() { + startIndex += parseInt($(this).attr('colspan')); + }); + var endIndex = startIndex + parseInt(prevTh.attr('colspan')); + + prevTh.show(); + prevTh.closest('table').find('tbody td').filter(function() { + return $(this).index() >= startIndex && $(this).index() < endIndex; + }).show(); + prevTh.closest('table').find('thead tr:last th').filter(function() { + return $(this).index() >= startIndex && $(this).index() < endIndex; + }).show(); + + prevTh.next('th').hide(); + prevTh.closest('table').find('tbody td').filter(function() { + return $(this).index() == endIndex; + }).hide(); + prevTh.closest('table').find('thead tr:last th').filter(function() { + return $(this).index() == endIndex; + }).hide(); + + $tr.closest('.list-view').find('.no-split').dataTable('refresh'); + }); + } else { + $th.html(trText); + } + return $th; + }; + + if (groupableColumns) { + $tr.addClass('groupable-header-columns').addClass('groupable-header'); + $.each(fields, function(key) { + var field = this; + if (field.columns) { + var colspan = Object.keys(field.columns).length; + addColumnToTr($tr, key, colspan, field.label, true); + } else { + var label = ''; + if (key == 'name') { + label = 'label.resources'; + } + addColumnToTr($tr, key, 1, label); + } + return true; + }); + if (detailView && !$.isFunction(detailView) && !detailView.noCompact && !uiCustom) { + addColumnToTr($tr, 'quick-view', 1, ''); + } + $tr = $('').appendTo($thead); + $tr.addClass('groupable-header'); + } + if (multiSelect) { - var $th = $('').addClass('multiselect').appendTo($thead.find('tr')); + var $th = $('').addClass('multiselect').appendTo($tr); var content = $('') .attr('type', 'checkbox') .addClass('multiSelectMasterCheckbox') @@ -794,18 +898,24 @@ if ($.inArray(key, hiddenFields) != -1) return true; var field = this; - var $th = $('').addClass(key).appendTo($thead.find('tr')); - - if ($th.index()) $th.addClass('reduced-hide'); - - $th.html(_l(field.label)); - + if (field.columns) { + $.each(field.columns, function(idx) { + var subfield = this; + addColumnToTr($tr, key, 1, subfield.label); + return true; + }); + var blankCell = addColumnToTr($tr, 'collapsible-column', 1, ''); + blankCell.css({'min-width': '10px', 'width': '10px'}); + blankCell.hide(); + } else { + addColumnToTr($tr, key, 1, field.label); + } return true; }); // Re-order row buttons if (reorder) { - $thead.find('tr').append( + $tr.append( $('').html(_l('label.order')).addClass('reorder-actions reduced-hide') ); } @@ -826,7 +936,7 @@ ); if (actions && !options.noActionCol && renderActionCol(actions) && actionsArray.length != headerActionsArray.length) { - $thead.find('tr').append( + $tr.append( $('') .html(_l('label.actions')) .addClass('actions reduced-hide') @@ -835,7 +945,7 @@ // Quick view if (detailView && !$.isFunction(detailView) && !detailView.noCompact && !uiCustom) { - $thead.find('tr').append( + $tr.append( $('') .html(_l('label.quickview')) .addClass('quick-view reduced-hide') @@ -1033,6 +1143,7 @@ var listViewArgs = $listView.data('view-args'); var uiCustom = listViewArgs.uiCustom; var subselect = uiCustom ? listViewArgs.listView.subselect : null; + var hasCollapsibleColumn = false; if (!(data && data.length)) { $listView.data('end-of-table', true); @@ -1088,8 +1199,25 @@ ); } - // Add field data + var reducedFields = {}; + var idx = 0; $.each(fields, function(key) { + var field = this; + if (field.columns) { + $.each(field.columns, function(innerKey) { + reducedFields[innerKey] = this; + }); + reducedFields['blank-cell-' + idx] = {blankCell: true}; + idx += 1; + hasCollapsibleColumn = true; + } else { + reducedFields[key] = this; + } + return true; + }); + + // Add field data + $.each(reducedFields, function(key) { if ($.inArray(key, hiddenFields) != -1) return true; var field = this; @@ -1103,6 +1231,11 @@ $td.addClass('truncated'); } + if (field.blankCell) { + $td.css({'min-width': '10px', 'width': '10px'}); + $td.hide(); + } + if (field.indicator) { $td.addClass('state').addClass(field.indicator[content]); @@ -1110,6 +1243,19 @@ //$tr.find('td:first').addClass('item-state-' + field.indicator[content]); } + if (field.thresholdcolor && field.thresholds) { + if ((field.thresholds.disable in dataItem) && (field.thresholds.notification in dataItem)) { + var disableThreshold = parseFloat(dataItem[field.thresholds.disable]); + var notificationThreshold = parseFloat(dataItem[field.thresholds.notification]); + var value = parseFloat(content); + if (value >= disableThreshold) { + $td.addClass('alert-disable-threshold'); + } else if (value >= notificationThreshold) { + $td.addClass('alert-notification-threshold'); + } + } + } + if (field.id == true) id = field.id; if ($td.index()) $td.addClass('reduced-hide'); if (field.action) { @@ -1140,9 +1286,12 @@ $('
').html(_s(content))
                         );
                     } else {
-                        $td.append(
-                            $('').html(_s(content))
-                        );
+                        var span = $('').html(_s(content));
+                        if (field.compact) {
+                            span.addClass('compact');
+                            span.html('');
+                        }
+                        $td.append(span);
                     }
                 }
 
@@ -1380,8 +1529,8 @@
                     .appendTo($tr);
                 $quickView.mouseover(
                     // Show quick view
-
                     function() {
+                        var $quickView = $(this);
                         var $quickViewTooltip = $('
').addClass('quick-view-tooltip hovered-elem'); var $tr = $quickView.closest('tr'); var $listView = $tr.closest('.list-view'); @@ -1465,7 +1614,7 @@ }); $quickViewTooltip.css({ position: 'absolute', - left: $tr.offset().left + $tr.width() - $quickViewTooltip.width(), + left: $quickView.offset().left + $quickView.outerWidth() - $quickViewTooltip.width() - 2*(parseInt($quickView.css('border-left-width')) + parseInt($quickView.css('border-right-width'))), top: $quickView.offset().top, zIndex: $tr.closest('.panel').zIndex() + 1 }); @@ -1480,6 +1629,14 @@ } }); + // Toggle collapsible column to fix alignment of hidden/shown cells + if (hasCollapsibleColumn) { + $tbody.closest('table').find('tr:first th.collapsible-column:visible').prev('th').click(); + } + + // Re-sort table if a column was previously sorted + $listView.find('thead tr:last th.sorted').click().click(); + return rows; }; @@ -1798,8 +1955,19 @@ reorder: reorder, detailView: listViewData.detailView, 'multiSelect': multiSelect, - noActionCol: listViewData.noActionCol + noActionCol: listViewData.noActionCol, + groupableColumns: listViewData.groupableColumns }); + + if (listViewData.noSplit) { + $table.addClass('no-split'); + } + + if (listViewData.horizontalOverflow) { + $table.addClass('horizontal-overflow'); + $table.parent().css({'overflow-x': 'auto'}); + } + createFilters($toolbar, listViewData.filters); if (listViewData.hideSearchBar != true) {