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