ONOS-3741: Bind Escape to Cancel and Enter to OK in dialog service.
- also allow arbitrary keybindings to arbitrary text buttons in dialogs.
Change-Id: I5a01abb13fce41f81e8686866d82d2d08c34a71b
diff --git a/web/gui/src/main/webapp/app/fw/layer/dialog.js b/web/gui/src/main/webapp/app/fw/layer/dialog.js
index f0a6b65..e19280d 100644
--- a/web/gui/src/main/webapp/app/fw/layer/dialog.js
+++ b/web/gui/src/main/webapp/app/fw/layer/dialog.js
@@ -23,7 +23,7 @@
'use strict';
// injected refs
- var $log, $window, fs, ps, bns;
+ var $log, $window, fs, ps, bns, ks;
// configuration
var defaultSettings = {
@@ -32,11 +32,8 @@
};
// internal state
- var pApi, panel, dApi;
-
- // TODO: ONOS-3741
- // TODO: ESC key invokes Cancel callback
- // TODO: Enter invokes OK callback
+ var pApi, panel, dApi,
+ keyBindings = {};
// create the dialog; return its API
function createDialog(id, opts) {
@@ -99,13 +96,20 @@
};
}
- function makeButton(text, callback) {
- var cb = fs.isF(callback);
+ function makeButton(text, callback, keyName) {
+ var cb = fs.isF(callback),
+ key = fs.isS(keyName);
function invoke() {
cb && cb();
+ clearBindings();
panel.hide();
}
+
+ if (key) {
+ keyBindings[key] = invoke;
+ }
+
return createDiv('dialog-button')
.text(text)
.on('click', invoke);
@@ -125,13 +129,26 @@
return dApi;
}
- function addButton(text, cb) {
+ function addButton(text, cb, key) {
if (pApi) {
- pApi.appendFooter(makeButton(text, cb));
+ pApi.appendFooter(makeButton(text, cb, key));
}
return dApi;
}
+ function addOk(cb) {
+ return addButton('OK', cb, 'enter');
+ }
+
+ function addCancel(cb) {
+ return addButton('Cancel', cb, 'esc');
+ }
+
+ function clearBindings() {
+ keyBindings = {};
+ ks.dialogKeys();
+ }
+
// opens the dialog (creates if necessary)
function openDialog(id, opts) {
$log.debug('Open DIALOG', id, opts);
@@ -145,7 +162,12 @@
dApi = {
setTitle: setTitle,
addContent: addContent,
- addButton: addButton
+ addButton: addButton,
+ addOk: addOk,
+ addCancel: addCancel,
+ bindKeys: function () {
+ ks.dialogKeys(keyBindings);
+ }
};
return dApi;
}
@@ -154,6 +176,7 @@
function closeDialog() {
$log.debug('Close DIALOG');
if (pApi) {
+ clearBindings();
panel.hide();
pApi.destroy();
pApi = null;
@@ -174,16 +197,18 @@
angular.module('onosLayer')
.factory('DialogService',
['$log', '$window', 'FnService', 'PanelService', 'ButtonService',
+ 'KeyService',
// 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_) {
+ function (_$log_, _$window_, _fs_, _ps_, _bns_, _ks_) {
$log = _$log_;
$window = _$window_;
fs = _fs_;
ps = _ps_;
bns = _bns_;
+ ks = _ks_;
return {
openDialog: openDialog,
diff --git a/web/gui/src/main/webapp/app/fw/util/keys.js b/web/gui/src/main/webapp/app/fw/util/keys.js
index 9c60e83..a3c5b78 100644
--- a/web/gui/src/main/webapp/app/fw/util/keys.js
+++ b/web/gui/src/main/webapp/app/fw/util/keys.js
@@ -29,6 +29,7 @@
keyHandler = {
globalKeys: {},
maskedKeys: {},
+ dialogKeys: {},
viewKeys: {},
viewFn: null,
viewGestures: []
@@ -104,6 +105,8 @@
kh = keyHandler,
gk = kh.globalKeys[key],
gcb = fs.isF(gk) || (fs.isA(gk) && fs.isF(gk[0])),
+ dk = kh.dialogKeys[key],
+ dcb = fs.isF(dk),
vk = kh.viewKeys[key],
kl = fs.isF(kh.viewKeys._keyListener),
vcb = fs.isF(vk) || (fs.isA(vk) && fs.isF(vk[0])) || fs.isF(kh.viewFn),
@@ -119,6 +122,12 @@
// if the event was 'handled', we are done
return;
}
+ // dialog callback?
+ if (dcb) {
+ dcb(token, key, keyCode, event);
+ // assume dialog handled the event
+ return;
+ }
// otherwise, let the view callback have a shot
if (vcb) {
vcb(token, key, keyCode, event);
@@ -170,26 +179,46 @@
return true;
}
- function setKeyBindings(keyArg) {
- var viewKeys,
- masked = [];
+ function filterMaskedKeys(map, caller, remove) {
+ var masked = [],
+ msgs = [];
- if (fs.isF(keyArg)) {
- // set general key handler callback
- keyHandler.viewFn = keyArg;
- } else {
- // set specific key filter map
- viewKeys = d3.map(keyArg).keys();
- viewKeys.forEach(function (key) {
- if (keyHandler.maskedKeys[key]) {
- masked.push('setKeyBindings(): Key "' + key + '" is reserved');
- }
- });
-
- if (masked.length) {
- $log.warn(masked.join('\n'));
+ d3.map(map).keys().forEach(function (key) {
+ if (keyHandler.maskedKeys[key]) {
+ masked.push(key);
+ msgs.push(caller, ': Key "' + key + '" is reserved');
}
- keyHandler.viewKeys = keyArg;
+ });
+
+ if (msgs.length) {
+ $log.warn(msgs.join('\n'));
+ }
+
+ if (remove) {
+ masked.forEach(function (k) {
+ delete map[k];
+ });
+ }
+ return masked;
+ }
+
+ function unexParam(fname, x) {
+ $log.warn(fname, ": unexpected parameter-- ", x);
+ }
+
+ function setKeyBindings(keyArg) {
+ var fname = 'setKeyBindings()',
+ kFunc = fs.isF(keyArg),
+ kMap = fs.isO(keyArg);
+
+ if (kFunc) {
+ // set general key handler callback
+ keyHandler.viewFn = kFunc;
+ } else if (kMap) {
+ filterMaskedKeys(kMap, fname, true);
+ keyHandler.viewKeys = kMap;
+ } else {
+ unexParam(fname, keyArg);
}
}
@@ -213,6 +242,22 @@
keyHandler.viewGestures = [];
}
+ function bindDialogKeys(map) {
+ var fname = 'bindDialogKeys()',
+ kMap = fs.isO(map);
+
+ if (kMap) {
+ filterMaskedKeys(map, fname, true);
+ keyHandler.dialogKeys = kMap;
+ } else {
+ unexParam(fname, map);
+ }
+ }
+
+ function unbindDialogKeys() {
+ keyHandler.dialogKeys = {};
+ }
+
function checkNotGlobal(o) {
var oops = [];
if (fs.isO(o)) {
@@ -259,6 +304,13 @@
}
},
unbindKeys: unbindKeys,
+ dialogKeys: function (x) {
+ if (x === undefined) {
+ unbindDialogKeys();
+ } else {
+ bindDialogKeys(x);
+ }
+ },
addSeq: function (word, data) {
fs.addToTrie(seq, word, data);
},
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 7f620ae..a297bcb 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -308,8 +308,9 @@
ds.openDialog(dialogId, dialogOpts)
.setTitle('Confirm Action')
.addContent(createConfirmationText(action, itemId))
- .addButton('OK', dOk)
- .addButton('Cancel', dCancel);
+ .addOk(dOk)
+ .addCancel(dCancel)
+ .bindKeys();
}
$scope.appAction = function (action) {