Simon Hunt
Committed by Gerrit Code Review

ONOS-2849: Refactored topo dialog to general DialogService. Implemented confirma…

…tion dialog in App view.

Change-Id: Ib20e98253b2d13f7d7debef2dea5a530b61ced99
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Dialog Service -- CSS file
*/
.dialog h2 {
padding: 0 4px;
margin: 0;
word-wrap: break-word;
display: inline-block;
width: 210px;
vertical-align: middle;
}
.light .dialog h2 {
color: black;
}
.dark .dialog h2 {
color: #ddd;
}
.dialog .dialog-button {
display: inline-block;
cursor: pointer;
height: 20px;
padding: 2px 6px;
margin: 4px;
float: right;
}
.light .dialog .dialog-button {
background-color: #fec;
}
.dark .dialog .dialog-button {
background-color: #369;
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Layer -- Dialog Service
Builds on the panel service to provide dialog functionality.
*/
(function () {
'use strict';
// injected refs
var $log, $window, fs, ps, bns;
// configuration
var defaultSettings = {
width: 300,
edge: 'left'
};
// internal state
var pApi, panel, dApi;
// TODO: ONOS-3741
// TODO: ESC key invokes Cancel callback
// TODO: Enter invokes OK callback
// create the dialog; return its API
function createDialog(id, opts) {
var header, body, footer,
settings = angular.extend({}, defaultSettings, opts),
p = ps.createPanel(id, settings),
cls = opts && opts.cssCls;
p.classed('dialog', true);
if (cls) {
p.classed(cls, true);
}
panel = p;
function reset() {
p.empty();
p.append('div').classed('header', true);
p.append('div').classed('body', true);
p.append('div').classed('footer', true);
header = p.el().select('.header');
body = p.el().select('.body');
footer = p.el().select('.footer');
}
function hAppend(x) {
if (typeof x === 'string') {
return header.append(x);
}
header.node().appendChild(x.node());
return header;
}
function bAppend(x) {
if (typeof x === 'string') {
return body.append(x);
}
body.node().appendChild(x.node());
return body;
}
function fAppend(x) {
if (typeof x === 'string') {
return footer.append(x);
}
footer.node().appendChild(x.node());
return footer;
}
function destroy() {
ps.destroyPanel(id);
}
return {
reset: reset,
appendHeader: hAppend,
appendBody: bAppend,
appendFooter: fAppend,
destroy: destroy
};
}
function makeButton(text, callback) {
var cb = fs.isF(callback);
function invoke() {
cb && cb();
panel.hide();
}
return createDiv('dialog-button')
.text(text)
.on('click', invoke);
}
function setTitle(title) {
if (pApi) {
pApi.appendHeader('h2').text(title);
}
return dApi;
}
function addContent(content) {
if (pApi) {
pApi.appendBody(content);
}
return dApi;
}
function addButton(text, cb) {
if (pApi) {
pApi.appendFooter(makeButton(text, cb));
}
return dApi;
}
// opens the dialog (creates if necessary)
function openDialog(id, opts) {
$log.debug('Open DIALOG', id, opts);
if (!pApi) {
pApi = createDialog(id, opts);
}
pApi.reset();
panel.show();
// return the dialog object API
dApi = {
setTitle: setTitle,
addContent: addContent,
addButton: addButton
};
return dApi;
}
// closes the dialog (destroying panel)
function closeDialog() {
$log.debug('Close DIALOG');
if (pApi) {
panel.hide();
pApi.destroy();
pApi = null;
dApi = null;
}
}
// creates a detached div, returning D3 selection
// optional CSS class may be provided
function createDiv(cls) {
var div = d3.select(document.createElement('div'));
if (cls) {
div.classed(cls, true);
}
return div;
}
angular.module('onosLayer')
.factory('DialogService',
['$log', '$window', 'FnService', 'PanelService', 'ButtonService',
// TODO: for now, $window is not used, but we should provide an option
// to center the dialog on the window.
function (_$log_, _$window_, _fs_, _ps_, _bns_) {
$log = _$log_;
$window = _$window_;
fs = _fs_;
ps = _ps_;
bns = _bns_;
return {
openDialog: openDialog,
closeDialog: closeDialog,
createDiv: createDiv
};
}]);
}());
......@@ -30,3 +30,8 @@
#ov-app input#uploadFile {
display: none;
}
#app-dialog p {
color: darkred;
font-size: 12pt;
}
......
......@@ -24,16 +24,20 @@
// constants
var INSTALLED = 'INSTALLED',
ACTIVE = 'ACTIVE',
APP_MGMENT_REQ = 'appManagementRequest',
FILE_UPLOAD_URL = 'applications/upload';
appMgmtReq = 'appManagementRequest',
fileUploadUrl = 'applications/upload',
dialogId = 'app-dialog',
dialogOpts = {
edge: 'right'
};
angular.module('ovApp', [])
.controller('OvAppCtrl',
['$log', '$scope', '$http',
'FnService', 'TableBuilderService', 'WebSocketService', 'UrlFnService',
'KeyService',
'KeyService', 'DialogService',
function ($log, $scope, $http, fs, tbs, wss, ufs, ks) {
function ($log, $scope, $http, fs, tbs, wss, ufs, ks, ds) {
$scope.ctrlBtnState = {};
$scope.uploadTip = 'Upload an application (.oar file)';
$scope.activateTip = 'Activate selected application';
......@@ -77,23 +81,49 @@
['scroll down', 'See more apps']
]);
$scope.appAction = function (action) {
if ($scope.ctrlBtnState.selection) {
$log.debug('Initiating ' + action + ' of ' + $scope.selId);
wss.sendEvent(APP_MGMENT_REQ, {
function createConfirmationText(action, sid) {
var content = ds.createDiv();
content.append('p').text(action + ' ' + sid);
return content;
}
function confirmAction(action) {
var sid = $scope.selId,
spar = $scope.sortParams;
function dOk() {
$log.debug('Initiating', action, 'of', sid);
wss.sendEvent(appMgmtReq, {
action: action,
name: $scope.selId,
sortCol: $scope.sortParams.sortCol,
sortDir: $scope.sortParams.sortDir
name: sid,
sortCol: spar.sortCol,
sortDir: spar.sortDir
});
}
function dCancel() {
$log.debug('Canceling', action, 'of', sid);
}
ds.openDialog(dialogId, dialogOpts)
.setTitle('Confirm Action')
.addContent(createConfirmationText(action, sid))
.addButton('OK', dOk)
.addButton('Cancel', dCancel);
}
$scope.appAction = function (action) {
if ($scope.ctrlBtnState.selection) {
confirmAction(action);
}
};
$scope.$on('FileChanged', function () {
var formData = new FormData();
if ($scope.appFile) {
formData.append('file', $scope.appFile);
$http.post(ufs.rsUrl(FILE_UPLOAD_URL), formData, {
$http.post(ufs.rsUrl(fileUploadUrl), formData, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
......
......@@ -96,23 +96,6 @@ html[data-platform='iPad'] #topo-p-detail {
height: 30px;
}
/* --- Topo Dialog Panel --- */
#topo-p-dialog .dialog-button {
display: inline-block;
cursor: pointer;
height: 20px;
padding: 2px 6px;
margin: 4px;
float: right;
}
.light #topo-p-dialog .dialog-button {
background-color: #fec;
}
.dark #topo-p-dialog .dialog-button {
background-color: #369;
}
/* --- general topo-panel styling --- */
......
......@@ -16,175 +16,29 @@
/*
ONOS GUI -- Topology Dialog Module.
Defines functions for manipulating a dialog box.
Creates a dialog box for the topology view.
*/
(function () {
'use strict';
// injected refs
var $log, $window, $rootScope, fs, ps, bns;
// constants
var pCls = 'topo-p dialog',
idDialog = 'topo-p-dialog',
panelOpts = {
width: 300,
edge: 'left'
};
// internal state
var pApi, panel, dApi;
// TODO: ESC key invokes Cancel callback
// TODO: Enter invokes OK callback
// create the dialog; return its API
function createDialog() {
var header, body, footer,
p = ps.createPanel(idDialog, panelOpts);
p.classed(pCls, true);
panel = p;
function reset() {
p.empty();
p.append('div').classed('header', true);
p.append('div').classed('body', true);
p.append('div').classed('footer', true);
header = p.el().select('.header');
body = p.el().select('.body');
footer = p.el().select('.footer');
}
function hAppend(x) {
if (typeof x === 'string') {
return header.append(x);
}
header.node().appendChild(x.node());
return header;
}
function bAppend(x) {
if (typeof x === 'string') {
return body.append(x);
}
body.node().appendChild(x.node());
return body;
}
function fAppend(x) {
if (typeof x === 'string') {
return footer.append(x);
}
footer.node().appendChild(x.node());
return footer;
}
function destroy() {
ps.destroyPanel(idDialog);
}
return {
reset: reset,
appendHeader: hAppend,
appendBody: bAppend,
appendFooter: fAppend,
destroy: destroy
var idDialog = 'topo-p-dialog',
opts = {
cssCls: 'topo-p'
};
}
function makeButton(text, callback) {
var cb = fs.isF(callback);
function invoke() {
cb && cb();
panel.hide();
}
return createDiv('dialog-button')
.text(text)
.on('click', invoke);
}
function setTitle(title) {
if (pApi) {
pApi.appendHeader('h2').text(title);
}
return dApi;
}
function addContent(content) {
if (pApi) {
pApi.appendBody(content);
}
return dApi;
}
function addButton(text, cb) {
if (pApi) {
pApi.appendFooter(makeButton(text, cb));
}
return dApi;
}
// opens the dialog (creates if necessary)
function openDialog() {
$log.debug('Open DIALOG');
if (!pApi) {
pApi = createDialog();
}
pApi.reset();
panel.show();
// return the dialog object API
dApi = {
setTitle: setTitle,
addContent: addContent,
addButton: addButton
};
return dApi;
}
// closes the dialog (destroying panel)
function closeDialog() {
$log.debug('Close DIALOG');
if (pApi) {
panel.hide();
pApi.destroy();
pApi = null;
dApi = null;
}
}
// creates a detached div, returning D3 selection
// optional CSS class may be provided
function createDiv(cls) {
var div = d3.select(document.createElement('div'));
if (cls) {
div.classed(cls, true);
}
return div;
}
// ==========================
angular.module('ovTopo')
.factory('TopoDialogService',
['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'ButtonService',
function (_$log_, _$window_, _$rootScope_,
_fs_, _ps_, _bns_) {
$log = _$log_;
$window = _$window_;
$rootScope = _$rootScope_;
fs = _fs_;
ps = _ps_;
bns = _bns_;
['DialogService',
function (ds) {
return {
openDialog: openDialog,
closeDialog: closeDialog,
createDiv: createDiv
openDialog: function () { return ds.openDialog(idDialog, opts); },
closeDialog: ds.closeDialog,
createDiv: ds.createDiv
};
}]);
}());
......
......@@ -73,6 +73,7 @@
<script src="app/fw/layer/layer.js"></script>
<script src="app/fw/layer/panel.js"></script>
<script src="app/fw/layer/dialog.js"></script>
<script src="app/fw/layer/flash.js"></script>
<script src="app/fw/layer/quickhelp.js"></script>
<script src="app/fw/layer/veil.js"></script>
......@@ -86,6 +87,7 @@
<link rel="stylesheet" href="app/fw/svg/glyph.css">
<link rel="stylesheet" href="app/fw/svg/icon.css">
<link rel="stylesheet" href="app/fw/layer/panel.css">
<link rel="stylesheet" href="app/fw/layer/dialog.css">
<link rel="stylesheet" href="app/fw/layer/flash.css">
<link rel="stylesheet" href="app/fw/layer/quickhelp.css">
<link rel="stylesheet" href="app/fw/layer/veil.css">
......