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 <[email protected]>
|
---|
8 | */
|
---|
9 | function 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 <[email protected]>
|
---|
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 input [type="submit"] with accesskey and register event -
|
---|
63 | * perform "click" on a button.
|
---|
64 | */
|
---|
65 | var inputs = document.getElementsByTagName("input");
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
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 <[email protected]>
|
---|
298 | */
|
---|
299 | function initializeHotkeys() {
|
---|
300 | var hotkeys = new Hotkeys();
|
---|
301 | hotkeys.initialize();
|
---|
302 | }
|
---|