hotkeys.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /**
  2. * Some of these scripts were taken from TinyMCE (http://tinymce.moxiecode.com/) and were modified for DokuWiki
  3. *
  4. * Class handles accesskeys using javascript and also provides ability
  5. * to register and use other hotkeys as well.
  6. *
  7. * @author Marek Sacha <sachamar@fel.cvut.cz>
  8. */
  9. function Hotkeys() {
  10. this.shortcuts = new Array();
  11. /**
  12. * Set modifier keys, for instance:
  13. * this.modifier = 'ctrl';
  14. * this.modifier = 'ctrl+shift';
  15. * this.modifier = 'ctrl+alt+shift';
  16. * this.modifier = 'alt';
  17. * this.modifier = 'alt+shift';
  18. *
  19. * overwritten in intitialize (see below)
  20. */
  21. this.modifier = 'ctrl+alt';
  22. /**
  23. * Initialization
  24. *
  25. * This function looks up all the accesskeys used in the current page
  26. * (at anchor elements and button elements [type="submit"]) and registers
  27. * appropriate shortcuts.
  28. *
  29. * Secondly, initialization registers listeners on document to catch all
  30. * keyboard events.
  31. *
  32. * @author Marek Sacha <sachamar@fel.cvut.cz>
  33. */
  34. this.initialize = function() {
  35. var t = this;
  36. //switch modifier key based on OS FS#1958
  37. if(is_macos){
  38. t.modifier = 'ctrl+alt';
  39. }else{
  40. t.modifier = 'alt';
  41. }
  42. /**
  43. * Lookup all anchors with accesskey and register event - go to anchor
  44. * target.
  45. */
  46. var anchors = document.getElementsByTagName("a");
  47. t.each(anchors, function(a) {
  48. if (a.accessKey != "") {
  49. t.addShortcut(t.modifier + '+' + a.accessKey, function() {
  50. location.href = a.href;
  51. });
  52. a.accessKey = '';
  53. }
  54. });
  55. /**
  56. * Lookup all button [type="submit"] with accesskey and register event -
  57. * perform "click" on a button.
  58. */
  59. var inputs = document.getElementsByTagName("button");
  60. t.each(inputs, function(i) {
  61. if (i.type == "submit" && i.accessKey != "") {
  62. t.addShortcut(t.modifier + '+' + i.accessKey, function() {
  63. i.click();
  64. });
  65. i.accessKey = '';
  66. }
  67. });
  68. /**
  69. * Lookup all buttons with accesskey and register event -
  70. * perform "click" on a button.
  71. */
  72. var buttons = document.getElementsByTagName("button");
  73. t.each(buttons, function(b) {
  74. if (b.accessKey != "") {
  75. t.addShortcut(t.modifier + '+' + b.accessKey, function() {
  76. b.click();
  77. });
  78. b.accessKey = '';
  79. }
  80. });
  81. /**
  82. * Register listeners on document to catch keyboard events.
  83. */
  84. addEvent(document,'keyup',function (e) {
  85. return t.onkeyup.call(t,e);
  86. });
  87. addEvent(document,'keypress',function (e) {
  88. return t.onkeypress.call(t,e);
  89. });
  90. addEvent(document,'keydown',function (e) {
  91. return t.onkeydown.call(t,e);
  92. });
  93. };
  94. /**
  95. * Keyup processing function
  96. * Function returns true if keyboard event has registered handler, and
  97. * executes the handler function.
  98. *
  99. * @param e KeyboardEvent
  100. * @author Marek Sacha <sachamar@fel.cvut.cz>
  101. * @return b boolean
  102. */
  103. this.onkeyup = function(e) {
  104. var t = this;
  105. var v = t.findShortcut(e);
  106. if (v != null && v != false) {
  107. v.func.call(t);
  108. return false;
  109. }
  110. return true;
  111. };
  112. /**
  113. * Keydown processing function
  114. * Function returns true if keyboard event has registered handler
  115. *
  116. * @param e KeyboardEvent
  117. * @author Marek Sacha <sachamar@fel.cvut.cz>
  118. * @return b boolean
  119. */
  120. this.onkeydown = function(e) {
  121. var t = this;
  122. var v = t.findShortcut(e);
  123. if (v != null && v != false) {
  124. return false;
  125. }
  126. return true;
  127. };
  128. /**
  129. * Keypress processing function
  130. * Function returns true if keyboard event has registered handler
  131. *
  132. * @param e KeyboardEvent
  133. * @author Marek Sacha <sachamar@fel.cvut.cz>
  134. * @return b
  135. */
  136. this.onkeypress = function(e) {
  137. var t = this;
  138. var v = t.findShortcut(e);
  139. if (v != null && v != false) {
  140. return false;
  141. }
  142. return true;
  143. };
  144. /**
  145. * Register new shortcut
  146. *
  147. * This function registers new shortcuts, each shortcut is defined by its
  148. * modifier keys and a key (with + as delimiter). If shortcut is pressed
  149. * cmd_function is performed.
  150. *
  151. * For example:
  152. * pa = "ctrl+alt+p";
  153. * pa = "shift+alt+s";
  154. *
  155. * Full example of method usage:
  156. * hotkeys.addShortcut('ctrl+s',function() {
  157. * document.getElementByID('form_1').submit();
  158. * });
  159. *
  160. * @param pa String description of the shortcut (ctrl+a, ctrl+shift+p, .. )
  161. * @param cmd_func Function to be called if shortcut is pressed
  162. * @author Marek Sacha <sachamar@fel.cvut.cz>
  163. */
  164. this.addShortcut = function(pa, cmd_func) {
  165. var t = this;
  166. var o = {
  167. func : cmd_func,
  168. alt : false,
  169. ctrl : false,
  170. shift : false
  171. };
  172. t.each(t.explode(pa, '+'), function(v) {
  173. switch (v) {
  174. case 'alt':
  175. case 'ctrl':
  176. case 'shift':
  177. o[v] = true;
  178. break;
  179. default:
  180. o.charCode = v.charCodeAt(0);
  181. o.keyCode = v.toUpperCase().charCodeAt(0);
  182. }
  183. });
  184. t.shortcuts.push((o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode, o);
  185. return true;
  186. };
  187. /**
  188. * @property isMac
  189. */
  190. this.isMac = is_macos;
  191. /**
  192. * Apply function cb on each element of o in the namespace of s
  193. * @param o Array of objects
  194. * @param cb Function to be called on each object
  195. * @param s Namespace to be used during call of cb (default namespace is o)
  196. * @author Marek Sacha <sachamar@fel.cvut.cz>
  197. */
  198. this.each = function(o, cb, s) {
  199. var n, l;
  200. if (!o)
  201. return 0;
  202. s = s || o;
  203. if (o.length !== undefined) {
  204. // Indexed arrays, needed for Safari
  205. for (n=0, l = o.length; n < l; n++) {
  206. if (cb.call(s, o[n], n, o) === false)
  207. return 0;
  208. }
  209. } else {
  210. // Hashtables
  211. for (n in o) {
  212. if (o.hasOwnProperty(n)) {
  213. if (cb.call(s, o[n], n, o) === false)
  214. return 0;
  215. }
  216. }
  217. }
  218. return 1;
  219. };
  220. /**
  221. * Explode string according to delimiter
  222. * @param s String
  223. * @param d Delimiter (default ',')
  224. * @author Marek Sacha <sachamar@fel.cvut.cz>
  225. * @return a Array of tokens
  226. */
  227. this.explode = function(s, d) {
  228. return s.split(d || ',');
  229. };
  230. /**
  231. * Find if the shortcut was registered
  232. *
  233. * @param e KeyboardEvent
  234. * @author Marek Sacha <sachamar@fel.cvut.cz>
  235. * @return v Shortcut structure or null if not found
  236. */
  237. this.findShortcut = function (e) {
  238. var t = this;
  239. var v = null;
  240. /* No modifier key used - shortcut does not exist */
  241. if (!e.altKey && !e.ctrlKey && !e.metaKey) {
  242. return v;
  243. }
  244. t.each(t.shortcuts, function(o) {
  245. if (o.ctrl != e.ctrlKey)
  246. return;
  247. if (o.alt != e.altKey)
  248. return;
  249. if (o.shift != e.shiftKey)
  250. return;
  251. if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) {
  252. v = o;
  253. return;
  254. }
  255. });
  256. return v;
  257. };
  258. }
  259. /**
  260. * Init function for hotkeys. Called from js.php, to ensure hotkyes are initialized after toolbar.
  261. * Call of addInitEvent(initializeHotkeys) is unnecessary now.
  262. *
  263. * @author Marek Sacha <sachamar@fel.cvut.cz>
  264. */
  265. function initializeHotkeys() {
  266. var hotkeys = new Hotkeys();
  267. hotkeys.initialize();
  268. }