blob: 699aad13f7098836c4630a945ebd7d99935917f6 [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Widget -- Table Service
*/
(function () {
'use strict';
// injected refs
var $log, $window, fs, mast, is;
// constants
var tableIconTdSize = 33,
mastPdg = 8,
h2Pdg = 40,
thPdg = 12,
tbodyPdg = 5,
colWidth = 'col-width',
tableIcon = 'table-icon';
// internal state
var currCol = {},
prevCol = {};
// Functions for creating a fixed header on a table (Angular Directive)
function setElemWidth(elem, size) {
elem.style('width', size + 'px')
}
function setColWidth(th, td, size) {
setElemWidth(th, size);
setElemWidth(td, size);
}
// count number of headers of
// - assigned width,
// - icon width,
// - and default width
// assumes assigned width is not given to icons
// returns the width of all columns that are not icons
// or have an assigned width
function getDefaultWidth(headers) {
var winWidth = fs.windowSize().width,
iconCols = 0,
regCols = 0,
cstmColWidth = 0;
headers.each(function (d, i) {
var thElement = d3.select(this),
cstmWidth = thElement.attr(colWidth);
if (cstmWidth) {
cstmColWidth += fs.noPx(cstmWidth);
} else if (thElement.classed(tableIcon)) {
iconCols += 1;
} else {
regCols += 1;
}
});
return Math.floor((winWidth - cstmColWidth -
(iconCols * tableIconTdSize)) / regCols);
}
function setTableWidth(t) {
var tHeaders = t.selectAll('th'),
defaultColWidth = getDefaultWidth(tHeaders);
tHeaders.each(function (d, i) {
var thElement = d3.select(this),
tdElement = t.select('td:nth-of-type(' + (i + 1) + ')'),
custWidth = thElement.attr(colWidth);
if (custWidth) {
setColWidth(thElement, tdElement, fs.noPx(custWidth));
} else if (thElement.classed(tableIcon)) {
setColWidth(thElement, tdElement, tableIconTdSize);
} else {
setColWidth(thElement, tdElement, defaultColWidth);
}
});
}
// get the size of the window and then subtract the extra space at the top
// to get the height of the table
function setTableHeight(thead, tbody) {
var titleHeight = h2Pdg + fs.noPxStyle(d3.select('h2'), 'height'),
thHeight = thPdg + fs.noPxStyle(d3.select('th'), 'height'),
totalHeight = titleHeight + thHeight + tbodyPdg + mastPdg,
tableHeight = fs.windowSize(mast.mastHeight() + totalHeight).height;
thead.style('display', 'block');
tbody.style({'display': 'block',
'height': (tableHeight + 'px'),
'overflow': 'auto'
});
}
function fixTable(t, th, tb) {
setTableWidth(t);
setTableHeight(th, tb);
}
// Functions for sorting table rows by header and choosing appropriate icon
function updateSortingIcons(thElem, api) {
var div;
currCol.colId = thElem.attr('colId');
if (currCol.colId === prevCol.colId) {
(currCol.icon === 'tableColSortDesc') ?
currCol.icon = 'tableColSortAsc' :
currCol.icon = 'tableColSortDesc';
prevCol.icon = currCol.icon;
} else {
currCol.icon = 'tableColSortAsc';
prevCol.icon = 'tableColSortNone';
}
div = thElem.select('div');
api.sortNone(div);
div = thElem.append('div');
if (currCol.icon === 'tableColSortAsc') {
api.sortAsc(div);
} else {
api.sortDesc(div);
}
if (prevCol.colId !== undefined &&
prevCol.icon === 'tableColSortNone') {
api.sortNone(prevCol.elem.select('div'));
}
prevCol.colId = currCol.colId;
prevCol.elem = thElem;
}
function sortRequestParams() {
return {
sortCol: currCol.colId,
sortDir: (currCol.icon === 'tableColSortAsc' ? 'asc' : 'desc')
};
}
angular.module('onosWidget')
.directive('onosFixedHeader', ['$window', 'FnService', 'MastService',
function (_$window_, _fs_, _mast_) {
return function (scope, element) {
$window = _$window_;
fs = _fs_;
mast = _mast_;
var w = angular.element($window),
table = d3.select(element[0]),
thead = table.select('thead'),
tbody = table.select('tbody'),
canAdjust = false;
scope.$watch(function () {
return {
h: window.innerHeight,
w: window.innerWidth
};
}, function (newVal) {
var wsz = fs.windowSize(0, 30);
scope.windowHeight = newVal.h;
scope.windowWidth = newVal.w;
// default table size in case no data elements
table.style('width', wsz.width + 'px');
scope.$on('LastElement', function () {
// only adjust the table once it's completely loaded
fixTable(table, thead, tbody);
canAdjust = true;
});
if (canAdjust) {
fixTable(table, thead, tbody);
}
}, true);
w.bind('onos-fixed-header', function () {
scope.$apply();
});
};
}])
.directive('onosSortableHeader', ['$log', 'IconService',
function (_$log_, _is_) {
return {
scope: {
ctrlCallback: '&sortCallback'
},
link: function (scope, element) {
$log = _$log_;
is = _is_;
var table = d3.select(element[0]),
sortIconAPI = is.createSortIcon();
// when a header is clicked, change its icon tag
// and get sorting order to send to the server.
table.selectAll('th').on('click', function () {
var thElem = d3.select(this);
if (thElem.attr('sortable') === '') {
updateSortingIcons(thElem, sortIconAPI);
scope.ctrlCallback({
requestParams: sortRequestParams()
});
}
});
}
};
}]);
}());