ONOS-1842 - GUI -- Tables have better resizing behavior -- column headers stay above their columns and table cell text is constrained to one size.
Change-Id: I89ca7d25d46d895c78c41b8250ce40408fbaba85
diff --git a/web/gui/src/main/webapp/app/fw/widget/table.css b/web/gui/src/main/webapp/app/fw/widget/table.css
index d7db019..ff222e7 100644
--- a/web/gui/src/main/webapp/app/fw/widget/table.css
+++ b/web/gui/src/main/webapp/app/fw/widget/table.css
@@ -16,68 +16,80 @@
/* ------ for summary-list tables ------ */
-table.summary-list {
- margin: 0 20px 16px 12px;
+div.summary-list {
+ margin: 0 20px 16px 10px;
font-size: 10pt;
border-spacing: 0;
}
-table.summary-list td.nodata {
+div.summary-list table {
+ border-collapse: collapse;
+ table-layout: fixed;
+ empty-cells: show;
+ margin: 0;
+}
+
+div.summary-list div.table-body {
+ overflow-y: scroll;
+}
+
+div.summary-list tr.no-data td {
text-align: center;
font-style: italic;
}
-.light table.summary-list tr:nth-child(even) {
+.light div.summary-list tr:nth-child(even) {
background-color: #ddd;
}
-.light table.summary-list tr:nth-child(odd) {
+.light div.summary-list tr:nth-child(odd) {
background-color: #eee;
}
-.dark table.summary-list tr:nth-child(even) {
+.dark div.summary-list tr:nth-child(even) {
background-color: #333;
}
-.dark table.summary-list tr:nth-child(odd) {
+.dark div.summary-list tr:nth-child(odd) {
background-color: #444;
}
-.light table.summary-list tr.selected {
+.light div.summary-list tr.selected {
background-color: deepskyblue;
}
-.dark table.summary-list tr.selected {
+.dark div.summary-list tr.selected {
background-color: #304860;
}
-table.summary-list td,
-table.summary-list th {
+div.summary-list td {
padding: 6px;
text-align: left;
+ word-wrap: break-word;
}
-table.summary-list th {
+div.summary-list .table-header td {
letter-spacing: 0.02em;
cursor: pointer;
+ font-weight: bold;
}
-table.summary-list th:first-child {
+div.summary-list .table-header td:first-child {
border-radius: 8px 0 0 0;
}
-table.summary-list th:last-child {
+div.summary-list .table-header td:last-child {
border-radius: 0 8px 0 0;
}
-.light table.summary-list th {
+.light div.summary-list .table-header td {
background-color: #bbb;
}
-.dark table.summary-list th {
+.dark div.summary-list .table-header td {
background-color: #222;
color: #ccc;
}
/* rows are selectable */
-table.summary-list td {
+div.summary-list .table-body td {
cursor: pointer;
}
-.dark table.summary-list td {
+.dark div.summary-list td {
color: #ccc;
}
diff --git a/web/gui/src/main/webapp/app/fw/widget/table.js b/web/gui/src/main/webapp/app/fw/widget/table.js
index d9fddda..caacab4 100644
--- a/web/gui/src/main/webapp/app/fw/widget/table.js
+++ b/web/gui/src/main/webapp/app/fw/widget/table.js
@@ -37,86 +37,68 @@
prevCol = {},
sortIconAPI;
- // Functions for creating a fixed header on a table (Angular Directive)
+ // Functions for creating a scrolling table body with fixed table header
- function setElemWidth(elem, size) {
- elem.style('width', size + 'px')
+ function _width(elem, width) {
+ elem.style('width', width);
}
- function setColWidth(th, td, size) {
- setElemWidth(th, size);
- setElemWidth(td, size);
+ function defaultSize(table, width) {
+ var thead = table.select('.table-header').select('table'),
+ tbody = table.select('.table-body').select('table'),
+ wpx = width + 'px';
+ _width(thead, wpx);
+ _width(tbody, wpx);
}
- // 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;
+ function adjustTable(table, width, height) {
+ var thead = table.select('.table-header').select('table'),
+ tbodyDiv = table.select('.table-body'),
+ tbody = tbodyDiv.select('table'),
+ cstmWidths = {};
- headers.each(function (d, i) {
- var thElement = d3.select(this),
- cstmWidth = thElement.attr(colWidth);
+ function findCstmWidths() {
+ var headers = thead.selectAll('td');
- if (cstmWidth) {
- cstmColWidth += fs.noPx(cstmWidth);
- } else if (thElement.classed(tableIcon)) {
- iconCols += 1;
- } else {
- regCols += 1;
- }
- });
+ headers.each(function (d, i) {
+ var h = d3.select(this),
+ index = i.toString();
+ if (h.classed(tableIcon)) {
+ cstmWidths[index] = tableIconTdSize + 'px';
+ }
+ if (h.attr(colWidth)) {
+ cstmWidths[index] = h.attr(colWidth);
+ }
+ });
+ $log.debug('Headers with custom widths: ', cstmWidths);
+ }
- return Math.floor((winWidth - cstmColWidth -
- (iconCols * tableIconTdSize)) / regCols);
- }
+ function setTdWidths(elem) {
+ var tds = elem.selectAll('tr:not(.ignore-width)').selectAll('td');
+ _width(elem, width + 'px');
- function setTableWidth(t) {
- var tHeaders = t.selectAll('th'),
- defaultColWidth = getDefaultWidth(tHeaders);
+ tds.each(function (d, i) {
+ var td = d3.select(this),
+ index = i.toString();
+ if (cstmWidths.hasOwnProperty(index)) {
+ _width(td, cstmWidths[index]);
+ }
+ });
+ }
- tHeaders.each(function (d, i) {
- var thElement = d3.select(this),
- tr = t.select('tr:nth-of-type(2)'),
- tdElement = tr.select('td:nth-of-type(' + (i + 1) + ')'),
- custWidth = thElement.attr(colWidth);
+ function setHeight(body) {
+ var h = height - (mast.mastHeight() +
+ fs.noPxStyle(d3.select('.tabular-header'), 'height') +
+ fs.noPxStyle(thead, 'height') + pdg);
+ body.style('height', h + 'px');
+ }
- if (custWidth) {
- setColWidth(thElement, tdElement, fs.noPx(custWidth));
- } else if (thElement.classed(tableIcon)) {
- setColWidth(thElement, tdElement, tableIconTdSize);
- } else {
- setColWidth(thElement, tdElement, defaultColWidth);
- }
- });
- }
+ findCstmWidths();
+ setTdWidths(thead);
+ setTdWidths(tbody);
+ setHeight(tbodyDiv);
- // 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 ttlHgt = fs.noPxStyle(d3.select('.tabular-header'), 'height'),
- thHgt = fs.noPxStyle(thead, 'height'),
- totalHgt = ttlHgt + thHgt + pdg,
- tbleHgt = fs.windowSize(mast.mastHeight() + totalHgt).height;
-
- thead.style('display', 'block');
- tbody.style({
- display: 'block',
- height: tbleHgt + 'px',
- overflow: 'auto'
- });
- }
-
- function fixTable(t, th, tb) {
- setTableWidth(t);
- setTableHeight(th, tb);
+ cstmWidths = {};
}
// Functions for sorting table rows by header
@@ -163,40 +145,42 @@
}
angular.module('onosWidget')
- .directive('onosFixedHeader', ['$window', 'FnService', 'MastService',
- function (_$window_, _fs_, _mast_) {
+ .directive('onosFixedHeader', ['$log','$window',
+ 'FnService', 'MastService',
+
+ function (_$log_, _$window_, _fs_, _mast_) {
return function (scope, element) {
+ $log = _$log_;
$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
+ h: $window.innerHeight,
+ w: $window.innerWidth
};
- }, function (newVal) {
- var wsz = fs.windowSize(0, 30);
- scope.windowHeight = newVal.h;
- scope.windowWidth = newVal.w;
+ }, function () {
+ var wsz = fs.windowSize(0, 30),
+ wWidth = wsz.width,
+ wHeight = wsz.height;
- // default table size in case no data elements
- table.style('width', wsz.width + 'px');
+ if (!scope.tableData.length) {
+ defaultSize(table, wWidth);
+ }
scope.$on('LastElement', function () {
// only adjust the table once it's completely loaded
- fixTable(table, thead, tbody);
+ adjustTable(table, wWidth, wHeight);
canAdjust = true;
});
if (canAdjust) {
- fixTable(table, thead, tbody);
+ adjustTable(table, wWidth, wHeight);
}
}, true);
@@ -215,16 +199,16 @@
link: function (scope, element) {
$log = _$log_;
is = _is_;
- var table = d3.select(element[0]);
+ var header = d3.select(element[0]);
sortIconAPI = is.sortIcons();
- // when a header is clicked, change its icon tag
+ // when a header is clicked, change its sort direction
// and get sorting order to send to the server.
- table.selectAll('th').on('click', function () {
- var thElem = d3.select(this);
+ header.selectAll('td').on('click', function () {
+ var col = d3.select(this);
- if (thElem.attr('sortable') === '') {
- updateSortDirection(thElem);
+ if (col.attr('sortable') === '') {
+ updateSortDirection(col);
scope.ctrlCallback({
requestParams: sortRequestParams()
});
@@ -234,9 +218,9 @@
};
}])
- .factory('TableService', ['$log', 'IconService',
+ .factory('TableService', ['IconService',
- function ($log, is) {
+ function (is) {
sortIconAPI = is.sortIcons();
return {
diff --git a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
index 1343b8f..3a97732 100644
--- a/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
+++ b/web/gui/src/main/webapp/app/fw/widget/tableBuilder.js
@@ -25,7 +25,6 @@
// example params to buildTable:
// {
- // self: this, <- controller object
// scope: $scope, <- controller scope
// tag: 'device', <- table identifier
// selCb: selCb <- row selection callback (optional)
@@ -43,10 +42,10 @@
resp = o.tag + 'DataResponse',
onSel = fs.isF(o.selCb);
- o.self.tableData = [];
+ o.scope.tableData = [];
function respCb(data) {
- o.self.tableData = data[root];
+ o.scope.tableData = data[root];
o.scope.$apply();
}
diff --git a/web/gui/src/main/webapp/app/view/app/app.html b/web/gui/src/main/webapp/app/view/app/app.html
index bb5f4ca..c57da76 100644
--- a/web/gui/src/main/webapp/app/view/app/app.html
+++ b/web/gui/src/main/webapp/app/view/app/app.html
@@ -1,7 +1,7 @@
<!-- app partial HTML -->
<div id="ov-app">
<div class="tabular-header">
- <h2>Applications ({{ctrl.tableData.length}} total)</h2>
+ <h2>Applications ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
@@ -19,39 +19,44 @@
</form>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="state" class="table-icon" sortable></th>
- <th colId="id" sortable>App ID </th>
- <th colId="version" sortable>Version </th>
- <th colId="origin" sortable>Origin </th>
- <th colId="desc" col-width="640px">Description </th>
- </tr>
- </thead>
+ <div class="summary-list" onos-fixed-header>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="5">
- No Applications found
- </td>
- </tr>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="state" class="table-icon" sortable></td>
+ <td colId="id" sortable>App ID </td>
+ <td colId="version" sortable>Version </td>
+ <td colId="origin" sortable>Origin </td>
+ <td colId="desc" col-width="475px">Description </td>
+ </tr>
+ </table>
+ </div>
- <tr ng-repeat="app in ctrl.tableData"
- ng-click="selectCallback($event, app)"
- ng-class="{selected: app === sel}"
- ng-repeat-done>
- <td class="table-icon">
- <div icon icon-id="{{app._iconid_state}}"></div>
- </td>
- <td>{{app.id}}</td>
- <td>{{app.version}}</td>
- <td>{{app.origin}}</td>
- <td>{{app.desc}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="5">
+ No Applications found
+ </td>
+ </tr>
+
+ <tr ng-repeat="app in tableData"
+ ng-click="selectCallback($event, app)"
+ ng-class="{selected: app === sel}"
+ ng-repeat-done>
+ <td class="table-icon">
+ <div icon icon-id="{{app._iconid_state}}"></div>
+ </td>
+ <td>{{app.id}}</td>
+ <td>{{app.version}}</td>
+ <td>{{app.origin}}</td>
+ <td>{{app.desc}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/app/app.js b/web/gui/src/main/webapp/app/view/app/app.js
index d0b561b..674407b 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -71,7 +71,6 @@
d3.select('#app-deactivate').on('click', function () { appAction('deactivate'); });
tbs.buildTable({
- self: this,
scope: $scope,
tag: 'app',
selCb: selCb
diff --git a/web/gui/src/main/webapp/app/view/cluster/cluster.html b/web/gui/src/main/webapp/app/view/cluster/cluster.html
index 2c58bc0..727974e 100644
--- a/web/gui/src/main/webapp/app/view/cluster/cluster.html
+++ b/web/gui/src/main/webapp/app/view/cluster/cluster.html
@@ -17,7 +17,7 @@
<!-- Cluster partial HTML -->
<div id="ov-cluster">
<div class="tabular-header">
- <h2>Cluster Nodes ({{ctrl.tableData.length}} total)</h2>
+ <h2>Cluster Nodes ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
@@ -25,37 +25,42 @@
</div>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="_iconid_state" class="table-icon" sortable></th>
- <th colId="id" sortable>ID </th>
- <th colId="ip" sortable>IP Address </th>
- <th colId="tcp" sortable>TCP Port </th>
- <th colId="updated" sortable>Last Updated </th>
- </tr>
- </thead>
+ <div class="summary-list" onos-fixed-header>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="5">
- No Cluster Nodes found
- </td>
- </tr>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="_iconid_state" class="table-icon" sortable></td>
+ <td colId="id" sortable>ID </td>
+ <td colId="ip" sortable>IP Address </td>
+ <td colId="tcp" sortable>TCP Port </td>
+ <td colId="updated" sortable>Last Updated </td>
+ </tr>
+ </table>
+ </div>
- <tr ng-repeat="node in ctrl.tableData"
- ng-repeat-done>
- <td class="table-icon">
- <div icon icon-id="{{node._iconid_state}}"></div>
- </td>
- <td>{{node.id}}</td>
- <td>{{node.ip}}</td>
- <td>{{node.tcp}}</td>
- <td>{{node.updated}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="5">
+ No Cluster Nodes found
+ </td>
+ </tr>
+
+ <tr ng-repeat="node in tableData"
+ ng-repeat-done>
+ <td class="table-icon">
+ <div icon icon-id="{{node._iconid_state}}"></div>
+ </td>
+ <td>{{node.id}}</td>
+ <td>{{node.ip}}</td>
+ <td>{{node.tcp}}</td>
+ <td>{{node.updated}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/cluster/cluster.js b/web/gui/src/main/webapp/app/view/cluster/cluster.js
index d88c03c..25e5bd2 100644
--- a/web/gui/src/main/webapp/app/view/cluster/cluster.js
+++ b/web/gui/src/main/webapp/app/view/cluster/cluster.js
@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
- self: this,
scope: $scope,
tag: 'cluster'
});
diff --git a/web/gui/src/main/webapp/app/view/device/device.html b/web/gui/src/main/webapp/app/view/device/device.html
index ba1cb4b..0c202e0 100644
--- a/web/gui/src/main/webapp/app/view/device/device.html
+++ b/web/gui/src/main/webapp/app/view/device/device.html
@@ -1,7 +1,7 @@
<!-- Device partial HTML -->
<div id="ov-device">
<div class="tabular-header">
- <h2>Devices ({{ctrl.tableData.length}} total)</h2>
+ <h2>Devices ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
@@ -9,49 +9,54 @@
</div>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="available" class="table-icon" sortable></th>
- <th colId="type" class="table-icon" sortable></th>
- <th colId="id" sortable>Device ID </th>
- <th colId="masterid" sortable>Master Instance </th>
- <th colId="num_ports" sortable>Ports </th>
- <th colId="mfr" sortable>Vendor </th>
- <th colId="hw" sortable>H/W Version </th>
- <th colId="sw" sortable>S/W Version </th>
- <th colId="protocol" sortable>Protocol </th>
- </tr>
- </thead>
+ <div class="summary-list" onos-fixed-header>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="9">
- No Devices found
- </td>
- </tr>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="available" class="table-icon" sortable></td>
+ <td colId="type" class="table-icon" sortable></td>
+ <td colId="id" sortable>Device ID </td>
+ <td colId="masterid" sortable>Master Instance </td>
+ <td colId="num_ports" sortable>Ports </td>
+ <td colId="mfr" sortable>Vendor </td>
+ <td colId="hw" sortable>H/W Version </td>
+ <td colId="sw" sortable>S/W Version </td>
+ <td colId="protocol" sortable>Protocol </td>
+ </tr>
+ </table>
+ </div>
- <tr ng-repeat="dev in ctrl.tableData"
- ng-click="selectCallback($event, dev)"
- ng-class="{selected: dev === sel}"
- ng-repeat-done>
- <td class="table-icon">
- <div icon icon-id="{{dev._iconid_available}}"></div>
- </td>
- <td class="table-icon">
- <div icon icon-id="{{dev._iconid_type}}"></div>
- </td>
- <td>{{dev.id}}</td>
- <td>{{dev.masterid}}</td>
- <td>{{dev.num_ports}}</td>
- <td>{{dev.mfr}}</td>
- <td>{{dev.hw}}</td>
- <td>{{dev.sw}}</td>
- <td>{{dev.protocol}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="9">
+ No Devices found
+ </td>
+ </tr>
+
+ <tr ng-repeat="dev in tableData"
+ ng-click="selectCallback($event, dev)"
+ ng-class="{selected: dev === sel}"
+ ng-repeat-done>
+ <td class="table-icon">
+ <div icon icon-id="{{dev._iconid_available}}"></div>
+ </td>
+ <td class="table-icon">
+ <div icon icon-id="{{dev._iconid_type}}"></div>
+ </td>
+ <td>{{dev.id}}</td>
+ <td>{{dev.masterid}}</td>
+ <td>{{dev.num_ports}}</td>
+ <td>{{dev.mfr}}</td>
+ <td>{{dev.hw}}</td>
+ <td>{{dev.sw}}</td>
+ <td>{{dev.protocol}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/device/device.js b/web/gui/src/main/webapp/app/view/device/device.js
index 38953d7..cd0799b 100644
--- a/web/gui/src/main/webapp/app/view/device/device.js
+++ b/web/gui/src/main/webapp/app/view/device/device.js
@@ -25,8 +25,7 @@
var $log, $scope, fs, mast, ps, wss, is, bns, ns, ttip;
// internal state
- var self,
- detailsPanel,
+ var detailsPanel,
pStartY, pHeight,
top, bottom, iconDiv,
wSize, selRow;
@@ -183,8 +182,8 @@
}
function respDetailsCb(data) {
- self.panelData = data.details;
- populateDetails(self.panelData);
+ $scope.panelData = data.details;
+ populateDetails($scope.panelData);
detailsPanel.show();
}
@@ -219,9 +218,8 @@
bns = _bns_;
ns = _ns_;
ttip = _ttip_;
- self = this;
var handlers = {};
- self.panelData = [];
+ $scope.panelData = [];
pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+ mast.mastHeight() + topPdg;
wSize = fs.windowSize(pStartY);
@@ -238,7 +236,6 @@
}
tbs.buildTable({
- self: self,
scope: $scope,
tag: 'device',
selCb: selCb
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.css b/web/gui/src/main/webapp/app/view/flow/flow.css
index ecbd217..3e5cb2c 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.css
+++ b/web/gui/src/main/webapp/app/view/flow/flow.css
@@ -50,4 +50,5 @@
#ov-flow td.selector,
#ov-flow td.treatment {
padding-left: 36px;
+ opacity: 0.65;
}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.html b/web/gui/src/main/webapp/app/view/flow/flow.html
index d2278ab..33fd548 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.html
+++ b/web/gui/src/main/webapp/app/view/flow/flow.html
@@ -2,8 +2,8 @@
<div id="ov-flow">
<div class="tabular-header">
<h2>
- Flows for Device {{ctrl.devId || "(No device selected)"}}
- ({{ctrl.tableData.length}} total)
+ Flows for Device {{devId || "(No device selected)"}}
+ ({{tableData.length}} total)
</h2>
<div class="ctrl-btns">
<div class="refresh active"
@@ -12,46 +12,52 @@
</div>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="id" sortable>Flow ID </th>
- <th colId="appId" sortable>App ID </th>
- <th colId="groupId" sortable>Group ID </th>
- <th colId="tableId" sortable>Table ID </th>
- <th colId="priority" sortable>Priority </th>
- <th colId="timeout" sortable>Timeout </th>
- <th colId="permanent" sortable>Permanent </th>
- <th colId="state" sortable>State </th>
- </tr>
- </thead>
+ <div class="summary-list" onos-fixed-header>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="8">
- No Flows found
- </td>
- </tr>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="id" col-width="180px" sortable>Flow ID </td>
+ <td colId="appId" sortable>App ID </td>
+ <td colId="groupId" sortable>Group ID </td>
+ <td colId="tableId" sortable>Table ID </td>
+ <td colId="priority" sortable>Priority </td>
+ <td colId="timeout" sortable>Timeout </td>
+ <td colId="permanent" sortable>Permanent </td>
+ <td colId="state" sortable>State </td>
+ </tr>
+ </table>
+ </div>
- <tr ng-repeat-start="flow in ctrl.tableData">
- <td>{{flow.id}}</td>
- <td>{{flow.appId}}</td>
- <td>{{flow.groupId}}</td>
- <td>{{flow.tableId}}</td>
- <td>{{flow.priority}}</td>
- <td>{{flow.timeout}}</td>
- <td>{{flow.permanent}}</td>
- <td>{{flow.state}}</td>
- </tr>
- <tr>
- <td class="selector" colspan="8">{{flow.selector}}</td>
- </tr>
- <tr ng-repeat-end ng-repeat-done>
- <td class="treatment" colspan="8">{{flow.treatment}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="8">
+ No Flows found
+ </td>
+ </tr>
+
+ <tr ng-repeat-start="flow in tableData">
+ <td>{{flow.id}}</td>
+ <td>{{flow.appId}}</td>
+ <td>{{flow.groupId}}</td>
+ <td>{{flow.tableId}}</td>
+ <td>{{flow.priority}}</td>
+ <td>{{flow.timeout}}</td>
+ <td>{{flow.permanent}}</td>
+ <td>{{flow.state}}</td>
+ </tr>
+ <tr class="ignore-width">
+ <td class="selector" colspan="8">{{flow.selector}}</td>
+ </tr>
+ <tr class="ignore-width"
+ ng-repeat-end ng-repeat-done>
+ <td class="treatment" colspan="8">{{flow.treatment}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.js b/web/gui/src/main/webapp/app/view/flow/flow.js
index bcd471b..c75ed87 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.js
+++ b/web/gui/src/main/webapp/app/view/flow/flow.js
@@ -30,8 +30,7 @@
'FnService', 'TableService', 'TableBuilderService',
function (_$log_, _$scope_, _$location_, _fs_, _ts_, _tbs_) {
- var self = this,
- params;
+ var params;
$log = _$log_;
$scope = _$scope_;
$location = _$location_;
@@ -41,11 +40,10 @@
params = $location.search();
if (params.hasOwnProperty('devId')) {
- self.devId = params['devId'];
+ $scope.devId = params['devId'];
}
tbs.buildTable({
- self: self,
scope: $scope,
tag: 'flow',
query: params
diff --git a/web/gui/src/main/webapp/app/view/host/host.html b/web/gui/src/main/webapp/app/view/host/host.html
index 9f70432..a4f8c4f 100644
--- a/web/gui/src/main/webapp/app/view/host/host.html
+++ b/web/gui/src/main/webapp/app/view/host/host.html
@@ -1,7 +1,7 @@
<!-- Host partial HTML -->
<div id="ov-host">
<div class="tabular-header">
- <h2>Hosts ({{ctrl.tableData.length}} total)</h2>
+ <h2>Hosts ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
@@ -9,39 +9,44 @@
</div>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="type" class="table-icon" sortable></th>
- <th colId="id" sortable>Host ID </th>
- <th colId="mac" sortable>MAC Address </th>
- <th colId="vlan" sortable>VLAN ID </th>
- <th colId="ips" sortable>IP Addresses </th>
- <th colId="location" sortable>Location </th>
- </tr>
- </thead>
+ <div class="summary-list" onos-fixed-header>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="6">
- No Hosts found
- </td>
- </tr>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="type" class="table-icon" sortable></td>
+ <td colId="id" sortable>Host ID </td>
+ <td colId="mac" sortable>MAC Address </td>
+ <td colId="vlan" sortable>VLAN ID </td>
+ <td colId="ips" sortable>IP Addresses </td>
+ <td colId="location" sortable>Location </td>
+ </tr>
+ </table>
+ </div>
- <tr ng-repeat="host in ctrl.tableData"
- ng-repeat-done>
- <td class="table-icon">
- <div icon icon-id="{{host._iconid_type}}"></div>
- </td>
- <td>{{host.id}}</td>
- <td>{{host.mac}}</td>
- <td>{{host.vlan}}</td>
- <td>{{host.ips}}</td>
- <td>{{host.location}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="6">
+ No Hosts found
+ </td>
+ </tr>
+
+ <tr ng-repeat="host in tableData"
+ ng-repeat-done>
+ <td class="table-icon">
+ <div icon icon-id="{{host._iconid_type}}"></div>
+ </td>
+ <td>{{host.id}}</td>
+ <td>{{host.mac}}</td>
+ <td>{{host.vlan}}</td>
+ <td>{{host.ips}}</td>
+ <td>{{host.location}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/host/host.js b/web/gui/src/main/webapp/app/view/host/host.js
index a3e43aa..e82c7da 100644
--- a/web/gui/src/main/webapp/app/view/host/host.js
+++ b/web/gui/src/main/webapp/app/view/host/host.js
@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
- self: this,
scope: $scope,
tag: 'host'
});
@@ -37,7 +36,7 @@
ts.resetSortIcons();
$scope.sortCallback();
};
-
+
$log.log('OvHostCtrl has been created');
}]);
}());
diff --git a/web/gui/src/main/webapp/app/view/intent/intent.css b/web/gui/src/main/webapp/app/view/intent/intent.css
index 4f9ea8a..49bfc18 100644
--- a/web/gui/src/main/webapp/app/view/intent/intent.css
+++ b/web/gui/src/main/webapp/app/view/intent/intent.css
@@ -50,4 +50,5 @@
#ov-intent td.resources,
#ov-intent td.details {
padding-left: 36px;
+ opacity: 0.65;
}
diff --git a/web/gui/src/main/webapp/app/view/intent/intent.html b/web/gui/src/main/webapp/app/view/intent/intent.html
index 2b737f4..c33df85 100644
--- a/web/gui/src/main/webapp/app/view/intent/intent.html
+++ b/web/gui/src/main/webapp/app/view/intent/intent.html
@@ -17,45 +17,51 @@
<!-- Intent partial HTML -->
<div id="ov-intent">
<div class="tabular-header">
- <h2>Intents ({{ctrl.tableData.length}} total)</h2>
+ <h2>Intents ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
ng-click="refresh()"></div>
</div>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="appId" sortable>Application ID </th>
- <th colId="key" sortable>Key </th>
- <th colId="type" sortable>Type </th>
- <th colId="priority" sortable>Priority </th>
- </tr>
- </thead>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="4">
- No Intents found
- </td>
- </tr>
+ <div class="summary-list" onos-fixed-header>
- <tr ng-repeat-start="intent in ctrl.tableData">
- <td>{{intent.appId}}</td>
- <td>{{intent.key}}</td>
- <td>{{intent.type}}</td>
- <td>{{intent.priority}}</td>
- </tr>
- <tr>
- <td class="resources" colspan="4">{{intent.resources}}</td>
- </tr>
- <tr ng-repeat-end ng-repeat-done>
- <td class="details" colspan="4">{{intent.details}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="appId" sortable>Application ID </td>
+ <td colId="key" sortable>Key </td>
+ <td colId="type" sortable>Type </td>
+ <td colId="priority" sortable>Priority </td>
+ </tr>
+ </table>
+ </div>
+
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="4">
+ No Intents found
+ </td>
+ </tr>
+
+ <tr ng-repeat-start="intent in tableData">
+ <td>{{intent.appId}}</td>
+ <td>{{intent.key}}</td>
+ <td>{{intent.type}}</td>
+ <td>{{intent.priority}}</td>
+ </tr>
+ <tr>
+ <td class="resources" colspan="4">{{intent.resources}}</td>
+ </tr>
+ <tr ng-repeat-end ng-repeat-done>
+ <td class="details" colspan="4">{{intent.details}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/intent/intent.js b/web/gui/src/main/webapp/app/view/intent/intent.js
index 4e23aec..e74e927 100644
--- a/web/gui/src/main/webapp/app/view/intent/intent.js
+++ b/web/gui/src/main/webapp/app/view/intent/intent.js
@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
- self: this,
scope: $scope,
tag: 'intent'
});
diff --git a/web/gui/src/main/webapp/app/view/link/link.html b/web/gui/src/main/webapp/app/view/link/link.html
index 29121c9..ab20b63 100644
--- a/web/gui/src/main/webapp/app/view/link/link.html
+++ b/web/gui/src/main/webapp/app/view/link/link.html
@@ -17,7 +17,7 @@
<!-- Link partial HTML -->
<div id="ov-link">
<div class="tabular-header">
- <h2>Links ({{ctrl.tableData.length}} total)</h2>
+ <h2>Links ({{tableData.length}} total)</h2>
<div class="ctrl-btns">
<div class="refresh active"
icon icon-size="36" icon-id="refresh"
@@ -25,39 +25,44 @@
</div>
</div>
- <table class="summary-list"
- onos-fixed-header
- onos-sortable-header
- sort-callback="sortCallback(requestParams)">
- <thead>
- <tr>
- <th colId="_iconid_state" class="table-icon" sortable></th>
- <th colId="one" sortable>Port 1 </th>
- <th colId="two" sortable>Port 2 </th>
- <th colId="type" sortable>Type </th>
- <th colId="direction" sortable>Direction </th>
- <th colId="durable" sortable>Durable </th>
- </tr>
- </thead>
+ <div class="summary-list" onos-fixed-header>
- <tbody>
- <tr ng-hide="ctrl.tableData.length">
- <td class="nodata" colspan="6">
- No Links found
- </td>
- </tr>
+ <div class="table-header"
+ onos-sortable-header sort-callback="sortCallback(requestParams)">
+ <table>
+ <tr>
+ <td colId="_iconid_state" class="table-icon" sortable></td>
+ <td colId="one" sortable>Port 1 </td>
+ <td colId="two" sortable>Port 2 </td>
+ <td colId="type" sortable>Type </td>
+ <td colId="direction" sortable>Direction </td>
+ <td colId="durable" sortable>Durable </td>
+ </tr>
+ </table>
+ </div>
- <tr ng-repeat="link in ctrl.tableData"
- ng-repeat-done>
- <td class="table-icon">
- <div icon icon-id="{{link._iconid_state}}"></div>
- </td>
- <td>{{link.one}}</td>
- <td>{{link.two}}</td>
- <td>{{link.type}}</td>
- <td>{{link.direction}}</td>
- <td>{{link.durable}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-body">
+ <table>
+ <tr ng-hide="tableData.length" class="no-data ignore-width">
+ <td colspan="6">
+ No Links found
+ </td>
+ </tr>
+
+ <tr ng-repeat="link in tableData"
+ ng-repeat-done>
+ <td class="table-icon">
+ <div icon icon-id="{{link._iconid_state}}"></div>
+ </td>
+ <td>{{link.one}}</td>
+ <td>{{link.two}}</td>
+ <td>{{link.type}}</td>
+ <td>{{link.direction}}</td>
+ <td>{{link.durable}}</td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
</div>
diff --git a/web/gui/src/main/webapp/app/view/link/link.js b/web/gui/src/main/webapp/app/view/link/link.js
index bc69430..743e90d 100644
--- a/web/gui/src/main/webapp/app/view/link/link.js
+++ b/web/gui/src/main/webapp/app/view/link/link.js
@@ -27,7 +27,6 @@
function ($log, $scope, ts, tbs) {
tbs.buildTable({
- self: this,
scope: $scope,
tag: 'link'
});
@@ -37,7 +36,7 @@
ts.resetSortIcons();
$scope.sortCallback();
};
-
+
$log.log('OvLinkCtrl has been created');
}]);
}());
diff --git a/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js b/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js
index 693f42d..6df87b3 100644
--- a/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js
@@ -20,71 +20,59 @@
describe('factory: fw/widget/table.js', function () {
var $log, $compile, $rootScope,
fs, ts, mast, is,
- scope, compiled,
- table, thead, tbody, mockHeader,
- mockH2Height = 20,
- mockMastHeight = 20,
- mockHeaderHeight = mockH2Height + mockMastHeight,
- tableIconTdSize = 100,
- numTestElems = 4;
+ scope,
+ containerDiv,
+ headerDiv, bodyDiv,
+ header, body,
+ mockHeader,
+ mockHeaderHeight = 40;
var onosFixedHeaderTags =
- '<table onos-fixed-header>' +
- '<thead style="height:27px;">' +
- '<tr>' +
- '<th></th>' +
- '<th>Device ID </th>' +
- '<th col-width="100px">H/W Version </th>' +
- '<th>S/W Version </th>' +
- '</tr>' +
- '</thead>' +
- '<tbody>' +
- '<tr>' +
- '<td colspan="4">' +
- 'No Devices found' +
- '</td>' +
- '</tr>' +
- '<tr>' +
- '<td class="table-icon">' +
- '<div icon icon-id="{{dev._iconid_available}}">' +
- '</div>' +
- '</td>' +
- '<td>Some ID</td>' +
- '<td>Some HW</td>' +
- '<td>Some Software</td>' +
- '</tr>' +
- '</tbody>' +
- '</table>',
+ '<div class="summary-list" onos-fixed-header>' +
+ '<div class="table-header">' +
+ '<table>' +
+ '<tr>' +
+ '<td colId="type" class="table-icon"></td>' +
+ '<td colId="id">Host ID </td>' +
+ '<td colId="mac" sortable>MAC Address </td>' +
+ '<td colId="location" col-width="110px">Location </td>' +
+ '</tr>' +
+ '</table>' +
+ '</div>' +
+
+ '<div class="table-body">' +
+ '<table>' +
+ '<tr class="ignore-width">' +
+ '<td class="not-picked"></td>' +
+ '</tr>' +
+ '<tr>' +
+ '<td class="table-icon">Some Icon</td>' +
+ '<td>Some ID</td>' +
+ '<td>Some MAC Address</td>' +
+ '<td>Some Location</td>' +
+ '</tr>' +
+ '</table>' +
+ '</div>' +
+ '</div>',
onosSortableHeaderTags =
- '<table onos-sortable-header ' +
+ '<div onos-sortable-header ' +
'sort-callback="sortCallback(requestParams)">' +
- '<thead>' +
- '<tr>' +
- '<th colId="available"></th>' +
- '<th colId="id" sortable>Device ID </th>' +
- '<th colId="hw" sortable>H/W Version </th>' +
- '<th colId="sw" sortable>S/W Version </th>' +
- '</tr>' +
- '</thead>' +
- '<tbody>' +
- '<tr>' +
- '<td>' +
- '<div icon icon-id="{{dev._iconid_available}}">' +
- '</div>' +
- '</td>' +
- '<td>Some ID</td>' +
- '<td>Some HW</td>' +
- '<td>Some Software</td>' +
- '</tr>' +
- '</tbody>' +
- '</table>';
+ '<table>' +
+ '<tr>' +
+ '<td colId="type"></td>' +
+ '<td colId="id" sortable>Host ID </td>' +
+ '<td colId="mac" sortable>MAC Address </td>' +
+ '<td colId="location" sortable>Location </td>' +
+ '</tr>' +
+ '</table>' +
+ '</div>';
beforeEach(module('onosWidget', 'onosUtil', 'onosMast', 'onosSvg'));
var mockWindow = {
- innerWidth: 400,
- innerHeight: 200,
+ innerWidth: 600,
+ innerHeight: 400,
navigator: {
userAgent: 'defaultUA'
},
@@ -111,23 +99,44 @@
beforeEach(function () {
scope = $rootScope.$new();
+ scope.tableData = [];
});
+ // Note: dummy header so that d3 doesn't trip up.
+ // $compile has to be used on the directive tag element, so it can't
+ // be included in the tag strings declared above.
beforeEach(function () {
mockHeader = d3.select('body')
.append('h2')
.classed('tabular-header', true)
- .style('height', mockHeaderHeight + 'px')
- .html('Some Header');
+ .style({
+ height: mockHeaderHeight + 'px',
+ margin: 0,
+ padding: 0
+ })
+ .text('Some Header');
});
afterEach(function () {
- table = null;
- thead = null;
- tbody = null;
+ containerDiv = undefined;
+ headerDiv = undefined;
+ bodyDiv = undefined;
+ header = undefined;
+ body = undefined;
mockHeader.remove();
});
+ function populateTableData() {
+ scope.tableData = [
+ {
+ type: 'endstation',
+ id: '1234',
+ mac: '00:00:03',
+ location: 'USA'
+ }
+ ];
+ }
+
it('should define TableBuilderService', function () {
expect(ts).toBeDefined();
});
@@ -138,83 +147,119 @@
])).toBeTruthy();
});
- function compileTable() {
- compiled = $compile(table);
+ function compile(elem) {
+ var compiled = $compile(elem);
compiled(scope);
scope.$digest();
}
- function verifyGivenTags(dirName) {
- expect(table).toBeDefined();
- expect(table.attr(dirName)).toBe('');
+ function selectTables() {
+ expect(containerDiv.find('div').length).toBe(2);
- thead = table.find('thead');
- expect(thead).toBeDefined();
- tbody = table.find('tbody');
- expect(tbody).toBeDefined();
+ headerDiv = angular.element(containerDiv[0].querySelector('.table-header'));
+ expect(headerDiv.length).toBe(1);
+
+ bodyDiv = angular.element(containerDiv[0].querySelector('.table-body'));
+ expect(bodyDiv.length).toBe(1);
+
+ header = headerDiv.find('table');
+ expect(header.length).toBe(1);
+
+ body = bodyDiv.find('table');
+ expect(body.length).toBe(1);
}
- function verifyCssDisplay() {
- var padding = 21, // bottom table constant 12 + mastPadding(?) 9
- tableHeight = fs.windowSize(mockHeaderHeight).height -
- (fs.noPx(table.find('thead').css('height')) + padding);
+ function verifyGivenTags(dirName, div) {
+ expect(div).toBeDefined();
+ expect(div.attr(dirName)).toBe('');
+ }
- expect(thead.css('display')).toBe('block');
- expect(tbody.css('display')).toBe('block');
- expect(tbody.css('height')).toBe(tableHeight + 'px');
- expect(tbody.css('overflow')).toBe('auto');
+ function verifyDefaultSize() {
+ expect(header.css('width')).toBe('570px');
+ expect(body.css('width')).toBe('570px');
+ }
- // TODO: investigate why math for calculating the height works better
- // in the browser window (thead height is 0 in this test?)
+ function verifyHeight() {
+ var padding = 12,
+ mastHeight = 36,
+ tableHeight = (mockWindow.innerHeight - mockHeaderHeight) -
+ (fs.noPx(headerDiv.css('height')) + mastHeight + padding);
+
+ expect(bodyDiv.css('height')).toBe(tableHeight + 'px');
}
function verifyColWidth() {
- var winWidth = fs.windowSize().width,
- colWidth, thElems, tr, tdElem;
+ var hdrs = header.find('td'),
+ cols = body.find('td');
- colWidth = Math.floor(winWidth / numTestElems);
+ expect(angular.element(hdrs[0]).css('width')).toBe('33px');
+ expect(angular.element(hdrs[3]).css('width')).toBe('110px');
- thElems = thead.find('th');
+ expect(angular.element(cols[1]).css('width')).toBe('33px');
+ expect(angular.element(cols[4]).css('width')).toBe('110px');
+ }
- angular.forEach(thElems, function (thElem, i) {
- thElem = angular.element(thElems[i]);
- tr = angular.element(tbody.find('tr').eq(1));
- tdElem = angular.element(tr.find('td').eq(i));
- var custWidth = thElem.attr('col-width');
+ function verifyCallbacks(h) {
+ expect(scope.sortCallback).not.toHaveBeenCalled();
- if (custWidth) {
- expect(thElem.css('width')).toBe(custWidth);
- expect(tdElem.css('width')).toBe(custWidth);
- } else if (tdElem.attr('class') === 'table-icon') {
- expect(thElem.css('width')).toBe(tableIconTdSize + 'px');
- expect(tdElem.css('width')).toBe(tableIconTdSize + 'px');
- } else {
- expect(thElem.css('width')).toBe(colWidth + 'px');
- expect(tdElem.css('width')).toBe(colWidth + 'px');
- }
+ h[0].click();
+ expect(scope.sortCallback).not.toHaveBeenCalled();
+
+ h[1].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'id',
+ sortDir: 'asc'
+ });
+ h[1].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'id',
+ sortDir: 'desc'
+ });
+ h[1].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'id',
+ sortDir: 'asc'
+ });
+
+ h[2].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'mac',
+ sortDir: 'asc'
+ });
+ h[2].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'mac',
+ sortDir: 'desc'
+ });
+ h[2].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'mac',
+ sortDir: 'asc'
+ });
+
+ h[3].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'location',
+ sortDir: 'asc'
+ });
+ h[3].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'location',
+ sortDir: 'desc'
+ });
+ h[3].click();
+ expect(scope.sortCallback).toHaveBeenCalledWith({
+ sortCol: 'location',
+ sortDir: 'asc'
});
}
- function verifyCallbacks(thElems) {
- expect(scope.sortCallback).not.toHaveBeenCalled();
+ function verifyIcons(h) {
+ var currH, div;
- // first test header has no 'sortable' attr
- thElems[0].click();
- expect(scope.sortCallback).not.toHaveBeenCalled();
-
- // the other headers have 'sortable'
- for(var i = 1; i < numTestElems; i += 1) {
- thElems[i].click();
- expect(scope.sortCallback).toHaveBeenCalled();
- }
- }
-
- function verifyIcons(thElems) {
- var currentTh, div;
- // make sure it has the correct icon after clicking
- thElems[1].click();
- currentTh = angular.element(thElems[1]);
- div = currentTh.find('div');
+ h[1].click();
+ currH = angular.element(h[1]);
+ div = currH.find('div');
expect(div.html()).toBe(
'<svg class="embeddedIcon" width="10" height="10" viewBox="0 0 ' +
'50 50"><g class="icon upArrow"><rect width="50" height="50" ' +
@@ -222,8 +267,8 @@
'xlink="http://www.w3.org/1999/xlink" xlink:href="#triangleUp">' +
'</use></g></svg>'
);
- thElems[1].click();
- div = currentTh.find('div');
+ h[1].click();
+ div = currH.find('div');
expect(div.html()).toBe(
'<svg class="embeddedIcon" width="10" height="10" viewBox="0 0 ' +
'50 50"><g class="icon downArrow"><rect width="50" height="50" ' +
@@ -232,14 +277,14 @@
'</use></g></svg>'
);
- thElems[2].click();
- div = currentTh.children();
+ h[2].click();
+ div = currH.children();
// clicked on a new element, so the previous icon should have been deleted
expect(div.html()).toBeFalsy();
// the new element should have the ascending icon
- currentTh = angular.element(thElems[2]);
- div = currentTh.children();
+ currH = angular.element(h[2]);
+ div = currH.children();
expect(div.html()).toBe(
'<svg class="embeddedIcon" width="10" height="10" viewBox="0 0 ' +
'50 50"><g class="icon upArrow"><rect width="50" height="50" ' +
@@ -250,31 +295,42 @@
}
it('should affirm that onos-fixed-header is working', function () {
- table = angular.element(onosFixedHeaderTags);
+ containerDiv = angular.element(onosFixedHeaderTags);
- compileTable();
- verifyGivenTags('onos-fixed-header');
+ compile(containerDiv);
- // table will not be fixed unless it receives the 'LastElement' event
+ verifyGivenTags('onos-fixed-header', containerDiv);
+ selectTables();
+ verifyDefaultSize();
+
+ populateTableData();
+
scope.$emit('LastElement');
scope.$digest();
- verifyCssDisplay();
+ verifyHeight();
+ verifyColWidth();
+
+ mockWindow.innerHeight = 300;
+ scope.$digest();
+ verifyHeight();
+
+ mockWindow.innerWidth = 500;
+ scope.$digest();
verifyColWidth();
});
it('should affirm that onos-sortable-header is working', function () {
- var thElems;
- table = angular.element(onosSortableHeaderTags);
+ headerDiv = angular.element(onosSortableHeaderTags);
- compileTable();
- verifyGivenTags('onos-sortable-header');
+ compile(headerDiv);
+ verifyGivenTags('onos-sortable-header', headerDiv);
scope.sortCallback = jasmine.createSpy('sortCallback');
- thElems = thead.find('th');
- verifyCallbacks(thElems);
- verifyIcons(thElems);
+ header = headerDiv.find('td');
+ verifyCallbacks(header);
+ verifyIcons(header);
});
// Note: testing resetSortIcons isn't feasible because due to the nature of
diff --git a/web/gui/src/main/webapp/tests/app/fw/widget/tableBuilder-spec.js b/web/gui/src/main/webapp/tests/app/fw/widget/tableBuilder-spec.js
index f631617..3353805 100644
--- a/web/gui/src/main/webapp/tests/app/fw/widget/tableBuilder-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/widget/tableBuilder-spec.js
@@ -48,7 +48,6 @@
beforeEach(function () {
mockObj = {
- self: {},
scope: $rootScope.$new(),
tag: 'foo',
selCb: mockSelCb
@@ -78,10 +77,10 @@
});
it('should set tableData', function () {
- expect(mockObj.self.tableData).not.toBeDefined();
+ expect(mockObj.scope.tableData).not.toBeDefined();
tbs.buildTable(mockObj);
- expect(fs.isA(mockObj.self.tableData)).toBeTruthy();
- expect(mockObj.self.tableData.length).toBe(0);
+ expect(fs.isA(mockObj.scope.tableData)).toBeTruthy();
+ expect(mockObj.scope.tableData.length).toBe(0);
});
it('should unbind handlers on destroyed scope', function () {