##// END OF EJS Templates
Clear timeout in multi-press keyboard shortcuts.
Brian E. Granger -
Show More
@@ -1,759 +1,764 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Keyboard management
9 // Keyboard management
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 // Setup global keycodes and inverse keycodes.
15 // Setup global keycodes and inverse keycodes.
16
16
17 // See http://unixpapa.com/js/key.html for a complete description. The short of
17 // See http://unixpapa.com/js/key.html for a complete description. The short of
18 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
18 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
19 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
19 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
20 // but have minor differences.
20 // but have minor differences.
21
21
22 // These apply to Firefox, (Webkit and IE)
22 // These apply to Firefox, (Webkit and IE)
23 var _keycodes = {
23 var _keycodes = {
24 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
24 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
25 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
25 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
26 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
26 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
27 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
27 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
28 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
28 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
29 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
29 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
30 '\\ |': 220, '\' "': 222,
30 '\\ |': 220, '\' "': 222,
31 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
31 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
32 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
32 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
33 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
33 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
34 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
34 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
35 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
35 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
36 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
36 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
37 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
37 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
38 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
38 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
39 'insert': 45, 'delete': 46, 'numlock': 144,
39 'insert': 45, 'delete': 46, 'numlock': 144,
40 };
40 };
41
41
42 // These apply to Firefox and Opera
42 // These apply to Firefox and Opera
43 var _mozilla_keycodes = {
43 var _mozilla_keycodes = {
44 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
44 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
45 }
45 }
46
46
47 // This apply to Webkit and IE
47 // This apply to Webkit and IE
48 var _ie_keycodes = {
48 var _ie_keycodes = {
49 '; :': 186, '= +': 187, '- _': 189,
49 '; :': 186, '= +': 187, '- _': 189,
50 }
50 }
51
51
52 var browser = IPython.utils.browser[0];
52 var browser = IPython.utils.browser[0];
53 var platform = IPython.utils.platform;
53 var platform = IPython.utils.platform;
54
54
55 if (browser === 'Firefox' || browser === 'Opera') {
55 if (browser === 'Firefox' || browser === 'Opera') {
56 $.extend(_keycodes, _mozilla_keycodes);
56 $.extend(_keycodes, _mozilla_keycodes);
57 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
57 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
58 $.extend(_keycodes, _ie_keycodes);
58 $.extend(_keycodes, _ie_keycodes);
59 }
59 }
60
60
61 var keycodes = {};
61 var keycodes = {};
62 var inv_keycodes = {};
62 var inv_keycodes = {};
63 for (var name in _keycodes) {
63 for (var name in _keycodes) {
64 var names = name.split(' ');
64 var names = name.split(' ');
65 if (names.length === 1) {
65 if (names.length === 1) {
66 var n = names[0]
66 var n = names[0]
67 keycodes[n] = _keycodes[n]
67 keycodes[n] = _keycodes[n]
68 inv_keycodes[_keycodes[n]] = n
68 inv_keycodes[_keycodes[n]] = n
69 } else {
69 } else {
70 var primary = names[0];
70 var primary = names[0];
71 var secondary = names[1];
71 var secondary = names[1];
72 keycodes[primary] = _keycodes[name]
72 keycodes[primary] = _keycodes[name]
73 keycodes[secondary] = _keycodes[name]
73 keycodes[secondary] = _keycodes[name]
74 inv_keycodes[_keycodes[name]] = primary
74 inv_keycodes[_keycodes[name]] = primary
75 }
75 }
76 }
76 }
77
77
78
78
79 // Default keyboard shortcuts
79 // Default keyboard shortcuts
80
80
81 var default_common_shortcuts = {
81 var default_common_shortcuts = {
82 'shift' : {
82 'shift' : {
83 help : '',
83 help : '',
84 help_index : '',
84 help_index : '',
85 handler : function (event) {
85 handler : function (event) {
86 // ignore shift keydown
86 // ignore shift keydown
87 return true;
87 return true;
88 }
88 }
89 },
89 },
90 'shift+enter' : {
90 'shift+enter' : {
91 help : 'run cell, select below',
91 help : 'run cell, select below',
92 help_index : 'ba',
92 help_index : 'ba',
93 handler : function (event) {
93 handler : function (event) {
94 IPython.notebook.execute_cell_and_select_below();
94 IPython.notebook.execute_cell_and_select_below();
95 return false;
95 return false;
96 }
96 }
97 },
97 },
98 'ctrl+enter' : {
98 'ctrl+enter' : {
99 help : 'run cell',
99 help : 'run cell',
100 help_index : 'bb',
100 help_index : 'bb',
101 handler : function (event) {
101 handler : function (event) {
102 IPython.notebook.execute_cell();
102 IPython.notebook.execute_cell();
103 return false;
103 return false;
104 }
104 }
105 },
105 },
106 'alt+enter' : {
106 'alt+enter' : {
107 help : 'run cell, insert below',
107 help : 'run cell, insert below',
108 help_index : 'bc',
108 help_index : 'bc',
109 handler : function (event) {
109 handler : function (event) {
110 IPython.notebook.execute_cell_and_insert_below();
110 IPython.notebook.execute_cell_and_insert_below();
111 return false;
111 return false;
112 }
112 }
113 }
113 }
114 }
114 }
115
115
116 if (platform === 'MacOS') {
116 if (platform === 'MacOS') {
117 default_common_shortcuts['cmd+s'] =
117 default_common_shortcuts['cmd+s'] =
118 {
118 {
119 help : 'save notebook',
119 help : 'save notebook',
120 help_index : 'fb',
120 help_index : 'fb',
121 handler : function (event) {
121 handler : function (event) {
122 IPython.notebook.save_checkpoint();
122 IPython.notebook.save_checkpoint();
123 event.preventDefault();
123 event.preventDefault();
124 return false;
124 return false;
125 }
125 }
126 };
126 };
127 } else {
127 } else {
128 default_common_shortcuts['ctrl+s'] =
128 default_common_shortcuts['ctrl+s'] =
129 {
129 {
130 help : 'save notebook',
130 help : 'save notebook',
131 help_index : 'fb',
131 help_index : 'fb',
132 handler : function (event) {
132 handler : function (event) {
133 IPython.notebook.save_checkpoint();
133 IPython.notebook.save_checkpoint();
134 event.preventDefault();
134 event.preventDefault();
135 return false;
135 return false;
136 }
136 }
137 };
137 };
138 }
138 }
139
139
140 // Edit mode defaults
140 // Edit mode defaults
141
141
142 var default_edit_shortcuts = {
142 var default_edit_shortcuts = {
143 'esc' : {
143 'esc' : {
144 help : 'command mode',
144 help : 'command mode',
145 help_index : 'aa',
145 help_index : 'aa',
146 handler : function (event) {
146 handler : function (event) {
147 IPython.notebook.command_mode();
147 IPython.notebook.command_mode();
148 IPython.notebook.focus_cell();
148 IPython.notebook.focus_cell();
149 return false;
149 return false;
150 }
150 }
151 },
151 },
152 'ctrl+m' : {
152 'ctrl+m' : {
153 help : 'command mode',
153 help : 'command mode',
154 help_index : 'ab',
154 help_index : 'ab',
155 handler : function (event) {
155 handler : function (event) {
156 IPython.notebook.command_mode();
156 IPython.notebook.command_mode();
157 IPython.notebook.focus_cell();
157 IPython.notebook.focus_cell();
158 return false;
158 return false;
159 }
159 }
160 },
160 },
161 'up' : {
161 'up' : {
162 help : '',
162 help : '',
163 help_index : '',
163 help_index : '',
164 handler : function (event) {
164 handler : function (event) {
165 var cell = IPython.notebook.get_selected_cell();
165 var cell = IPython.notebook.get_selected_cell();
166 if (cell && cell.at_top()) {
166 if (cell && cell.at_top()) {
167 event.preventDefault();
167 event.preventDefault();
168 IPython.notebook.command_mode()
168 IPython.notebook.command_mode()
169 IPython.notebook.select_prev();
169 IPython.notebook.select_prev();
170 IPython.notebook.edit_mode();
170 IPython.notebook.edit_mode();
171 return false;
171 return false;
172 };
172 };
173 }
173 }
174 },
174 },
175 'down' : {
175 'down' : {
176 help : '',
176 help : '',
177 help_index : '',
177 help_index : '',
178 handler : function (event) {
178 handler : function (event) {
179 var cell = IPython.notebook.get_selected_cell();
179 var cell = IPython.notebook.get_selected_cell();
180 if (cell && cell.at_bottom()) {
180 if (cell && cell.at_bottom()) {
181 event.preventDefault();
181 event.preventDefault();
182 IPython.notebook.command_mode()
182 IPython.notebook.command_mode()
183 IPython.notebook.select_next();
183 IPython.notebook.select_next();
184 IPython.notebook.edit_mode();
184 IPython.notebook.edit_mode();
185 return false;
185 return false;
186 };
186 };
187 }
187 }
188 },
188 },
189 'alt+-' : {
189 'alt+-' : {
190 help : 'split cell',
190 help : 'split cell',
191 help_index : 'ea',
191 help_index : 'ea',
192 handler : function (event) {
192 handler : function (event) {
193 IPython.notebook.split_cell();
193 IPython.notebook.split_cell();
194 return false;
194 return false;
195 }
195 }
196 },
196 },
197 'alt+subtract' : {
197 'alt+subtract' : {
198 help : '',
198 help : '',
199 help_index : 'eb',
199 help_index : 'eb',
200 handler : function (event) {
200 handler : function (event) {
201 IPython.notebook.split_cell();
201 IPython.notebook.split_cell();
202 return false;
202 return false;
203 }
203 }
204 },
204 },
205 'tab' : {
205 'tab' : {
206 help : 'indent or complete',
206 help : 'indent or complete',
207 help_index : 'ec',
207 help_index : 'ec',
208 },
208 },
209 'shift+tab' : {
209 'shift+tab' : {
210 help : 'tooltip',
210 help : 'tooltip',
211 help_index : 'ed',
211 help_index : 'ed',
212 },
212 },
213 }
213 }
214
214
215 if (platform === 'MacOS') {
215 if (platform === 'MacOS') {
216 default_edit_shortcuts['cmd+/'] =
216 default_edit_shortcuts['cmd+/'] =
217 {
217 {
218 help : 'toggle comment',
218 help : 'toggle comment',
219 help_index : 'ee'
219 help_index : 'ee'
220 };
220 };
221 default_edit_shortcuts['cmd+]'] =
221 default_edit_shortcuts['cmd+]'] =
222 {
222 {
223 help : 'indent',
223 help : 'indent',
224 help_index : 'ef'
224 help_index : 'ef'
225 };
225 };
226 default_edit_shortcuts['cmd+['] =
226 default_edit_shortcuts['cmd+['] =
227 {
227 {
228 help : 'dedent',
228 help : 'dedent',
229 help_index : 'eg'
229 help_index : 'eg'
230 };
230 };
231 } else {
231 } else {
232 default_edit_shortcuts['ctrl+/'] =
232 default_edit_shortcuts['ctrl+/'] =
233 {
233 {
234 help : 'toggle comment',
234 help : 'toggle comment',
235 help_index : 'ee'
235 help_index : 'ee'
236 };
236 };
237 default_edit_shortcuts['ctrl+]'] =
237 default_edit_shortcuts['ctrl+]'] =
238 {
238 {
239 help : 'indent',
239 help : 'indent',
240 help_index : 'ef'
240 help_index : 'ef'
241 };
241 };
242 default_edit_shortcuts['ctrl+['] =
242 default_edit_shortcuts['ctrl+['] =
243 {
243 {
244 help : 'dedent',
244 help : 'dedent',
245 help_index : 'eg'
245 help_index : 'eg'
246 };
246 };
247 }
247 }
248
248
249 // Command mode defaults
249 // Command mode defaults
250
250
251 var default_command_shortcuts = {
251 var default_command_shortcuts = {
252 'enter' : {
252 'enter' : {
253 help : 'edit mode',
253 help : 'edit mode',
254 help_index : 'aa',
254 help_index : 'aa',
255 handler : function (event) {
255 handler : function (event) {
256 IPython.notebook.edit_mode();
256 IPython.notebook.edit_mode();
257 return false;
257 return false;
258 }
258 }
259 },
259 },
260 'up' : {
260 'up' : {
261 help : 'select previous cell',
261 help : 'select previous cell',
262 help_index : 'da',
262 help_index : 'da',
263 handler : function (event) {
263 handler : function (event) {
264 var index = IPython.notebook.get_selected_index();
264 var index = IPython.notebook.get_selected_index();
265 if (index !== 0 && index !== null) {
265 if (index !== 0 && index !== null) {
266 IPython.notebook.select_prev();
266 IPython.notebook.select_prev();
267 var cell = IPython.notebook.get_selected_cell();
267 var cell = IPython.notebook.get_selected_cell();
268 cell.focus_cell();
268 cell.focus_cell();
269 };
269 };
270 return false;
270 return false;
271 }
271 }
272 },
272 },
273 'down' : {
273 'down' : {
274 help : 'select next cell',
274 help : 'select next cell',
275 help_index : 'db',
275 help_index : 'db',
276 handler : function (event) {
276 handler : function (event) {
277 var index = IPython.notebook.get_selected_index();
277 var index = IPython.notebook.get_selected_index();
278 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
278 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
279 IPython.notebook.select_next();
279 IPython.notebook.select_next();
280 var cell = IPython.notebook.get_selected_cell();
280 var cell = IPython.notebook.get_selected_cell();
281 cell.focus_cell();
281 cell.focus_cell();
282 };
282 };
283 return false;
283 return false;
284 }
284 }
285 },
285 },
286 'k' : {
286 'k' : {
287 help : 'select previous cell',
287 help : 'select previous cell',
288 help_index : 'dc',
288 help_index : 'dc',
289 handler : function (event) {
289 handler : function (event) {
290 var index = IPython.notebook.get_selected_index();
290 var index = IPython.notebook.get_selected_index();
291 if (index !== 0 && index !== null) {
291 if (index !== 0 && index !== null) {
292 IPython.notebook.select_prev();
292 IPython.notebook.select_prev();
293 var cell = IPython.notebook.get_selected_cell();
293 var cell = IPython.notebook.get_selected_cell();
294 cell.focus_cell();
294 cell.focus_cell();
295 };
295 };
296 return false;
296 return false;
297 }
297 }
298 },
298 },
299 'j' : {
299 'j' : {
300 help : 'select next cell',
300 help : 'select next cell',
301 help_index : 'dd',
301 help_index : 'dd',
302 handler : function (event) {
302 handler : function (event) {
303 var index = IPython.notebook.get_selected_index();
303 var index = IPython.notebook.get_selected_index();
304 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
304 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
305 IPython.notebook.select_next();
305 IPython.notebook.select_next();
306 var cell = IPython.notebook.get_selected_cell();
306 var cell = IPython.notebook.get_selected_cell();
307 cell.focus_cell();
307 cell.focus_cell();
308 };
308 };
309 return false;
309 return false;
310 }
310 }
311 },
311 },
312 'x' : {
312 'x' : {
313 help : 'cut cell',
313 help : 'cut cell',
314 help_index : 'ee',
314 help_index : 'ee',
315 handler : function (event) {
315 handler : function (event) {
316 IPython.notebook.cut_cell();
316 IPython.notebook.cut_cell();
317 return false;
317 return false;
318 }
318 }
319 },
319 },
320 'c' : {
320 'c' : {
321 help : 'copy cell',
321 help : 'copy cell',
322 help_index : 'ef',
322 help_index : 'ef',
323 handler : function (event) {
323 handler : function (event) {
324 IPython.notebook.copy_cell();
324 IPython.notebook.copy_cell();
325 return false;
325 return false;
326 }
326 }
327 },
327 },
328 'shift+v' : {
328 'shift+v' : {
329 help : 'paste cell above',
329 help : 'paste cell above',
330 help_index : 'eg',
330 help_index : 'eg',
331 handler : function (event) {
331 handler : function (event) {
332 IPython.notebook.paste_cell_above();
332 IPython.notebook.paste_cell_above();
333 return false;
333 return false;
334 }
334 }
335 },
335 },
336 'v' : {
336 'v' : {
337 help : 'paste cell below',
337 help : 'paste cell below',
338 help_index : 'eh',
338 help_index : 'eh',
339 handler : function (event) {
339 handler : function (event) {
340 IPython.notebook.paste_cell_below();
340 IPython.notebook.paste_cell_below();
341 return false;
341 return false;
342 }
342 }
343 },
343 },
344 'd' : {
344 'd' : {
345 help : 'delete cell (press twice)',
345 help : 'delete cell (press twice)',
346 help_index : 'ej',
346 help_index : 'ej',
347 count: 2,
347 count: 2,
348 handler : function (event) {
348 handler : function (event) {
349 IPython.notebook.delete_cell();
349 IPython.notebook.delete_cell();
350 return false;
350 return false;
351 }
351 }
352 },
352 },
353 'a' : {
353 'a' : {
354 help : 'insert cell above',
354 help : 'insert cell above',
355 help_index : 'ec',
355 help_index : 'ec',
356 handler : function (event) {
356 handler : function (event) {
357 IPython.notebook.insert_cell_above('code');
357 IPython.notebook.insert_cell_above('code');
358 IPython.notebook.select_prev();
358 IPython.notebook.select_prev();
359 IPython.notebook.focus_cell();
359 IPython.notebook.focus_cell();
360 return false;
360 return false;
361 }
361 }
362 },
362 },
363 'b' : {
363 'b' : {
364 help : 'insert cell below',
364 help : 'insert cell below',
365 help_index : 'ed',
365 help_index : 'ed',
366 handler : function (event) {
366 handler : function (event) {
367 IPython.notebook.insert_cell_below('code');
367 IPython.notebook.insert_cell_below('code');
368 IPython.notebook.select_next();
368 IPython.notebook.select_next();
369 IPython.notebook.focus_cell();
369 IPython.notebook.focus_cell();
370 return false;
370 return false;
371 }
371 }
372 },
372 },
373 'y' : {
373 'y' : {
374 help : 'to code',
374 help : 'to code',
375 help_index : 'ca',
375 help_index : 'ca',
376 handler : function (event) {
376 handler : function (event) {
377 IPython.notebook.to_code();
377 IPython.notebook.to_code();
378 return false;
378 return false;
379 }
379 }
380 },
380 },
381 'm' : {
381 'm' : {
382 help : 'to markdown',
382 help : 'to markdown',
383 help_index : 'cb',
383 help_index : 'cb',
384 handler : function (event) {
384 handler : function (event) {
385 IPython.notebook.to_markdown();
385 IPython.notebook.to_markdown();
386 return false;
386 return false;
387 }
387 }
388 },
388 },
389 'r' : {
389 'r' : {
390 help : 'to raw',
390 help : 'to raw',
391 help_index : 'cc',
391 help_index : 'cc',
392 handler : function (event) {
392 handler : function (event) {
393 IPython.notebook.to_raw();
393 IPython.notebook.to_raw();
394 return false;
394 return false;
395 }
395 }
396 },
396 },
397 '1' : {
397 '1' : {
398 help : 'to heading 1',
398 help : 'to heading 1',
399 help_index : 'cd',
399 help_index : 'cd',
400 handler : function (event) {
400 handler : function (event) {
401 IPython.notebook.to_heading(undefined, 1);
401 IPython.notebook.to_heading(undefined, 1);
402 return false;
402 return false;
403 }
403 }
404 },
404 },
405 '2' : {
405 '2' : {
406 help : 'to heading 2',
406 help : 'to heading 2',
407 help_index : 'ce',
407 help_index : 'ce',
408 handler : function (event) {
408 handler : function (event) {
409 IPython.notebook.to_heading(undefined, 2);
409 IPython.notebook.to_heading(undefined, 2);
410 return false;
410 return false;
411 }
411 }
412 },
412 },
413 '3' : {
413 '3' : {
414 help : 'to heading 3',
414 help : 'to heading 3',
415 help_index : 'cf',
415 help_index : 'cf',
416 handler : function (event) {
416 handler : function (event) {
417 IPython.notebook.to_heading(undefined, 3);
417 IPython.notebook.to_heading(undefined, 3);
418 return false;
418 return false;
419 }
419 }
420 },
420 },
421 '4' : {
421 '4' : {
422 help : 'to heading 4',
422 help : 'to heading 4',
423 help_index : 'cg',
423 help_index : 'cg',
424 handler : function (event) {
424 handler : function (event) {
425 IPython.notebook.to_heading(undefined, 4);
425 IPython.notebook.to_heading(undefined, 4);
426 return false;
426 return false;
427 }
427 }
428 },
428 },
429 '5' : {
429 '5' : {
430 help : 'to heading 5',
430 help : 'to heading 5',
431 help_index : 'ch',
431 help_index : 'ch',
432 handler : function (event) {
432 handler : function (event) {
433 IPython.notebook.to_heading(undefined, 5);
433 IPython.notebook.to_heading(undefined, 5);
434 return false;
434 return false;
435 }
435 }
436 },
436 },
437 '6' : {
437 '6' : {
438 help : 'to heading 6',
438 help : 'to heading 6',
439 help_index : 'ci',
439 help_index : 'ci',
440 handler : function (event) {
440 handler : function (event) {
441 IPython.notebook.to_heading(undefined, 6);
441 IPython.notebook.to_heading(undefined, 6);
442 return false;
442 return false;
443 }
443 }
444 },
444 },
445 'o' : {
445 'o' : {
446 help : 'toggle output',
446 help : 'toggle output',
447 help_index : 'gb',
447 help_index : 'gb',
448 handler : function (event) {
448 handler : function (event) {
449 IPython.notebook.toggle_output();
449 IPython.notebook.toggle_output();
450 return false;
450 return false;
451 }
451 }
452 },
452 },
453 'shift+o' : {
453 'shift+o' : {
454 help : 'toggle output scrolling',
454 help : 'toggle output scrolling',
455 help_index : 'gc',
455 help_index : 'gc',
456 handler : function (event) {
456 handler : function (event) {
457 IPython.notebook.toggle_output_scroll();
457 IPython.notebook.toggle_output_scroll();
458 return false;
458 return false;
459 }
459 }
460 },
460 },
461 's' : {
461 's' : {
462 help : 'save notebook',
462 help : 'save notebook',
463 help_index : 'fa',
463 help_index : 'fa',
464 handler : function (event) {
464 handler : function (event) {
465 IPython.notebook.save_checkpoint();
465 IPython.notebook.save_checkpoint();
466 return false;
466 return false;
467 }
467 }
468 },
468 },
469 'ctrl+j' : {
469 'ctrl+j' : {
470 help : 'move cell down',
470 help : 'move cell down',
471 help_index : 'eb',
471 help_index : 'eb',
472 handler : function (event) {
472 handler : function (event) {
473 IPython.notebook.move_cell_down();
473 IPython.notebook.move_cell_down();
474 return false;
474 return false;
475 }
475 }
476 },
476 },
477 'ctrl+k' : {
477 'ctrl+k' : {
478 help : 'move cell up',
478 help : 'move cell up',
479 help_index : 'ea',
479 help_index : 'ea',
480 handler : function (event) {
480 handler : function (event) {
481 IPython.notebook.move_cell_up();
481 IPython.notebook.move_cell_up();
482 return false;
482 return false;
483 }
483 }
484 },
484 },
485 'l' : {
485 'l' : {
486 help : 'toggle line numbers',
486 help : 'toggle line numbers',
487 help_index : 'ga',
487 help_index : 'ga',
488 handler : function (event) {
488 handler : function (event) {
489 IPython.notebook.cell_toggle_line_numbers();
489 IPython.notebook.cell_toggle_line_numbers();
490 return false;
490 return false;
491 }
491 }
492 },
492 },
493 'i' : {
493 'i' : {
494 help : 'interrupt kernel (press twice)',
494 help : 'interrupt kernel (press twice)',
495 help_index : 'ha',
495 help_index : 'ha',
496 count: 2,
496 count: 2,
497 handler : function (event) {
497 handler : function (event) {
498 IPython.notebook.kernel.interrupt();
498 IPython.notebook.kernel.interrupt();
499 return false;
499 return false;
500 }
500 }
501 },
501 },
502 '0' : {
502 '0' : {
503 help : 'restart kernel (press twice)',
503 help : 'restart kernel (press twice)',
504 help_index : 'hb',
504 help_index : 'hb',
505 count: 2,
505 count: 2,
506 handler : function (event) {
506 handler : function (event) {
507 IPython.notebook.restart_kernel();
507 IPython.notebook.restart_kernel();
508 return false;
508 return false;
509 }
509 }
510 },
510 },
511 'h' : {
511 'h' : {
512 help : 'keyboard shortcuts',
512 help : 'keyboard shortcuts',
513 help_index : 'gd',
513 help_index : 'gd',
514 handler : function (event) {
514 handler : function (event) {
515 IPython.quick_help.show_keyboard_shortcuts();
515 IPython.quick_help.show_keyboard_shortcuts();
516 return false;
516 return false;
517 }
517 }
518 },
518 },
519 'z' : {
519 'z' : {
520 help : 'undo last delete',
520 help : 'undo last delete',
521 help_index : 'ei',
521 help_index : 'ei',
522 handler : function (event) {
522 handler : function (event) {
523 IPython.notebook.undelete_cell();
523 IPython.notebook.undelete_cell();
524 return false;
524 return false;
525 }
525 }
526 },
526 },
527 'shift+m' : {
527 'shift+m' : {
528 help : 'merge cell below',
528 help : 'merge cell below',
529 help_index : 'ek',
529 help_index : 'ek',
530 handler : function (event) {
530 handler : function (event) {
531 IPython.notebook.merge_cell_below();
531 IPython.notebook.merge_cell_below();
532 return false;
532 return false;
533 }
533 }
534 },
534 },
535 }
535 }
536
536
537
537
538 // Shortcut manager class
538 // Shortcut manager class
539
539
540 var ShortcutManager = function (delay) {
540 var ShortcutManager = function (delay) {
541 this._shortcuts = {}
541 this._shortcuts = {}
542 this._counts = {}
542 this._counts = {}
543 this._timers = {}
543 this.delay = delay || 800; // delay in milliseconds
544 this.delay = delay || 800; // delay in milliseconds
544 }
545 }
545
546
546 ShortcutManager.prototype.help = function () {
547 ShortcutManager.prototype.help = function () {
547 var help = [];
548 var help = [];
548 for (var shortcut in this._shortcuts) {
549 for (var shortcut in this._shortcuts) {
549 var help_string = this._shortcuts[shortcut]['help'];
550 var help_string = this._shortcuts[shortcut]['help'];
550 var help_index = this._shortcuts[shortcut]['help_index'];
551 var help_index = this._shortcuts[shortcut]['help_index'];
551 if (help_string) {
552 if (help_string) {
552 if (platform === 'MacOS') {
553 if (platform === 'MacOS') {
553 shortcut = shortcut.replace('meta', 'cmd');
554 shortcut = shortcut.replace('meta', 'cmd');
554 }
555 }
555 help.push({
556 help.push({
556 shortcut: shortcut,
557 shortcut: shortcut,
557 help: help_string,
558 help: help_string,
558 help_index: help_index}
559 help_index: help_index}
559 );
560 );
560 }
561 }
561 }
562 }
562 help.sort(function (a, b) {
563 help.sort(function (a, b) {
563 if (a.help_index > b.help_index)
564 if (a.help_index > b.help_index)
564 return 1;
565 return 1;
565 if (a.help_index < b.help_index)
566 if (a.help_index < b.help_index)
566 return -1;
567 return -1;
567 return 0;
568 return 0;
568 });
569 });
569 return help;
570 return help;
570 }
571 }
571
572
572 ShortcutManager.prototype.normalize_key = function (key) {
573 ShortcutManager.prototype.normalize_key = function (key) {
573 return inv_keycodes[keycodes[key]];
574 return inv_keycodes[keycodes[key]];
574 }
575 }
575
576
576 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
577 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
577 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
578 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
578 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
579 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
579 var values = shortcut.split("+");
580 var values = shortcut.split("+");
580 if (values.length === 1) {
581 if (values.length === 1) {
581 return this.normalize_key(values[0])
582 return this.normalize_key(values[0])
582 } else {
583 } else {
583 var modifiers = values.slice(0,-1);
584 var modifiers = values.slice(0,-1);
584 var key = this.normalize_key(values[values.length-1]);
585 var key = this.normalize_key(values[values.length-1]);
585 modifiers.sort();
586 modifiers.sort();
586 return modifiers.join('+') + '+' + key;
587 return modifiers.join('+') + '+' + key;
587 }
588 }
588 }
589 }
589
590
590 ShortcutManager.prototype.event_to_shortcut = function (event) {
591 ShortcutManager.prototype.event_to_shortcut = function (event) {
591 // Convert a jQuery keyboard event to a strong based keyboard shortcut
592 // Convert a jQuery keyboard event to a strong based keyboard shortcut
592 var shortcut = '';
593 var shortcut = '';
593 var key = inv_keycodes[event.which]
594 var key = inv_keycodes[event.which]
594 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
595 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
595 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
596 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
596 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
597 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
597 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
598 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
598 shortcut += key;
599 shortcut += key;
599 return shortcut
600 return shortcut
600 }
601 }
601
602
602 ShortcutManager.prototype.clear_shortcuts = function () {
603 ShortcutManager.prototype.clear_shortcuts = function () {
603 this._shortcuts = {};
604 this._shortcuts = {};
604 }
605 }
605
606
606 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
607 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
607 if (typeof(data) === 'function') {
608 if (typeof(data) === 'function') {
608 data = {help: '', help_index: '', handler: data}
609 data = {help: '', help_index: '', handler: data}
609 }
610 }
610 data.help_index = data.help_index || '';
611 data.help_index = data.help_index || '';
611 data.help = data.help || '';
612 data.help = data.help || '';
612 data.count = data.count || 1;
613 data.count = data.count || 1;
613 if (data.help_index === '') {
614 if (data.help_index === '') {
614 data.help_index = 'zz';
615 data.help_index = 'zz';
615 }
616 }
616 shortcut = this.normalize_shortcut(shortcut);
617 shortcut = this.normalize_shortcut(shortcut);
617 this._counts[shortcut] = 0;
618 this._counts[shortcut] = 0;
618 this._shortcuts[shortcut] = data;
619 this._shortcuts[shortcut] = data;
619 }
620 }
620
621
621 ShortcutManager.prototype.add_shortcuts = function (data) {
622 ShortcutManager.prototype.add_shortcuts = function (data) {
622 for (var shortcut in data) {
623 for (var shortcut in data) {
623 this.add_shortcut(shortcut, data[shortcut]);
624 this.add_shortcut(shortcut, data[shortcut]);
624 }
625 }
625 }
626 }
626
627
627 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
628 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
628 shortcut = this.normalize_shortcut(shortcut);
629 shortcut = this.normalize_shortcut(shortcut);
629 delete this._counts[shortcut];
630 delete this._counts[shortcut];
630 delete this._shortcuts[shortcut];
631 delete this._shortcuts[shortcut];
631 }
632 }
632
633
633 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
634 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
634 var that = this;
635 var that = this;
635 var c = this._counts;
636 var c = this._counts;
637 var t = this._timers;
638 var timer = null;
636 if (c[shortcut] === data.count-1) {
639 if (c[shortcut] === data.count-1) {
637 c[shortcut] = 0;
640 c[shortcut] = 0;
641 var timer = t[shortcut];
642 if (timer) {clearTimeout(timer);}
638 return data.handler(event);
643 return data.handler(event);
639 } else {
644 } else {
640 c[shortcut] = c[shortcut] + 1;
645 c[shortcut] = c[shortcut] + 1;
641 setTimeout(function () {
646 timer = setTimeout(function () {
642 c[shortcut] = 0;
647 c[shortcut] = 0;
643 }, that.delay);
648 }, that.delay);
649 t[shortcut] = timer;
644 }
650 }
645 return false;
651 return false;
646
647 }
652 }
648
653
649 ShortcutManager.prototype.call_handler = function (event) {
654 ShortcutManager.prototype.call_handler = function (event) {
650 var shortcut = this.event_to_shortcut(event);
655 var shortcut = this.event_to_shortcut(event);
651 var data = this._shortcuts[shortcut];
656 var data = this._shortcuts[shortcut];
652 if (data) {
657 if (data) {
653 var handler = data['handler'];
658 var handler = data['handler'];
654 if (handler) {
659 if (handler) {
655 if (data.count === 1) {
660 if (data.count === 1) {
656 return handler(event);
661 return handler(event);
657 } else if (data.count > 1) {
662 } else if (data.count > 1) {
658 return this.count_handler(shortcut, event, data);
663 return this.count_handler(shortcut, event, data);
659 }
664 }
660 }
665 }
661 }
666 }
662 return true;
667 return true;
663 }
668 }
664
669
665
670
666
671
667 // Main keyboard manager for the notebook
672 // Main keyboard manager for the notebook
668
673
669 var KeyboardManager = function () {
674 var KeyboardManager = function () {
670 this.mode = 'command';
675 this.mode = 'command';
671 this.enabled = true;
676 this.enabled = true;
672 this.bind_events();
677 this.bind_events();
673 this.command_shortcuts = new ShortcutManager();
678 this.command_shortcuts = new ShortcutManager();
674 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
679 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
675 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
680 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
676 this.edit_shortcuts = new ShortcutManager();
681 this.edit_shortcuts = new ShortcutManager();
677 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
682 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
678 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
683 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
679 };
684 };
680
685
681 KeyboardManager.prototype.bind_events = function () {
686 KeyboardManager.prototype.bind_events = function () {
682 var that = this;
687 var that = this;
683 $(document).keydown(function (event) {
688 $(document).keydown(function (event) {
684 return that.handle_keydown(event);
689 return that.handle_keydown(event);
685 });
690 });
686 };
691 };
687
692
688 KeyboardManager.prototype.handle_keydown = function (event) {
693 KeyboardManager.prototype.handle_keydown = function (event) {
689 var notebook = IPython.notebook;
694 var notebook = IPython.notebook;
690
695
691 if (event.which === keycodes['esc']) {
696 if (event.which === keycodes['esc']) {
692 // Intercept escape at highest level to avoid closing
697 // Intercept escape at highest level to avoid closing
693 // websocket connection with firefox
698 // websocket connection with firefox
694 event.preventDefault();
699 event.preventDefault();
695 }
700 }
696
701
697 if (!this.enabled) {
702 if (!this.enabled) {
698 if (event.which === keycodes['esc']) {
703 if (event.which === keycodes['esc']) {
699 // ESC
704 // ESC
700 notebook.command_mode();
705 notebook.command_mode();
701 return false;
706 return false;
702 }
707 }
703 return true;
708 return true;
704 }
709 }
705
710
706 if (this.mode === 'edit') {
711 if (this.mode === 'edit') {
707 return this.edit_shortcuts.call_handler(event);
712 return this.edit_shortcuts.call_handler(event);
708 } else if (this.mode === 'command') {
713 } else if (this.mode === 'command') {
709 return this.command_shortcuts.call_handler(event);
714 return this.command_shortcuts.call_handler(event);
710 }
715 }
711 return true;
716 return true;
712 }
717 }
713
718
714 KeyboardManager.prototype.edit_mode = function () {
719 KeyboardManager.prototype.edit_mode = function () {
715 this.last_mode = this.mode;
720 this.last_mode = this.mode;
716 this.mode = 'edit';
721 this.mode = 'edit';
717 }
722 }
718
723
719 KeyboardManager.prototype.command_mode = function () {
724 KeyboardManager.prototype.command_mode = function () {
720 this.last_mode = this.mode;
725 this.last_mode = this.mode;
721 this.mode = 'command';
726 this.mode = 'command';
722 }
727 }
723
728
724 KeyboardManager.prototype.enable = function () {
729 KeyboardManager.prototype.enable = function () {
725 this.enabled = true;
730 this.enabled = true;
726 }
731 }
727
732
728 KeyboardManager.prototype.disable = function () {
733 KeyboardManager.prototype.disable = function () {
729 this.enabled = false;
734 this.enabled = false;
730 }
735 }
731
736
732 KeyboardManager.prototype.register_events = function (e) {
737 KeyboardManager.prototype.register_events = function (e) {
733 var that = this;
738 var that = this;
734 e.on('focusin', function () {
739 e.on('focusin', function () {
735 that.disable();
740 that.disable();
736 });
741 });
737 e.on('focusout', function () {
742 e.on('focusout', function () {
738 that.enable();
743 that.enable();
739 });
744 });
740 // There are times (raw_input) where we remove the element from the DOM before
745 // There are times (raw_input) where we remove the element from the DOM before
741 // focusout is called. In this case we bind to the remove event of jQueryUI,
746 // focusout is called. In this case we bind to the remove event of jQueryUI,
742 // which gets triggered upon removal.
747 // which gets triggered upon removal.
743 e.on('remove', function () {
748 e.on('remove', function () {
744 that.enable();
749 that.enable();
745 });
750 });
746 }
751 }
747
752
748
753
749 IPython.keycodes = keycodes;
754 IPython.keycodes = keycodes;
750 IPython.inv_keycodes = inv_keycodes;
755 IPython.inv_keycodes = inv_keycodes;
751 IPython.default_common_shortcuts = default_common_shortcuts;
756 IPython.default_common_shortcuts = default_common_shortcuts;
752 IPython.default_edit_shortcuts = default_edit_shortcuts;
757 IPython.default_edit_shortcuts = default_edit_shortcuts;
753 IPython.default_command_shortcuts = default_command_shortcuts;
758 IPython.default_command_shortcuts = default_command_shortcuts;
754 IPython.ShortcutManager = ShortcutManager;
759 IPython.ShortcutManager = ShortcutManager;
755 IPython.KeyboardManager = KeyboardManager;
760 IPython.KeyboardManager = KeyboardManager;
756
761
757 return IPython;
762 return IPython;
758
763
759 }(IPython));
764 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now