Show More
This diff has been collapsed as it changes many lines, (503 lines changed) Show them Hide them | |||
@@ -0,0 +1,503 b'' | |||
|
1 | // Copyright (c) IPython Development Team. | |
|
2 | // Distributed under the terms of the Modified BSD License. | |
|
3 | ||
|
4 | define(['require' | |
|
5 | ], function(require) { | |
|
6 | "use strict"; | |
|
7 | ||
|
8 | var ActionHandler = function (env) { | |
|
9 | this.env = env || {}; | |
|
10 | Object.seal(this); | |
|
11 | }; | |
|
12 | ||
|
13 | /** | |
|
14 | * A bunch of predefined `Simple Actions` used by IPython. | |
|
15 | * `Simple Actions` have the following keys: | |
|
16 | * help (optional): a short string the describe the action. | |
|
17 | * will be used in various context, like as menu name, tool tips on buttons, | |
|
18 | * and short description in help menu. | |
|
19 | * help_index (optional): a string used to sort action in help menu. | |
|
20 | * icon (optional): a short string that represent the icon that have to be used with this | |
|
21 | * action. this should mainly correspond to a Font_awesome class. | |
|
22 | * handler : a function which is called when the action is activated. It will receive at first parameter | |
|
23 | * a dictionary containing various handle to element of the notebook. | |
|
24 | * | |
|
25 | * action need to be registered with a **name** that can be use to refer to this action. | |
|
26 | * | |
|
27 | * | |
|
28 | * if `help` is not provided it will be derived by replacing any dash by space | |
|
29 | * in the **name** of the action. It is advised to provide a prefix to action name to | |
|
30 | * avoid conflict the prefix should be all lowercase and end with a dot `.` | |
|
31 | * in the absence of a prefix the behavior of the action is undefined. | |
|
32 | * | |
|
33 | * All action provided by IPython are prefixed with `ipython.`. | |
|
34 | * | |
|
35 | * One can register extra actions or replace an existing action with another one is possible | |
|
36 | * but is considered undefined behavior. | |
|
37 | * | |
|
38 | **/ | |
|
39 | var _action = { | |
|
40 | 'run-select-next': { | |
|
41 | icon: 'fa-play', | |
|
42 | help : 'run cell, select below', | |
|
43 | help_index : 'ba', | |
|
44 | handler : function (env) { | |
|
45 | env.notebook.execute_cell_and_select_below(); | |
|
46 | } | |
|
47 | }, | |
|
48 | 'execute-in-place':{ | |
|
49 | help : 'run cell', | |
|
50 | help_index : 'bb', | |
|
51 | handler : function (env) { | |
|
52 | env.notebook.execute_cell(); | |
|
53 | } | |
|
54 | }, | |
|
55 | 'execute-and-insert-after':{ | |
|
56 | help : 'run cell, insert below', | |
|
57 | help_index : 'bc', | |
|
58 | handler : function (env) { | |
|
59 | env.notebook.execute_cell_and_insert_below(); | |
|
60 | } | |
|
61 | }, | |
|
62 | 'go-to-command-mode': { | |
|
63 | help : 'command mode', | |
|
64 | help_index : 'aa', | |
|
65 | handler : function (env) { | |
|
66 | env.notebook.command_mode(); | |
|
67 | } | |
|
68 | }, | |
|
69 | 'split-cell-at-cursor': { | |
|
70 | help : 'split cell', | |
|
71 | help_index : 'ea', | |
|
72 | handler : function (env) { | |
|
73 | env.notebook.split_cell(); | |
|
74 | } | |
|
75 | }, | |
|
76 | 'enter-edit-mode' : { | |
|
77 | help_index : 'aa', | |
|
78 | handler : function (env) { | |
|
79 | env.notebook.edit_mode(); | |
|
80 | } | |
|
81 | }, | |
|
82 | 'select-previous-cell' : { | |
|
83 | help_index : 'da', | |
|
84 | handler : function (env) { | |
|
85 | var index = env.notebook.get_selected_index(); | |
|
86 | if (index !== 0 && index !== null) { | |
|
87 | env.notebook.select_prev(); | |
|
88 | env.notebook.focus_cell(); | |
|
89 | } | |
|
90 | } | |
|
91 | }, | |
|
92 | 'select-next-cell' : { | |
|
93 | help_index : 'db', | |
|
94 | handler : function (env) { | |
|
95 | var index = env.notebook.get_selected_index(); | |
|
96 | if (index !== (env.notebook.ncells()-1) && index !== null) { | |
|
97 | env.notebook.select_next(); | |
|
98 | env.notebook.focus_cell(); | |
|
99 | } | |
|
100 | } | |
|
101 | }, | |
|
102 | 'cut-selected-cell' : { | |
|
103 | icon: 'fa-cut', | |
|
104 | help_index : 'ee', | |
|
105 | handler : function (env) { | |
|
106 | env.notebook.cut_cell(); | |
|
107 | } | |
|
108 | }, | |
|
109 | 'copy-selected-cell' : { | |
|
110 | icon: 'fa-copy', | |
|
111 | help_index : 'ef', | |
|
112 | handler : function (env) { | |
|
113 | env.notebook.copy_cell(); | |
|
114 | } | |
|
115 | }, | |
|
116 | 'paste-cell-before' : { | |
|
117 | help_index : 'eg', | |
|
118 | handler : function (env) { | |
|
119 | env.notebook.paste_cell_above(); | |
|
120 | } | |
|
121 | }, | |
|
122 | 'paste-cell-after' : { | |
|
123 | icon: 'fa-paste', | |
|
124 | help_index : 'eh', | |
|
125 | handler : function (env) { | |
|
126 | env.notebook.paste_cell_below(); | |
|
127 | } | |
|
128 | }, | |
|
129 | 'insert-cell-before' : { | |
|
130 | help_index : 'ec', | |
|
131 | handler : function (env) { | |
|
132 | env.notebook.insert_cell_above(); | |
|
133 | env.notebook.select_prev(); | |
|
134 | env.notebook.focus_cell(); | |
|
135 | } | |
|
136 | }, | |
|
137 | 'insert-cell-after' : { | |
|
138 | icon : 'fa-plus', | |
|
139 | help_index : 'ed', | |
|
140 | handler : function (env) { | |
|
141 | env.notebook.insert_cell_below(); | |
|
142 | env.notebook.select_next(); | |
|
143 | env.notebook.focus_cell(); | |
|
144 | } | |
|
145 | }, | |
|
146 | 'change-selected-cell-to-code-cell' : { | |
|
147 | help : 'to code', | |
|
148 | help_index : 'ca', | |
|
149 | handler : function (env) { | |
|
150 | env.notebook.to_code(); | |
|
151 | } | |
|
152 | }, | |
|
153 | 'change-selected-cell-to-markdown-cell' : { | |
|
154 | help : 'to markdown', | |
|
155 | help_index : 'cb', | |
|
156 | handler : function (env) { | |
|
157 | env.notebook.to_markdown(); | |
|
158 | } | |
|
159 | }, | |
|
160 | 'change-selected-cell-to-raw-cell' : { | |
|
161 | help : 'to raw', | |
|
162 | help_index : 'cc', | |
|
163 | handler : function (env) { | |
|
164 | env.notebook.to_raw(); | |
|
165 | } | |
|
166 | }, | |
|
167 | 'change-selected-cell-to-heading-1' : { | |
|
168 | help : 'to heading 1', | |
|
169 | help_index : 'cd', | |
|
170 | handler : function (env) { | |
|
171 | env.notebook.to_heading(undefined, 1); | |
|
172 | } | |
|
173 | }, | |
|
174 | 'change-selected-cell-to-heading-2' : { | |
|
175 | help : 'to heading 2', | |
|
176 | help_index : 'ce', | |
|
177 | handler : function (env) { | |
|
178 | env.notebook.to_heading(undefined, 2); | |
|
179 | } | |
|
180 | }, | |
|
181 | 'change-selected-cell-to-heading-3' : { | |
|
182 | help : 'to heading 3', | |
|
183 | help_index : 'cf', | |
|
184 | handler : function (env) { | |
|
185 | env.notebook.to_heading(undefined, 3); | |
|
186 | } | |
|
187 | }, | |
|
188 | 'change-selected-cell-to-heading-4' : { | |
|
189 | help : 'to heading 4', | |
|
190 | help_index : 'cg', | |
|
191 | handler : function (env) { | |
|
192 | env.notebook.to_heading(undefined, 4); | |
|
193 | } | |
|
194 | }, | |
|
195 | 'change-selected-cell-to-heading-5' : { | |
|
196 | help : 'to heading 5', | |
|
197 | help_index : 'ch', | |
|
198 | handler : function (env) { | |
|
199 | env.notebook.to_heading(undefined, 5); | |
|
200 | } | |
|
201 | }, | |
|
202 | 'change-selected-cell-to-heading-6' : { | |
|
203 | help : 'to heading 6', | |
|
204 | help_index : 'ci', | |
|
205 | handler : function (env) { | |
|
206 | env.notebook.to_heading(undefined, 6); | |
|
207 | } | |
|
208 | }, | |
|
209 | 'toggle-output-visibility-selected-cell' : { | |
|
210 | help : 'toggle output', | |
|
211 | help_index : 'gb', | |
|
212 | handler : function (env) { | |
|
213 | env.notebook.toggle_output(); | |
|
214 | } | |
|
215 | }, | |
|
216 | 'toggle-output-scrolling-selected-cell' : { | |
|
217 | help : 'toggle output scrolling', | |
|
218 | help_index : 'gc', | |
|
219 | handler : function (env) { | |
|
220 | env.notebook.toggle_output_scroll(); | |
|
221 | } | |
|
222 | }, | |
|
223 | 'move-selected-cell-down' : { | |
|
224 | icon: 'fa-arrow-down', | |
|
225 | help_index : 'eb', | |
|
226 | handler : function (env) { | |
|
227 | env.notebook.move_cell_down(); | |
|
228 | } | |
|
229 | }, | |
|
230 | 'move-selected-cell-up' : { | |
|
231 | icon: 'fa-arrow-up', | |
|
232 | help_index : 'ea', | |
|
233 | handler : function (env) { | |
|
234 | env.notebook.move_cell_up(); | |
|
235 | } | |
|
236 | }, | |
|
237 | 'toggle-line-number-selected-cell' : { | |
|
238 | help : 'toggle line numbers', | |
|
239 | help_index : 'ga', | |
|
240 | handler : function (env) { | |
|
241 | env.notebook.cell_toggle_line_numbers(); | |
|
242 | } | |
|
243 | }, | |
|
244 | 'show-keyboard-shortcut-help-dialog' : { | |
|
245 | help_index : 'ge', | |
|
246 | handler : function (env) { | |
|
247 | env.quick_help.show_keyboard_shortcuts(); | |
|
248 | } | |
|
249 | }, | |
|
250 | 'delete-cell': { | |
|
251 | help_index : 'ej', | |
|
252 | handler : function (env) { | |
|
253 | env.notebook.delete_cell(); | |
|
254 | } | |
|
255 | }, | |
|
256 | 'interrupt-kernel':{ | |
|
257 | icon: 'fa-stop', | |
|
258 | help_index : 'ha', | |
|
259 | handler : function (env) { | |
|
260 | env.notebook.kernel.interrupt(); | |
|
261 | } | |
|
262 | }, | |
|
263 | 'restart-kernel':{ | |
|
264 | icon: 'fa-repeat', | |
|
265 | help_index : 'hb', | |
|
266 | handler : function (env) { | |
|
267 | env.notebook.restart_kernel(); | |
|
268 | } | |
|
269 | }, | |
|
270 | 'undo-last-cell-deletion' : { | |
|
271 | help_index : 'ei', | |
|
272 | handler : function (env) { | |
|
273 | env.notebook.undelete_cell(); | |
|
274 | } | |
|
275 | }, | |
|
276 | 'merge-selected-cell-with-cell-after' : { | |
|
277 | help : 'merge cell below', | |
|
278 | help_index : 'ek', | |
|
279 | handler : function (env) { | |
|
280 | env.notebook.merge_cell_below(); | |
|
281 | } | |
|
282 | }, | |
|
283 | 'close-pager' : { | |
|
284 | help_index : 'gd', | |
|
285 | handler : function (env) { | |
|
286 | env.pager.collapse(); | |
|
287 | } | |
|
288 | } | |
|
289 | ||
|
290 | }; | |
|
291 | ||
|
292 | /** | |
|
293 | * A bunch of `Advance actions` for IPython. | |
|
294 | * Cf `Simple Action` plus the following properties. | |
|
295 | * | |
|
296 | * handler: first argument of the handler is the event that triggerd the action | |
|
297 | * (typically keypress). The handler is responsible for any modification of the | |
|
298 | * event and event propagation. | |
|
299 | * Is also responsible for returning false if the event have to be further ignored, | |
|
300 | * true, to tell keyboard manager that it ignored the event. | |
|
301 | * | |
|
302 | * the second parameter of the handler is the environemnt passed to Simple Actions | |
|
303 | * | |
|
304 | **/ | |
|
305 | var custom_ignore = { | |
|
306 | 'ignore':{ | |
|
307 | handler : function () { | |
|
308 | return true; | |
|
309 | } | |
|
310 | }, | |
|
311 | 'move-cursor-up-or-previous-cell':{ | |
|
312 | handler : function (env, event) { | |
|
313 | var index = env.notebook.get_selected_index(); | |
|
314 | var cell = env.notebook.get_cell(index); | |
|
315 | var cm = env.notebook.get_selected_cell().code_mirror; | |
|
316 | var cur = cm.getCursor(); | |
|
317 | if (cell && cell.at_top() && index !== 0 && cur.ch === 0) { | |
|
318 | if(event){ | |
|
319 | event.preventDefault(); | |
|
320 | } | |
|
321 | env.notebook.command_mode(); | |
|
322 | env.notebook.select_prev(); | |
|
323 | env.notebook.edit_mode(); | |
|
324 | cm = env.notebook.get_selected_cell().code_mirror; | |
|
325 | cm.setCursor(cm.lastLine(), 0); | |
|
326 | } | |
|
327 | return false; | |
|
328 | } | |
|
329 | }, | |
|
330 | 'move-cursor-down-or-next-cell':{ | |
|
331 | handler : function (env, event) { | |
|
332 | var index = env.notebook.get_selected_index(); | |
|
333 | var cell = env.notebook.get_cell(index); | |
|
334 | if (cell.at_bottom() && index !== (env.notebook.ncells()-1)) { | |
|
335 | if(event){ | |
|
336 | event.preventDefault(); | |
|
337 | } | |
|
338 | env.notebook.command_mode(); | |
|
339 | env.notebook.select_next(); | |
|
340 | env.notebook.edit_mode(); | |
|
341 | var cm = env.notebook.get_selected_cell().code_mirror; | |
|
342 | cm.setCursor(0, 0); | |
|
343 | } | |
|
344 | return false; | |
|
345 | } | |
|
346 | }, | |
|
347 | 'scroll-down': { | |
|
348 | handler: function(env, event) { | |
|
349 | if(event){ | |
|
350 | event.preventDefault(); | |
|
351 | } | |
|
352 | return env.notebook.scroll_manager.scroll(1); | |
|
353 | }, | |
|
354 | }, | |
|
355 | 'scroll-up': { | |
|
356 | handler: function(env, event) { | |
|
357 | if(event){ | |
|
358 | event.preventDefault(); | |
|
359 | } | |
|
360 | return env.notebook.scroll_manager.scroll(-1); | |
|
361 | }, | |
|
362 | }, | |
|
363 | 'save-notebook':{ | |
|
364 | help: "Save and Checkpoint", | |
|
365 | help_index : 'fb', | |
|
366 | icon: 'fa-save', | |
|
367 | handler : function (env, event) { | |
|
368 | env.notebook.save_checkpoint(); | |
|
369 | if(event){ | |
|
370 | event.preventDefault(); | |
|
371 | } | |
|
372 | return false; | |
|
373 | } | |
|
374 | }, | |
|
375 | }; | |
|
376 | ||
|
377 | // private stuff that prepend `.ipython` to actions names | |
|
378 | // and uniformize/fill in missing pieces in of an action. | |
|
379 | var _prepare_handler = function(registry, subkey, source){ | |
|
380 | registry['ipython.'+subkey] = {}; | |
|
381 | registry['ipython.'+subkey].help = source[subkey].help||subkey.replace(/-/g,' '); | |
|
382 | registry['ipython.'+subkey].help_index = source[subkey].help_index; | |
|
383 | registry['ipython.'+subkey].icon = source[subkey].icon; | |
|
384 | return source[subkey].handler; | |
|
385 | }; | |
|
386 | ||
|
387 | // Will actually generate/register all the IPython actions | |
|
388 | var fun = function(){ | |
|
389 | var final_actions = {}; | |
|
390 | for(var k in _action){ | |
|
391 | // Js closure are function level not block level need to wrap in a IIFE | |
|
392 | // and append ipython to event name these things do intercept event so are wrapped | |
|
393 | // in a function that return false. | |
|
394 | var handler = _prepare_handler(final_actions, k, _action); | |
|
395 | (function(key, handler){ | |
|
396 | final_actions['ipython.'+key].handler = function(env, event){ | |
|
397 | handler(env); | |
|
398 | if(event){ | |
|
399 | event.preventDefault(); | |
|
400 | } | |
|
401 | return false; | |
|
402 | }; | |
|
403 | })(k, handler); | |
|
404 | } | |
|
405 | ||
|
406 | for(var k in custom_ignore){ | |
|
407 | // Js closure are function level not block level need to wrap in a IIFE | |
|
408 | // same as above, but decide for themselves wether or not they intercept events. | |
|
409 | var handler = _prepare_handler(final_actions, k, custom_ignore); | |
|
410 | (function(key, handler){ | |
|
411 | final_actions['ipython.'+key].handler = function(env, event){ | |
|
412 | return handler(env, event); | |
|
413 | }; | |
|
414 | })(k, handler); | |
|
415 | } | |
|
416 | ||
|
417 | return final_actions; | |
|
418 | }; | |
|
419 | ActionHandler.prototype._actions = fun(); | |
|
420 | ||
|
421 | ||
|
422 | /** | |
|
423 | * extend the environment variable that will be pass to handlers | |
|
424 | **/ | |
|
425 | ActionHandler.prototype.extend_env = function(env){ | |
|
426 | for(var k in env){ | |
|
427 | this.env[k] = env[k]; | |
|
428 | } | |
|
429 | }; | |
|
430 | ||
|
431 | ActionHandler.prototype.register = function(action, name, prefix){ | |
|
432 | /** | |
|
433 | * Register an `action` with an optional name and prefix. | |
|
434 | * | |
|
435 | * if name and prefix are not given they will be determined automatically. | |
|
436 | * if action if just a `function` it will be wrapped in an anonymous action. | |
|
437 | * | |
|
438 | * @return the full name to access this action . | |
|
439 | **/ | |
|
440 | action = this.normalise(action); | |
|
441 | if( !name ){ | |
|
442 | name = 'autogenerated-'+String(action.handler); | |
|
443 | } | |
|
444 | prefix = prefix || 'auto'; | |
|
445 | var full_name = prefix+'.'+name; | |
|
446 | this._actions[full_name] = action; | |
|
447 | return full_name; | |
|
448 | ||
|
449 | }; | |
|
450 | ||
|
451 | ||
|
452 | ActionHandler.prototype.normalise = function(data){ | |
|
453 | /** | |
|
454 | * given an `action` or `function`, return a normalised `action` | |
|
455 | * by setting all known attributes and removing unknown attributes; | |
|
456 | **/ | |
|
457 | if(typeof(data) === 'function'){ | |
|
458 | data = {handler:data}; | |
|
459 | } | |
|
460 | if(typeof(data.handler) !== 'function'){ | |
|
461 | throw('unknown datatype, cannot register'); | |
|
462 | } | |
|
463 | var _data = data; | |
|
464 | data = {}; | |
|
465 | data.handler = _data.handler; | |
|
466 | data.help = data.help || ''; | |
|
467 | data.icon = data.icon || ''; | |
|
468 | data.help_index = data.help_index || ''; | |
|
469 | return data; | |
|
470 | }; | |
|
471 | ||
|
472 | ActionHandler.prototype.get_name = function(name_or_data){ | |
|
473 | /** | |
|
474 | * given an `action` or `name` of a action, return the name attached to this action. | |
|
475 | * if given the name of and corresponding actions does not exist in registry, return `null`. | |
|
476 | **/ | |
|
477 | ||
|
478 | if(typeof(name_or_data) === 'string'){ | |
|
479 | if(this.exists(name_or_data)){ | |
|
480 | return name_or_data; | |
|
481 | } else { | |
|
482 | return null; | |
|
483 | } | |
|
484 | } else { | |
|
485 | return this.register(name_or_data); | |
|
486 | } | |
|
487 | }; | |
|
488 | ||
|
489 | ActionHandler.prototype.get = function(name){ | |
|
490 | return this._actions[name]; | |
|
491 | }; | |
|
492 | ||
|
493 | ActionHandler.prototype.call = function(name, event, env){ | |
|
494 | return this._actions[name].handler(env|| this.env, event); | |
|
495 | }; | |
|
496 | ||
|
497 | ActionHandler.prototype.exists = function(name){ | |
|
498 | return (typeof(this._actions[name]) !== 'undefined'); | |
|
499 | }; | |
|
500 | ||
|
501 | return {init:ActionHandler}; | |
|
502 | ||
|
503 | }); |
@@ -12,18 +12,22 b' define([' | |||
|
12 | 12 | 'base/js/namespace', |
|
13 | 13 | 'jquery', |
|
14 | 14 | 'base/js/utils', |
|
15 | ], function(IPython, $, utils) { | |
|
15 | 'underscore', | |
|
16 | ], function(IPython, $, utils, _) { | |
|
16 | 17 | "use strict"; |
|
17 | 18 | |
|
18 | 19 | |
|
19 | // Setup global keycodes and inverse keycodes. | |
|
20 | /** | |
|
21 | * Setup global keycodes and inverse keycodes. | |
|
22 | * | |
|
23 | * See http://unixpapa.com/js/key.html for a complete description. The short of | |
|
24 | * it is that there are different keycode sets. Firefox uses the "Mozilla keycodes" | |
|
25 | * and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same | |
|
26 | * but have minor differences. | |
|
27 | **/ | |
|
20 | 28 | |
|
21 | // See http://unixpapa.com/js/key.html for a complete description. The short of | |
|
22 | // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes" | |
|
23 | // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same | |
|
24 | // but have minor differences. | |
|
25 | ||
|
26 | // These apply to Firefox, (Webkit and IE) | |
|
29 | // These apply to Firefox, (Webkit and IE) | |
|
30 | // This does work **only** on US keyboard. | |
|
27 | 31 | var _keycodes = { |
|
28 | 32 | 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73, |
|
29 | 33 | 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82, |
@@ -84,13 +88,32 b' define([' | |||
|
84 | 88 | }; |
|
85 | 89 | |
|
86 | 90 | var normalize_shortcut = function (shortcut) { |
|
87 | // Put a shortcut into normalized form: | |
|
88 | // 1. Make lowercase | |
|
89 | // 2. Replace cmd by meta | |
|
90 | // 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift | |
|
91 | // 4. Normalize keys | |
|
91 | /** | |
|
92 | * @function _normalize_shortcut | |
|
93 | * @private | |
|
94 | * return a dict containing the normalized shortcut and the number of time it should be pressed: | |
|
95 | * | |
|
96 | * Put a shortcut into normalized form: | |
|
97 | * 1. Make lowercase | |
|
98 | * 2. Replace cmd by meta | |
|
99 | * 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift | |
|
100 | * 4. Normalize keys | |
|
101 | **/ | |
|
102 | if (platform === 'MacOS') { | |
|
103 | shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'cmd-'); | |
|
104 | } else { | |
|
105 | shortcut = shortcut.toLowerCase().replace('cmdtrl-', 'ctrl-'); | |
|
106 | } | |
|
107 | ||
|
92 | 108 | shortcut = shortcut.toLowerCase().replace('cmd', 'meta'); |
|
93 | 109 | shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key |
|
110 | shortcut = shortcut.replace(/,$/, 'comma'); // catch shortcuts using '-' key | |
|
111 | if(shortcut.indexOf(',') !== -1){ | |
|
112 | var sht = shortcut.split(','); | |
|
113 | sht = _.map(sht, normalize_shortcut); | |
|
114 | return shortcut; | |
|
115 | } | |
|
116 | shortcut = shortcut.replace(/comma/g, ','); // catch shortcuts using '-' key | |
|
94 | 117 | var values = shortcut.split("-"); |
|
95 | 118 | if (values.length === 1) { |
|
96 | 119 | return normalize_key(values[0]); |
@@ -103,7 +126,9 b' define([' | |||
|
103 | 126 | }; |
|
104 | 127 | |
|
105 | 128 | var shortcut_to_event = function (shortcut, type) { |
|
106 | // Convert a shortcut (shift-r) to a jQuery Event object | |
|
129 | /** | |
|
130 | * Convert a shortcut (shift-r) to a jQuery Event object | |
|
131 | **/ | |
|
107 | 132 | type = type || 'keydown'; |
|
108 | 133 | shortcut = normalize_shortcut(shortcut); |
|
109 | 134 | shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key |
@@ -118,8 +143,21 b' define([' | |||
|
118 | 143 | return $.Event(type, opts); |
|
119 | 144 | }; |
|
120 | 145 | |
|
146 | var only_modifier_event = function(event){ | |
|
147 | /** | |
|
148 | * Return `true` if the event only contains modifiers keys. | |
|
149 | * false otherwise | |
|
150 | **/ | |
|
151 | var key = inv_keycodes[event.which]; | |
|
152 | return ((event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) && | |
|
153 | (key === 'alt'|| key === 'ctrl'|| key === 'meta'|| key === 'shift')); | |
|
154 | ||
|
155 | }; | |
|
156 | ||
|
121 | 157 | var event_to_shortcut = function (event) { |
|
122 | // Convert a jQuery Event object to a shortcut (shift-r) | |
|
158 | /** | |
|
159 | * Convert a jQuery Event object to a normalized shortcut string (shift-r) | |
|
160 | **/ | |
|
123 | 161 | var shortcut = ''; |
|
124 | 162 | var key = inv_keycodes[event.which]; |
|
125 | 163 | if (event.altKey && key !== 'alt') {shortcut += 'alt-';} |
@@ -132,7 +170,7 b' define([' | |||
|
132 | 170 | |
|
133 | 171 | // Shortcut manager class |
|
134 | 172 | |
|
135 | var ShortcutManager = function (delay, events) { | |
|
173 | var ShortcutManager = function (delay, events, actions, env) { | |
|
136 | 174 | /** |
|
137 | 175 | * A class to deal with keyboard event and shortcut |
|
138 | 176 | * |
@@ -140,33 +178,78 b' define([' | |||
|
140 | 178 | * @constructor |
|
141 | 179 | */ |
|
142 | 180 | this._shortcuts = {}; |
|
143 | this._counts = {}; | |
|
144 | this._timers = {}; | |
|
145 | 181 | this.delay = delay || 800; // delay in milliseconds |
|
146 | 182 | this.events = events; |
|
183 | this.actions = actions; | |
|
184 | this.actions.extend_env(env); | |
|
185 | this._queue = []; | |
|
186 | this._cleartimeout = null; | |
|
187 | Object.seal(this); | |
|
188 | }; | |
|
189 | ||
|
190 | ShortcutManager.prototype.clearsoon = function(){ | |
|
191 | /** | |
|
192 | * Clear the pending shortcut soon, and cancel previous clearing | |
|
193 | * that might be registered. | |
|
194 | **/ | |
|
195 | var that = this; | |
|
196 | clearTimeout(this._cleartimeout); | |
|
197 | this._cleartimeout = setTimeout(function(){that.clearqueue();}, this.delay); | |
|
198 | }; | |
|
199 | ||
|
200 | ||
|
201 | ShortcutManager.prototype.clearqueue = function(){ | |
|
202 | /** | |
|
203 | * clear the pending shortcut sequence now. | |
|
204 | **/ | |
|
205 | this._queue = []; | |
|
206 | clearTimeout(this._cleartimeout); | |
|
207 | }; | |
|
208 | ||
|
209 | ||
|
210 | var flatten_shorttree = function(tree){ | |
|
211 | /** | |
|
212 | * Flatten a tree of shortcut sequences. | |
|
213 | * use full to iterate over all the key/values of available shortcuts. | |
|
214 | **/ | |
|
215 | var dct = {}; | |
|
216 | for(var key in tree){ | |
|
217 | var value = tree[key]; | |
|
218 | if(typeof(value) === 'string'){ | |
|
219 | dct[key] = value; | |
|
220 | } else { | |
|
221 | var ftree=flatten_shorttree(value); | |
|
222 | for(var subkey in ftree){ | |
|
223 | dct[key+','+subkey] = ftree[subkey]; | |
|
224 | } | |
|
225 | } | |
|
226 | } | |
|
227 | return dct; | |
|
147 | 228 | }; |
|
148 | 229 | |
|
149 | 230 | ShortcutManager.prototype.help = function () { |
|
150 | 231 | var help = []; |
|
151 |
|
|
|
152 | var help_string = this._shortcuts[shortcut].help; | |
|
153 |
var |
|
|
232 | var ftree = flatten_shorttree(this._shortcuts); | |
|
233 | for (var shortcut in ftree) { | |
|
234 | var action = this.actions.get(ftree[shortcut]); | |
|
235 | var help_string = action.help||'== no help =='; | |
|
236 | var help_index = action.help_index; | |
|
154 | 237 | if (help_string) { |
|
155 | if (platform === 'MacOS') { | |
|
156 | shortcut = shortcut.replace('meta', 'cmd'); | |
|
157 | } | |
|
238 | var shortstring = (action.shortstring||shortcut); | |
|
158 | 239 | help.push({ |
|
159 |
shortcut: short |
|
|
240 | shortcut: shortstring, | |
|
160 | 241 | help: help_string, |
|
161 | 242 | help_index: help_index} |
|
162 | 243 | ); |
|
163 | 244 | } |
|
164 | 245 | } |
|
165 | 246 | help.sort(function (a, b) { |
|
166 | if (a.help_index > b.help_index) | |
|
247 | if (a.help_index > b.help_index){ | |
|
167 | 248 | return 1; |
|
168 | if (a.help_index < b.help_index) | |
|
249 | } | |
|
250 | if (a.help_index < b.help_index){ | |
|
169 | 251 | return -1; |
|
252 | } | |
|
170 | 253 | return 0; |
|
171 | 254 | }); |
|
172 | 255 | return help; |
@@ -176,19 +259,105 b' define([' | |||
|
176 | 259 | this._shortcuts = {}; |
|
177 | 260 | }; |
|
178 | 261 | |
|
179 |
ShortcutManager.prototype. |
|
|
180 | if (typeof(data) === 'function') { | |
|
181 | data = {help: '', help_index: '', handler: data}; | |
|
262 | ShortcutManager.prototype.get_shortcut = function (shortcut){ | |
|
263 | /** | |
|
264 | * return a node of the shortcut tree which an action name (string) if leaf, | |
|
265 | * and an object with `object.subtree===true` | |
|
266 | **/ | |
|
267 | if(typeof(shortcut) === 'string'){ | |
|
268 | shortcut = shortcut.split(','); | |
|
269 | } | |
|
270 | ||
|
271 | return this._get_leaf(shortcut, this._shortcuts); | |
|
272 | }; | |
|
273 | ||
|
274 | ||
|
275 | ShortcutManager.prototype._get_leaf = function(shortcut_array, tree){ | |
|
276 | /** | |
|
277 | * @private | |
|
278 | * find a leaf/node in a subtree of the keyboard shortcut | |
|
279 | * | |
|
280 | **/ | |
|
281 | if(shortcut_array.length === 1){ | |
|
282 | return tree[shortcut_array[0]]; | |
|
283 | } else if( typeof(tree[shortcut_array[0]]) !== 'string'){ | |
|
284 | return this._get_leaf(shortcut_array.slice(1), tree[shortcut_array[0]]); | |
|
285 | } | |
|
286 | return null; | |
|
287 | }; | |
|
288 | ||
|
289 | ShortcutManager.prototype.set_shortcut = function( shortcut, action_name){ | |
|
290 | if( typeof(action_name) !== 'string'){ throw('action is not a string', action_name);} | |
|
291 | if( typeof(shortcut) === 'string'){ | |
|
292 | shortcut = shortcut.split(','); | |
|
293 | } | |
|
294 | return this._set_leaf(shortcut, action_name, this._shortcuts); | |
|
295 | }; | |
|
296 | ||
|
297 | ShortcutManager.prototype._is_leaf = function(shortcut_array, tree){ | |
|
298 | if(shortcut_array.length === 1){ | |
|
299 | return(typeof(tree[shortcut_array[0]]) === 'string'); | |
|
300 | } else { | |
|
301 | var subtree = tree[shortcut_array[0]]; | |
|
302 | return this._is_leaf(shortcut_array.slice(1), subtree ); | |
|
303 | } | |
|
304 | }; | |
|
305 | ||
|
306 | ShortcutManager.prototype._remove_leaf = function(shortcut_array, tree, allow_node){ | |
|
307 | if(shortcut_array.length === 1){ | |
|
308 | var current_node = tree[shortcut_array[0]]; | |
|
309 | if(typeof(current_node) === 'string'){ | |
|
310 | delete tree[shortcut_array[0]]; | |
|
311 | } else { | |
|
312 | throw('try to delete non-leaf'); | |
|
313 | } | |
|
314 | } else { | |
|
315 | this._remove_leaf(shortcut_array.slice(1), tree[shortcut_array[0]], allow_node); | |
|
316 | if(_.keys(tree[shortcut_array[0]]).length === 0){ | |
|
317 | delete tree[shortcut_array[0]]; | |
|
318 | } | |
|
319 | } | |
|
320 | }; | |
|
321 | ||
|
322 | ShortcutManager.prototype._set_leaf = function(shortcut_array, action_name, tree){ | |
|
323 | var current_node = tree[shortcut_array[0]]; | |
|
324 | if(shortcut_array.length === 1){ | |
|
325 | if(current_node !== undefined && typeof(current_node) !== 'string'){ | |
|
326 | console.warn('[warning], you are overriting a long shortcut with a shorter one'); | |
|
327 | } | |
|
328 | tree[shortcut_array[0]] = action_name; | |
|
329 | return true; | |
|
330 | } else { | |
|
331 | if(typeof(current_node) === 'string'){ | |
|
332 | console.warn('you are trying to set a shortcut that will be shadowed'+ | |
|
333 | 'by a more specific one. Aborting for :', action_name, 'the follwing '+ | |
|
334 | 'will take precedence', current_node); | |
|
335 | return false; | |
|
336 | } else { | |
|
337 | tree[shortcut_array[0]] = tree[shortcut_array[0]]||{}; | |
|
338 | } | |
|
339 | this._set_leaf(shortcut_array.slice(1), action_name, tree[shortcut_array[0]]); | |
|
340 | return true; | |
|
182 | 341 | } |
|
183 | data.help_index = data.help_index || ''; | |
|
184 | data.help = data.help || ''; | |
|
185 | data.count = data.count || 1; | |
|
186 | if (data.help_index === '') { | |
|
187 | data.help_index = 'zz'; | |
|
342 | }; | |
|
343 | ||
|
344 | ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) { | |
|
345 | /** | |
|
346 | * Add a action to be handled by shortcut manager. | |
|
347 | * | |
|
348 | * - `shortcut` should be a `Shortcut Sequence` of the for `Ctrl-Alt-C,Meta-X`... | |
|
349 | * - `data` could be an `action name`, an `action` or a `function`. | |
|
350 | * if a `function` is passed it will be converted to an anonymous `action`. | |
|
351 | * | |
|
352 | **/ | |
|
353 | var action_name = this.actions.get_name(data); | |
|
354 | if (! action_name){ | |
|
355 | throw('does nto know how to deal with ', data); | |
|
188 | 356 | } |
|
357 | ||
|
189 | 358 | shortcut = normalize_shortcut(shortcut); |
|
190 | this._counts[shortcut] = 0; | |
|
191 | this._shortcuts[shortcut] = data; | |
|
359 | this.set_shortcut(shortcut, action_name); | |
|
360 | ||
|
192 | 361 | if (!suppress_help_update) { |
|
193 | 362 | // update the keyboard shortcuts notebook help |
|
194 | 363 | this.events.trigger('rebuild.QuickHelp'); |
@@ -196,6 +365,11 b' define([' | |||
|
196 | 365 | }; |
|
197 | 366 | |
|
198 | 367 | ShortcutManager.prototype.add_shortcuts = function (data) { |
|
368 | /** | |
|
369 | * Convenient methods to call `add_shortcut(key, value)` on several items | |
|
370 | * | |
|
371 | * data : Dict of the form {key:value, ...} | |
|
372 | **/ | |
|
199 | 373 | for (var shortcut in data) { |
|
200 | 374 | this.add_shortcut(shortcut, data[shortcut], true); |
|
201 | 375 | } |
@@ -204,44 +378,22 b' define([' | |||
|
204 | 378 | }; |
|
205 | 379 | |
|
206 | 380 | ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) { |
|
381 | /** | |
|
382 | * Remove the binding of shortcut `sortcut` with its action. | |
|
383 | * throw an error if trying to remove a non-exiting shortcut | |
|
384 | **/ | |
|
207 | 385 | shortcut = normalize_shortcut(shortcut); |
|
208 | delete this._counts[shortcut]; | |
|
209 |
|
|
|
386 | if( typeof(shortcut) === 'string'){ | |
|
387 | shortcut = shortcut.split(','); | |
|
388 | } | |
|
389 | this._remove_leaf(shortcut, this._shortcuts); | |
|
210 | 390 | if (!suppress_help_update) { |
|
211 | 391 | // update the keyboard shortcuts notebook help |
|
212 | 392 | this.events.trigger('rebuild.QuickHelp'); |
|
213 | 393 | } |
|
214 | 394 | }; |
|
215 | 395 | |
|
216 | ShortcutManager.prototype.count_handler = function (shortcut, event, data) { | |
|
217 | /** | |
|
218 | * Seem to allow to call an handler only after several key press. | |
|
219 | * like, I suppose `dd` that delete the current cell only after | |
|
220 | * `d` has been pressed twice.. | |
|
221 | * @method count_handler | |
|
222 | * @return {Boolean} `true|false`, whether or not the event has been handled. | |
|
223 | * @param shortcut {shortcut} | |
|
224 | * @param event {event} | |
|
225 | * @param data {data} | |
|
226 | */ | |
|
227 | var that = this; | |
|
228 | var c = this._counts; | |
|
229 | var t = this._timers; | |
|
230 | var timer = null; | |
|
231 | if (c[shortcut] === data.count-1) { | |
|
232 | c[shortcut] = 0; | |
|
233 | timer = t[shortcut]; | |
|
234 | if (timer) {clearTimeout(timer); delete t[shortcut];} | |
|
235 | return data.handler(event); | |
|
236 | } else { | |
|
237 | c[shortcut] = c[shortcut] + 1; | |
|
238 | timer = setTimeout(function () { | |
|
239 | c[shortcut] = 0; | |
|
240 | }, that.delay); | |
|
241 | t[shortcut] = timer; | |
|
242 | } | |
|
243 | return false; | |
|
244 | }; | |
|
396 | ||
|
245 | 397 | |
|
246 | 398 | ShortcutManager.prototype.call_handler = function (event) { |
|
247 | 399 | /** |
@@ -249,26 +401,40 b' define([' | |||
|
249 | 401 | * @method call_handler |
|
250 | 402 | * @return {Boolean} `true|false`, `false` if no handler was found, otherwise the value return by the handler. |
|
251 | 403 | * @param event {event} |
|
252 |
* |
|
|
404 | * | |
|
405 | * given an event, call the corresponding shortcut. | |
|
406 | * return false is event wan handled, true otherwise | |
|
407 | * in any case returning false stop event propagation | |
|
408 | **/ | |
|
409 | ||
|
410 | ||
|
411 | this.clearsoon(); | |
|
412 | if(only_modifier_event(event)){ | |
|
413 | return true; | |
|
414 | } | |
|
253 | 415 | var shortcut = event_to_shortcut(event); |
|
254 | var data = this._shortcuts[shortcut]; | |
|
255 | if (data) { | |
|
256 | var handler = data.handler; | |
|
257 | if (handler) { | |
|
258 | if (data.count === 1) { | |
|
259 |
|
|
|
260 | } else if (data.count > 1) { | |
|
261 | return this.count_handler(shortcut, event, data); | |
|
262 | } | |
|
263 | } | |
|
416 | this._queue.push(shortcut); | |
|
417 | var action_name = this.get_shortcut(this._queue); | |
|
418 | ||
|
419 | if (typeof(action_name) === 'undefined'|| action_name === null){ | |
|
420 | this.clearqueue(); | |
|
421 | return true; | |
|
422 | } | |
|
423 | ||
|
424 | if (this.actions.exists(action_name)) { | |
|
425 | event.preventDefault(); | |
|
426 | this.clearqueue(); | |
|
427 | return this.actions.call(action_name, event); | |
|
264 | 428 | } |
|
265 | return true; | |
|
429 | ||
|
430 | return false; | |
|
266 | 431 | }; |
|
267 | 432 | |
|
433 | ||
|
268 | 434 | ShortcutManager.prototype.handles = function (event) { |
|
269 | 435 | var shortcut = event_to_shortcut(event); |
|
270 |
var |
|
|
271 | return !( data === undefined || data.handler === undefined ); | |
|
436 | var action_name = this.get_shortcut(this._queue.concat(shortcut)); | |
|
437 | return (typeof(action_name) !== 'undefined'); | |
|
272 | 438 | }; |
|
273 | 439 | |
|
274 | 440 | var keyboard = { |
@@ -278,7 +444,7 b' define([' | |||
|
278 | 444 | normalize_key : normalize_key, |
|
279 | 445 | normalize_shortcut : normalize_shortcut, |
|
280 | 446 | shortcut_to_event : shortcut_to_event, |
|
281 | event_to_shortcut : event_to_shortcut | |
|
447 | event_to_shortcut : event_to_shortcut, | |
|
282 | 448 | }; |
|
283 | 449 | |
|
284 | 450 | // For backwards compatibility. |
This diff has been collapsed as it changes many lines, (533 lines changed) Show them Hide them | |||
@@ -16,9 +16,6 b' define([' | |||
|
16 | 16 | ], function(IPython, $, utils, keyboard) { |
|
17 | 17 | "use strict"; |
|
18 | 18 | |
|
19 | var browser = utils.browser[0]; | |
|
20 | var platform = utils.platform; | |
|
21 | ||
|
22 | 19 | // Main keyboard manager for the notebook |
|
23 | 20 | var keycodes = keyboard.keycodes; |
|
24 | 21 | |
@@ -37,470 +34,101 b' define([' | |||
|
37 | 34 | this.pager = options.pager; |
|
38 | 35 | this.quick_help = undefined; |
|
39 | 36 | this.notebook = undefined; |
|
37 | this.last_mode = undefined; | |
|
40 | 38 | this.bind_events(); |
|
41 | this.command_shortcuts = new keyboard.ShortcutManager(undefined, options.events); | |
|
39 | this.env = {pager:this.pager}; | |
|
40 | this.actions = options.actions; | |
|
41 | this.command_shortcuts = new keyboard.ShortcutManager(undefined, options.events, this.actions, this.env ); | |
|
42 | 42 | this.command_shortcuts.add_shortcuts(this.get_default_common_shortcuts()); |
|
43 | 43 | this.command_shortcuts.add_shortcuts(this.get_default_command_shortcuts()); |
|
44 | this.edit_shortcuts = new keyboard.ShortcutManager(undefined, options.events); | |
|
44 | this.edit_shortcuts = new keyboard.ShortcutManager(undefined, options.events, this.actions, this.env); | |
|
45 | 45 | this.edit_shortcuts.add_shortcuts(this.get_default_common_shortcuts()); |
|
46 | 46 | this.edit_shortcuts.add_shortcuts(this.get_default_edit_shortcuts()); |
|
47 | Object.seal(this); | |
|
47 | 48 | }; |
|
48 | 49 | |
|
50 | ||
|
51 | ||
|
52 | ||
|
49 | 53 | /** |
|
50 | 54 | * Return a dict of common shortcut |
|
51 | 55 | * @method get_default_common_shortcuts |
|
52 | 56 | * |
|
53 | 57 | * @example Example of returned shortcut |
|
54 | 58 | * ``` |
|
55 | * 'shortcut-key': // a string representing the shortcut as dash separated value. | |
|
56 | * // e.g. 'shift' , 'shift-enter', 'cmd-t' | |
|
57 | * { | |
|
58 | * help: String // user facing help string | |
|
59 | * help_index: String // string used internally to order the shortcut on the quickhelp | |
|
60 | * handler: function(event){return true|false} // function that takes an even as first and only parameter | |
|
61 | * // and return a boolean indicating whether or not the event should been handled further. | |
|
62 | * } | |
|
59 | * 'shortcut-key': 'action-name' | |
|
60 | * // a string representing the shortcut as dash separated value. | |
|
61 | * // e.g. 'shift' , 'shift-enter', 'cmd-t' | |
|
63 | 62 | *``` |
|
64 | 63 | */ |
|
65 | 64 | KeyboardManager.prototype.get_default_common_shortcuts = function() { |
|
66 | var that = this; | |
|
67 | var shortcuts = { | |
|
68 | 'shift' : { | |
|
69 | help : '', | |
|
70 | help_index : '', | |
|
71 | handler : function (event) { | |
|
72 | // ignore shift keydown | |
|
73 | return true; | |
|
74 | } | |
|
75 | }, | |
|
76 | 'shift-enter' : { | |
|
77 | help : 'run cell, select below', | |
|
78 | help_index : 'ba', | |
|
79 | handler : function (event) { | |
|
80 | that.notebook.execute_cell_and_select_below(); | |
|
81 | return false; | |
|
82 | } | |
|
83 | }, | |
|
84 | 'ctrl-enter' : { | |
|
85 | help : 'run cell', | |
|
86 | help_index : 'bb', | |
|
87 | handler : function (event) { | |
|
88 | that.notebook.execute_cell(); | |
|
89 | return false; | |
|
90 | } | |
|
91 | }, | |
|
92 | 'alt-enter' : { | |
|
93 | help : 'run cell, insert below', | |
|
94 | help_index : 'bc', | |
|
95 | handler : function (event) { | |
|
96 | that.notebook.execute_cell_and_insert_below(); | |
|
97 | return false; | |
|
98 | } | |
|
99 | } | |
|
65 | return { | |
|
66 | 'shift' : 'ipython.ignore', | |
|
67 | 'shift-enter' : 'ipython.run-select-next', | |
|
68 | 'ctrl-enter' : 'ipython.execute-in-place', | |
|
69 | 'alt-enter' : 'ipython.execute-and-insert-after', | |
|
70 | // cmd on mac, ctrl otherwise | |
|
71 | 'cmdtrl-s' : 'ipython.save-notebook', | |
|
100 | 72 | }; |
|
101 | ||
|
102 | if (platform === 'MacOS') { | |
|
103 | shortcuts['cmd-s'] = | |
|
104 | { | |
|
105 | help : 'save notebook', | |
|
106 | help_index : 'fb', | |
|
107 | handler : function (event) { | |
|
108 | that.notebook.save_checkpoint(); | |
|
109 | event.preventDefault(); | |
|
110 | return false; | |
|
111 | } | |
|
112 | }; | |
|
113 | } else { | |
|
114 | shortcuts['ctrl-s'] = | |
|
115 | { | |
|
116 | help : 'save notebook', | |
|
117 | help_index : 'fb', | |
|
118 | handler : function (event) { | |
|
119 | that.notebook.save_checkpoint(); | |
|
120 | event.preventDefault(); | |
|
121 | return false; | |
|
122 | } | |
|
123 | }; | |
|
124 | } | |
|
125 | return shortcuts; | |
|
126 | 73 | }; |
|
127 | 74 | |
|
128 | 75 | KeyboardManager.prototype.get_default_edit_shortcuts = function() { |
|
129 | var that = this; | |
|
130 | 76 | return { |
|
131 | 'esc' : { | |
|
132 | help : 'command mode', | |
|
133 | help_index : 'aa', | |
|
134 | handler : function (event) { | |
|
135 | that.notebook.command_mode(); | |
|
136 | return false; | |
|
137 | } | |
|
138 | }, | |
|
139 | 'ctrl-m' : { | |
|
140 | help : 'command mode', | |
|
141 | help_index : 'ab', | |
|
142 | handler : function (event) { | |
|
143 | that.notebook.command_mode(); | |
|
144 | return false; | |
|
145 | } | |
|
146 | }, | |
|
147 | 'up' : { | |
|
148 | help : '', | |
|
149 | help_index : '', | |
|
150 | handler : function (event) { | |
|
151 | var index = that.notebook.get_selected_index(); | |
|
152 | var cell = that.notebook.get_cell(index); | |
|
153 | var cm = that.notebook.get_selected_cell().code_mirror; | |
|
154 | var cur = cm.getCursor() | |
|
155 | if (cell && cell.at_top() && index !== 0 && cur.ch === 0) { | |
|
156 | event.preventDefault(); | |
|
157 | that.notebook.command_mode(); | |
|
158 | that.notebook.select_prev(); | |
|
159 | that.notebook.edit_mode(); | |
|
160 | var cm = that.notebook.get_selected_cell().code_mirror; | |
|
161 | cm.setCursor(cm.lastLine(), 0); | |
|
162 | } | |
|
163 | return false; | |
|
164 | } | |
|
165 | }, | |
|
166 | 'down' : { | |
|
167 | help : '', | |
|
168 | help_index : '', | |
|
169 | handler : function (event) { | |
|
170 | var index = that.notebook.get_selected_index(); | |
|
171 | var cell = that.notebook.get_cell(index); | |
|
172 | if (cell.at_bottom() && index !== (that.notebook.ncells()-1)) { | |
|
173 | event.preventDefault(); | |
|
174 | that.notebook.command_mode(); | |
|
175 | that.notebook.select_next(); | |
|
176 | that.notebook.edit_mode(); | |
|
177 | var cm = that.notebook.get_selected_cell().code_mirror; | |
|
178 | cm.setCursor(0, 0); | |
|
179 | return false; | |
|
180 | } | |
|
181 | return false; | |
|
182 | } | |
|
183 | }, | |
|
184 | 'ctrl-shift--' : { | |
|
185 | help : 'split cell', | |
|
186 | help_index : 'ea', | |
|
187 | handler : function (event) { | |
|
188 | that.notebook.split_cell(); | |
|
189 | return false; | |
|
190 | } | |
|
191 | }, | |
|
192 | 'ctrl-shift-subtract' : { | |
|
193 | help : '', | |
|
194 | help_index : 'eb', | |
|
195 | handler : function (event) { | |
|
196 | that.notebook.split_cell(); | |
|
197 | return false; | |
|
198 | } | |
|
199 | }, | |
|
77 | 'esc' : 'ipython.go-to-command-mode', | |
|
78 | 'ctrl-m' : 'ipython.go-to-command-mode', | |
|
79 | 'up' : 'ipython.move-cursor-up-or-previous-cell', | |
|
80 | 'down' : 'ipython.move-cursor-down-or-next-cell', | |
|
81 | 'ctrl-shift--' : 'ipython.split-cell-at-cursor', | |
|
82 | 'ctrl-shift-subtract' : 'ipython.split-cell-at-cursor' | |
|
200 | 83 | }; |
|
201 | 84 | }; |
|
202 | 85 | |
|
203 | 86 | KeyboardManager.prototype.get_default_command_shortcuts = function() { |
|
204 | var that = this; | |
|
205 | 87 | return { |
|
206 |
'space': |
|
|
207 | help: "Scroll down", | |
|
208 | handler: function(event) { | |
|
209 | return that.notebook.scroll_manager.scroll(1); | |
|
210 | }, | |
|
211 | }, | |
|
212 | 'shift-space': { | |
|
213 | help: "Scroll up", | |
|
214 | handler: function(event) { | |
|
215 | return that.notebook.scroll_manager.scroll(-1); | |
|
216 | }, | |
|
217 | }, | |
|
218 | 'enter' : { | |
|
219 | help : 'edit mode', | |
|
220 | help_index : 'aa', | |
|
221 | handler : function (event) { | |
|
222 | that.notebook.edit_mode(); | |
|
223 | return false; | |
|
224 | } | |
|
225 | }, | |
|
226 | 'up' : { | |
|
227 | help : 'select previous cell', | |
|
228 | help_index : 'da', | |
|
229 | handler : function (event) { | |
|
230 | var index = that.notebook.get_selected_index(); | |
|
231 | if (index !== 0 && index !== null) { | |
|
232 | that.notebook.select_prev(); | |
|
233 | that.notebook.focus_cell(); | |
|
234 | } | |
|
235 | return false; | |
|
236 | } | |
|
237 | }, | |
|
238 | 'down' : { | |
|
239 | help : 'select next cell', | |
|
240 | help_index : 'db', | |
|
241 | handler : function (event) { | |
|
242 | var index = that.notebook.get_selected_index(); | |
|
243 | if (index !== (that.notebook.ncells()-1) && index !== null) { | |
|
244 | that.notebook.select_next(); | |
|
245 | that.notebook.focus_cell(); | |
|
246 | } | |
|
247 | return false; | |
|
248 | } | |
|
249 | }, | |
|
250 | 'k' : { | |
|
251 | help : 'select previous cell', | |
|
252 | help_index : 'dc', | |
|
253 | handler : function (event) { | |
|
254 | var index = that.notebook.get_selected_index(); | |
|
255 | if (index !== 0 && index !== null) { | |
|
256 | that.notebook.select_prev(); | |
|
257 | that.notebook.focus_cell(); | |
|
258 | } | |
|
259 | return false; | |
|
260 | } | |
|
261 | }, | |
|
262 | 'j' : { | |
|
263 | help : 'select next cell', | |
|
264 | help_index : 'dd', | |
|
265 | handler : function (event) { | |
|
266 | var index = that.notebook.get_selected_index(); | |
|
267 | if (index !== (that.notebook.ncells()-1) && index !== null) { | |
|
268 | that.notebook.select_next(); | |
|
269 | that.notebook.focus_cell(); | |
|
270 | } | |
|
271 | return false; | |
|
272 | } | |
|
273 | }, | |
|
274 | 'x' : { | |
|
275 | help : 'cut cell', | |
|
276 | help_index : 'ee', | |
|
277 | handler : function (event) { | |
|
278 | that.notebook.cut_cell(); | |
|
279 | return false; | |
|
280 | } | |
|
281 | }, | |
|
282 | 'c' : { | |
|
283 | help : 'copy cell', | |
|
284 | help_index : 'ef', | |
|
285 | handler : function (event) { | |
|
286 | that.notebook.copy_cell(); | |
|
287 | return false; | |
|
288 | } | |
|
289 | }, | |
|
290 | 'shift-v' : { | |
|
291 | help : 'paste cell above', | |
|
292 | help_index : 'eg', | |
|
293 | handler : function (event) { | |
|
294 | that.notebook.paste_cell_above(); | |
|
295 | return false; | |
|
296 | } | |
|
297 | }, | |
|
298 | 'v' : { | |
|
299 | help : 'paste cell below', | |
|
300 | help_index : 'eh', | |
|
301 | handler : function (event) { | |
|
302 | that.notebook.paste_cell_below(); | |
|
303 | return false; | |
|
304 | } | |
|
305 | }, | |
|
306 | 'd' : { | |
|
307 | help : 'delete cell (press twice)', | |
|
308 | help_index : 'ej', | |
|
309 | count: 2, | |
|
310 | handler : function (event) { | |
|
311 | that.notebook.delete_cell(); | |
|
312 | return false; | |
|
313 | } | |
|
314 | }, | |
|
315 | 'a' : { | |
|
316 | help : 'insert cell above', | |
|
317 | help_index : 'ec', | |
|
318 | handler : function (event) { | |
|
319 | that.notebook.insert_cell_above(); | |
|
320 | that.notebook.select_prev(); | |
|
321 | that.notebook.focus_cell(); | |
|
322 | return false; | |
|
323 | } | |
|
324 | }, | |
|
325 | 'b' : { | |
|
326 | help : 'insert cell below', | |
|
327 | help_index : 'ed', | |
|
328 | handler : function (event) { | |
|
329 | that.notebook.insert_cell_below(); | |
|
330 | that.notebook.select_next(); | |
|
331 | that.notebook.focus_cell(); | |
|
332 | return false; | |
|
333 | } | |
|
334 | }, | |
|
335 | 'y' : { | |
|
336 | help : 'to code', | |
|
337 | help_index : 'ca', | |
|
338 | handler : function (event) { | |
|
339 | that.notebook.to_code(); | |
|
340 | return false; | |
|
341 | } | |
|
342 | }, | |
|
343 | 'm' : { | |
|
344 | help : 'to markdown', | |
|
345 | help_index : 'cb', | |
|
346 | handler : function (event) { | |
|
347 | that.notebook.to_markdown(); | |
|
348 | return false; | |
|
349 | } | |
|
350 | }, | |
|
351 | 'r' : { | |
|
352 | help : 'to raw', | |
|
353 | help_index : 'cc', | |
|
354 | handler : function (event) { | |
|
355 | that.notebook.to_raw(); | |
|
356 | return false; | |
|
357 | } | |
|
358 | }, | |
|
359 | '1' : { | |
|
360 | help : 'to heading 1', | |
|
361 | help_index : 'cd', | |
|
362 | handler : function (event) { | |
|
363 | that.notebook.to_heading(undefined, 1); | |
|
364 | return false; | |
|
365 | } | |
|
366 | }, | |
|
367 | '2' : { | |
|
368 | help : 'to heading 2', | |
|
369 | help_index : 'ce', | |
|
370 | handler : function (event) { | |
|
371 | that.notebook.to_heading(undefined, 2); | |
|
372 | return false; | |
|
373 | } | |
|
374 | }, | |
|
375 | '3' : { | |
|
376 | help : 'to heading 3', | |
|
377 | help_index : 'cf', | |
|
378 | handler : function (event) { | |
|
379 | that.notebook.to_heading(undefined, 3); | |
|
380 | return false; | |
|
381 | } | |
|
382 | }, | |
|
383 | '4' : { | |
|
384 | help : 'to heading 4', | |
|
385 | help_index : 'cg', | |
|
386 | handler : function (event) { | |
|
387 | that.notebook.to_heading(undefined, 4); | |
|
388 | return false; | |
|
389 | } | |
|
390 | }, | |
|
391 | '5' : { | |
|
392 | help : 'to heading 5', | |
|
393 | help_index : 'ch', | |
|
394 | handler : function (event) { | |
|
395 | that.notebook.to_heading(undefined, 5); | |
|
396 | return false; | |
|
397 | } | |
|
398 | }, | |
|
399 | '6' : { | |
|
400 | help : 'to heading 6', | |
|
401 | help_index : 'ci', | |
|
402 | handler : function (event) { | |
|
403 | that.notebook.to_heading(undefined, 6); | |
|
404 | return false; | |
|
405 | } | |
|
406 | }, | |
|
407 | 'o' : { | |
|
408 | help : 'toggle output', | |
|
409 | help_index : 'gb', | |
|
410 | handler : function (event) { | |
|
411 | that.notebook.toggle_output(); | |
|
412 | return false; | |
|
413 | } | |
|
414 | }, | |
|
415 | 'shift-o' : { | |
|
416 | help : 'toggle output scrolling', | |
|
417 | help_index : 'gc', | |
|
418 | handler : function (event) { | |
|
419 | that.notebook.toggle_output_scroll(); | |
|
420 | return false; | |
|
421 | } | |
|
422 | }, | |
|
423 | 's' : { | |
|
424 | help : 'save notebook', | |
|
425 | help_index : 'fa', | |
|
426 | handler : function (event) { | |
|
427 | that.notebook.save_checkpoint(); | |
|
428 | return false; | |
|
429 | } | |
|
430 | }, | |
|
431 | 'ctrl-j' : { | |
|
432 | help : 'move cell down', | |
|
433 | help_index : 'eb', | |
|
434 | handler : function (event) { | |
|
435 | that.notebook.move_cell_down(); | |
|
436 | return false; | |
|
437 | } | |
|
438 | }, | |
|
439 | 'ctrl-k' : { | |
|
440 | help : 'move cell up', | |
|
441 | help_index : 'ea', | |
|
442 | handler : function (event) { | |
|
443 | that.notebook.move_cell_up(); | |
|
444 | return false; | |
|
445 | } | |
|
446 | }, | |
|
447 | 'l' : { | |
|
448 | help : 'toggle line numbers', | |
|
449 | help_index : 'ga', | |
|
450 | handler : function (event) { | |
|
451 | that.notebook.cell_toggle_line_numbers(); | |
|
452 | return false; | |
|
453 | } | |
|
454 | }, | |
|
455 | 'i' : { | |
|
456 | help : 'interrupt kernel (press twice)', | |
|
457 | help_index : 'ha', | |
|
458 | count: 2, | |
|
459 | handler : function (event) { | |
|
460 | that.notebook.kernel.interrupt(); | |
|
461 | return false; | |
|
462 | } | |
|
463 | }, | |
|
464 | '0' : { | |
|
465 | help : 'restart kernel (press twice)', | |
|
466 | help_index : 'hb', | |
|
467 | count: 2, | |
|
468 | handler : function (event) { | |
|
469 | that.notebook.restart_kernel(); | |
|
470 | return false; | |
|
471 | } | |
|
472 | }, | |
|
473 | 'h' : { | |
|
474 | help : 'keyboard shortcuts', | |
|
475 | help_index : 'ge', | |
|
476 | handler : function (event) { | |
|
477 | that.quick_help.show_keyboard_shortcuts(); | |
|
478 | return false; | |
|
479 | } | |
|
480 | }, | |
|
481 | 'z' : { | |
|
482 | help : 'undo last delete', | |
|
483 | help_index : 'ei', | |
|
484 | handler : function (event) { | |
|
485 | that.notebook.undelete_cell(); | |
|
486 | return false; | |
|
487 | } | |
|
488 | }, | |
|
489 | 'shift-m' : { | |
|
490 | help : 'merge cell below', | |
|
491 | help_index : 'ek', | |
|
492 | handler : function (event) { | |
|
493 | that.notebook.merge_cell_below(); | |
|
494 | return false; | |
|
495 | } | |
|
496 | }, | |
|
497 | 'q' : { | |
|
498 | help : 'close pager', | |
|
499 | help_index : 'gd', | |
|
500 | handler : function (event) { | |
|
501 | that.pager.collapse(); | |
|
502 | return false; | |
|
503 | } | |
|
88 | 'shift-space': 'ipython.scroll-up', | |
|
89 | 'shift-v' : 'ipython.paste-cell-before', | |
|
90 | 'shift-m' : 'ipython.merge-selected-cell-with-cell-after', | |
|
91 | 'shift-o' : 'ipython.toggle-output-scrolling-selected-cell', | |
|
92 | 'ctrl-j' : 'ipython.move-selected-cell-down', | |
|
93 | 'ctrl-k' : 'ipython.move-selected-cell-up', | |
|
94 | 'enter' : 'ipython.enter-edit-mode', | |
|
95 | 'space' : 'ipython.scroll-down', | |
|
96 | 'down' : 'ipython.select-next-cell', | |
|
97 | 'i,i' : 'ipython.interrupt-kernel', | |
|
98 | '0,0' : 'ipython.restart-kernel', | |
|
99 | 'd,d' : 'ipython.delete-cell', | |
|
100 | 'up' : 'ipython.select-previous-cell', | |
|
101 | 'k' : 'ipython.select-previous-cell', | |
|
102 | 'j' : 'ipython.select-next-cell', | |
|
103 | 'x' : 'ipython.cut-selected-cell', | |
|
104 | 'c' : 'ipython.copy-selected-cell', | |
|
105 | 'v' : 'ipython.paste-cell-after', | |
|
106 | 'a' : 'ipython.insert-cell-before', | |
|
107 | 'b' : 'ipython.insert-cell-after', | |
|
108 | 'y' : 'ipython.change-selected-cell-to-code-cell', | |
|
109 | 'm' : 'ipython.change-selected-cell-to-markdown-cell', | |
|
110 | 'r' : 'ipython.change-selected-cell-to-raw-cell', | |
|
111 | '1' : 'ipython.change-selected-cell-to-heading-1', | |
|
112 | '2' : 'ipython.change-selected-cell-to-heading-2', | |
|
113 | '3' : 'ipython.change-selected-cell-to-heading-3', | |
|
114 | '4' : 'ipython.change-selected-cell-to-heading-4', | |
|
115 | '5' : 'ipython.change-selected-cell-to-heading-5', | |
|
116 | '6' : 'ipython.change-selected-cell-to-heading-6', | |
|
117 | 'o' : 'ipython.toggle-output-visibility-selected-cell', | |
|
118 | 's' : 'ipython.save-notebook', | |
|
119 | 'l' : 'ipython.toggle-line-number-selected-cell', | |
|
120 | 'h' : 'ipython.show-keyboard-shortcut-help-dialog', | |
|
121 | 'z' : 'ipython.undo-last-cell-deletion', | |
|
122 | 'q' : 'ipython.close-pager', | |
|
123 | 'i,e,e,e,e,e' : function(){console.log('[[===>>> 5E <<<===]]');}, | |
|
124 | 'i,d,d,q,d' : function(){console.log('[[===>>> Trigger god mode <<<===]]');}, | |
|
125 | 'i,d,d' : function(){console.log('[[===>>> should warn at registration <<<===]]');}, | |
|
126 | 'i,d,k' : function(){console.log('[[===>>> Trigger shadow mode <<<===]]');}, | |
|
127 | 'i,d,k,r,q' : function(){console.log('[[===>>> Trigger invisibility mode <<<===]]');}, | |
|
128 | ';,up,down,up,down,left,right,left,right,b,a' : function(){console.log('[[===>>> Konami <<<===]]');}, | |
|
129 | 'ctrl-x,meta-c,meta-b,u,t,t,e,r,f,l,y' : function(){ | |
|
130 | console.log('[[Are you a real Programmer ?]]'); | |
|
131 | window.open('http://xkcd.com/378/','_blank'); | |
|
504 | 132 | }, |
|
505 | 133 | }; |
|
506 | 134 | }; |
@@ -508,16 +136,27 b' define([' | |||
|
508 | 136 | KeyboardManager.prototype.bind_events = function () { |
|
509 | 137 | var that = this; |
|
510 | 138 | $(document).keydown(function (event) { |
|
511 | ||
|
512 | if(event._ipkmIgnore==true||(event.originalEvent||{})._ipkmIgnore==true){ | |
|
139 | if(event._ipkmIgnore===true||(event.originalEvent||{})._ipkmIgnore===true){ | |
|
513 | 140 | return false; |
|
514 | 141 | } |
|
515 | 142 | return that.handle_keydown(event); |
|
516 | 143 | }); |
|
517 | 144 | }; |
|
518 | 145 | |
|
146 | KeyboardManager.prototype.set_notebook = function (notebook) { | |
|
147 | this.notebook = notebook; | |
|
148 | this.actions.extend_env({notebook:notebook}); | |
|
149 | }; | |
|
150 | ||
|
151 | KeyboardManager.prototype.set_quickhelp = function (notebook) { | |
|
152 | this.actions.extend_env({quick_help:notebook}); | |
|
153 | }; | |
|
154 | ||
|
155 | ||
|
519 | 156 | KeyboardManager.prototype.handle_keydown = function (event) { |
|
520 | var notebook = this.notebook; | |
|
157 | /** | |
|
158 | * returning false from this will stop event propagation | |
|
159 | **/ | |
|
521 | 160 | |
|
522 | 161 | if (event.which === keycodes.esc) { |
|
523 | 162 | // Intercept escape at highest level to avoid closing |
@@ -527,8 +166,7 b' define([' | |||
|
527 | 166 | |
|
528 | 167 | if (!this.enabled) { |
|
529 | 168 | if (event.which === keycodes.esc) { |
|
530 | // ESC | |
|
531 | notebook.command_mode(); | |
|
169 | this.notebook.command_mode(); | |
|
532 | 170 | return false; |
|
533 | 171 | } |
|
534 | 172 | return true; |
@@ -595,7 +233,8 b' define([' | |||
|
595 | 233 | }); |
|
596 | 234 | }; |
|
597 | 235 | |
|
598 | // For backwards compatability. | |
|
236 | ||
|
237 | // For backwards compatibility. | |
|
599 | 238 | IPython.KeyboardManager = KeyboardManager; |
|
600 | 239 | |
|
601 | 240 | return {'KeyboardManager': KeyboardManager}; |
@@ -16,6 +16,7 b' require([' | |||
|
16 | 16 | 'notebook/js/menubar', |
|
17 | 17 | 'notebook/js/notificationarea', |
|
18 | 18 | 'notebook/js/savewidget', |
|
19 | 'notebook/js/actions', | |
|
19 | 20 | 'notebook/js/keyboardmanager', |
|
20 | 21 | 'notebook/js/config', |
|
21 | 22 | 'notebook/js/kernelselector', |
@@ -36,7 +37,8 b' require([' | |||
|
36 | 37 | quickhelp, |
|
37 | 38 | menubar, |
|
38 | 39 | notificationarea, |
|
39 |
savewidget, |
|
|
40 | savewidget, | |
|
41 | actions, | |
|
40 | 42 | keyboardmanager, |
|
41 | 43 | config, |
|
42 | 44 | kernelselector, |
@@ -62,9 +64,11 b' require([' | |||
|
62 | 64 | var pager = new pager.Pager('div#pager', 'div#pager_splitter', { |
|
63 | 65 | layout_manager: layout_manager, |
|
64 | 66 | events: events}); |
|
67 | var acts = new actions.init(); | |
|
65 | 68 | var keyboard_manager = new keyboardmanager.KeyboardManager({ |
|
66 | 69 | pager: pager, |
|
67 |
events: events |
|
|
70 | events: events, | |
|
71 | actions: acts }); | |
|
68 | 72 | var save_widget = new savewidget.SaveWidget('span#save_widget', { |
|
69 | 73 | events: events, |
|
70 | 74 | keyboard_manager: keyboard_manager}); |
@@ -77,11 +81,14 b' require([' | |||
|
77 | 81 | var login_widget = new loginwidget.LoginWidget('span#login_widget', common_options); |
|
78 | 82 | var toolbar = new maintoolbar.MainToolBar('#maintoolbar-container', { |
|
79 | 83 | notebook: notebook, |
|
80 |
events: events |
|
|
84 | events: events, | |
|
85 | actions: acts}); | |
|
81 | 86 | var quick_help = new quickhelp.QuickHelp({ |
|
82 | 87 | keyboard_manager: keyboard_manager, |
|
83 | 88 | events: events, |
|
84 | 89 | notebook: notebook}); |
|
90 | keyboard_manager.set_notebook(notebook); | |
|
91 | keyboard_manager.set_quickhelp(quick_help); | |
|
85 | 92 | var menubar = new menubar.MenuBar('#menubar', $.extend({ |
|
86 | 93 | notebook: notebook, |
|
87 | 94 | layout_manager: layout_manager, |
@@ -34,10 +34,10 b' define([' | |||
|
34 | 34 | platform_specific = [ |
|
35 | 35 | { shortcut: "Cmd-Up", help:"go to cell start" }, |
|
36 | 36 | { shortcut: "Cmd-Down", help:"go to cell end" }, |
|
37 |
{ shortcut: " |
|
|
38 |
{ shortcut: " |
|
|
39 |
{ shortcut: " |
|
|
40 |
{ shortcut: " |
|
|
37 | { shortcut: "Alt-Left", help:"go one word left" }, | |
|
38 | { shortcut: "Alt-Right", help:"go one word right" }, | |
|
39 | { shortcut: "Alt-Backspace", help:"del word before" }, | |
|
40 | { shortcut: "Alt-Delete", help:"del word after" }, | |
|
41 | 41 | ]; |
|
42 | 42 | } else { |
|
43 | 43 | // PC specific |
@@ -65,10 +65,6 b' define([' | |||
|
65 | 65 | ].concat( platform_specific ); |
|
66 | 66 | |
|
67 | 67 | |
|
68 | ||
|
69 | ||
|
70 | ||
|
71 | ||
|
72 | 68 | QuickHelp.prototype.show_keyboard_shortcuts = function () { |
|
73 | 69 | // toggles display of keyboard shortcut dialog |
|
74 | 70 | var that = this; |
@@ -139,7 +135,9 b' define([' | |||
|
139 | 135 | keys[i] = "<code><strong>" + k + "</strong></code>"; |
|
140 | 136 | continue; // leave individual keys lower-cased |
|
141 | 137 | } |
|
142 | keys[i] = ( special_case[k] ? special_case[k] : k.charAt(0).toUpperCase() + k.slice(1) ); | |
|
138 | if (k.indexOf(',') === -1){ | |
|
139 | keys[i] = ( special_case[k] ? special_case[k] : k.charAt(0).toUpperCase() + k.slice(1) ); | |
|
140 | } | |
|
143 | 141 | keys[i] = "<code><strong>" + keys[i] + "</strong></code>"; |
|
144 | 142 | } |
|
145 | 143 | return keys.join('-'); |
@@ -155,7 +153,12 b' define([' | |||
|
155 | 153 | |
|
156 | 154 | var build_one = function (s) { |
|
157 | 155 | var help = s.help; |
|
158 |
var shortcut = |
|
|
156 | var shortcut = ''; | |
|
157 | if(s.shortcut){ | |
|
158 | shortcut = prettify(s.shortcut); | |
|
159 | } else { | |
|
160 | console.error('[debug] - nothing for', s) | |
|
161 | } | |
|
159 | 162 | return $('<div>').addClass('quickhelp'). |
|
160 | 163 | append($('<span/>').addClass('shortcut_key').append($(shortcut))). |
|
161 | 164 | append($('<span/>').addClass('shortcut_descr').text(' : ' + help)); |
General Comments 0
You need to be logged in to leave comments.
Login now