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