##// END OF EJS Templates
Check down too.
Jonathan Frederic -
Show More
@@ -1,787 +1,792
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 index = IPython.notebook.get_selected_index();
165 var index = IPython.notebook.get_selected_index();
166 var cell = IPython.notebook.get_selected_cell();
166 var cell = IPython.notebook.get_cell(index);
167 if (index !== 0 && cell && cell.at_top()) {
167 if (index !== null && index !== 0) {
168 event.preventDefault();
168 if (cell && cell.at_top()) {
169 IPython.notebook.command_mode();
169 event.preventDefault();
170 IPython.notebook.select_prev();
170 IPython.notebook.command_mode();
171 IPython.notebook.edit_mode();
171 IPython.notebook.select_prev();
172 return false;
172 IPython.notebook.edit_mode();
173 return false;
174 }
173 }
175 }
174 }
176 }
175 },
177 },
176 'down' : {
178 'down' : {
177 help : '',
179 help : '',
178 help_index : '',
180 help_index : '',
179 handler : function (event) {
181 handler : function (event) {
180 var cell = IPython.notebook.get_selected_cell();
182 var index = IPython.notebook.get_selected_index();
181 if (cell && cell.at_bottom()) {
183 var cell = IPython.notebook.get_cell(index);
182 event.preventDefault();
184 if (index !== null && index !== (IPython.notebook.ncells()-1)) {
183 IPython.notebook.command_mode();
185 if (cell && cell.at_bottom()) {
184 IPython.notebook.select_next();
186 event.preventDefault();
185 IPython.notebook.edit_mode();
187 IPython.notebook.command_mode();
186 return false;
188 IPython.notebook.select_next();
189 IPython.notebook.edit_mode();
190 return false;
191 }
187 }
192 }
188 }
193 }
189 },
194 },
190 'alt+-' : {
195 'alt+-' : {
191 help : 'split cell',
196 help : 'split cell',
192 help_index : 'ea',
197 help_index : 'ea',
193 handler : function (event) {
198 handler : function (event) {
194 IPython.notebook.split_cell();
199 IPython.notebook.split_cell();
195 return false;
200 return false;
196 }
201 }
197 },
202 },
198 'alt+subtract' : {
203 'alt+subtract' : {
199 help : '',
204 help : '',
200 help_index : 'eb',
205 help_index : 'eb',
201 handler : function (event) {
206 handler : function (event) {
202 IPython.notebook.split_cell();
207 IPython.notebook.split_cell();
203 return false;
208 return false;
204 }
209 }
205 },
210 },
206 'tab' : {
211 'tab' : {
207 help : 'indent or complete',
212 help : 'indent or complete',
208 help_index : 'ec',
213 help_index : 'ec',
209 },
214 },
210 'shift+tab' : {
215 'shift+tab' : {
211 help : 'tooltip',
216 help : 'tooltip',
212 help_index : 'ed',
217 help_index : 'ed',
213 },
218 },
214 };
219 };
215
220
216 if (platform === 'MacOS') {
221 if (platform === 'MacOS') {
217 default_edit_shortcuts['cmd+/'] =
222 default_edit_shortcuts['cmd+/'] =
218 {
223 {
219 help : 'toggle comment',
224 help : 'toggle comment',
220 help_index : 'ee'
225 help_index : 'ee'
221 };
226 };
222 default_edit_shortcuts['cmd+]'] =
227 default_edit_shortcuts['cmd+]'] =
223 {
228 {
224 help : 'indent',
229 help : 'indent',
225 help_index : 'ef'
230 help_index : 'ef'
226 };
231 };
227 default_edit_shortcuts['cmd+['] =
232 default_edit_shortcuts['cmd+['] =
228 {
233 {
229 help : 'dedent',
234 help : 'dedent',
230 help_index : 'eg'
235 help_index : 'eg'
231 };
236 };
232 } else {
237 } else {
233 default_edit_shortcuts['ctrl+/'] =
238 default_edit_shortcuts['ctrl+/'] =
234 {
239 {
235 help : 'toggle comment',
240 help : 'toggle comment',
236 help_index : 'ee'
241 help_index : 'ee'
237 };
242 };
238 default_edit_shortcuts['ctrl+]'] =
243 default_edit_shortcuts['ctrl+]'] =
239 {
244 {
240 help : 'indent',
245 help : 'indent',
241 help_index : 'ef'
246 help_index : 'ef'
242 };
247 };
243 default_edit_shortcuts['ctrl+['] =
248 default_edit_shortcuts['ctrl+['] =
244 {
249 {
245 help : 'dedent',
250 help : 'dedent',
246 help_index : 'eg'
251 help_index : 'eg'
247 };
252 };
248 }
253 }
249
254
250 // Command mode defaults
255 // Command mode defaults
251
256
252 var default_command_shortcuts = {
257 var default_command_shortcuts = {
253 'enter' : {
258 'enter' : {
254 help : 'edit mode',
259 help : 'edit mode',
255 help_index : 'aa',
260 help_index : 'aa',
256 handler : function (event) {
261 handler : function (event) {
257 IPython.notebook.edit_mode();
262 IPython.notebook.edit_mode();
258 return false;
263 return false;
259 }
264 }
260 },
265 },
261 'up' : {
266 'up' : {
262 help : 'select previous cell',
267 help : 'select previous cell',
263 help_index : 'da',
268 help_index : 'da',
264 handler : function (event) {
269 handler : function (event) {
265 var index = IPython.notebook.get_selected_index();
270 var index = IPython.notebook.get_selected_index();
266 if (index !== 0 && index !== null) {
271 if (index !== 0 && index !== null) {
267 IPython.notebook.select_prev();
272 IPython.notebook.select_prev();
268 IPython.notebook.focus_cell();
273 IPython.notebook.focus_cell();
269 }
274 }
270 return false;
275 return false;
271 }
276 }
272 },
277 },
273 'down' : {
278 'down' : {
274 help : 'select next cell',
279 help : 'select next cell',
275 help_index : 'db',
280 help_index : 'db',
276 handler : function (event) {
281 handler : function (event) {
277 var index = IPython.notebook.get_selected_index();
282 var index = IPython.notebook.get_selected_index();
278 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
283 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
279 IPython.notebook.select_next();
284 IPython.notebook.select_next();
280 IPython.notebook.focus_cell();
285 IPython.notebook.focus_cell();
281 }
286 }
282 return false;
287 return false;
283 }
288 }
284 },
289 },
285 'k' : {
290 'k' : {
286 help : 'select previous cell',
291 help : 'select previous cell',
287 help_index : 'dc',
292 help_index : 'dc',
288 handler : function (event) {
293 handler : function (event) {
289 var index = IPython.notebook.get_selected_index();
294 var index = IPython.notebook.get_selected_index();
290 if (index !== 0 && index !== null) {
295 if (index !== 0 && index !== null) {
291 IPython.notebook.select_prev();
296 IPython.notebook.select_prev();
292 IPython.notebook.focus_cell();
297 IPython.notebook.focus_cell();
293 }
298 }
294 return false;
299 return false;
295 }
300 }
296 },
301 },
297 'j' : {
302 'j' : {
298 help : 'select next cell',
303 help : 'select next cell',
299 help_index : 'dd',
304 help_index : 'dd',
300 handler : function (event) {
305 handler : function (event) {
301 var index = IPython.notebook.get_selected_index();
306 var index = IPython.notebook.get_selected_index();
302 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
307 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
303 IPython.notebook.select_next();
308 IPython.notebook.select_next();
304 IPython.notebook.focus_cell();
309 IPython.notebook.focus_cell();
305 }
310 }
306 return false;
311 return false;
307 }
312 }
308 },
313 },
309 'x' : {
314 'x' : {
310 help : 'cut cell',
315 help : 'cut cell',
311 help_index : 'ee',
316 help_index : 'ee',
312 handler : function (event) {
317 handler : function (event) {
313 IPython.notebook.cut_cell();
318 IPython.notebook.cut_cell();
314 return false;
319 return false;
315 }
320 }
316 },
321 },
317 'c' : {
322 'c' : {
318 help : 'copy cell',
323 help : 'copy cell',
319 help_index : 'ef',
324 help_index : 'ef',
320 handler : function (event) {
325 handler : function (event) {
321 IPython.notebook.copy_cell();
326 IPython.notebook.copy_cell();
322 return false;
327 return false;
323 }
328 }
324 },
329 },
325 'shift+v' : {
330 'shift+v' : {
326 help : 'paste cell above',
331 help : 'paste cell above',
327 help_index : 'eg',
332 help_index : 'eg',
328 handler : function (event) {
333 handler : function (event) {
329 IPython.notebook.paste_cell_above();
334 IPython.notebook.paste_cell_above();
330 return false;
335 return false;
331 }
336 }
332 },
337 },
333 'v' : {
338 'v' : {
334 help : 'paste cell below',
339 help : 'paste cell below',
335 help_index : 'eh',
340 help_index : 'eh',
336 handler : function (event) {
341 handler : function (event) {
337 IPython.notebook.paste_cell_below();
342 IPython.notebook.paste_cell_below();
338 return false;
343 return false;
339 }
344 }
340 },
345 },
341 'd' : {
346 'd' : {
342 help : 'delete cell (press twice)',
347 help : 'delete cell (press twice)',
343 help_index : 'ej',
348 help_index : 'ej',
344 count: 2,
349 count: 2,
345 handler : function (event) {
350 handler : function (event) {
346 IPython.notebook.delete_cell();
351 IPython.notebook.delete_cell();
347 return false;
352 return false;
348 }
353 }
349 },
354 },
350 'a' : {
355 'a' : {
351 help : 'insert cell above',
356 help : 'insert cell above',
352 help_index : 'ec',
357 help_index : 'ec',
353 handler : function (event) {
358 handler : function (event) {
354 IPython.notebook.insert_cell_above('code');
359 IPython.notebook.insert_cell_above('code');
355 IPython.notebook.select_prev();
360 IPython.notebook.select_prev();
356 IPython.notebook.focus_cell();
361 IPython.notebook.focus_cell();
357 return false;
362 return false;
358 }
363 }
359 },
364 },
360 'b' : {
365 'b' : {
361 help : 'insert cell below',
366 help : 'insert cell below',
362 help_index : 'ed',
367 help_index : 'ed',
363 handler : function (event) {
368 handler : function (event) {
364 IPython.notebook.insert_cell_below('code');
369 IPython.notebook.insert_cell_below('code');
365 IPython.notebook.select_next();
370 IPython.notebook.select_next();
366 IPython.notebook.focus_cell();
371 IPython.notebook.focus_cell();
367 return false;
372 return false;
368 }
373 }
369 },
374 },
370 'y' : {
375 'y' : {
371 help : 'to code',
376 help : 'to code',
372 help_index : 'ca',
377 help_index : 'ca',
373 handler : function (event) {
378 handler : function (event) {
374 IPython.notebook.to_code();
379 IPython.notebook.to_code();
375 return false;
380 return false;
376 }
381 }
377 },
382 },
378 'm' : {
383 'm' : {
379 help : 'to markdown',
384 help : 'to markdown',
380 help_index : 'cb',
385 help_index : 'cb',
381 handler : function (event) {
386 handler : function (event) {
382 IPython.notebook.to_markdown();
387 IPython.notebook.to_markdown();
383 return false;
388 return false;
384 }
389 }
385 },
390 },
386 'r' : {
391 'r' : {
387 help : 'to raw',
392 help : 'to raw',
388 help_index : 'cc',
393 help_index : 'cc',
389 handler : function (event) {
394 handler : function (event) {
390 IPython.notebook.to_raw();
395 IPython.notebook.to_raw();
391 return false;
396 return false;
392 }
397 }
393 },
398 },
394 '1' : {
399 '1' : {
395 help : 'to heading 1',
400 help : 'to heading 1',
396 help_index : 'cd',
401 help_index : 'cd',
397 handler : function (event) {
402 handler : function (event) {
398 IPython.notebook.to_heading(undefined, 1);
403 IPython.notebook.to_heading(undefined, 1);
399 return false;
404 return false;
400 }
405 }
401 },
406 },
402 '2' : {
407 '2' : {
403 help : 'to heading 2',
408 help : 'to heading 2',
404 help_index : 'ce',
409 help_index : 'ce',
405 handler : function (event) {
410 handler : function (event) {
406 IPython.notebook.to_heading(undefined, 2);
411 IPython.notebook.to_heading(undefined, 2);
407 return false;
412 return false;
408 }
413 }
409 },
414 },
410 '3' : {
415 '3' : {
411 help : 'to heading 3',
416 help : 'to heading 3',
412 help_index : 'cf',
417 help_index : 'cf',
413 handler : function (event) {
418 handler : function (event) {
414 IPython.notebook.to_heading(undefined, 3);
419 IPython.notebook.to_heading(undefined, 3);
415 return false;
420 return false;
416 }
421 }
417 },
422 },
418 '4' : {
423 '4' : {
419 help : 'to heading 4',
424 help : 'to heading 4',
420 help_index : 'cg',
425 help_index : 'cg',
421 handler : function (event) {
426 handler : function (event) {
422 IPython.notebook.to_heading(undefined, 4);
427 IPython.notebook.to_heading(undefined, 4);
423 return false;
428 return false;
424 }
429 }
425 },
430 },
426 '5' : {
431 '5' : {
427 help : 'to heading 5',
432 help : 'to heading 5',
428 help_index : 'ch',
433 help_index : 'ch',
429 handler : function (event) {
434 handler : function (event) {
430 IPython.notebook.to_heading(undefined, 5);
435 IPython.notebook.to_heading(undefined, 5);
431 return false;
436 return false;
432 }
437 }
433 },
438 },
434 '6' : {
439 '6' : {
435 help : 'to heading 6',
440 help : 'to heading 6',
436 help_index : 'ci',
441 help_index : 'ci',
437 handler : function (event) {
442 handler : function (event) {
438 IPython.notebook.to_heading(undefined, 6);
443 IPython.notebook.to_heading(undefined, 6);
439 return false;
444 return false;
440 }
445 }
441 },
446 },
442 'o' : {
447 'o' : {
443 help : 'toggle output',
448 help : 'toggle output',
444 help_index : 'gb',
449 help_index : 'gb',
445 handler : function (event) {
450 handler : function (event) {
446 IPython.notebook.toggle_output();
451 IPython.notebook.toggle_output();
447 return false;
452 return false;
448 }
453 }
449 },
454 },
450 'shift+o' : {
455 'shift+o' : {
451 help : 'toggle output scrolling',
456 help : 'toggle output scrolling',
452 help_index : 'gc',
457 help_index : 'gc',
453 handler : function (event) {
458 handler : function (event) {
454 IPython.notebook.toggle_output_scroll();
459 IPython.notebook.toggle_output_scroll();
455 return false;
460 return false;
456 }
461 }
457 },
462 },
458 's' : {
463 's' : {
459 help : 'save notebook',
464 help : 'save notebook',
460 help_index : 'fa',
465 help_index : 'fa',
461 handler : function (event) {
466 handler : function (event) {
462 IPython.notebook.save_checkpoint();
467 IPython.notebook.save_checkpoint();
463 return false;
468 return false;
464 }
469 }
465 },
470 },
466 'ctrl+j' : {
471 'ctrl+j' : {
467 help : 'move cell down',
472 help : 'move cell down',
468 help_index : 'eb',
473 help_index : 'eb',
469 handler : function (event) {
474 handler : function (event) {
470 IPython.notebook.move_cell_down();
475 IPython.notebook.move_cell_down();
471 return false;
476 return false;
472 }
477 }
473 },
478 },
474 'ctrl+k' : {
479 'ctrl+k' : {
475 help : 'move cell up',
480 help : 'move cell up',
476 help_index : 'ea',
481 help_index : 'ea',
477 handler : function (event) {
482 handler : function (event) {
478 IPython.notebook.move_cell_up();
483 IPython.notebook.move_cell_up();
479 return false;
484 return false;
480 }
485 }
481 },
486 },
482 'l' : {
487 'l' : {
483 help : 'toggle line numbers',
488 help : 'toggle line numbers',
484 help_index : 'ga',
489 help_index : 'ga',
485 handler : function (event) {
490 handler : function (event) {
486 IPython.notebook.cell_toggle_line_numbers();
491 IPython.notebook.cell_toggle_line_numbers();
487 return false;
492 return false;
488 }
493 }
489 },
494 },
490 'i' : {
495 'i' : {
491 help : 'interrupt kernel (press twice)',
496 help : 'interrupt kernel (press twice)',
492 help_index : 'ha',
497 help_index : 'ha',
493 count: 2,
498 count: 2,
494 handler : function (event) {
499 handler : function (event) {
495 IPython.notebook.kernel.interrupt();
500 IPython.notebook.kernel.interrupt();
496 return false;
501 return false;
497 }
502 }
498 },
503 },
499 '0' : {
504 '0' : {
500 help : 'restart kernel (press twice)',
505 help : 'restart kernel (press twice)',
501 help_index : 'hb',
506 help_index : 'hb',
502 count: 2,
507 count: 2,
503 handler : function (event) {
508 handler : function (event) {
504 IPython.notebook.restart_kernel();
509 IPython.notebook.restart_kernel();
505 return false;
510 return false;
506 }
511 }
507 },
512 },
508 'h' : {
513 'h' : {
509 help : 'keyboard shortcuts',
514 help : 'keyboard shortcuts',
510 help_index : 'ge',
515 help_index : 'ge',
511 handler : function (event) {
516 handler : function (event) {
512 IPython.quick_help.show_keyboard_shortcuts();
517 IPython.quick_help.show_keyboard_shortcuts();
513 return false;
518 return false;
514 }
519 }
515 },
520 },
516 'z' : {
521 'z' : {
517 help : 'undo last delete',
522 help : 'undo last delete',
518 help_index : 'ei',
523 help_index : 'ei',
519 handler : function (event) {
524 handler : function (event) {
520 IPython.notebook.undelete_cell();
525 IPython.notebook.undelete_cell();
521 return false;
526 return false;
522 }
527 }
523 },
528 },
524 'shift+m' : {
529 'shift+m' : {
525 help : 'merge cell below',
530 help : 'merge cell below',
526 help_index : 'ek',
531 help_index : 'ek',
527 handler : function (event) {
532 handler : function (event) {
528 IPython.notebook.merge_cell_below();
533 IPython.notebook.merge_cell_below();
529 return false;
534 return false;
530 }
535 }
531 },
536 },
532 'q' : {
537 'q' : {
533 help : 'close pager',
538 help : 'close pager',
534 help_index : 'gd',
539 help_index : 'gd',
535 handler : function (event) {
540 handler : function (event) {
536 IPython.pager.collapse();
541 IPython.pager.collapse();
537 return false;
542 return false;
538 }
543 }
539 },
544 },
540 };
545 };
541
546
542
547
543 // Shortcut manager class
548 // Shortcut manager class
544
549
545 var ShortcutManager = function (delay) {
550 var ShortcutManager = function (delay) {
546 this._shortcuts = {};
551 this._shortcuts = {};
547 this._counts = {};
552 this._counts = {};
548 this._timers = {};
553 this._timers = {};
549 this.delay = delay || 800; // delay in milliseconds
554 this.delay = delay || 800; // delay in milliseconds
550 };
555 };
551
556
552 ShortcutManager.prototype.help = function () {
557 ShortcutManager.prototype.help = function () {
553 var help = [];
558 var help = [];
554 for (var shortcut in this._shortcuts) {
559 for (var shortcut in this._shortcuts) {
555 var help_string = this._shortcuts[shortcut].help;
560 var help_string = this._shortcuts[shortcut].help;
556 var help_index = this._shortcuts[shortcut].help_index;
561 var help_index = this._shortcuts[shortcut].help_index;
557 if (help_string) {
562 if (help_string) {
558 if (platform === 'MacOS') {
563 if (platform === 'MacOS') {
559 shortcut = shortcut.replace('meta', 'cmd');
564 shortcut = shortcut.replace('meta', 'cmd');
560 }
565 }
561 help.push({
566 help.push({
562 shortcut: shortcut,
567 shortcut: shortcut,
563 help: help_string,
568 help: help_string,
564 help_index: help_index}
569 help_index: help_index}
565 );
570 );
566 }
571 }
567 }
572 }
568 help.sort(function (a, b) {
573 help.sort(function (a, b) {
569 if (a.help_index > b.help_index)
574 if (a.help_index > b.help_index)
570 return 1;
575 return 1;
571 if (a.help_index < b.help_index)
576 if (a.help_index < b.help_index)
572 return -1;
577 return -1;
573 return 0;
578 return 0;
574 });
579 });
575 return help;
580 return help;
576 };
581 };
577
582
578 ShortcutManager.prototype.normalize_key = function (key) {
583 ShortcutManager.prototype.normalize_key = function (key) {
579 return inv_keycodes[keycodes[key]];
584 return inv_keycodes[keycodes[key]];
580 };
585 };
581
586
582 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
587 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
583 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
588 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
584 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
589 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
585 var values = shortcut.split("+");
590 var values = shortcut.split("+");
586 if (values.length === 1) {
591 if (values.length === 1) {
587 return this.normalize_key(values[0]);
592 return this.normalize_key(values[0]);
588 } else {
593 } else {
589 var modifiers = values.slice(0,-1);
594 var modifiers = values.slice(0,-1);
590 var key = this.normalize_key(values[values.length-1]);
595 var key = this.normalize_key(values[values.length-1]);
591 modifiers.sort();
596 modifiers.sort();
592 return modifiers.join('+') + '+' + key;
597 return modifiers.join('+') + '+' + key;
593 }
598 }
594 };
599 };
595
600
596 ShortcutManager.prototype.event_to_shortcut = function (event) {
601 ShortcutManager.prototype.event_to_shortcut = function (event) {
597 // Convert a jQuery keyboard event to a strong based keyboard shortcut
602 // Convert a jQuery keyboard event to a strong based keyboard shortcut
598 var shortcut = '';
603 var shortcut = '';
599 var key = inv_keycodes[event.which];
604 var key = inv_keycodes[event.which];
600 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
605 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
601 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
606 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
602 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
607 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
603 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
608 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
604 shortcut += key;
609 shortcut += key;
605 return shortcut;
610 return shortcut;
606 };
611 };
607
612
608 ShortcutManager.prototype.clear_shortcuts = function () {
613 ShortcutManager.prototype.clear_shortcuts = function () {
609 this._shortcuts = {};
614 this._shortcuts = {};
610 };
615 };
611
616
612 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
617 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
613 if (typeof(data) === 'function') {
618 if (typeof(data) === 'function') {
614 data = {help: '', help_index: '', handler: data};
619 data = {help: '', help_index: '', handler: data};
615 }
620 }
616 data.help_index = data.help_index || '';
621 data.help_index = data.help_index || '';
617 data.help = data.help || '';
622 data.help = data.help || '';
618 data.count = data.count || 1;
623 data.count = data.count || 1;
619 if (data.help_index === '') {
624 if (data.help_index === '') {
620 data.help_index = 'zz';
625 data.help_index = 'zz';
621 }
626 }
622 shortcut = this.normalize_shortcut(shortcut);
627 shortcut = this.normalize_shortcut(shortcut);
623 this._counts[shortcut] = 0;
628 this._counts[shortcut] = 0;
624 this._shortcuts[shortcut] = data;
629 this._shortcuts[shortcut] = data;
625 };
630 };
626
631
627 ShortcutManager.prototype.add_shortcuts = function (data) {
632 ShortcutManager.prototype.add_shortcuts = function (data) {
628 for (var shortcut in data) {
633 for (var shortcut in data) {
629 this.add_shortcut(shortcut, data[shortcut]);
634 this.add_shortcut(shortcut, data[shortcut]);
630 }
635 }
631 };
636 };
632
637
633 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
638 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
634 shortcut = this.normalize_shortcut(shortcut);
639 shortcut = this.normalize_shortcut(shortcut);
635 delete this._counts[shortcut];
640 delete this._counts[shortcut];
636 delete this._shortcuts[shortcut];
641 delete this._shortcuts[shortcut];
637 };
642 };
638
643
639 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
644 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
640 var that = this;
645 var that = this;
641 var c = this._counts;
646 var c = this._counts;
642 var t = this._timers;
647 var t = this._timers;
643 var timer = null;
648 var timer = null;
644 if (c[shortcut] === data.count-1) {
649 if (c[shortcut] === data.count-1) {
645 c[shortcut] = 0;
650 c[shortcut] = 0;
646 timer = t[shortcut];
651 timer = t[shortcut];
647 if (timer) {clearTimeout(timer); delete t[shortcut];}
652 if (timer) {clearTimeout(timer); delete t[shortcut];}
648 return data.handler(event);
653 return data.handler(event);
649 } else {
654 } else {
650 c[shortcut] = c[shortcut] + 1;
655 c[shortcut] = c[shortcut] + 1;
651 timer = setTimeout(function () {
656 timer = setTimeout(function () {
652 c[shortcut] = 0;
657 c[shortcut] = 0;
653 }, that.delay);
658 }, that.delay);
654 t[shortcut] = timer;
659 t[shortcut] = timer;
655 }
660 }
656 return false;
661 return false;
657 };
662 };
658
663
659 ShortcutManager.prototype.call_handler = function (event) {
664 ShortcutManager.prototype.call_handler = function (event) {
660 var shortcut = this.event_to_shortcut(event);
665 var shortcut = this.event_to_shortcut(event);
661 var data = this._shortcuts[shortcut];
666 var data = this._shortcuts[shortcut];
662 if (data) {
667 if (data) {
663 var handler = data.handler;
668 var handler = data.handler;
664 if (handler) {
669 if (handler) {
665 if (data.count === 1) {
670 if (data.count === 1) {
666 return handler(event);
671 return handler(event);
667 } else if (data.count > 1) {
672 } else if (data.count > 1) {
668 return this.count_handler(shortcut, event, data);
673 return this.count_handler(shortcut, event, data);
669 }
674 }
670 }
675 }
671 }
676 }
672 return true;
677 return true;
673 };
678 };
674
679
675
680
676 // Main keyboard manager for the notebook
681 // Main keyboard manager for the notebook
677
682
678 var KeyboardManager = function () {
683 var KeyboardManager = function () {
679 this.mode = 'command';
684 this.mode = 'command';
680 this.enabled = true;
685 this.enabled = true;
681 this.bind_events();
686 this.bind_events();
682 this.command_shortcuts = new ShortcutManager();
687 this.command_shortcuts = new ShortcutManager();
683 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
688 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
684 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
689 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
685 this.edit_shortcuts = new ShortcutManager();
690 this.edit_shortcuts = new ShortcutManager();
686 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
691 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
687 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
692 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
688 };
693 };
689
694
690 KeyboardManager.prototype.bind_events = function () {
695 KeyboardManager.prototype.bind_events = function () {
691 var that = this;
696 var that = this;
692 $(document).keydown(function (event) {
697 $(document).keydown(function (event) {
693 return that.handle_keydown(event);
698 return that.handle_keydown(event);
694 });
699 });
695 };
700 };
696
701
697 KeyboardManager.prototype.handle_keydown = function (event) {
702 KeyboardManager.prototype.handle_keydown = function (event) {
698 var notebook = IPython.notebook;
703 var notebook = IPython.notebook;
699
704
700 if (event.which === keycodes.esc) {
705 if (event.which === keycodes.esc) {
701 // Intercept escape at highest level to avoid closing
706 // Intercept escape at highest level to avoid closing
702 // websocket connection with firefox
707 // websocket connection with firefox
703 event.preventDefault();
708 event.preventDefault();
704 }
709 }
705
710
706 if (!this.enabled) {
711 if (!this.enabled) {
707 if (event.which === keycodes.esc) {
712 if (event.which === keycodes.esc) {
708 // ESC
713 // ESC
709 notebook.command_mode();
714 notebook.command_mode();
710 return false;
715 return false;
711 }
716 }
712 return true;
717 return true;
713 }
718 }
714
719
715 if (this.mode === 'edit') {
720 if (this.mode === 'edit') {
716 return this.edit_shortcuts.call_handler(event);
721 return this.edit_shortcuts.call_handler(event);
717 } else if (this.mode === 'command') {
722 } else if (this.mode === 'command') {
718 return this.command_shortcuts.call_handler(event);
723 return this.command_shortcuts.call_handler(event);
719 }
724 }
720 return true;
725 return true;
721 };
726 };
722
727
723 KeyboardManager.prototype.edit_mode = function () {
728 KeyboardManager.prototype.edit_mode = function () {
724 this.last_mode = this.mode;
729 this.last_mode = this.mode;
725 this.mode = 'edit';
730 this.mode = 'edit';
726 };
731 };
727
732
728 KeyboardManager.prototype.command_mode = function () {
733 KeyboardManager.prototype.command_mode = function () {
729 this.last_mode = this.mode;
734 this.last_mode = this.mode;
730 this.mode = 'command';
735 this.mode = 'command';
731 };
736 };
732
737
733 KeyboardManager.prototype.enable = function () {
738 KeyboardManager.prototype.enable = function () {
734 this.enabled = true;
739 this.enabled = true;
735 };
740 };
736
741
737 KeyboardManager.prototype.disable = function () {
742 KeyboardManager.prototype.disable = function () {
738 this.enabled = false;
743 this.enabled = false;
739 };
744 };
740
745
741 KeyboardManager.prototype.register_events = function (e) {
746 KeyboardManager.prototype.register_events = function (e) {
742 var that = this;
747 var that = this;
743 var handle_focus = function () {
748 var handle_focus = function () {
744 that.disable();
749 that.disable();
745 };
750 };
746 var handle_blur = function () {
751 var handle_blur = function () {
747 that.enable();
752 that.enable();
748 };
753 };
749 e.on('focusin', handle_focus);
754 e.on('focusin', handle_focus);
750 e.on('focusout', handle_blur);
755 e.on('focusout', handle_blur);
751 // TODO: Very strange. The focusout event does not seem fire for the
756 // TODO: Very strange. The focusout event does not seem fire for the
752 // bootstrap textboxes on FF25&26... This works around that by
757 // bootstrap textboxes on FF25&26... This works around that by
753 // registering focus and blur events recursively on all inputs within
758 // registering focus and blur events recursively on all inputs within
754 // registered element.
759 // registered element.
755 e.find('input').blur(handle_blur);
760 e.find('input').blur(handle_blur);
756 e.on('DOMNodeInserted', function (event) {
761 e.on('DOMNodeInserted', function (event) {
757 var target = $(event.target);
762 var target = $(event.target);
758 if (target.is('input')) {
763 if (target.is('input')) {
759 target.blur(handle_blur);
764 target.blur(handle_blur);
760 } else {
765 } else {
761 target.find('input').blur(handle_blur);
766 target.find('input').blur(handle_blur);
762 }
767 }
763 });
768 });
764 // There are times (raw_input) where we remove the element from the DOM before
769 // There are times (raw_input) where we remove the element from the DOM before
765 // focusout is called. In this case we bind to the remove event of jQueryUI,
770 // focusout is called. In this case we bind to the remove event of jQueryUI,
766 // which gets triggered upon removal, iff it is focused at the time.
771 // which gets triggered upon removal, iff it is focused at the time.
767 // is_focused must be used to check for the case where an element within
772 // is_focused must be used to check for the case where an element within
768 // the element being removed is focused.
773 // the element being removed is focused.
769 e.on('remove', function () {
774 e.on('remove', function () {
770 if (IPython.utils.is_focused(e[0])) {
775 if (IPython.utils.is_focused(e[0])) {
771 that.enable();
776 that.enable();
772 }
777 }
773 });
778 });
774 };
779 };
775
780
776
781
777 IPython.keycodes = keycodes;
782 IPython.keycodes = keycodes;
778 IPython.inv_keycodes = inv_keycodes;
783 IPython.inv_keycodes = inv_keycodes;
779 IPython.default_common_shortcuts = default_common_shortcuts;
784 IPython.default_common_shortcuts = default_common_shortcuts;
780 IPython.default_edit_shortcuts = default_edit_shortcuts;
785 IPython.default_edit_shortcuts = default_edit_shortcuts;
781 IPython.default_command_shortcuts = default_command_shortcuts;
786 IPython.default_command_shortcuts = default_command_shortcuts;
782 IPython.ShortcutManager = ShortcutManager;
787 IPython.ShortcutManager = ShortcutManager;
783 IPython.KeyboardManager = KeyboardManager;
788 IPython.KeyboardManager = KeyboardManager;
784
789
785 return IPython;
790 return IPython;
786
791
787 }(IPython));
792 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now