blob: 13b223b3158ebdbdb8b4c8ea335ae276844a1ede [file] [log] [blame]
Bri Prebilic Cole093739a2015-01-23 10:22:50 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Bri Prebilic Cole093739a2015-01-23 10:22:50 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 ONOS GUI -- Widget -- Table Service
19 */
20(function () {
21 'use strict';
22
Bri Prebilic Cole08d08d42015-04-01 14:37:02 -070023 // injected refs
Bri Prebilic Cole264c5ec2015-04-07 10:22:26 -070024 var $log, $window, fs, mast, is;
Bri Prebilic Cole08d08d42015-04-01 14:37:02 -070025
26 // constants
27 var tableIconTdSize = 33,
Bri Prebilic Cole9a5e0062015-05-11 17:20:57 -070028 pdg = 22,
Bri Prebilic Cole0e7a1bd2015-07-21 10:22:43 -070029 flashTime = 1500,
Bri Prebilic Cole08d08d42015-04-01 14:37:02 -070030 colWidth = 'col-width',
Simon Hunt051e9fa2016-01-19 15:54:22 -080031 tableIcon = 'table-icon';
Bri Prebilic Cole08d08d42015-04-01 14:37:02 -070032
33 // internal state
Simon Hunt051e9fa2016-01-19 15:54:22 -080034 var cstmWidths = {},
35 api;
Bri Prebilic Cole093739a2015-01-23 10:22:50 -080036
Bri Prebilic Coleb3a6afe2015-06-24 14:10:41 -070037 // Functions for resizing a tabular view to the window
Bri Prebilic Cole9ca0f9c2015-01-29 15:44:20 -080038
Bri Prebilic Colee568ead2015-05-01 09:51:28 -070039 function _width(elem, width) {
40 elem.style('width', width);
Bri Prebilic Cole08d08d42015-04-01 14:37:02 -070041 }
Bri Prebilic Cole9ca0f9c2015-01-29 15:44:20 -080042
Bri Prebilic Coleb3a6afe2015-06-24 14:10:41 -070043 function findCstmWidths(table) {
44 var headers = table.select('.table-header').selectAll('td');
45
46 headers.each(function (d, i) {
47 var h = d3.select(this),
48 index = i.toString();
49 if (h.classed(tableIcon)) {
50 cstmWidths[index] = tableIconTdSize + 'px';
51 }
52 if (h.attr(colWidth)) {
53 cstmWidths[index] = h.attr(colWidth);
54 }
55 });
56 if (fs.debugOn('widget')) {
57 $log.debug('Headers with custom widths: ', cstmWidths);
58 }
Bri Prebilic Cole08d08d42015-04-01 14:37:02 -070059 }
Thomas Vachuska0fa583c2015-03-30 23:07:41 -070060
Bri Prebilic Coleb3a6afe2015-06-24 14:10:41 -070061 function setTdWidths(elem, width) {
62 var tds = elem.select('tr:first-child').selectAll('td');
63 _width(elem, width + 'px');
Bri Prebilic Cole9ca0f9c2015-01-29 15:44:20 -080064
Bri Prebilic Coleb3a6afe2015-06-24 14:10:41 -070065 tds.each(function (d, i) {
66 var td = d3.select(this),
67 index = i.toString();
68 if (cstmWidths.hasOwnProperty(index)) {
69 _width(td, cstmWidths[index]);
Simon Hunt4deb0e82015-06-10 16:18:25 -070070 }
Bri Prebilic Coleb3a6afe2015-06-24 14:10:41 -070071 });
72 }
73
74 function setHeight(thead, body, height) {
75 var h = height - (mast.mastHeight() +
76 fs.noPxStyle(d3.select('.tabular-header'), 'height') +
77 fs.noPxStyle(thead, 'height') + pdg);
78 body.style('height', h + 'px');
79 }
80
81 function adjustTable(haveItems, tableElems, width, height) {
82 if (haveItems) {
83 setTdWidths(tableElems.thead, width);
84 setTdWidths(tableElems.tbody, width);
85 setHeight(tableElems.thead, tableElems.table.select('.table-body'), height);
86 } else {
87 setTdWidths(tableElems.thead, width);
88 _width(tableElems.tbody, width + 'px');
Bri Prebilic Colee568ead2015-05-01 09:51:28 -070089 }
Bri Prebilic Cole9ca0f9c2015-01-29 15:44:20 -080090 }
91
Simon Hunt051e9fa2016-01-19 15:54:22 -080092 // sort columns state model and functions
93 var sortState = {
94 s: {
95 first: null,
96 second: null,
97 touched: null
98 },
99
100 reset: function () {
101 var s = sortState.s;
102 s.first && api.none(s.first.adiv);
103 s.second && api.none(s.second.adiv);
104 sortState.s = { first: null, second: null, touched: null };
105 },
106
107 touch: function (id, adiv) {
108 var s = sortState.s,
109 s1 = s.first,
110 d;
111
112 if (!s.touched) {
113 s.first = { id: id, dir: 'asc', adiv: adiv };
114 s.touched = id;
115 } else {
116 if (id === s.touched) {
117 d = s1.dir === 'asc' ? 'desc' : 'asc';
118 s1.dir = d;
119 s1.adiv = adiv;
120
121 } else {
122 s.second = s.first;
123 s.first = { id: id, dir: 'asc', adiv: adiv };
124 s.touched = id;
125 }
126 }
127 },
128
129 update: function () {
130 var s = sortState.s,
131 s1 = s.first,
132 s2 = s.second;
133 api[s1.dir](s1.adiv);
134 s2 && api.none(s2.adiv);
135 }
136 };
137
Bri Prebilic Cole3d4d01c2015-04-30 13:48:36 -0700138 // Functions for sorting table rows by header
Bri Prebilic Colee1bda3f2015-02-13 17:01:49 -0800139
Bri Prebilic Cole3d4d01c2015-04-30 13:48:36 -0700140 function updateSortDirection(thElem) {
Simon Hunt051e9fa2016-01-19 15:54:22 -0800141 var adiv = thElem.select('div'),
142 id = thElem.attr('colId');
Bri Prebilic Cole902cb042015-02-11 14:04:15 -0800143
Simon Hunt051e9fa2016-01-19 15:54:22 -0800144 api.none(adiv);
145 adiv = thElem.append('div');
146 sortState.touch(id, adiv);
147 sortState.update();
Bri Prebilic Cole902cb042015-02-11 14:04:15 -0800148 }
149
Bri Prebilic Cole19a32dd2015-03-26 18:00:03 -0700150 function sortRequestParams() {
Simon Hunt051e9fa2016-01-19 15:54:22 -0800151 var s = sortState.s,
152 s1 = s.first,
153 s2 = s.second,
154 id2 = s2 && s2.id,
155 dir2 = s2 && s2.dir;
Bri Prebilic Cole19a32dd2015-03-26 18:00:03 -0700156 return {
Simon Hunt051e9fa2016-01-19 15:54:22 -0800157 firstCol: s1.id,
158 firstDir: s1.dir,
159 secondCol: id2,
160 secondDir: dir2
Bri Prebilic Cole19a32dd2015-03-26 18:00:03 -0700161 };
Bri Prebilic Cole902cb042015-02-11 14:04:15 -0800162 }
163
Bri Prebilic Cole093739a2015-01-23 10:22:50 -0800164 angular.module('onosWidget')
Simon Hunt051e9fa2016-01-19 15:54:22 -0800165 .directive('onosTableResize', ['$log','$window', 'FnService', 'MastService',
Bri Prebilic Colee568ead2015-05-01 09:51:28 -0700166
Simon Hunt051e9fa2016-01-19 15:54:22 -0800167 function (_$log_, _$window_, _fs_, _mast_) {
168 return function (scope, element) {
169 $log = _$log_;
170 $window = _$window_;
171 fs = _fs_;
172 mast = _mast_;
Bri Prebilic Cole264c5ec2015-04-07 10:22:26 -0700173
Simon Hunt051e9fa2016-01-19 15:54:22 -0800174 var table = d3.select(element[0]),
175 tableElems = {
176 table: table,
177 thead: table.select('.table-header').select('table'),
178 tbody: table.select('.table-body').select('table')
179 },
180 wsz;
Bri Prebilic Cole9ca0f9c2015-01-29 15:44:20 -0800181
Simon Hunt051e9fa2016-01-19 15:54:22 -0800182 findCstmWidths(table);
Bri Prebilic Coleb3a6afe2015-06-24 14:10:41 -0700183
Simon Hunt051e9fa2016-01-19 15:54:22 -0800184 // adjust table on window resize
185 scope.$watchCollection(function () {
186 return {
187 h: $window.innerHeight,
188 w: $window.innerWidth
189 };
190 }, function () {
191 wsz = fs.windowSize(0, 30);
192 adjustTable(
193 scope.tableData.length,
194 tableElems,
195 wsz.width, wsz.height
196 );
197 });
Bri Prebilic Cole9ca0f9c2015-01-29 15:44:20 -0800198
Simon Hunt051e9fa2016-01-19 15:54:22 -0800199 // adjust table when data changes
200 scope.$watchCollection('tableData', function () {
201 adjustTable(
202 scope.tableData.length,
203 tableElems,
204 wsz.width, wsz.height
205 );
206 });
Simon Hunt0c2c4c52015-04-02 17:42:45 -0700207
Simon Hunt051e9fa2016-01-19 15:54:22 -0800208 scope.$on('$destroy', function () {
209 cstmWidths = {};
210 });
211 };
212 }])
Bri Prebilic Cole1f93be22015-02-10 17:16:46 -0800213
Simon Hunt051e9fa2016-01-19 15:54:22 -0800214 .directive('onosSortableHeader', ['$log', 'IconService',
215 function (_$log_, _is_) {
216 return function (scope, element) {
217 $log = _$log_;
218 is = _is_;
219 var header = d3.select(element[0]);
Bri Prebilic Cole1f93be22015-02-10 17:16:46 -0800220
Simon Hunt051e9fa2016-01-19 15:54:22 -0800221 api = is.sortIcons();
Bri Prebilic Cole1f93be22015-02-10 17:16:46 -0800222
Simon Hunt051e9fa2016-01-19 15:54:22 -0800223 header.selectAll('td').on('click', function () {
224 var col = d3.select(this);
Bri Prebilic Cole3d4d01c2015-04-30 13:48:36 -0700225
Simon Hunt051e9fa2016-01-19 15:54:22 -0800226 if (col.attr('sortable') === '') {
227 updateSortDirection(col);
228 scope.sortParams = sortRequestParams();
229 scope.sortCallback(scope.sortParams);
Bri Prebilic Cole70aacc42015-07-22 11:28:34 -0700230 }
Simon Hunt051e9fa2016-01-19 15:54:22 -0800231 });
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700232
Simon Hunt051e9fa2016-01-19 15:54:22 -0800233 scope.$on('$destroy', function () {
234 sortState.reset();
235 });
236 };
237 }])
Bri Prebilic Cole0e7a1bd2015-07-21 10:22:43 -0700238
Simon Hunt051e9fa2016-01-19 15:54:22 -0800239 .directive('onosFlashChanges',
240 ['$log', '$parse', '$timeout', 'FnService',
241 function ($log, $parse, $timeout, fs) {
242
243 return function (scope, element, attrs) {
244 var idProp = attrs.idProp,
245 table = d3.select(element[0]),
246 trs, promise;
247
248 function highlightRows() {
249 var changedRows = [];
250 function classRows(b) {
251 if (changedRows.length) {
252 angular.forEach(changedRows, function (tr) {
253 tr.classed('data-change', b);
254 });
255 }
256 }
257 // timeout because 'row-id' was the un-interpolated value
258 // "{{link.one}}" for example, instead of link.one evaluated
259 // timeout executes on the next digest -- after evaluation
260 $timeout(function () {
261 if (scope.tableData.length) {
262 trs = table.selectAll('tr');
263 }
264
265 if (trs && !trs.empty()) {
266 trs.each(function () {
267 var tr = d3.select(this);
268 if (fs.find(tr.attr('row-id'),
269 scope.changedData,
270 idProp) > -1) {
271 changedRows.push(tr);
272 }
273 });
274 classRows(true);
275 promise = $timeout(function () {
276 classRows(false);
277 }, flashTime);
278 trs = undefined;
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700279 }
280 });
Simon Hunt051e9fa2016-01-19 15:54:22 -0800281 }
282
283 // new items added:
284 scope.$on('ngRepeatComplete', highlightRows);
285 // items changed in existing set:
286 scope.$watchCollection('changedData', highlightRows);
287
288 scope.$on('$destroy', function () {
289 if (promise) {
290 $timeout.cancel(promise);
291 }
292 });
293 };
294 }]);
Bri Prebilic Cole093739a2015-01-23 10:22:50 -0800295
296}());