blob: a71cb2d0f1252f55cb5fe760e27723c02182bd36 [file] [log] [blame]
Thomas Vachuska0fa583c2015-03-30 23:07:41 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska0fa583c2015-03-30 23:07:41 -07003 *
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -07004 * Licensed under the Apache License, Version 2.0 (the 'License');
Thomas Vachuska0fa583c2015-03-30 23:07:41 -07005 * 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
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -070011 * distributed under the License is distributed on an 'AS IS' BASIS,
Thomas Vachuska0fa583c2015-03-30 23:07:41 -070012 * 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 -- App View Module
19 */
20
21(function () {
22 'use strict';
23
Jian Lia54de5a2016-01-20 23:10:39 -080024 // injected refs
Simon Hunt31642932016-01-22 20:34:00 -080025 var $log, $scope, wss, fs, ks, ps, is;
Jian Lia54de5a2016-01-20 23:10:39 -080026
27 // internal state
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -080028 var detailsPanel,
29 pStartY,
30 pHeight,
31 top,
32 middle,
33 bottom,
34 wSize = false,
Jayasree Ghosh25e21662016-12-23 15:59:47 +053035 activateImmediately = '';
Jian Lia54de5a2016-01-20 23:10:39 -080036
Bri Prebilic Cole522e7562015-06-22 15:56:25 -070037 // constants
38 var INSTALLED = 'INSTALLED',
39 ACTIVE = 'ACTIVE',
Simon Hunt8d28a552016-01-11 14:01:02 -080040 appMgmtReq = 'appManagementRequest',
Simon Hunt047f4052016-06-06 16:51:11 -070041 topPdg = 60,
42 panelWidth = 540,
Jian Lia54de5a2016-01-20 23:10:39 -080043 pName = 'application-details-panel',
44 detailsReq = 'appDetailsRequest',
45 detailsResp = 'appDetailsResponse',
Simon Hunt8d28a552016-01-11 14:01:02 -080046 fileUploadUrl = 'applications/upload',
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -080047 activateOption = '?activate=true',
Jian Lia54de5a2016-01-20 23:10:39 -080048 iconUrlPrefix = 'rs/applications/',
49 iconUrlSuffix = '/icon',
Simon Hunt8d28a552016-01-11 14:01:02 -080050 dialogId = 'app-dialog',
51 dialogOpts = {
Simon Hunt0991b342016-06-08 13:18:16 -070052 edge: 'right',
53 width: 400
Simon Hunt3f92c432016-01-12 17:34:23 -080054 },
55 strongWarning = {
56 'org.onosproject.drivers': true
57 },
58 discouragement = 'Deactivating or uninstalling this component can' +
Simon Hunt0991b342016-06-08 13:18:16 -070059 ' have serious negative consequences! <br> = DO SO AT YOUR OWN RISK =',
Simon Hunt31642932016-01-22 20:34:00 -080060 propOrder = ['id', 'state', 'category', 'version', 'origin', 'role'],
61 friendlyProps = ['App ID', 'State', 'Category', 'Version', 'Origin', 'Role'];
62 // note: url is handled separately
Jian Lia54de5a2016-01-20 23:10:39 -080063
64 function createDetailsPane() {
65 detailsPanel = ps.createPanel(pName, {
66 width: wSize.width,
67 margin: 0,
68 hideMargin: 0
69 });
70 detailsPanel.el().style({
71 position: 'absolute',
72 top: pStartY + 'px'
73 });
74 $scope.hidePanel = function () { detailsPanel.hide(); };
75 detailsPanel.hide();
76 }
77
78 function closePanel() {
79 if (detailsPanel.isVisible()) {
80 $scope.selId = null;
81 detailsPanel.hide();
82 return true;
83 }
84 return false;
85 }
86
Jian Lia54de5a2016-01-20 23:10:39 -080087 function addCloseBtn(div) {
Simon Hunte6e09842016-06-07 11:11:26 -070088 is.loadEmbeddedIcon(div, 'close', 26);
Jian Lia54de5a2016-01-20 23:10:39 -080089 div.on('click', closePanel);
90 }
91
92 function setUpPanel() {
Simon Hunt31642932016-01-22 20:34:00 -080093 var container, closeBtn, div;
94
Jian Lia54de5a2016-01-20 23:10:39 -080095 detailsPanel.empty();
Simon Hunt31642932016-01-22 20:34:00 -080096 detailsPanel.width(panelWidth);
Jian Lia54de5a2016-01-20 23:10:39 -080097
98 container = detailsPanel.append('div').classed('container', true);
99
100 top = container.append('div').classed('top', true);
101 closeBtn = top.append('div').classed('close-btn', true);
102 addCloseBtn(closeBtn);
Jian Lia54de5a2016-01-20 23:10:39 -0800103
Simon Hunt31642932016-01-22 20:34:00 -0800104 div = top.append('div').classed('top-content', true);
Jian Lia54de5a2016-01-20 23:10:39 -0800105
Simon Hunt31642932016-01-22 20:34:00 -0800106 function ndiv(cls, tcls) {
107 var d = div.append('div').classed(cls, true);
108 if (tcls) {
109 d.append('table').classed(tcls, true);
110 }
111 }
112
Simon Hunt877ee982016-03-09 10:53:16 -0800113 ndiv('app-title');
Simon Hunt31642932016-01-22 20:34:00 -0800114 ndiv('left app-icon');
115 ndiv('right', 'app-props');
116 ndiv('app-url');
117
118 container.append('hr');
Jian Lia54de5a2016-01-20 23:10:39 -0800119
Jian Lida253e02016-01-21 17:46:17 -0800120 middle = container.append('div').classed('middle', true);
Simon Hunt31642932016-01-22 20:34:00 -0800121 middle.append('div').classed('app-readme', true);
Jian Lida253e02016-01-21 17:46:17 -0800122
Simon Hunt31642932016-01-22 20:34:00 -0800123 container.append('hr');
Jian Lida253e02016-01-21 17:46:17 -0800124
Simon Hunt31642932016-01-22 20:34:00 -0800125 // TODO: make bottom container scrollable
Jian Lia54de5a2016-01-20 23:10:39 -0800126 bottom = container.append('div').classed('bottom', true);
Simon Hunt31642932016-01-22 20:34:00 -0800127
128 function nTable(hdr, cls) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700129 bottom.append('h2').text(hdr);
Simon Hunt31642932016-01-22 20:34:00 -0800130 bottom.append('div').classed(cls, true).append('table');
131 }
132
133 nTable('Features', 'features');
134 nTable('Required Apps', 'required-apps');
135 nTable('Permissions', 'permissions');
Jian Lia54de5a2016-01-20 23:10:39 -0800136 }
137
138 function addProp(tbody, index, value) {
Simon Hunt811d8572016-06-02 13:40:14 -0700139 var tr = tbody.append('tr');
Jian Lia54de5a2016-01-20 23:10:39 -0800140
141 function addCell(cls, txt) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700142 tr.append('td').attr('class', cls).text(txt);
Jian Lia54de5a2016-01-20 23:10:39 -0800143 }
Simon Hunt31642932016-01-22 20:34:00 -0800144
145 addCell('label', friendlyProps[index] + ':');
Simon Hunt811d8572016-06-02 13:40:14 -0700146 addCell('value', value);
Jian Lia54de5a2016-01-20 23:10:39 -0800147 }
148
Simon Hunt31642932016-01-22 20:34:00 -0800149 function urlize(u) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700150 u = fs.sanitize(u);
Thomas Vachuska3bdfa772017-05-10 18:33:42 -0700151 return '<a href="' + u + '" target="_blank">' + u + '</a>';
Simon Hunta477b602016-01-22 12:10:07 -0800152 }
153
Simon Hunt31642932016-01-22 20:34:00 -0800154 function addIcon(elem, value) {
155 elem.append('img').attr('src', iconUrlPrefix + value + iconUrlSuffix);
Jian Lia54de5a2016-01-20 23:10:39 -0800156 }
157
Simon Hunt31642932016-01-22 20:34:00 -0800158 function populateTop(details) {
159 var propsBody = top.select('.app-props').append('tbody'),
160 url = details.url;
Jian Lia54de5a2016-01-20 23:10:39 -0800161
Simon Hunt877ee982016-03-09 10:53:16 -0800162 top.select('.app-title').text(details.title);
163
Simon Hunt31642932016-01-22 20:34:00 -0800164 addIcon(top.select('.app-icon'), details.id);
Jian Lia54de5a2016-01-20 23:10:39 -0800165
Jian Lia54de5a2016-01-20 23:10:39 -0800166 propOrder.forEach(function (prop, i) {
Simon Hunt31642932016-01-22 20:34:00 -0800167 addProp(propsBody, i, details[prop]);
Jian Lia54de5a2016-01-20 23:10:39 -0800168 });
169
Simon Hunt31642932016-01-22 20:34:00 -0800170 if (url) {
171 top.select('.app-url').html(urlize(url));
172 }
Jian Lida253e02016-01-21 17:46:17 -0800173 }
174
Simon Hunt31642932016-01-22 20:34:00 -0800175 function populateMiddle(details) {
176 middle.select('.app-readme').text(details.readme);
Jian Lia54de5a2016-01-20 23:10:39 -0800177 }
178
Simon Hunt31642932016-01-22 20:34:00 -0800179 function populateBottom(details) {
180
181 function addItems(cls, items) {
182 var table = bottom.select('.' + cls).select('table'),
183 tbody = table.append('tbody');
184
185 items.forEach(function (item) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700186 tbody.append('tr').append('td').text(item);
Simon Hunt31642932016-01-22 20:34:00 -0800187 });
188 }
189
190 addItems('features', details.features);
191 addItems('required-apps', details.required_apps);
192 addItems('permissions', details.permissions);
Jian Lia54de5a2016-01-20 23:10:39 -0800193 }
194
195 function populateDetails(details) {
Jian Lia54de5a2016-01-20 23:10:39 -0800196 setUpPanel();
Simon Hunt31642932016-01-22 20:34:00 -0800197 populateTop(details);
198 populateMiddle(details);
199 populateBottom(details);
Jian Lia54de5a2016-01-20 23:10:39 -0800200 detailsPanel.height(pHeight);
201 }
202
Jian Lia54de5a2016-01-20 23:10:39 -0800203 function respDetailsCb(data) {
204 $scope.panelData = data.details;
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800205 $scope.selId = data.details.id;
206 $scope.ctrlBtnState.selection = data.details.id;
Jian Lia54de5a2016-01-20 23:10:39 -0800207 $scope.$apply();
208 }
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700209
Thomas Vachuska0fa583c2015-03-30 23:07:41 -0700210 angular.module('ovApp', [])
211 .controller('OvAppCtrl',
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800212 ['$log', '$scope', '$http', '$timeout',
Simon Hunt31642932016-01-22 20:34:00 -0800213 'WebSocketService', 'FnService', 'KeyService', 'PanelService',
214 'IconService', 'UrlFnService', 'DialogService', 'TableBuilderService',
Thomas Vachuska0fa583c2015-03-30 23:07:41 -0700215
Simon Huntf51bf462016-06-29 16:22:57 -0700216 function (_$log_, _$scope_, $http, $timeout, _wss_, _fs_, _ks_, _ps_, _is_,
217 ufs, ds, tbs) {
Jian Lia54de5a2016-01-20 23:10:39 -0800218 $log = _$log_;
219 $scope = _$scope_;
220 wss = _wss_;
Jian Lia54de5a2016-01-20 23:10:39 -0800221 fs = _fs_;
Simon Hunt31642932016-01-22 20:34:00 -0800222 ks = _ks_;
Jian Lia54de5a2016-01-20 23:10:39 -0800223 ps = _ps_;
224 is = _is_;
225 $scope.panelData = {};
Bri Prebilic Cole6b95a3f2015-06-04 09:15:00 -0700226 $scope.ctrlBtnState = {};
Bri Prebilic Cole6c82ade2015-08-05 11:12:30 -0700227 $scope.uploadTip = 'Upload an application (.oar file)';
Bri Prebilic Coleeef67ae2015-07-01 16:26:59 -0700228 $scope.activateTip = 'Activate selected application';
229 $scope.deactivateTip = 'Deactivate selected application';
230 $scope.uninstallTip = 'Uninstall selected application';
Bri Prebilic Cole6b95a3f2015-06-04 09:15:00 -0700231
Jian Lia54de5a2016-01-20 23:10:39 -0800232 var handlers = {};
233
234 // details panel handlers
235 handlers[detailsResp] = respDetailsCb;
236 wss.bindHandlers(handlers);
237
Bri Prebilic Coleb699a162015-04-13 12:01:39 -0700238 function selCb($event, row) {
Simon Hunt3f92c432016-01-12 17:34:23 -0800239 // $scope.selId is set by code in tableBuilder
Bri Prebilic Cole6b95a3f2015-06-04 09:15:00 -0700240 $scope.ctrlBtnState.selection = !!$scope.selId;
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700241 refreshCtrls();
Simon Hunt3f92c432016-01-12 17:34:23 -0800242 ds.closeDialog(); // don't want dialog from previous selection
Jian Lia54de5a2016-01-20 23:10:39 -0800243
244 if ($scope.selId) {
245 wss.sendEvent(detailsReq, { id: row.id });
246 } else {
247 $scope.hidePanel();
248 }
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700249 }
250
Bri Prebilic Colea7f81e52015-06-23 10:11:08 -0700251 function refreshCtrls() {
252 var row, rowIdx;
253 if ($scope.ctrlBtnState.selection) {
254 rowIdx = fs.find($scope.selId, $scope.tableData);
255 row = rowIdx >= 0 ? $scope.tableData[rowIdx] : null;
256
257 $scope.ctrlBtnState.installed = row && row.state === INSTALLED;
258 $scope.ctrlBtnState.active = row && row.state === ACTIVE;
259 } else {
260 $scope.ctrlBtnState.installed = false;
261 $scope.ctrlBtnState.active = false;
262 }
Thomas Vachuska619c5382015-04-02 13:41:47 -0700263 }
Thomas Vachuska0fa583c2015-03-30 23:07:41 -0700264
Bri Prebilic Cole6b95a3f2015-06-04 09:15:00 -0700265 tbs.buildTable({
266 scope: $scope,
267 tag: 'app',
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700268 selCb: selCb,
Simon Hunta678b842016-01-11 17:14:18 -0800269 respCb: refreshCtrls,
270 // pre-populate sort so active apps are at the top of the list
271 sortParams: {
Simon Hunt051e9fa2016-01-19 15:54:22 -0800272 firstCol: 'state',
273 firstDir: 'desc',
Simon Hunt877ee982016-03-09 10:53:16 -0800274 secondCol: 'title',
Simon Hunt051e9fa2016-01-19 15:54:22 -0800275 secondDir: 'asc'
Simon Hunta678b842016-01-11 17:14:18 -0800276 }
Bri Prebilic Cole6b95a3f2015-06-04 09:15:00 -0700277 });
278
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700279 // TODO: reexamine where keybindings should be - directive or controller?
280 ks.keyBindings({
Simon Hunt31642932016-01-22 20:34:00 -0800281 esc: [$scope.selectCallback, 'Deselect application'],
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700282 _helpFormat: ['esc']
283 });
284 ks.gestureNotes([
Simon Hunt31642932016-01-22 20:34:00 -0800285 ['click row', 'Select / deselect application'],
286 ['scroll down', 'See more applications']
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700287 ]);
288
Simon Hunt3f92c432016-01-12 17:34:23 -0800289 function createConfirmationText(action, itemId) {
Simon Hunt8d28a552016-01-11 14:01:02 -0800290 var content = ds.createDiv();
Simon Hunt40927332016-01-22 15:29:47 -0800291 content.append('p').text(fs.cap(action) + ' ' + itemId);
Simon Hunt3f92c432016-01-12 17:34:23 -0800292 if (strongWarning[itemId]) {
Simon Hunt239f09e2017-05-18 13:10:09 -0700293 content.append('p').html(fs.sanitize(discouragement))
294 .classed('strong', true);
Simon Hunt3f92c432016-01-12 17:34:23 -0800295 }
Simon Hunt8d28a552016-01-11 14:01:02 -0800296 return content;
297 }
298
299 function confirmAction(action) {
Simon Hunt3f92c432016-01-12 17:34:23 -0800300 var itemId = $scope.selId,
Simon Hunt8d28a552016-01-11 14:01:02 -0800301 spar = $scope.sortParams;
302
303 function dOk() {
Simon Hunt3f92c432016-01-12 17:34:23 -0800304 $log.debug('Initiating', action, 'of', itemId);
Simon Hunt8d28a552016-01-11 14:01:02 -0800305 wss.sendEvent(appMgmtReq, {
306 action: action,
Simon Hunt3f92c432016-01-12 17:34:23 -0800307 name: itemId,
Simon Hunt8d28a552016-01-11 14:01:02 -0800308 sortCol: spar.sortCol,
309 sortDir: spar.sortDir
310 });
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800311 if (action == 'uninstall') {
312 detailsPanel.hide();
313 } else {
314 wss.sendEvent(detailsReq, {id: itemId});
315 }
Simon Hunt8d28a552016-01-11 14:01:02 -0800316 }
317
318 function dCancel() {
Simon Hunt3f92c432016-01-12 17:34:23 -0800319 $log.debug('Canceling', action, 'of', itemId);
Simon Hunt8d28a552016-01-11 14:01:02 -0800320 }
321
322 ds.openDialog(dialogId, dialogOpts)
323 .setTitle('Confirm Action')
Simon Hunt3f92c432016-01-12 17:34:23 -0800324 .addContent(createConfirmationText(action, itemId))
Simon Hunt5198f082016-02-04 13:41:17 -0800325 .addOk(dOk)
326 .addCancel(dCancel)
327 .bindKeys();
Simon Hunt8d28a552016-01-11 14:01:02 -0800328 }
329
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700330 $scope.appAction = function (action) {
331 if ($scope.ctrlBtnState.selection) {
Simon Hunt8d28a552016-01-11 14:01:02 -0800332 confirmAction(action);
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700333 }
Bri Prebilic Colebd0bc772015-05-13 13:02:26 -0700334 };
Thomas Vachuska530e52a2015-05-06 19:51:32 -0700335
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700336 $scope.$on('FileChanged', function () {
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800337 var formData = new FormData(),
338 url;
Simon Huntf51bf462016-06-29 16:22:57 -0700339
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700340 if ($scope.appFile) {
341 formData.append('file', $scope.appFile);
Simon Huntf51bf462016-06-29 16:22:57 -0700342 url = fileUploadUrl + activateImmediately;
343
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800344 $http.post(ufs.rsUrl(url), formData, {
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700345 transformRequest: angular.identity,
346 headers: {
347 'Content-Type': undefined
348 }
349 })
Simon Huntf51bf462016-06-29 16:22:57 -0700350 .finally(function () {
351 activateImmediately = '';
352 $scope.sortCallback($scope.sortParams);
353 document.getElementById('inputFileForm').reset();
354 $timeout(function () { wss.sendEvent(detailsReq); }, 250);
355 });
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -0700356 }
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -0700357 });
358
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800359 $scope.appDropped = function() {
360 activateImmediately = activateOption;
361 $scope.$emit('FileChanged');
362 $scope.appFile = null;
363 };
364
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700365 $scope.$on('$destroy', function () {
366 ks.unbindKeys();
Jian Lia54de5a2016-01-20 23:10:39 -0800367 wss.unbindHandlers(handlers);
Simon Hunt0991b342016-06-08 13:18:16 -0700368 ds.closeDialog();
Bri Prebilic Cole9dcaea52015-07-21 14:39:48 -0700369 });
370
Thomas Vachuska619c5382015-04-02 13:41:47 -0700371 $log.log('OvAppCtrl has been created');
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700372 }])
373
374 // triggers the input form to appear when button is clicked
375 .directive('triggerForm', function () {
376 return {
377 restrict: 'A',
378 link: function (scope, elem) {
379 elem.bind('click', function () {
380 document.getElementById('uploadFile')
Bri Prebilic Cole6c82ade2015-08-05 11:12:30 -0700381 .dispatchEvent(new MouseEvent('click'));
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700382 });
383 }
384 };
385 })
386
387 // binds the model file to the scope in scope.appFile
388 // sends upload request to the server
389 .directive('fileModel', ['$parse',
Simon Huntf51bf462016-06-29 16:22:57 -0700390 function ($parse) {
391 return {
392 restrict: 'A',
393 link: function (scope, elem, attrs) {
394 var model = $parse(attrs.fileModel),
395 modelSetter = model.assign;
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700396
Simon Huntf51bf462016-06-29 16:22:57 -0700397 elem.bind('change', function () {
398 scope.$apply(function () {
399 modelSetter(scope, elem[0].files[0]);
400 });
401 scope.$emit('FileChanged');
Bri Prebilic Cole522e7562015-06-22 15:56:25 -0700402 });
Simon Huntf51bf462016-06-29 16:22:57 -0700403 }
404 };
405 }])
Jian Lia54de5a2016-01-20 23:10:39 -0800406
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800407 .directive("filedrop", function ($parse, $document) {
408 return {
409 restrict: "A",
410 link: function (scope, element, attrs) {
411 var onAppDrop = $parse(attrs.onFileDrop);
412
413 // When an item is dragged over the document
414 var onDragOver = function (e) {
Thomas Vachuskaebf3be02016-04-11 09:52:06 -0700415 d3.select('#frame').classed('dropping', true);
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800416 e.preventDefault();
417 };
418
419 // When the user leaves the window, cancels the drag or drops the item
420 var onDragEnd = function (e) {
Thomas Vachuskaebf3be02016-04-11 09:52:06 -0700421 d3.select('#frame').classed('dropping', false);
Thomas Vachuskaa42ce0b2016-03-09 09:02:49 -0800422 e.preventDefault();
423 };
424
425 // When a file is dropped
426 var loadFile = function (file) {
427 scope.appFile = file;
428 scope.$apply(onAppDrop(scope));
429 };
430
431 // Dragging begins on the document
432 $document.bind("dragover", onDragOver);
433
434 // Dragging ends on the overlay, which takes the whole window
435 element.bind("dragleave", onDragEnd)
436 .bind("drop", function (e) {
437 $log.info('Drag leave', e);
438 loadFile(e.dataTransfer.files[0]);
439 onDragEnd(e);
440 });
441 }
442 };
443 })
444
Jian Lia54de5a2016-01-20 23:10:39 -0800445 .directive('applicationDetailsPanel',
446 ['$rootScope', '$window', '$timeout', 'KeyService',
447 function ($rootScope, $window, $timeout, ks) {
448 return function (scope) {
449 var unbindWatch;
450
451 function heightCalc() {
452 pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
453 + topPdg;
454 wSize = fs.windowSize(pStartY);
455 pHeight = wSize.height;
456 }
457
458 function initPanel() {
459 heightCalc();
460 createDetailsPane();
461 $log.debug('start to initialize panel!');
462 }
463
464 // Safari has a bug where it renders the fixed-layout table wrong
465 // if you ask for the window's size too early
466 if (scope.onos.browser === 'safari') {
467 $timeout(initPanel);
468 } else {
469 initPanel();
470 }
471 // create key bindings to handle panel
472 ks.keyBindings({
Simon Hunta477b602016-01-22 12:10:07 -0800473 esc: [closePanel, 'Close the details panel'],
Jian Lia54de5a2016-01-20 23:10:39 -0800474 _helpFormat: ['esc']
475 });
476 ks.gestureNotes([
477 ['click', 'Select a row to show application details'],
Simon Huntd721f292016-06-22 21:42:23 -0700478 ['scroll down', 'See more applications']
Jian Lia54de5a2016-01-20 23:10:39 -0800479 ]);
480
481 // if the panelData changes
482 scope.$watch('panelData', function () {
483 if (!fs.isEmptyObject(scope.panelData)) {
484 populateDetails(scope.panelData);
485 detailsPanel.show();
486 }
487 });
488
489 // if the window size changes
490 unbindWatch = $rootScope.$watchCollection(
491 function () {
492 return {
493 h: $window.innerHeight,
494 w: $window.innerWidth
495 };
496 }, function () {
497 if (!fs.isEmptyObject(scope.panelData)) {
498 heightCalc();
499 populateDetails(scope.panelData);
500 }
501 }
502 );
503
504 scope.$on('$destroy', function () {
505 unbindWatch();
506 ks.unbindKeys();
507 ps.destroyPanel(pName);
508 });
509 };
510 }]);
Thomas Vachuska0fa583c2015-03-30 23:07:41 -0700511}());