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