blob: 303e425f7ecb7e4b01e2ce81e29960f9bc72db3e [file] [log] [blame]
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -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/*
Bri Prebilic Coleaa0f0882015-02-04 15:27:55 -080018 ONOS GUI -- Device View Module
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -080019 */
20
21(function () {
22 'use strict';
23
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070024 // injected refs
Simon Huntd5579252015-10-06 15:09:14 -070025 var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070026
27 // internal state
Bri Prebilic Colee568ead2015-05-01 09:51:28 -070028 var detailsPanel,
Simon Huntd766c312015-10-06 11:46:32 -070029 pStartY,
30 pHeight,
31 top,
32 bottom,
33 iconDiv,
34 wSize,
Alan Deikman8d858752017-02-14 18:08:29 -080035 editingName = false,
36 device;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070037
38 // constants
Simon Hunt986b92f2016-06-03 15:46:59 -070039 var topPdg = 28,
Bri Prebilic Cole45069382015-04-14 15:21:38 -070040 ctnrPdg = 24,
Bri Prebilic Cole9cf1a8d2015-04-21 13:15:29 -070041 scrollSize = 17,
Bri Prebilic Cole45069382015-04-14 15:21:38 -070042 portsTblPdg = 50,
43
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070044 pName = 'device-details-panel',
45 detailsReq = 'deviceDetailsRequest',
46 detailsResp = 'deviceDetailsResponse',
Simon Huntd5579252015-10-06 15:09:14 -070047 nameChangeReq = 'deviceNameChangeRequest',
48 nameChangeResp = 'deviceNameChangeResponse',
Bri Prebilic Cole45069382015-04-14 15:21:38 -070049
Simon Hunta9301bb2016-10-20 11:38:10 -070050 propSplit = 4,
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070051 propOrder = [
Simon Huntd5579252015-10-06 15:09:14 -070052 'id', 'type', 'masterid', 'chassisid',
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070053 'mfr', 'hw', 'sw', 'protocol', 'serial'
54 ],
55 friendlyProps = [
Simon Huntd5579252015-10-06 15:09:14 -070056 'URI', 'Type', 'Master ID', 'Chassis ID',
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070057 'Vendor', 'H/W Version', 'S/W Version', 'Protocol', 'Serial #'
58 ],
59 portCols = [
Thomas Vachuskab52a0142015-04-21 17:48:15 -070060 'enabled', 'id', 'speed', 'type', 'elinks_dest', 'name'
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070061 ],
62 friendlyPortCols = [
Thomas Vachuskab52a0142015-04-21 17:48:15 -070063 'Enabled', 'ID', 'Speed', 'Type', 'Egress Links', 'Name'
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -070064 ];
65
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070066 function closePanel() {
67 if (detailsPanel.isVisible()) {
68 $scope.selId = null;
69 detailsPanel.hide();
Simon Huntd766c312015-10-06 11:46:32 -070070 return true;
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070071 }
Simon Huntd766c312015-10-06 11:46:32 -070072 return false;
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070073 }
74
Bri Prebilic Coleb699a162015-04-13 12:01:39 -070075 function addCloseBtn(div) {
Simon Hunt986b92f2016-06-03 15:46:59 -070076 is.loadEmbeddedIcon(div, 'close', 20);
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -070077 div.on('click', closePanel);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -070078 }
79
Simon Huntd5579252015-10-06 15:09:14 -070080 function exitEditMode(nameH2, name) {
81 nameH2.html(name);
Simon Hunt986b92f2016-06-03 15:46:59 -070082 nameH2.classed('editable clickable', true);
Simon Huntd5579252015-10-06 15:09:14 -070083 editingName = false;
84 ks.enableGlobalKeys(true);
Simon Huntd766c312015-10-06 11:46:32 -070085 }
86
87 function editNameSave() {
Simon Huntd5579252015-10-06 15:09:14 -070088 var nameH2 = top.select('h2'),
89 id = $scope.panelData.id,
90 val,
Simon Huntd766c312015-10-06 11:46:32 -070091 newVal;
Simon Huntd5579252015-10-06 15:09:14 -070092
Simon Huntd766c312015-10-06 11:46:32 -070093 if (editingName) {
Simon Huntd5579252015-10-06 15:09:14 -070094 val = nameH2.select('input').property('value').trim();
95 newVal = val || id;
Simon Huntd766c312015-10-06 11:46:32 -070096
Simon Huntd5579252015-10-06 15:09:14 -070097 exitEditMode(nameH2, newVal);
Simon Huntd766c312015-10-06 11:46:32 -070098 $scope.panelData.name = newVal;
Simon Huntd5579252015-10-06 15:09:14 -070099 wss.sendEvent(nameChangeReq, { id: id, name: val });
Simon Huntd766c312015-10-06 11:46:32 -0700100 }
101 }
102
103 function editNameCancel() {
Simon Huntd766c312015-10-06 11:46:32 -0700104 if (editingName) {
Simon Huntd5579252015-10-06 15:09:14 -0700105 exitEditMode(top.select('h2'), $scope.panelData.name);
Simon Huntd766c312015-10-06 11:46:32 -0700106 return true;
107 }
108 return false;
109 }
110
111 function editName() {
Simon Huntd5579252015-10-06 15:09:14 -0700112 var nameH2 = top.select('h2'),
113 tf, el;
114
Simon Huntd766c312015-10-06 11:46:32 -0700115 if (!editingName) {
Simon Hunt986b92f2016-06-03 15:46:59 -0700116 nameH2.classed('editable clickable', false);
Simon Huntd5579252015-10-06 15:09:14 -0700117 nameH2.html('');
118 tf = nameH2.append('input').classed('name-input', true)
Simon Huntd766c312015-10-06 11:46:32 -0700119 .attr('type', 'text')
120 .attr('value', $scope.panelData.name);
Simon Huntd5579252015-10-06 15:09:14 -0700121 el = tf[0][0];
122 el.focus();
123 el.select();
124 editingName = true;
125 ks.enableGlobalKeys(false);
Simon Huntd766c312015-10-06 11:46:32 -0700126 }
127 }
128
129 function handleEscape() {
130 return editNameCancel() || closePanel();
131 }
132
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700133 function setUpPanel() {
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700134 var container, closeBtn, tblDiv;
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700135 detailsPanel.empty();
136
137 container = detailsPanel.append('div').classed('container', true);
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700138
139 top = container.append('div').classed('top', true);
140 closeBtn = top.append('div').classed('close-btn', true);
141 addCloseBtn(closeBtn);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700142 iconDiv = top.append('div').classed('dev-icon', true);
Simon Hunt986b92f2016-06-03 15:46:59 -0700143 top.append('h2').classed('editable clickable', true).on('click', editName);
Simon Huntd766c312015-10-06 11:46:32 -0700144
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700145 tblDiv = top.append('div').classed('top-tables', true);
146 tblDiv.append('div').classed('left', true).append('table');
147 tblDiv.append('div').classed('right', true).append('table');
148
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700149 top.append('hr');
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700150
151 bottom = container.append('div').classed('bottom', true);
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700152 bottom.append('h2').classed('ports-title', true).html('Ports');
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700153 bottom.append('table');
154 }
155
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700156 function addProp(tbody, index, value) {
157 var tr = tbody.append('tr');
158
159 function addCell(cls, txt) {
160 tr.append('td').attr('class', cls).html(txt);
161 }
162 addCell('label', friendlyProps[index] + ' :');
163 addCell('value', value);
164 }
165
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700166 function populateTop(tblDiv, details) {
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700167 var leftTbl = tblDiv.select('.left')
168 .select('table')
169 .append('tbody'),
170 rightTbl = tblDiv.select('.right')
171 .select('table')
172 .append('tbody');
173
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700174 is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
Simon Huntd5579252015-10-06 15:09:14 -0700175 top.select('h2').html(details.name);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700176
Alan Deikman8d858752017-02-14 18:08:29 -0800177 // === demonstrate use of JsonCodec object see ONOS-5976
178 addProp(leftTbl, 0, device.id);
179 addProp(leftTbl, 1, device.type);
180 addProp(leftTbl, 2, details['masterid']);
181 addProp(leftTbl, 3, details['chassid']);
182 addProp(rightTbl, 4, device.mfr);
183 addProp(rightTbl, 5, device.hw);
184 addProp(rightTbl, 6, device.sw);
185 addProp(rightTbl, 7, details['protocol']);
186 addProp(rightTbl, 8, device.serial);
187
188 // propOrder.forEach(function (prop, i) {
189 // // properties are split into two tables
190 // addProp(i < propSplit ? leftTbl : rightTbl, i, details[prop]);
191 // });
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700192 }
193
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700194 function addPortRow(tbody, port) {
195 var tr = tbody.append('tr');
196
197 portCols.forEach(function (col) {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700198 tr.append('td').html(port[col]);
199 });
200 }
201
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700202 function populateBottom(table, ports) {
203 var theader = table.append('thead').append('tr'),
204 tbody = table.append('tbody'),
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700205 tbWidth, tbHeight;
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700206
207 friendlyPortCols.forEach(function (col) {
208 theader.append('th').html(col);
209 });
210 ports.forEach(function (port) {
211 addPortRow(tbody, port);
212 });
213
214 tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700215 tbHeight = pHeight
216 - (fs.noPxStyle(detailsPanel.el()
217 .select('.top'), 'height')
218 + fs.noPxStyle(detailsPanel.el()
219 .select('.ports-title'), 'height')
220 + portsTblPdg);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700221
222 table.style({
223 height: tbHeight + 'px',
224 width: tbWidth + 'px',
225 overflow: 'auto',
226 display: 'block'
227 });
228
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700229 detailsPanel.width(tbWidth + ctnrPdg);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700230 }
231
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700232 function populateDetails(details) {
Simon Hunta9301bb2016-10-20 11:38:10 -0700233 var topTbs, btmTbl, ports;
234
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700235 setUpPanel();
236
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700237 topTbs = top.select('.top-tables');
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700238 btmTbl = bottom.select('table');
239 ports = details.ports;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700240
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700241 populateTop(topTbs, details);
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700242 populateBottom(btmTbl, ports);
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700243
244 detailsPanel.height(pHeight);
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700245 }
246
247 function respDetailsCb(data) {
Bri Prebilic Colee568ead2015-05-01 09:51:28 -0700248 $scope.panelData = data.details;
Alan Deikman8d858752017-02-14 18:08:29 -0800249 device = data.device;
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700250 $scope.$apply();
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700251 }
252
Simon Huntd5579252015-10-06 15:09:14 -0700253 function respNameCb(data) {
254 if (data.warn) {
255 $log.warn(data.warn, data.id);
256 top.select('h2').html(data.id);
257 }
258 }
259
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700260 function createDetailsPane() {
261 detailsPanel = ps.createPanel(pName, {
262 width: wSize.width,
263 margin: 0,
264 hideMargin: 0
265 });
266 detailsPanel.el().style({
267 position: 'absolute',
268 top: pStartY + 'px'
269 });
Bri Prebilic Cole68844ba2015-07-22 15:41:37 -0700270 $scope.hidePanel = function () { detailsPanel.hide(); };
Bri Prebilic Cole45069382015-04-14 15:21:38 -0700271 detailsPanel.hide();
272 }
273
Simon Hunt400ebbf2017-01-06 20:07:50 -0800274 // Sample functions for detail panel creation
275 function popTop(div) {
276 $log.debug('populateTop');
277 // TODO: real work
278 // div.append(.....);
279 // div.append(.....);
280 // div.append(.....);
281 }
282
283 function popMid(div) {
284 $log.debug('populateMiddle');
285 // TODO: real work
286 }
287
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -0800288 angular.module('ovDevice', [])
Simon Hunta89f0f92015-02-26 16:47:12 -0800289 .controller('OvDeviceCtrl',
Simon Hunt400ebbf2017-01-06 20:07:50 -0800290 ['$log', '$scope', '$location', 'TableBuilderService',
291 'TableDetailService', 'FnService',
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700292 'MastService', 'PanelService', 'WebSocketService', 'IconService',
Simon Huntd5579252015-10-06 15:09:14 -0700293 'NavService', 'KeyService',
Simon Hunta89f0f92015-02-26 16:47:12 -0800294
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700295 function (_$log_, _$scope_, _$location_,
Simon Hunt400ebbf2017-01-06 20:07:50 -0800296 tbs, tds, _fs_, _mast_, _ps_, _wss_, _is_, _ns_, _ks_) {
Simon Huntd5579252015-10-06 15:09:14 -0700297 var params,
298 handlers = {};
299
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700300 $log = _$log_;
301 $scope = _$scope_;
Simon Huntd5579252015-10-06 15:09:14 -0700302 $loc = _$location_;
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700303 fs = _fs_;
304 mast = _mast_;
305 ps = _ps_;
306 wss = _wss_;
307 is = _is_;
Bri Prebilic Cole8f07f0d2015-04-23 13:28:43 -0700308 ns = _ns_;
Simon Huntd5579252015-10-06 15:09:14 -0700309 ks = _ks_;
310
311 params = $loc.search();
312
Bri Prebilic Cole68844ba2015-07-22 15:41:37 -0700313 $scope.panelData = {};
Bri Prebilic Coleeef67ae2015-07-01 16:26:59 -0700314 $scope.flowTip = 'Show flow view for selected device';
315 $scope.portTip = 'Show port view for selected device';
316 $scope.groupTip = 'Show group view for selected device';
Jian Li1f544732015-12-30 23:36:37 -0800317 $scope.meterTip = 'Show meter view for selected device';
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700318
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700319 // details panel handlers
320 handlers[detailsResp] = respDetailsCb;
Simon Huntd5579252015-10-06 15:09:14 -0700321 handlers[nameChangeResp] = respNameCb;
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700322 wss.bindHandlers(handlers);
323
324 // query for if a certain device needs to be highlighted
325 if (params.hasOwnProperty('devId')) {
326 $scope.selId = params['devId'];
327 wss.sendEvent(detailsReq, { id: $scope.selId });
328 }
329
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700330 function selCb($event, row) {
Bri Prebilic Colebfab9c72015-06-01 14:33:18 -0700331 if ($scope.selId) {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700332 wss.sendEvent(detailsReq, { id: row.id });
333 } else {
Bri Prebilic Cole68844ba2015-07-22 15:41:37 -0700334 $scope.hidePanel();
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700335 }
336 $log.debug('Got a click on:', row);
337 }
338
Bri Prebilic Cole864cdd62015-04-02 15:46:47 -0700339 tbs.buildTable({
Bri Prebilic Cole864cdd62015-04-02 15:46:47 -0700340 scope: $scope,
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700341 tag: 'device',
342 selCb: selCb
343 });
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700344
Simon Hunt400ebbf2017-01-06 20:07:50 -0800345
346 // ==================== for testing for now ===============
347 // TODO: more than just an example
348 tds.buildBasePanel({
349 popTop: popTop,
350 popMid: popMid
351 });
352 // ==================== for testing for now ===============
353
354
Bri Prebilic Cole9b1fb9a2015-07-01 13:57:11 -0700355 $scope.nav = function (path) {
356 if ($scope.selId) {
357 ns.navTo(path, { devId: $scope.selId });
358 }
359 };
360
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700361 $scope.$on('$destroy', function () {
Bri Prebilic Cole0feedc02015-04-09 14:17:37 -0700362 wss.unbindHandlers(handlers);
Simon Hunta89f0f92015-02-26 16:47:12 -0800363 });
364
Bri Prebilic Cole72eb6db2015-03-30 16:58:53 -0700365 $log.log('OvDeviceCtrl has been created');
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700366 }])
367
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700368 .directive('deviceDetailsPanel',
369 ['$rootScope', '$window', '$timeout', 'KeyService',
370 function ($rootScope, $window, $timeout, ks) {
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700371 return function (scope) {
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700372 var unbindWatch;
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700373
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700374 function heightCalc() {
375 pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
376 + mast.mastHeight() + topPdg;
377 wSize = fs.windowSize(pStartY);
378 pHeight = wSize.height;
379 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700380
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700381 function initPanel() {
382 heightCalc();
383 createDetailsPane();
384 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700385
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700386 // Safari has a bug where it renders the fixed-layout table wrong
387 // if you ask for the window's size too early
388 if (scope.onos.browser === 'safari') {
389 $timeout(initPanel);
390 } else {
391 initPanel();
392 }
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700393 // create key bindings to handle panel
394 ks.keyBindings({
Simon Huntd766c312015-10-06 11:46:32 -0700395 enter: editNameSave,
396 esc: [handleEscape, 'Close the details panel'],
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700397 _helpFormat: ['esc']
398 });
399 ks.gestureNotes([
400 ['click', 'Select a row to show device details'],
401 ['scroll down', 'See more devices']
402 ]);
403
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700404 // if the panelData changes
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700405 scope.$watch('panelData', function () {
406 if (!fs.isEmptyObject(scope.panelData)) {
407 populateDetails(scope.panelData);
408 detailsPanel.show();
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700409 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700410 });
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700411
Bri Prebilic Cole55ee09b2015-08-04 14:34:07 -0700412 // if the window size changes
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700413 unbindWatch = $rootScope.$watchCollection(
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700414 function () {
415 return {
416 h: $window.innerHeight,
417 w: $window.innerWidth
418 };
419 }, function () {
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700420 if (!fs.isEmptyObject(scope.panelData)) {
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700421 heightCalc();
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700422 populateDetails(scope.panelData);
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700423 }
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700424 }
425 );
Bri Prebilic Cole54bbfb92015-05-28 16:02:28 -0700426
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700427 scope.$on('$destroy', function () {
Bri Prebilic Cole0bc4de22015-07-20 17:07:55 -0700428 unbindWatch();
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700429 ks.unbindKeys();
Bri Prebilic Cole17c6d0a2015-07-16 14:56:40 -0700430 ps.destroyPanel(pName);
431 });
432 };
433 }]);
Bri Prebilic Cole7c92a3d2015-01-09 16:50:03 -0800434}());