##// END OF EJS Templates
canonicalize -> normalize in keyboard manager.
Brian E. Granger -
Show More
@@ -1,617 +1,617
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
53
54 if (browser === 'Firefox' || browser === 'Opera') {
54 if (browser === 'Firefox' || browser === 'Opera') {
55 $.extend(_keycodes, _mozilla_keycodes);
55 $.extend(_keycodes, _mozilla_keycodes);
56 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
56 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
57 $.extend(_keycodes, _ie_keycodes);
57 $.extend(_keycodes, _ie_keycodes);
58 }
58 }
59
59
60 var keycodes = {};
60 var keycodes = {};
61 var inv_keycodes = {};
61 var inv_keycodes = {};
62 for (var name in _keycodes) {
62 for (var name in _keycodes) {
63 var names = name.split(' ');
63 var names = name.split(' ');
64 if (names.length === 1) {
64 if (names.length === 1) {
65 var n = names[0]
65 var n = names[0]
66 keycodes[n] = _keycodes[n]
66 keycodes[n] = _keycodes[n]
67 inv_keycodes[_keycodes[n]] = n
67 inv_keycodes[_keycodes[n]] = n
68 } else {
68 } else {
69 var primary = names[0];
69 var primary = names[0];
70 var secondary = names[1];
70 var secondary = names[1];
71 keycodes[primary] = _keycodes[name]
71 keycodes[primary] = _keycodes[name]
72 keycodes[secondary] = _keycodes[name]
72 keycodes[secondary] = _keycodes[name]
73 inv_keycodes[_keycodes[name]] = primary
73 inv_keycodes[_keycodes[name]] = primary
74 }
74 }
75 }
75 }
76
76
77
77
78 // Default keyboard shortcuts
78 // Default keyboard shortcuts
79
79
80 var default_common_shortcuts = {
80 var default_common_shortcuts = {
81 'meta+s' : {
81 'meta+s' : {
82 help : 'save notebook',
82 help : 'save notebook',
83 handler : function (event) {
83 handler : function (event) {
84 IPython.notebook.save_checkpoint();
84 IPython.notebook.save_checkpoint();
85 event.preventDefault();
85 event.preventDefault();
86 return false;
86 return false;
87 }
87 }
88 },
88 },
89 'ctrl+s' : {
89 'ctrl+s' : {
90 help : 'save notebook',
90 help : 'save notebook',
91 handler : function (event) {
91 handler : function (event) {
92 IPython.notebook.save_checkpoint();
92 IPython.notebook.save_checkpoint();
93 event.preventDefault();
93 event.preventDefault();
94 return false;
94 return false;
95 }
95 }
96 },
96 },
97 'shift' : {
97 'shift' : {
98 help : '',
98 help : '',
99 handler : function (event) {
99 handler : function (event) {
100 // ignore shift keydown
100 // ignore shift keydown
101 return true;
101 return true;
102 }
102 }
103 },
103 },
104 'shift+enter' : {
104 'shift+enter' : {
105 help : 'run cell',
105 help : 'run cell',
106 handler : function (event) {
106 handler : function (event) {
107 IPython.notebook.execute_cell();
107 IPython.notebook.execute_cell();
108 return false;
108 return false;
109 }
109 }
110 },
110 },
111 'alt+enter' : {
111 'alt+enter' : {
112 help : 'run cell, insert below',
112 help : 'run cell, insert below',
113 handler : function (event) {
113 handler : function (event) {
114 IPython.notebook.execute_cell_and_insert_below();
114 IPython.notebook.execute_cell_and_insert_below();
115 return false;
115 return false;
116 }
116 }
117 },
117 },
118 'ctrl+enter' : {
118 'ctrl+enter' : {
119 help : 'run cell, select below',
119 help : 'run cell, select below',
120 handler : function (event) {
120 handler : function (event) {
121 IPython.notebook.execute_cell_and_select_below();
121 IPython.notebook.execute_cell_and_select_below();
122 return false;
122 return false;
123 }
123 }
124 }
124 }
125 }
125 }
126
126
127 // Edit mode defaults
127 // Edit mode defaults
128
128
129 var default_edit_shortcuts = {
129 var default_edit_shortcuts = {
130 'esc' : {
130 'esc' : {
131 help : 'command mode',
131 help : 'command mode',
132 handler : function (event) {
132 handler : function (event) {
133 IPython.notebook.command_mode();
133 IPython.notebook.command_mode();
134 IPython.notebook.focus_cell();
134 IPython.notebook.focus_cell();
135 return false;
135 return false;
136 }
136 }
137 },
137 },
138 'ctrl+m' : {
138 'ctrl+m' : {
139 help : 'command mode',
139 help : 'command mode',
140 handler : function (event) {
140 handler : function (event) {
141 IPython.notebook.command_mode();
141 IPython.notebook.command_mode();
142 IPython.notebook.focus_cell();
142 IPython.notebook.focus_cell();
143 return false;
143 return false;
144 }
144 }
145 },
145 },
146 'up' : {
146 'up' : {
147 help : 'select previous cell',
147 help : 'select previous cell',
148 handler : function (event) {
148 handler : function (event) {
149 var cell = IPython.notebook.get_selected_cell();
149 var cell = IPython.notebook.get_selected_cell();
150 if (cell && cell.at_top()) {
150 if (cell && cell.at_top()) {
151 event.preventDefault();
151 event.preventDefault();
152 IPython.notebook.command_mode()
152 IPython.notebook.command_mode()
153 IPython.notebook.select_prev();
153 IPython.notebook.select_prev();
154 IPython.notebook.edit_mode();
154 IPython.notebook.edit_mode();
155 return false;
155 return false;
156 };
156 };
157 }
157 }
158 },
158 },
159 'down' : {
159 'down' : {
160 help : 'select next cell',
160 help : 'select next cell',
161 handler : function (event) {
161 handler : function (event) {
162 var cell = IPython.notebook.get_selected_cell();
162 var cell = IPython.notebook.get_selected_cell();
163 if (cell && cell.at_bottom()) {
163 if (cell && cell.at_bottom()) {
164 event.preventDefault();
164 event.preventDefault();
165 IPython.notebook.command_mode()
165 IPython.notebook.command_mode()
166 IPython.notebook.select_next();
166 IPython.notebook.select_next();
167 IPython.notebook.edit_mode();
167 IPython.notebook.edit_mode();
168 return false;
168 return false;
169 };
169 };
170 }
170 }
171 },
171 },
172 'alt+-' : {
172 'alt+-' : {
173 help : 'split cell',
173 help : 'split cell',
174 handler : function (event) {
174 handler : function (event) {
175 IPython.notebook.split_cell();
175 IPython.notebook.split_cell();
176 return false;
176 return false;
177 }
177 }
178 },
178 },
179 'alt+subtract' : {
179 'alt+subtract' : {
180 help : 'split cell',
180 help : 'split cell',
181 handler : function (event) {
181 handler : function (event) {
182 IPython.notebook.split_cell();
182 IPython.notebook.split_cell();
183 return false;
183 return false;
184 }
184 }
185 },
185 },
186 }
186 }
187
187
188 // Command mode defaults
188 // Command mode defaults
189
189
190 var default_command_shortcuts = {
190 var default_command_shortcuts = {
191 'enter' : {
191 'enter' : {
192 help : 'edit mode',
192 help : 'edit mode',
193 handler : function (event) {
193 handler : function (event) {
194 IPython.notebook.edit_mode();
194 IPython.notebook.edit_mode();
195 return false;
195 return false;
196 }
196 }
197 },
197 },
198 'up' : {
198 'up' : {
199 help : 'select previous cell',
199 help : 'select previous cell',
200 handler : function (event) {
200 handler : function (event) {
201 var index = IPython.notebook.get_selected_index();
201 var index = IPython.notebook.get_selected_index();
202 if (index !== 0 && index !== null) {
202 if (index !== 0 && index !== null) {
203 IPython.notebook.select_prev();
203 IPython.notebook.select_prev();
204 var cell = IPython.notebook.get_selected_cell();
204 var cell = IPython.notebook.get_selected_cell();
205 cell.focus_cell();
205 cell.focus_cell();
206 };
206 };
207 return false;
207 return false;
208 }
208 }
209 },
209 },
210 'down' : {
210 'down' : {
211 help : 'select next cell',
211 help : 'select next cell',
212 handler : function (event) {
212 handler : function (event) {
213 var index = IPython.notebook.get_selected_index();
213 var index = IPython.notebook.get_selected_index();
214 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
214 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
215 IPython.notebook.select_next();
215 IPython.notebook.select_next();
216 var cell = IPython.notebook.get_selected_cell();
216 var cell = IPython.notebook.get_selected_cell();
217 cell.focus_cell();
217 cell.focus_cell();
218 };
218 };
219 return false;
219 return false;
220 }
220 }
221 },
221 },
222 'k' : {
222 'k' : {
223 help : 'select previous cell',
223 help : 'select previous cell',
224 handler : function (event) {
224 handler : function (event) {
225 var index = IPython.notebook.get_selected_index();
225 var index = IPython.notebook.get_selected_index();
226 if (index !== 0 && index !== null) {
226 if (index !== 0 && index !== null) {
227 IPython.notebook.select_prev();
227 IPython.notebook.select_prev();
228 var cell = IPython.notebook.get_selected_cell();
228 var cell = IPython.notebook.get_selected_cell();
229 cell.focus_cell();
229 cell.focus_cell();
230 };
230 };
231 return false;
231 return false;
232 }
232 }
233 },
233 },
234 'j' : {
234 'j' : {
235 help : 'select next cell',
235 help : 'select next cell',
236 handler : function (event) {
236 handler : function (event) {
237 var index = IPython.notebook.get_selected_index();
237 var index = IPython.notebook.get_selected_index();
238 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
238 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
239 IPython.notebook.select_next();
239 IPython.notebook.select_next();
240 var cell = IPython.notebook.get_selected_cell();
240 var cell = IPython.notebook.get_selected_cell();
241 cell.focus_cell();
241 cell.focus_cell();
242 };
242 };
243 return false;
243 return false;
244 }
244 }
245 },
245 },
246 'x' : {
246 'x' : {
247 help : 'cut cell',
247 help : 'cut cell',
248 handler : function (event) {
248 handler : function (event) {
249 IPython.notebook.cut_cell();
249 IPython.notebook.cut_cell();
250 return false;
250 return false;
251 }
251 }
252 },
252 },
253 'c' : {
253 'c' : {
254 help : 'copy cell',
254 help : 'copy cell',
255 handler : function (event) {
255 handler : function (event) {
256 IPython.notebook.copy_cell();
256 IPython.notebook.copy_cell();
257 return false;
257 return false;
258 }
258 }
259 },
259 },
260 'v' : {
260 'v' : {
261 help : 'paste cell below',
261 help : 'paste cell below',
262 handler : function (event) {
262 handler : function (event) {
263 IPython.notebook.paste_cell_below();
263 IPython.notebook.paste_cell_below();
264 return false;
264 return false;
265 }
265 }
266 },
266 },
267 'd' : {
267 'd' : {
268 help : 'delete cell (press twice)',
268 help : 'delete cell (press twice)',
269 handler : function (event) {
269 handler : function (event) {
270 var dc = IPython.keyboard_manager._delete_count;
270 var dc = IPython.keyboard_manager._delete_count;
271 if (dc === 0) {
271 if (dc === 0) {
272 IPython.keyboard_manager._delete_count = 1;
272 IPython.keyboard_manager._delete_count = 1;
273 setTimeout(function () {
273 setTimeout(function () {
274 IPython.keyboard_manager._delete_count = 0;
274 IPython.keyboard_manager._delete_count = 0;
275 }, 800);
275 }, 800);
276 } else if (dc === 1) {
276 } else if (dc === 1) {
277 IPython.notebook.delete_cell();
277 IPython.notebook.delete_cell();
278 IPython.keyboard_manager._delete_count = 0;
278 IPython.keyboard_manager._delete_count = 0;
279 }
279 }
280 return false;
280 return false;
281 }
281 }
282 },
282 },
283 'a' : {
283 'a' : {
284 help : 'insert cell above',
284 help : 'insert cell above',
285 handler : function (event) {
285 handler : function (event) {
286 IPython.notebook.insert_cell_above('code');
286 IPython.notebook.insert_cell_above('code');
287 IPython.notebook.select_prev();
287 IPython.notebook.select_prev();
288 IPython.notebook.focus_cell();
288 IPython.notebook.focus_cell();
289 return false;
289 return false;
290 }
290 }
291 },
291 },
292 'b' : {
292 'b' : {
293 help : 'insert cell below',
293 help : 'insert cell below',
294 handler : function (event) {
294 handler : function (event) {
295 IPython.notebook.insert_cell_below('code');
295 IPython.notebook.insert_cell_below('code');
296 IPython.notebook.select_next();
296 IPython.notebook.select_next();
297 IPython.notebook.focus_cell();
297 IPython.notebook.focus_cell();
298 return false;
298 return false;
299 }
299 }
300 },
300 },
301 'y' : {
301 'y' : {
302 help : 'to code',
302 help : 'to code',
303 handler : function (event) {
303 handler : function (event) {
304 IPython.notebook.to_code();
304 IPython.notebook.to_code();
305 return false;
305 return false;
306 }
306 }
307 },
307 },
308 'm' : {
308 'm' : {
309 help : 'to markdown',
309 help : 'to markdown',
310 handler : function (event) {
310 handler : function (event) {
311 IPython.notebook.to_markdown();
311 IPython.notebook.to_markdown();
312 return false;
312 return false;
313 }
313 }
314 },
314 },
315 't' : {
315 't' : {
316 help : 'to raw',
316 help : 'to raw',
317 handler : function (event) {
317 handler : function (event) {
318 IPython.notebook.to_raw();
318 IPython.notebook.to_raw();
319 return false;
319 return false;
320 }
320 }
321 },
321 },
322 '1' : {
322 '1' : {
323 help : 'to heading 1',
323 help : 'to heading 1',
324 handler : function (event) {
324 handler : function (event) {
325 IPython.notebook.to_heading(undefined, 1);
325 IPython.notebook.to_heading(undefined, 1);
326 return false;
326 return false;
327 }
327 }
328 },
328 },
329 '2' : {
329 '2' : {
330 help : 'to heading 2',
330 help : 'to heading 2',
331 handler : function (event) {
331 handler : function (event) {
332 IPython.notebook.to_heading(undefined, 2);
332 IPython.notebook.to_heading(undefined, 2);
333 return false;
333 return false;
334 }
334 }
335 },
335 },
336 '3' : {
336 '3' : {
337 help : 'to heading 3',
337 help : 'to heading 3',
338 handler : function (event) {
338 handler : function (event) {
339 IPython.notebook.to_heading(undefined, 3);
339 IPython.notebook.to_heading(undefined, 3);
340 return false;
340 return false;
341 }
341 }
342 },
342 },
343 '4' : {
343 '4' : {
344 help : 'to heading 4',
344 help : 'to heading 4',
345 handler : function (event) {
345 handler : function (event) {
346 IPython.notebook.to_heading(undefined, 4);
346 IPython.notebook.to_heading(undefined, 4);
347 return false;
347 return false;
348 }
348 }
349 },
349 },
350 '5' : {
350 '5' : {
351 help : 'to heading 5',
351 help : 'to heading 5',
352 handler : function (event) {
352 handler : function (event) {
353 IPython.notebook.to_heading(undefined, 5);
353 IPython.notebook.to_heading(undefined, 5);
354 return false;
354 return false;
355 }
355 }
356 },
356 },
357 '6' : {
357 '6' : {
358 help : 'to heading 6',
358 help : 'to heading 6',
359 handler : function (event) {
359 handler : function (event) {
360 IPython.notebook.to_heading(undefined, 6);
360 IPython.notebook.to_heading(undefined, 6);
361 return false;
361 return false;
362 }
362 }
363 },
363 },
364 'o' : {
364 'o' : {
365 help : 'toggle output',
365 help : 'toggle output',
366 handler : function (event) {
366 handler : function (event) {
367 IPython.notebook.toggle_output();
367 IPython.notebook.toggle_output();
368 return false;
368 return false;
369 }
369 }
370 },
370 },
371 'shift+o' : {
371 'shift+o' : {
372 help : 'toggle output',
372 help : 'toggle output',
373 handler : function (event) {
373 handler : function (event) {
374 IPython.notebook.toggle_output_scroll();
374 IPython.notebook.toggle_output_scroll();
375 return false;
375 return false;
376 }
376 }
377 },
377 },
378 's' : {
378 's' : {
379 help : 'save notebook',
379 help : 'save notebook',
380 handler : function (event) {
380 handler : function (event) {
381 IPython.notebook.save_checkpoint();
381 IPython.notebook.save_checkpoint();
382 return false;
382 return false;
383 }
383 }
384 },
384 },
385 'ctrl+j' : {
385 'ctrl+j' : {
386 help : 'move cell down',
386 help : 'move cell down',
387 handler : function (event) {
387 handler : function (event) {
388 IPython.notebook.move_cell_down();
388 IPython.notebook.move_cell_down();
389 return false;
389 return false;
390 }
390 }
391 },
391 },
392 'ctrl+k' : {
392 'ctrl+k' : {
393 help : 'move cell up',
393 help : 'move cell up',
394 handler : function (event) {
394 handler : function (event) {
395 IPython.notebook.move_cell_up();
395 IPython.notebook.move_cell_up();
396 return false;
396 return false;
397 }
397 }
398 },
398 },
399 'l' : {
399 'l' : {
400 help : 'toggle line numbers',
400 help : 'toggle line numbers',
401 handler : function (event) {
401 handler : function (event) {
402 IPython.notebook.cell_toggle_line_numbers();
402 IPython.notebook.cell_toggle_line_numbers();
403 return false;
403 return false;
404 }
404 }
405 },
405 },
406 'i' : {
406 'i' : {
407 help : 'interrupt kernel',
407 help : 'interrupt kernel',
408 handler : function (event) {
408 handler : function (event) {
409 IPython.notebook.kernel.interrupt();
409 IPython.notebook.kernel.interrupt();
410 return false;
410 return false;
411 }
411 }
412 },
412 },
413 '.' : {
413 '.' : {
414 help : 'restart kernel',
414 help : 'restart kernel',
415 handler : function (event) {
415 handler : function (event) {
416 IPython.notebook.restart_kernel();
416 IPython.notebook.restart_kernel();
417 return false;
417 return false;
418 }
418 }
419 },
419 },
420 'h' : {
420 'h' : {
421 help : 'keyboard shortcuts',
421 help : 'keyboard shortcuts',
422 handler : function (event) {
422 handler : function (event) {
423 IPython.quick_help.show_keyboard_shortcuts();
423 IPython.quick_help.show_keyboard_shortcuts();
424 return false;
424 return false;
425 }
425 }
426 },
426 },
427 'z' : {
427 'z' : {
428 help : 'undo last delete',
428 help : 'undo last delete',
429 handler : function (event) {
429 handler : function (event) {
430 IPython.notebook.undelete_cell();
430 IPython.notebook.undelete_cell();
431 return false;
431 return false;
432 }
432 }
433 },
433 },
434 'shift+=' : {
434 'shift+=' : {
435 help : 'merge cell below',
435 help : 'merge cell below',
436 handler : function (event) {
436 handler : function (event) {
437 IPython.notebook.merge_cell_below();
437 IPython.notebook.merge_cell_below();
438 return false;
438 return false;
439 }
439 }
440 },
440 },
441 }
441 }
442
442
443
443
444 // Shortcut manager class
444 // Shortcut manager class
445
445
446 var ShortcutManager = function () {
446 var ShortcutManager = function () {
447 this._shortcuts = {}
447 this._shortcuts = {}
448 }
448 }
449
449
450 ShortcutManager.prototype.help = function () {
450 ShortcutManager.prototype.help = function () {
451 var help = [];
451 var help = [];
452 for (var shortcut in this._shortcuts) {
452 for (var shortcut in this._shortcuts) {
453 help.push({shortcut: shortcut, help: this._shortcuts[shortcut]['help']});
453 help.push({shortcut: shortcut, help: this._shortcuts[shortcut]['help']});
454 }
454 }
455 return help;
455 return help;
456 }
456 }
457
457
458 ShortcutManager.prototype.canonicalize_key = function (key) {
458 ShortcutManager.prototype.normalize_key = function (key) {
459 return inv_keycodes[keycodes[key]];
459 return inv_keycodes[keycodes[key]];
460 }
460 }
461
461
462 ShortcutManager.prototype.canonicalize_shortcut = function (shortcut) {
462 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
463 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
463 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
464 var values = shortcut.split("+");
464 var values = shortcut.split("+");
465 if (values.length === 1) {
465 if (values.length === 1) {
466 return this.canonicalize_key(values[0])
466 return this.normalize_key(values[0])
467 } else {
467 } else {
468 var modifiers = values.slice(0,-1);
468 var modifiers = values.slice(0,-1);
469 var key = this.canonicalize_key(values[values.length-1]);
469 var key = this.normalize_key(values[values.length-1]);
470 modifiers.sort();
470 modifiers.sort();
471 return modifiers.join('+') + '+' + key;
471 return modifiers.join('+') + '+' + key;
472 }
472 }
473 }
473 }
474
474
475 ShortcutManager.prototype.event_to_shortcut = function (event) {
475 ShortcutManager.prototype.event_to_shortcut = function (event) {
476 // Convert a jQuery keyboard event to a strong based keyboard shortcut
476 // Convert a jQuery keyboard event to a strong based keyboard shortcut
477 var shortcut = '';
477 var shortcut = '';
478 var key = inv_keycodes[event.which]
478 var key = inv_keycodes[event.which]
479 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
479 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
480 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
480 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
481 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
481 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
482 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
482 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
483 shortcut += key;
483 shortcut += key;
484 return shortcut
484 return shortcut
485 }
485 }
486
486
487 ShortcutManager.prototype.clear_shortcuts = function () {
487 ShortcutManager.prototype.clear_shortcuts = function () {
488 this._shortcuts = {};
488 this._shortcuts = {};
489 }
489 }
490
490
491 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
491 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
492 shortcut = this.canonicalize_shortcut(shortcut);
492 shortcut = this.normalize_shortcut(shortcut);
493 this._shortcuts[shortcut] = data;
493 this._shortcuts[shortcut] = data;
494 }
494 }
495
495
496 ShortcutManager.prototype.add_shortcuts = function (data) {
496 ShortcutManager.prototype.add_shortcuts = function (data) {
497 for (var shortcut in data) {
497 for (var shortcut in data) {
498 this.add_shortcut(shortcut, data[shortcut]);
498 this.add_shortcut(shortcut, data[shortcut]);
499 }
499 }
500 }
500 }
501
501
502 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
502 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
503 shortcut = this.canonicalize_shortcut(shortcut);
503 shortcut = this.normalize_shortcut(shortcut);
504 delete this._shortcuts[shortcut];
504 delete this._shortcuts[shortcut];
505 }
505 }
506
506
507 ShortcutManager.prototype.call_handler = function (event) {
507 ShortcutManager.prototype.call_handler = function (event) {
508 var shortcut = this.event_to_shortcut(event);
508 var shortcut = this.event_to_shortcut(event);
509 var data = this._shortcuts[shortcut];
509 var data = this._shortcuts[shortcut];
510 if (data !== undefined) {
510 if (data !== undefined) {
511 var handler = data['handler'];
511 var handler = data['handler'];
512 if (handler !== undefined) {
512 if (handler !== undefined) {
513 return handler(event);
513 return handler(event);
514 }
514 }
515 }
515 }
516 return true;
516 return true;
517 }
517 }
518
518
519
519
520
520
521 // Main keyboard manager for the notebook
521 // Main keyboard manager for the notebook
522
522
523 var KeyboardManager = function () {
523 var KeyboardManager = function () {
524 this.mode = 'command';
524 this.mode = 'command';
525 this.enabled = true;
525 this.enabled = true;
526 this._delete_count = 0;
526 this._delete_count = 0;
527 this.bind_events();
527 this.bind_events();
528 this.command_shortcuts = new ShortcutManager();
528 this.command_shortcuts = new ShortcutManager();
529 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
529 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
530 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
530 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
531 this.edit_shortcuts = new ShortcutManager();
531 this.edit_shortcuts = new ShortcutManager();
532 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
532 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
533 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
533 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
534 };
534 };
535
535
536 KeyboardManager.prototype.bind_events = function () {
536 KeyboardManager.prototype.bind_events = function () {
537 var that = this;
537 var that = this;
538 $(document).keydown(function (event) {
538 $(document).keydown(function (event) {
539 return that.handle_keydown(event);
539 return that.handle_keydown(event);
540 });
540 });
541 };
541 };
542
542
543 KeyboardManager.prototype.handle_keydown = function (event) {
543 KeyboardManager.prototype.handle_keydown = function (event) {
544 var notebook = IPython.notebook;
544 var notebook = IPython.notebook;
545
545
546 if (event.which === keycodes['esc']) {
546 if (event.which === keycodes['esc']) {
547 // Intercept escape at highest level to avoid closing
547 // Intercept escape at highest level to avoid closing
548 // websocket connection with firefox
548 // websocket connection with firefox
549 event.preventDefault();
549 event.preventDefault();
550 }
550 }
551
551
552 if (!this.enabled) {
552 if (!this.enabled) {
553 if (event.which === keycodes['esc']) {
553 if (event.which === keycodes['esc']) {
554 // ESC
554 // ESC
555 notebook.command_mode();
555 notebook.command_mode();
556 return false;
556 return false;
557 }
557 }
558 return true;
558 return true;
559 }
559 }
560
560
561 if (this.mode === 'edit') {
561 if (this.mode === 'edit') {
562 return this.edit_shortcuts.call_handler(event);
562 return this.edit_shortcuts.call_handler(event);
563 } else if (this.mode === 'command') {
563 } else if (this.mode === 'command') {
564 return this.command_shortcuts.call_handler(event);
564 return this.command_shortcuts.call_handler(event);
565 }
565 }
566 return true;
566 return true;
567 }
567 }
568
568
569 KeyboardManager.prototype.edit_mode = function () {
569 KeyboardManager.prototype.edit_mode = function () {
570 this.last_mode = this.mode;
570 this.last_mode = this.mode;
571 this.mode = 'edit';
571 this.mode = 'edit';
572 }
572 }
573
573
574 KeyboardManager.prototype.command_mode = function () {
574 KeyboardManager.prototype.command_mode = function () {
575 this.last_mode = this.mode;
575 this.last_mode = this.mode;
576 this.mode = 'command';
576 this.mode = 'command';
577 }
577 }
578
578
579 KeyboardManager.prototype.enable = function () {
579 KeyboardManager.prototype.enable = function () {
580 this.enabled = true;
580 this.enabled = true;
581 }
581 }
582
582
583 KeyboardManager.prototype.disable = function () {
583 KeyboardManager.prototype.disable = function () {
584 this.enabled = false;
584 this.enabled = false;
585 }
585 }
586
586
587 KeyboardManager.prototype.register_events = function (e) {
587 KeyboardManager.prototype.register_events = function (e) {
588 var that = this;
588 var that = this;
589 e.on('focusin', function () {
589 e.on('focusin', function () {
590 that.command_mode();
590 that.command_mode();
591 that.disable();
591 that.disable();
592 });
592 });
593 e.on('focusout', function () {
593 e.on('focusout', function () {
594 that.command_mode();
594 that.command_mode();
595 that.enable();
595 that.enable();
596 });
596 });
597 // There are times (raw_input) where we remove the element from the DOM before
597 // There are times (raw_input) where we remove the element from the DOM before
598 // focusout is called. In this case we bind to the remove event of jQueryUI,
598 // focusout is called. In this case we bind to the remove event of jQueryUI,
599 // which gets triggered upon removal.
599 // which gets triggered upon removal.
600 e.on('remove', function () {
600 e.on('remove', function () {
601 that.command_mode();
601 that.command_mode();
602 that.enable();
602 that.enable();
603 });
603 });
604 }
604 }
605
605
606
606
607 IPython.keycodes = keycodes;
607 IPython.keycodes = keycodes;
608 IPython.inv_keycodes = inv_keycodes;
608 IPython.inv_keycodes = inv_keycodes;
609 IPython.default_common_shortcuts = default_common_shortcuts;
609 IPython.default_common_shortcuts = default_common_shortcuts;
610 IPython.default_edit_shortcuts = default_edit_shortcuts;
610 IPython.default_edit_shortcuts = default_edit_shortcuts;
611 IPython.default_command_shortcuts = default_command_shortcuts;
611 IPython.default_command_shortcuts = default_command_shortcuts;
612 IPython.ShortcutManager = ShortcutManager;
612 IPython.ShortcutManager = ShortcutManager;
613 IPython.KeyboardManager = KeyboardManager;
613 IPython.KeyboardManager = KeyboardManager;
614
614
615 return IPython;
615 return IPython;
616
616
617 }(IPython));
617 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now