GUI -- Added global key bindings mechanism
- 'T' now toggles theme (light/dark) -- mast CSS done, other CSS to do
- 'ESC' now closes alerts box if it is open
- Minor cleanup to topo2.js
Change-Id: I506a6add4299a6c03dcb717c33394ad94be26997
diff --git a/web/gui/src/main/webapp/onos2.js b/web/gui/src/main/webapp/onos2.js
index 31d89fa..4aeb23e 100644
--- a/web/gui/src/main/webapp/onos2.js
+++ b/web/gui/src/main/webapp/onos2.js
@@ -37,23 +37,34 @@
var defaultOptions = {
trace: false,
+ theme: 'light',
startVid: defaultVid
};
// compute runtime settings
var settings = $.extend({}, defaultOptions, options);
+ // set the selected theme
+ d3.select('body').classed(settings.theme, true);
+
// internal state
var views = {},
current = {
view: null,
- ctx: ''
+ ctx: '',
+ theme: settings.theme
},
built = false,
errorCount = 0,
keyHandler = {
- fn: null,
- map: {}
+ globalKeys: {},
+ maskedKeys: {},
+ viewKeys: {},
+ viewFn: null
+ },
+ alerts = {
+ open: false,
+ count: 0
};
// DOM elements etc.
@@ -240,8 +251,8 @@
// detach radio buttons, key handlers, etc.
$('#mastRadio').children().detach();
- keyHandler.fn = null;
- keyHandler.map = {};
+ keyHandler.viewKeys = {};
+ keyHandler.viewFn = null;
}
// cache new view and context
@@ -322,20 +333,74 @@
$mastRadio.node().appendChild(btnG.node());
}
+ function setupGlobalKeys() {
+ keyHandler.globalKeys = {
+ esc: escapeKey,
+ T: toggleTheme
+ };
+ // Masked keys are global key handlers that always return true.
+ // That is, the view will never see the event for that key.
+ keyHandler.maskedKeys = {
+ T: true
+ };
+ }
+
+ function escapeKey(view, key, code, ev) {
+ if (alerts.open) {
+ closeAlerts();
+ return true;
+ }
+ return false;
+ }
+
+ function toggleTheme(view, key, code, ev) {
+ var body = d3.select('body');
+ current.theme = (current.theme === 'light') ? 'dark' : 'light';
+ body.classed('light dark', false);
+ body.classed(current.theme, true);
+ return true;
+ }
+
function setKeyBindings(keyArg) {
+ var viewKeys,
+ masked = [];
+
if ($.isFunction(keyArg)) {
// set general key handler callback
- keyHandler.fn = keyArg;
+ keyHandler.viewFn = keyArg;
} else {
// set specific key filter map
- keyHandler.map = keyArg;
+ viewKeys = d3.map(keyArg).keys();
+ viewKeys.forEach(function (key) {
+ if (keyHandler.maskedKeys[key]) {
+ masked.push(' Key "' + key + '" is reserved');
+ }
+ });
+
+ if (masked.length) {
+ doAlert('WARNING...\n\nsetKeys():\n' + masked.join('\n'));
+ }
+ keyHandler.viewKeys = keyArg;
}
}
- var alerts = {
- open: false,
- count: 0
- };
+ function keyIn() {
+ var event = d3.event,
+ keyCode = event.keyCode,
+ key = whatKey(keyCode),
+ gcb = isF(keyHandler.globalKeys[key]),
+ vcb = isF(keyHandler.viewKeys[key]) || isF(keyHandler.viewFn);
+
+ // global callback?
+ if (gcb && gcb(current.view.token(), key, keyCode, event)) {
+ // if the event was 'handled', we are done
+ return;
+ }
+ // otherwise, let the view callback have a shot
+ if (vcb) {
+ vcb(current.view.token(), key, keyCode, event);
+ }
+ }
function createAlerts() {
var al = d3.select('#alerts')
@@ -345,15 +410,16 @@
.text('X')
.on('click', closeAlerts);
al.append('pre');
+ al.append('p').attr('class', 'footnote')
+ .text('Press ESCAPE to close');
alerts.open = true;
alerts.count = 0;
}
function closeAlerts() {
d3.select('#alerts')
- .style('display', 'none');
- d3.select('#alerts span').remove();
- d3.select('#alerts pre').remove();
+ .style('display', 'none')
+ .html('');
alerts.open = false;
}
@@ -384,17 +450,6 @@
addAlert(msg);
}
- function keyIn() {
- var event = d3.event,
- keyCode = event.keyCode,
- key = whatKey(keyCode),
- cb = isF(keyHandler.map[key]) || isF(keyHandler.fn);
-
- if (cb) {
- cb(current.view.token(), key, keyCode, event);
- }
- }
-
function resize(e) {
d3.selectAll('.onosView').call(setViewDimensions);
// allow current view to react to resize event...
@@ -683,6 +738,7 @@
$(window).on('resize', resize);
d3.select('body').on('keydown', keyIn);
+ setupGlobalKeys();
// Invoke hashchange callback to navigate to content
// indicated by the window location hash.