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