keyboard_manager.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. define([
  2. 'angular',
  3. 'lodash',
  4. '../core_module',
  5. ],
  6. function (angular, _, coreModule) {
  7. 'use strict';
  8. // This service was based on OpenJS library available in BSD License
  9. // http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php
  10. coreModule.default.factory('keyboardManager', ['$window', '$timeout', function ($window, $timeout) {
  11. var keyboardManagerService = {};
  12. var defaultOpt = {
  13. 'type': 'keydown',
  14. 'propagate': false,
  15. 'inputDisabled': false,
  16. 'target': $window.document,
  17. 'keyCode': false
  18. };
  19. // Store all keyboard combination shortcuts
  20. keyboardManagerService.keyboardEvent = {};
  21. // Add a new keyboard combination shortcut
  22. keyboardManagerService.bind = function (label, callback, opt) {
  23. var fct, elt, code, k;
  24. // Initialize opt object
  25. opt = angular.extend({}, defaultOpt, opt);
  26. label = label.toLowerCase();
  27. elt = opt.target;
  28. if (typeof opt.target === 'string') {
  29. elt = document.getElementById(opt.target);
  30. }
  31. fct = function (e) {
  32. e = e || $window.event;
  33. // Disable event handler when focus input and textarea
  34. if (opt['inputDisabled']) {
  35. var elt;
  36. if (e.target) {
  37. elt = e.target;
  38. }
  39. else if (e.srcElement) {
  40. elt = e.srcElement;
  41. }
  42. if (elt.nodeType === 3) {
  43. elt = elt.parentNode;
  44. }
  45. if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA') {
  46. return;
  47. }
  48. }
  49. // Find out which key is pressed
  50. if (e.keyCode) {
  51. code = e.keyCode;
  52. }
  53. else if (e.which) {
  54. code = e.which;
  55. }
  56. var character = String.fromCharCode(code).toLowerCase();
  57. if (code === 188) {
  58. character = ","; // If the user presses , when the type is onkeydown
  59. }
  60. if (code === 190) {
  61. character = "."; // If the user presses , when the type is onkeydown
  62. }
  63. var keys = label.split("+");
  64. // Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
  65. var kp = 0;
  66. // Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
  67. var shift_nums = {
  68. "`": "~",
  69. "1": "!",
  70. "2": "@",
  71. "3": "#",
  72. "4": "$",
  73. "5": "%",
  74. "6": "^",
  75. "7": "&",
  76. "8": "*",
  77. "9": "(",
  78. "0": ")",
  79. "-": "_",
  80. "=": "+",
  81. ";": ":",
  82. "'": "\"",
  83. ",": "<",
  84. ".": ">",
  85. "/": "?",
  86. "»": "?",
  87. "«": "?",
  88. "¿": "?",
  89. "\\": "|"
  90. };
  91. // Special Keys - and their codes
  92. var special_keys = {
  93. 'esc': 27,
  94. 'escape': 27,
  95. 'tab': 9,
  96. 'space': 32,
  97. 'return': 13,
  98. 'enter': 13,
  99. 'backspace': 8,
  100. 'scrolllock': 145,
  101. 'scroll_lock': 145,
  102. 'scroll': 145,
  103. 'capslock': 20,
  104. 'caps_lock': 20,
  105. 'caps': 20,
  106. 'numlock': 144,
  107. 'num_lock': 144,
  108. 'num': 144,
  109. 'pause': 19,
  110. 'break': 19,
  111. 'insert': 45,
  112. 'home': 36,
  113. 'delete': 46,
  114. 'end': 35,
  115. 'pageup': 33,
  116. 'page_up': 33,
  117. 'pu': 33,
  118. 'pagedown': 34,
  119. 'page_down': 34,
  120. 'pd': 34,
  121. 'left': 37,
  122. 'up': 38,
  123. 'right': 39,
  124. 'down': 40,
  125. 'f1': 112,
  126. 'f2': 113,
  127. 'f3': 114,
  128. 'f4': 115,
  129. 'f5': 116,
  130. 'f6': 117,
  131. 'f7': 118,
  132. 'f8': 119,
  133. 'f9': 120,
  134. 'f10': 121,
  135. 'f11': 122,
  136. 'f12': 123
  137. };
  138. // Some modifiers key
  139. var modifiers = {
  140. shift: {
  141. wanted: false,
  142. pressed: e.shiftKey ? true : false
  143. },
  144. ctrl : {
  145. wanted: false,
  146. pressed: e.ctrlKey ? true : false
  147. },
  148. alt : {
  149. wanted: false,
  150. pressed: e.altKey ? true : false
  151. },
  152. meta : { //Meta is Mac specific
  153. wanted: false,
  154. pressed: e.metaKey ? true : false
  155. }
  156. };
  157. // Foreach keys in label (split on +)
  158. for (var i = 0, l = keys.length; k = keys[i], i < l; i++) {
  159. switch (k) {
  160. case 'ctrl':
  161. case 'control':
  162. kp++;
  163. modifiers.ctrl.wanted = true;
  164. break;
  165. case 'shift':
  166. case 'alt':
  167. case 'meta':
  168. kp++;
  169. modifiers[k].wanted = true;
  170. break;
  171. }
  172. if (k.length > 1) { // If it is a special key
  173. if (special_keys[k] === code) {
  174. kp++;
  175. }
  176. } else if (opt['keyCode']) { // If a specific key is set into the config
  177. if (opt['keyCode'] === code) {
  178. kp++;
  179. }
  180. } else { // The special keys did not match
  181. if (character === k) {
  182. kp++;
  183. }
  184. else {
  185. if (shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase
  186. character = shift_nums[character];
  187. if (character === k) {
  188. kp++;
  189. }
  190. }
  191. }
  192. }
  193. }
  194. if (kp === keys.length &&
  195. modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
  196. modifiers.shift.pressed === modifiers.shift.wanted &&
  197. modifiers.alt.pressed === modifiers.alt.wanted &&
  198. modifiers.meta.pressed === modifiers.meta.wanted) {
  199. $timeout(function() {
  200. callback(e);
  201. }, 1);
  202. if (!opt['propagate']) { // Stop the event
  203. // e.cancelBubble is supported by IE - this will kill the bubbling process.
  204. e.cancelBubble = true;
  205. e.returnValue = false;
  206. // e.stopPropagation works in Firefox.
  207. if (e.stopPropagation) {
  208. e.stopPropagation();
  209. e.preventDefault();
  210. }
  211. return false;
  212. }
  213. }
  214. };
  215. // Store shortcut
  216. keyboardManagerService.keyboardEvent[label] = {
  217. 'callback': fct,
  218. 'target': elt,
  219. 'event': opt['type']
  220. };
  221. //Attach the function with the event
  222. if (elt.addEventListener) {
  223. elt.addEventListener(opt['type'], fct, false);
  224. }
  225. else if (elt.attachEvent) {
  226. elt.attachEvent('on' + opt['type'], fct);
  227. }
  228. else {
  229. elt['on' + opt['type']] = fct;
  230. }
  231. };
  232. keyboardManagerService.unbindAll = function() {
  233. _.each(keyboardManagerService.keyboardEvent, function(value, key) {
  234. keyboardManagerService.unbind(key);
  235. });
  236. };
  237. // Remove the shortcut - just specify the shortcut and I will remove the binding
  238. keyboardManagerService.unbind = function (label) {
  239. label = label.toLowerCase();
  240. var binding = keyboardManagerService.keyboardEvent[label];
  241. delete(keyboardManagerService.keyboardEvent[label]);
  242. if (!binding) {
  243. return;
  244. }
  245. var type = binding['event'],
  246. elt = binding['target'],
  247. callback = binding['callback'];
  248. if (elt.detachEvent) {
  249. elt.detachEvent('on' + type, callback);
  250. }
  251. else if (elt.removeEventListener) {
  252. elt.removeEventListener(type, callback, false);
  253. }
  254. else {
  255. elt['on' + type] = false;
  256. }
  257. };
  258. //
  259. return keyboardManagerService;
  260. }]);
  261. });