From 8d28a55fe3da2891a9961fb10b9b4848d1c673cc Mon Sep 17 00:00:00 2001 From: Simon Hunt Date: Mon, 11 Jan 2016 14:01:02 -0800 Subject: [PATCH] ONOS-2849: Refactored topo dialog to general DialogService. Implemented confirmation dialog in App view. Change-Id: Ib20e98253b2d13f7d7debef2dea5a530b61ced99 --- .../src/main/webapp/app/fw/layer/dialog.css | 50 +++++ .../src/main/webapp/app/fw/layer/dialog.js | 195 ++++++++++++++++++ web/gui/src/main/webapp/app/view/app/app.css | 5 + web/gui/src/main/webapp/app/view/app/app.js | 54 +++-- .../src/main/webapp/app/view/topo/topo.css | 17 -- .../main/webapp/app/view/topo/topoDialog.js | 164 +-------------- web/gui/src/main/webapp/index.html | 2 + 7 files changed, 303 insertions(+), 184 deletions(-) create mode 100644 web/gui/src/main/webapp/app/fw/layer/dialog.css create mode 100644 web/gui/src/main/webapp/app/fw/layer/dialog.js 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 0000000000..2c0499223d --- /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 0000000000..f0a6b655c0 --- /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 9413369ad4..528c6221d3 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 7cc081cb45..3b27c38ec9 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 0319b9b795..69f500f690 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 @@ 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 --- */ 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 0c47511b27..c5e89ddd60 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', - - 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 }; }]); }()); diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html index 8cf75e05f4..adead69aff 100644 --- a/web/gui/src/main/webapp/index.html +++ b/web/gui/src/main/webapp/index.html @@ -73,6 +73,7 @@ + @@ -86,6 +87,7 @@ +