From b5e05ab7e749f27366d8318a6459312ff334536a Mon Sep 17 00:00:00 2001 From: Torkel Odegaard Date: Sun, 15 Dec 2013 18:30:25 +0100 Subject: [PATCH] added keyboard manager and shortcuts to search, and escape to exit full edit mode --- src/app/controllers/dash.js | 6 +- src/app/controllers/search.js | 11 +- src/app/services/all.js | 3 +- src/app/services/keyboardManager.js | 235 ++++++++++++++++++++++++++++ 4 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 src/app/services/keyboardManager.js diff --git a/src/app/controllers/dash.js b/src/app/controllers/dash.js index 3ce25543330..ef912287ca9 100644 --- a/src/app/controllers/dash.js +++ b/src/app/controllers/dash.js @@ -29,7 +29,7 @@ function (angular, config, _) { var module = angular.module('kibana.controllers'); module.controller('DashCtrl', function( - $scope, $rootScope, $route, ejsResource, fields, dashboard, alertSrv, panelMove, esVersion) { + $scope, $rootScope, $route, ejsResource, fields, dashboard, alertSrv, panelMove, esVersion, keyboardManager) { $scope.requiredElasticSearchVersion = ">=0.90.3"; @@ -65,6 +65,10 @@ function (angular, config, _) { $rootScope.$on('fullEditMode', function(evt, enabled) { $scope.fullEditMode = enabled; }); + + keyboardManager.bind('esc', function() { + $rootScope.$emit('fullEditMode', false); + }); }; $scope.isPanel = function(obj) { diff --git a/src/app/controllers/search.js b/src/app/controllers/search.js index 991fe208811..2d5165ce853 100644 --- a/src/app/controllers/search.js +++ b/src/app/controllers/search.js @@ -9,12 +9,21 @@ function (angular, _, config, $) { var module = angular.module('kibana.controllers'); - module.controller('SearchCtrl', function($scope, dashboard) { + module.controller('SearchCtrl', function($scope, dashboard, keyboardManager, $element) { $scope.init = function() { $scope.elasticsearch = $scope.elasticsearch || {}; $scope.giveSearchFocus = 0; $scope.selectedIndex = null; + + keyboardManager.bind('s', function() { + $element.find('.dropdown').addClass('open'); + $scope.giveSearchFocus += 1; + }); + + keyboardManager.bind('esc', function() { + $element.find('.dropdown').removeClass('open'); + }); }; $scope.keyDown = function (evt) { diff --git a/src/app/services/all.js b/src/app/services/all.js index fdc54080abb..9f1c27d8425 100644 --- a/src/app/services/all.js +++ b/src/app/services/all.js @@ -7,6 +7,7 @@ define([ './querySrv', './timer', './panelMove', - './esVersion' + './esVersion', + './keyboardManager', ], function () {}); \ No newline at end of file diff --git a/src/app/services/keyboardManager.js b/src/app/services/keyboardManager.js new file mode 100644 index 00000000000..6d75afd1f73 --- /dev/null +++ b/src/app/services/keyboardManager.js @@ -0,0 +1,235 @@ +define([ + 'angular', + 'underscore', + 'jquery' +], +function (angular, _, $) { + 'use strict'; + + var module = angular.module('kibana.services'); + + // This service was based on OpenJS library available in BSD License + // http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php + module.factory('keyboardManager', ['$window', '$timeout', function ($window, $timeout) { + var keyboardManagerService = {}; + + var defaultOpt = { + 'type': 'keydown', + 'propagate': false, + 'inputDisabled': false, + 'target': $window.document, + 'keyCode': false + }; + // Store all keyboard combination shortcuts + keyboardManagerService.keyboardEvent = {} + // Add a new keyboard combination shortcut + keyboardManagerService.bind = function (label, callback, opt) { + var fct, elt, code, k; + // Initialize opt object + opt = angular.extend({}, defaultOpt, opt); + label = label.toLowerCase(); + elt = opt.target; + if(typeof opt.target == 'string') elt = document.getElementById(opt.target); + + fct = function (e) { + e = e || $window.event; + + // Disable event handler when focus input and textarea + if (opt['inputDisabled']) { + var elt; + if (e.target) elt = e.target; + else if (e.srcElement) elt = e.srcElement; + if (elt.nodeType == 3) elt = elt.parentNode; + if (elt.tagName == 'INPUT' || elt.tagName == 'TEXTAREA') return; + } + + // Find out which key is pressed + if (e.keyCode) code = e.keyCode; + else if (e.which) code = e.which; + var character = String.fromCharCode(code).toLowerCase(); + + if (code == 188) character = ","; // If the user presses , when the type is onkeydown + if (code == 190) character = "."; // If the user presses , when the type is onkeydown + + var keys = label.split("+"); + // Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked + var kp = 0; + // Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken + var shift_nums = { + "`":"~", + "1":"!", + "2":"@", + "3":"#", + "4":"$", + "5":"%", + "6":"^", + "7":"&", + "8":"*", + "9":"(", + "0":")", + "-":"_", + "=":"+", + ";":":", + "'":"\"", + ",":"<", + ".":">", + "/":"?", + "\\":"|" + }; + // Special Keys - and their codes + var special_keys = { + 'esc':27, + 'escape':27, + 'tab':9, + 'space':32, + 'return':13, + 'enter':13, + 'backspace':8, + + 'scrolllock':145, + 'scroll_lock':145, + 'scroll':145, + 'capslock':20, + 'caps_lock':20, + 'caps':20, + 'numlock':144, + 'num_lock':144, + 'num':144, + + 'pause':19, + 'break':19, + + 'insert':45, + 'home':36, + 'delete':46, + 'end':35, + + 'pageup':33, + 'page_up':33, + 'pu':33, + + 'pagedown':34, + 'page_down':34, + 'pd':34, + + 'left':37, + 'up':38, + 'right':39, + 'down':40, + + 'f1':112, + 'f2':113, + 'f3':114, + 'f4':115, + 'f5':116, + 'f6':117, + 'f7':118, + 'f8':119, + 'f9':120, + 'f10':121, + 'f11':122, + 'f12':123 + }; + // Some modifiers key + var modifiers = { + shift: { + wanted: false, + pressed: e.shiftKey ? true : false + }, + ctrl : { + wanted: false, + pressed: e.ctrlKey ? true : false + }, + alt : { + wanted: false, + pressed: e.altKey ? true : false + }, + meta : { //Meta is Mac specific + wanted: false, + pressed: e.metaKey ? true : false + } + }; + // Foreach keys in label (split on +) + for(var i=0, l=keys.length; k=keys[i],i 1) { // If it is a special key + if(special_keys[k] == code) kp++; + } else if (opt['keyCode']) { // If a specific key is set into the config + if (opt['keyCode'] == code) kp++; + } else { // The special keys did not match + if(character == k) kp++; + else { + if(shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase + character = shift_nums[character]; + if(character == k) kp++; + } + } + } + } + + if(kp == keys.length && + modifiers.ctrl.pressed == modifiers.ctrl.wanted && + modifiers.shift.pressed == modifiers.shift.wanted && + modifiers.alt.pressed == modifiers.alt.wanted && + modifiers.meta.pressed == modifiers.meta.wanted) { + $timeout(function() { + callback(e); + }, 1); + + if(!opt['propagate']) { // Stop the event + // e.cancelBubble is supported by IE - this will kill the bubbling process. + e.cancelBubble = true; + e.returnValue = false; + + // e.stopPropagation works in Firefox. + if (e.stopPropagation) { + e.stopPropagation(); + e.preventDefault(); + } + return false; + } + } + + }; + // Store shortcut + keyboardManagerService.keyboardEvent[label] = { + 'callback': fct, + 'target': elt, + 'event': opt['type'] + }; + //Attach the function with the event + if(elt.addEventListener) elt.addEventListener(opt['type'], fct, false); + else if(elt.attachEvent) elt.attachEvent('on' + opt['type'], fct); + else elt['on' + opt['type']] = fct; + }; + // Remove the shortcut - just specify the shortcut and I will remove the binding + keyboardManagerService.unbind = function (label) { + label = label.toLowerCase(); + var binding = keyboardManagerService.keyboardEvent[label]; + delete(keyboardManagerService.keyboardEvent[label]) + if(!binding) return; + var type = binding['event'], + elt = binding['target'], + callback = binding['callback']; + if(elt.detachEvent) elt.detachEvent('on' + type, callback); + else if(elt.removeEventListener) elt.removeEventListener(type, callback, false); + else elt['on'+type] = false; + }; + // + return keyboardManagerService; + }]); + +}); \ No newline at end of file