ONOS-2849: Refactored topo dialog to general DialogService. Implemented confirmation dialog in App view.
Change-Id: Ib20e98253b2d13f7d7debef2dea5a530b61ced99
diff --git a/web/gui/src/main/webapp/app/fw/layer/dialog.css b/web/gui/src/main/webapp/app/fw/layer/dialog.css
new file mode 100644
index 0000000..2c04992
--- /dev/null
+++ b/web/gui/src/main/webapp/app/fw/layer/dialog.css
@@ -0,0 +1,50 @@
+/*
+ * 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;
+}
diff --git a/web/gui/src/main/webapp/app/fw/layer/dialog.js b/web/gui/src/main/webapp/app/fw/layer/dialog.js
new file mode 100644
index 0000000..f0a6b65
--- /dev/null
+++ b/web/gui/src/main/webapp/app/fw/layer/dialog.js
@@ -0,0 +1,195 @@
+/*
+ * 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
+ };
+ }]);
+
+}());
diff --git a/web/gui/src/main/webapp/app/view/app/app.css b/web/gui/src/main/webapp/app/view/app/app.css
index 9413369..528c622 100644
--- a/web/gui/src/main/webapp/app/view/app/app.css
+++ b/web/gui/src/main/webapp/app/view/app/app.css
@@ -30,3 +30,8 @@
#ov-app input#uploadFile {
display: none;
}
+
+#app-dialog p {
+ color: darkred;
+ font-size: 12pt;
+}
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 7cc081c..3b27c38 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -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,15 +81,41 @@
['scroll down', 'See more apps']
]);
+
+ 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: 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) {
- $log.debug('Initiating ' + action + ' of ' + $scope.selId);
- wss.sendEvent(APP_MGMENT_REQ, {
- action: action,
- name: $scope.selId,
- sortCol: $scope.sortParams.sortCol,
- sortDir: $scope.sortParams.sortDir
- });
+ confirmAction(action);
}
};
@@ -93,7 +123,7 @@
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
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.css b/web/gui/src/main/webapp/app/view/topo/topo.css
index 0319b9b..69f500f 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.css
+++ b/web/gui/src/main/webapp/app/view/topo/topo.css
@@ -96,23 +96,6 @@
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 --- */
diff --git a/web/gui/src/main/webapp/app/view/topo/topoDialog.js b/web/gui/src/main/webapp/app/view/topo/topoDialog.js
index 0c47511..c5e89dd 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoDialog.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoDialog.js
@@ -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'
+ var idDialog = 'topo-p-dialog',
+ opts = {
+ cssCls: 'topo-p'
};
- // 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
- };
- }
-
- 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',
+ ['DialogService',
- function (_$log_, _$window_, _$rootScope_,
- _fs_, _ps_, _bns_) {
- $log = _$log_;
- $window = _$window_;
- $rootScope = _$rootScope_;
- fs = _fs_;
- ps = _ps_;
- bns = _bns_;
-
+ function (ds) {
return {
- openDialog: openDialog,
- closeDialog: closeDialog,
- createDiv: createDiv
+ openDialog: function () { return ds.openDialog(idDialog, opts); },
+ closeDialog: ds.closeDialog,
+ createDiv: ds.createDiv
};
}]);
}());
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 8cf75e0..adead69 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -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">