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