##// END OF EJS Templates
Delete old timeout.
Brian E. Granger -
Show More
@@ -1,764 +1,764
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._timers = {}
544 this.delay = delay || 800; // delay in milliseconds
544 this.delay = delay || 800; // delay in milliseconds
545 }
545 }
546
546
547 ShortcutManager.prototype.help = function () {
547 ShortcutManager.prototype.help = function () {
548 var help = [];
548 var help = [];
549 for (var shortcut in this._shortcuts) {
549 for (var shortcut in this._shortcuts) {
550 var help_string = this._shortcuts[shortcut]['help'];
550 var help_string = this._shortcuts[shortcut]['help'];
551 var help_index = this._shortcuts[shortcut]['help_index'];
551 var help_index = this._shortcuts[shortcut]['help_index'];
552 if (help_string) {
552 if (help_string) {
553 if (platform === 'MacOS') {
553 if (platform === 'MacOS') {
554 shortcut = shortcut.replace('meta', 'cmd');
554 shortcut = shortcut.replace('meta', 'cmd');
555 }
555 }
556 help.push({
556 help.push({
557 shortcut: shortcut,
557 shortcut: shortcut,
558 help: help_string,
558 help: help_string,
559 help_index: help_index}
559 help_index: help_index}
560 );
560 );
561 }
561 }
562 }
562 }
563 help.sort(function (a, b) {
563 help.sort(function (a, b) {
564 if (a.help_index > b.help_index)
564 if (a.help_index > b.help_index)
565 return 1;
565 return 1;
566 if (a.help_index < b.help_index)
566 if (a.help_index < b.help_index)
567 return -1;
567 return -1;
568 return 0;
568 return 0;
569 });
569 });
570 return help;
570 return help;
571 }
571 }
572
572
573 ShortcutManager.prototype.normalize_key = function (key) {
573 ShortcutManager.prototype.normalize_key = function (key) {
574 return inv_keycodes[keycodes[key]];
574 return inv_keycodes[keycodes[key]];
575 }
575 }
576
576
577 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
577 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
578 // 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
579 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
579 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
580 var values = shortcut.split("+");
580 var values = shortcut.split("+");
581 if (values.length === 1) {
581 if (values.length === 1) {
582 return this.normalize_key(values[0])
582 return this.normalize_key(values[0])
583 } else {
583 } else {
584 var modifiers = values.slice(0,-1);
584 var modifiers = values.slice(0,-1);
585 var key = this.normalize_key(values[values.length-1]);
585 var key = this.normalize_key(values[values.length-1]);
586 modifiers.sort();
586 modifiers.sort();
587 return modifiers.join('+') + '+' + key;
587 return modifiers.join('+') + '+' + key;
588 }
588 }
589 }
589 }
590
590
591 ShortcutManager.prototype.event_to_shortcut = function (event) {
591 ShortcutManager.prototype.event_to_shortcut = function (event) {
592 // Convert a jQuery keyboard event to a strong based keyboard shortcut
592 // Convert a jQuery keyboard event to a strong based keyboard shortcut
593 var shortcut = '';
593 var shortcut = '';
594 var key = inv_keycodes[event.which]
594 var key = inv_keycodes[event.which]
595 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
595 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
596 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
596 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
597 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
597 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
598 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
598 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
599 shortcut += key;
599 shortcut += key;
600 return shortcut
600 return shortcut
601 }
601 }
602
602
603 ShortcutManager.prototype.clear_shortcuts = function () {
603 ShortcutManager.prototype.clear_shortcuts = function () {
604 this._shortcuts = {};
604 this._shortcuts = {};
605 }
605 }
606
606
607 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
607 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
608 if (typeof(data) === 'function') {
608 if (typeof(data) === 'function') {
609 data = {help: '', help_index: '', handler: data}
609 data = {help: '', help_index: '', handler: data}
610 }
610 }
611 data.help_index = data.help_index || '';
611 data.help_index = data.help_index || '';
612 data.help = data.help || '';
612 data.help = data.help || '';
613 data.count = data.count || 1;
613 data.count = data.count || 1;
614 if (data.help_index === '') {
614 if (data.help_index === '') {
615 data.help_index = 'zz';
615 data.help_index = 'zz';
616 }
616 }
617 shortcut = this.normalize_shortcut(shortcut);
617 shortcut = this.normalize_shortcut(shortcut);
618 this._counts[shortcut] = 0;
618 this._counts[shortcut] = 0;
619 this._shortcuts[shortcut] = data;
619 this._shortcuts[shortcut] = data;
620 }
620 }
621
621
622 ShortcutManager.prototype.add_shortcuts = function (data) {
622 ShortcutManager.prototype.add_shortcuts = function (data) {
623 for (var shortcut in data) {
623 for (var shortcut in data) {
624 this.add_shortcut(shortcut, data[shortcut]);
624 this.add_shortcut(shortcut, data[shortcut]);
625 }
625 }
626 }
626 }
627
627
628 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
628 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
629 shortcut = this.normalize_shortcut(shortcut);
629 shortcut = this.normalize_shortcut(shortcut);
630 delete this._counts[shortcut];
630 delete this._counts[shortcut];
631 delete this._shortcuts[shortcut];
631 delete this._shortcuts[shortcut];
632 }
632 }
633
633
634 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
634 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
635 var that = this;
635 var that = this;
636 var c = this._counts;
636 var c = this._counts;
637 var t = this._timers;
637 var t = this._timers;
638 var timer = null;
638 var timer = null;
639 if (c[shortcut] === data.count-1) {
639 if (c[shortcut] === data.count-1) {
640 c[shortcut] = 0;
640 c[shortcut] = 0;
641 var timer = t[shortcut];
641 var timer = t[shortcut];
642 if (timer) {clearTimeout(timer);}
642 if (timer) {clearTimeout(timer); delete t[shortcut];}
643 return data.handler(event);
643 return data.handler(event);
644 } else {
644 } else {
645 c[shortcut] = c[shortcut] + 1;
645 c[shortcut] = c[shortcut] + 1;
646 timer = setTimeout(function () {
646 timer = setTimeout(function () {
647 c[shortcut] = 0;
647 c[shortcut] = 0;
648 }, that.delay);
648 }, that.delay);
649 t[shortcut] = timer;
649 t[shortcut] = timer;
650 }
650 }
651 return false;
651 return false;
652 }
652 }
653
653
654 ShortcutManager.prototype.call_handler = function (event) {
654 ShortcutManager.prototype.call_handler = function (event) {
655 var shortcut = this.event_to_shortcut(event);
655 var shortcut = this.event_to_shortcut(event);
656 var data = this._shortcuts[shortcut];
656 var data = this._shortcuts[shortcut];
657 if (data) {
657 if (data) {
658 var handler = data['handler'];
658 var handler = data['handler'];
659 if (handler) {
659 if (handler) {
660 if (data.count === 1) {
660 if (data.count === 1) {
661 return handler(event);
661 return handler(event);
662 } else if (data.count > 1) {
662 } else if (data.count > 1) {
663 return this.count_handler(shortcut, event, data);
663 return this.count_handler(shortcut, event, data);
664 }
664 }
665 }
665 }
666 }
666 }
667 return true;
667 return true;
668 }
668 }
669
669
670
670
671
671
672 // Main keyboard manager for the notebook
672 // Main keyboard manager for the notebook
673
673
674 var KeyboardManager = function () {
674 var KeyboardManager = function () {
675 this.mode = 'command';
675 this.mode = 'command';
676 this.enabled = true;
676 this.enabled = true;
677 this.bind_events();
677 this.bind_events();
678 this.command_shortcuts = new ShortcutManager();
678 this.command_shortcuts = new ShortcutManager();
679 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
679 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
680 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
680 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
681 this.edit_shortcuts = new ShortcutManager();
681 this.edit_shortcuts = new ShortcutManager();
682 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
682 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
683 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
683 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
684 };
684 };
685
685
686 KeyboardManager.prototype.bind_events = function () {
686 KeyboardManager.prototype.bind_events = function () {
687 var that = this;
687 var that = this;
688 $(document).keydown(function (event) {
688 $(document).keydown(function (event) {
689 return that.handle_keydown(event);
689 return that.handle_keydown(event);
690 });
690 });
691 };
691 };
692
692
693 KeyboardManager.prototype.handle_keydown = function (event) {
693 KeyboardManager.prototype.handle_keydown = function (event) {
694 var notebook = IPython.notebook;
694 var notebook = IPython.notebook;
695
695
696 if (event.which === keycodes['esc']) {
696 if (event.which === keycodes['esc']) {
697 // Intercept escape at highest level to avoid closing
697 // Intercept escape at highest level to avoid closing
698 // websocket connection with firefox
698 // websocket connection with firefox
699 event.preventDefault();
699 event.preventDefault();
700 }
700 }
701
701
702 if (!this.enabled) {
702 if (!this.enabled) {
703 if (event.which === keycodes['esc']) {
703 if (event.which === keycodes['esc']) {
704 // ESC
704 // ESC
705 notebook.command_mode();
705 notebook.command_mode();
706 return false;
706 return false;
707 }
707 }
708 return true;
708 return true;
709 }
709 }
710
710
711 if (this.mode === 'edit') {
711 if (this.mode === 'edit') {
712 return this.edit_shortcuts.call_handler(event);
712 return this.edit_shortcuts.call_handler(event);
713 } else if (this.mode === 'command') {
713 } else if (this.mode === 'command') {
714 return this.command_shortcuts.call_handler(event);
714 return this.command_shortcuts.call_handler(event);
715 }
715 }
716 return true;
716 return true;
717 }
717 }
718
718
719 KeyboardManager.prototype.edit_mode = function () {
719 KeyboardManager.prototype.edit_mode = function () {
720 this.last_mode = this.mode;
720 this.last_mode = this.mode;
721 this.mode = 'edit';
721 this.mode = 'edit';
722 }
722 }
723
723
724 KeyboardManager.prototype.command_mode = function () {
724 KeyboardManager.prototype.command_mode = function () {
725 this.last_mode = this.mode;
725 this.last_mode = this.mode;
726 this.mode = 'command';
726 this.mode = 'command';
727 }
727 }
728
728
729 KeyboardManager.prototype.enable = function () {
729 KeyboardManager.prototype.enable = function () {
730 this.enabled = true;
730 this.enabled = true;
731 }
731 }
732
732
733 KeyboardManager.prototype.disable = function () {
733 KeyboardManager.prototype.disable = function () {
734 this.enabled = false;
734 this.enabled = false;
735 }
735 }
736
736
737 KeyboardManager.prototype.register_events = function (e) {
737 KeyboardManager.prototype.register_events = function (e) {
738 var that = this;
738 var that = this;
739 e.on('focusin', function () {
739 e.on('focusin', function () {
740 that.disable();
740 that.disable();
741 });
741 });
742 e.on('focusout', function () {
742 e.on('focusout', function () {
743 that.enable();
743 that.enable();
744 });
744 });
745 // 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
746 // 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,
747 // which gets triggered upon removal.
747 // which gets triggered upon removal.
748 e.on('remove', function () {
748 e.on('remove', function () {
749 that.enable();
749 that.enable();
750 });
750 });
751 }
751 }
752
752
753
753
754 IPython.keycodes = keycodes;
754 IPython.keycodes = keycodes;
755 IPython.inv_keycodes = inv_keycodes;
755 IPython.inv_keycodes = inv_keycodes;
756 IPython.default_common_shortcuts = default_common_shortcuts;
756 IPython.default_common_shortcuts = default_common_shortcuts;
757 IPython.default_edit_shortcuts = default_edit_shortcuts;
757 IPython.default_edit_shortcuts = default_edit_shortcuts;
758 IPython.default_command_shortcuts = default_command_shortcuts;
758 IPython.default_command_shortcuts = default_command_shortcuts;
759 IPython.ShortcutManager = ShortcutManager;
759 IPython.ShortcutManager = ShortcutManager;
760 IPython.KeyboardManager = KeyboardManager;
760 IPython.KeyboardManager = KeyboardManager;
761
761
762 return IPython;
762 return IPython;
763
763
764 }(IPython));
764 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now