##// END OF EJS Templates
go to appropriate line when coming from another cell...
Paul Ivanov -
Show More
@@ -1,606 +1,614 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Keyboard management
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var browser = IPython.utils.browser[0];
16 16 var platform = IPython.utils.platform;
17 17
18 18 // Default keyboard shortcuts
19 19
20 20 var default_common_shortcuts = {
21 21 'shift' : {
22 22 help : '',
23 23 help_index : '',
24 24 handler : function (event) {
25 25 // ignore shift keydown
26 26 return true;
27 27 }
28 28 },
29 29 'shift+enter' : {
30 30 help : 'run cell, select below',
31 31 help_index : 'ba',
32 32 handler : function (event) {
33 33 IPython.notebook.execute_cell_and_select_below();
34 34 return false;
35 35 }
36 36 },
37 37 'ctrl+enter' : {
38 38 help : 'run cell',
39 39 help_index : 'bb',
40 40 handler : function (event) {
41 41 IPython.notebook.execute_cell();
42 42 return false;
43 43 }
44 44 },
45 45 'alt+enter' : {
46 46 help : 'run cell, insert below',
47 47 help_index : 'bc',
48 48 handler : function (event) {
49 49 IPython.notebook.execute_cell_and_insert_below();
50 50 return false;
51 51 }
52 52 }
53 53 };
54 54
55 55 if (platform === 'MacOS') {
56 56 default_common_shortcuts['cmd+s'] =
57 57 {
58 58 help : 'save notebook',
59 59 help_index : 'fb',
60 60 handler : function (event) {
61 61 IPython.notebook.save_checkpoint();
62 62 event.preventDefault();
63 63 return false;
64 64 }
65 65 };
66 66 } else {
67 67 default_common_shortcuts['ctrl+s'] =
68 68 {
69 69 help : 'save notebook',
70 70 help_index : 'fb',
71 71 handler : function (event) {
72 72 IPython.notebook.save_checkpoint();
73 73 event.preventDefault();
74 74 return false;
75 75 }
76 76 };
77 77 }
78 78
79 79 // Edit mode defaults
80 80
81 81 var default_edit_shortcuts = {
82 82 'esc' : {
83 83 help : 'command mode',
84 84 help_index : 'aa',
85 85 handler : function (event) {
86 86 IPython.notebook.command_mode();
87 87 return false;
88 88 }
89 89 },
90 90 'ctrl+m' : {
91 91 help : 'command mode',
92 92 help_index : 'ab',
93 93 handler : function (event) {
94 94 IPython.notebook.command_mode();
95 95 return false;
96 96 }
97 97 },
98 98 'up' : {
99 99 help : '',
100 100 help_index : '',
101 101 handler : function (event) {
102 102 var index = IPython.notebook.get_selected_index();
103 103 if (index !== null && index !== 0) {
104 104 var cell = IPython.notebook.get_cell(index);
105 105 if (cell && cell.at_top()) {
106 106 event.preventDefault();
107 107 IPython.notebook.command_mode();
108 108 IPython.notebook.select_prev();
109 109 IPython.notebook.edit_mode();
110 var cm = IPython.notebook.get_selected_cell().code_mirror;
111 var prev_cursor = cell.code_mirror.getCursor();
112 cm.setCursor(cm.lastLine(), prev_cursor.ch)
110 113 return false;
111 114 } else if (cell) {
112 115 var cm = cell.code_mirror;
113 116 var cursor = cm.getCursor();
114 117 cursor.line -= 1;
115 118 cm.setCursor(cursor);
119 return false;
116 120 }
117 121 }
118 122 }
119 123 },
120 124 'down' : {
121 125 help : '',
122 126 help_index : '',
123 127 handler : function (event) {
124 128 var index = IPython.notebook.get_selected_index();
125 129 if (index !== null && index !== (IPython.notebook.ncells()-1)) {
126 130 var cell = IPython.notebook.get_cell(index);
127 131 if (cell && cell.at_bottom()) {
128 132 event.preventDefault();
129 133 IPython.notebook.command_mode();
130 134 IPython.notebook.select_next();
131 135 IPython.notebook.edit_mode();
136 var cm = IPython.notebook.get_selected_cell().code_mirror;
137 var prev_cursor = cell.code_mirror.getCursor();
138 cm.setCursor(0, prev_cursor.ch);
132 139 return false;
133 140 } else if (cell) {
134 141 var cm = cell.code_mirror;
135 142 var cursor = cm.getCursor();
136 143 cursor.line += 1;
137 144 cm.setCursor(cursor);
145 return false;
138 146 }
139 147 }
140 148 }
141 149 },
142 150 'alt+-' : {
143 151 help : 'split cell',
144 152 help_index : 'ea',
145 153 handler : function (event) {
146 154 IPython.notebook.split_cell();
147 155 return false;
148 156 }
149 157 },
150 158 'alt+subtract' : {
151 159 help : '',
152 160 help_index : 'eb',
153 161 handler : function (event) {
154 162 IPython.notebook.split_cell();
155 163 return false;
156 164 }
157 165 },
158 166 'tab' : {
159 167 help : 'indent or complete',
160 168 help_index : 'ec',
161 169 },
162 170 'shift+tab' : {
163 171 help : 'tooltip',
164 172 help_index : 'ed',
165 173 },
166 174 };
167 175
168 176 if (platform === 'MacOS') {
169 177 default_edit_shortcuts['cmd+/'] =
170 178 {
171 179 help : 'toggle comment',
172 180 help_index : 'ee'
173 181 };
174 182 default_edit_shortcuts['cmd+]'] =
175 183 {
176 184 help : 'indent',
177 185 help_index : 'ef'
178 186 };
179 187 default_edit_shortcuts['cmd+['] =
180 188 {
181 189 help : 'dedent',
182 190 help_index : 'eg'
183 191 };
184 192 } else {
185 193 default_edit_shortcuts['ctrl+/'] =
186 194 {
187 195 help : 'toggle comment',
188 196 help_index : 'ee'
189 197 };
190 198 default_edit_shortcuts['ctrl+]'] =
191 199 {
192 200 help : 'indent',
193 201 help_index : 'ef'
194 202 };
195 203 default_edit_shortcuts['ctrl+['] =
196 204 {
197 205 help : 'dedent',
198 206 help_index : 'eg'
199 207 };
200 208 }
201 209
202 210 // Command mode defaults
203 211
204 212 var default_command_shortcuts = {
205 213 'enter' : {
206 214 help : 'edit mode',
207 215 help_index : 'aa',
208 216 handler : function (event) {
209 217 IPython.notebook.edit_mode();
210 218 return false;
211 219 }
212 220 },
213 221 'up' : {
214 222 help : 'select previous cell',
215 223 help_index : 'da',
216 224 handler : function (event) {
217 225 var index = IPython.notebook.get_selected_index();
218 226 if (index !== 0 && index !== null) {
219 227 IPython.notebook.select_prev();
220 228 IPython.notebook.focus_cell();
221 229 }
222 230 return false;
223 231 }
224 232 },
225 233 'down' : {
226 234 help : 'select next cell',
227 235 help_index : 'db',
228 236 handler : function (event) {
229 237 var index = IPython.notebook.get_selected_index();
230 238 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
231 239 IPython.notebook.select_next();
232 240 IPython.notebook.focus_cell();
233 241 }
234 242 return false;
235 243 }
236 244 },
237 245 'k' : {
238 246 help : 'select previous cell',
239 247 help_index : 'dc',
240 248 handler : function (event) {
241 249 var index = IPython.notebook.get_selected_index();
242 250 if (index !== 0 && index !== null) {
243 251 IPython.notebook.select_prev();
244 252 IPython.notebook.focus_cell();
245 253 }
246 254 return false;
247 255 }
248 256 },
249 257 'j' : {
250 258 help : 'select next cell',
251 259 help_index : 'dd',
252 260 handler : function (event) {
253 261 var index = IPython.notebook.get_selected_index();
254 262 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
255 263 IPython.notebook.select_next();
256 264 IPython.notebook.focus_cell();
257 265 }
258 266 return false;
259 267 }
260 268 },
261 269 'x' : {
262 270 help : 'cut cell',
263 271 help_index : 'ee',
264 272 handler : function (event) {
265 273 IPython.notebook.cut_cell();
266 274 return false;
267 275 }
268 276 },
269 277 'c' : {
270 278 help : 'copy cell',
271 279 help_index : 'ef',
272 280 handler : function (event) {
273 281 IPython.notebook.copy_cell();
274 282 return false;
275 283 }
276 284 },
277 285 'shift+v' : {
278 286 help : 'paste cell above',
279 287 help_index : 'eg',
280 288 handler : function (event) {
281 289 IPython.notebook.paste_cell_above();
282 290 return false;
283 291 }
284 292 },
285 293 'v' : {
286 294 help : 'paste cell below',
287 295 help_index : 'eh',
288 296 handler : function (event) {
289 297 IPython.notebook.paste_cell_below();
290 298 return false;
291 299 }
292 300 },
293 301 'd' : {
294 302 help : 'delete cell (press twice)',
295 303 help_index : 'ej',
296 304 count: 2,
297 305 handler : function (event) {
298 306 IPython.notebook.delete_cell();
299 307 return false;
300 308 }
301 309 },
302 310 'a' : {
303 311 help : 'insert cell above',
304 312 help_index : 'ec',
305 313 handler : function (event) {
306 314 IPython.notebook.insert_cell_above('code');
307 315 IPython.notebook.select_prev();
308 316 IPython.notebook.focus_cell();
309 317 return false;
310 318 }
311 319 },
312 320 'b' : {
313 321 help : 'insert cell below',
314 322 help_index : 'ed',
315 323 handler : function (event) {
316 324 IPython.notebook.insert_cell_below('code');
317 325 IPython.notebook.select_next();
318 326 IPython.notebook.focus_cell();
319 327 return false;
320 328 }
321 329 },
322 330 'y' : {
323 331 help : 'to code',
324 332 help_index : 'ca',
325 333 handler : function (event) {
326 334 IPython.notebook.to_code();
327 335 return false;
328 336 }
329 337 },
330 338 'm' : {
331 339 help : 'to markdown',
332 340 help_index : 'cb',
333 341 handler : function (event) {
334 342 IPython.notebook.to_markdown();
335 343 return false;
336 344 }
337 345 },
338 346 'r' : {
339 347 help : 'to raw',
340 348 help_index : 'cc',
341 349 handler : function (event) {
342 350 IPython.notebook.to_raw();
343 351 return false;
344 352 }
345 353 },
346 354 '1' : {
347 355 help : 'to heading 1',
348 356 help_index : 'cd',
349 357 handler : function (event) {
350 358 IPython.notebook.to_heading(undefined, 1);
351 359 return false;
352 360 }
353 361 },
354 362 '2' : {
355 363 help : 'to heading 2',
356 364 help_index : 'ce',
357 365 handler : function (event) {
358 366 IPython.notebook.to_heading(undefined, 2);
359 367 return false;
360 368 }
361 369 },
362 370 '3' : {
363 371 help : 'to heading 3',
364 372 help_index : 'cf',
365 373 handler : function (event) {
366 374 IPython.notebook.to_heading(undefined, 3);
367 375 return false;
368 376 }
369 377 },
370 378 '4' : {
371 379 help : 'to heading 4',
372 380 help_index : 'cg',
373 381 handler : function (event) {
374 382 IPython.notebook.to_heading(undefined, 4);
375 383 return false;
376 384 }
377 385 },
378 386 '5' : {
379 387 help : 'to heading 5',
380 388 help_index : 'ch',
381 389 handler : function (event) {
382 390 IPython.notebook.to_heading(undefined, 5);
383 391 return false;
384 392 }
385 393 },
386 394 '6' : {
387 395 help : 'to heading 6',
388 396 help_index : 'ci',
389 397 handler : function (event) {
390 398 IPython.notebook.to_heading(undefined, 6);
391 399 return false;
392 400 }
393 401 },
394 402 'o' : {
395 403 help : 'toggle output',
396 404 help_index : 'gb',
397 405 handler : function (event) {
398 406 IPython.notebook.toggle_output();
399 407 return false;
400 408 }
401 409 },
402 410 'shift+o' : {
403 411 help : 'toggle output scrolling',
404 412 help_index : 'gc',
405 413 handler : function (event) {
406 414 IPython.notebook.toggle_output_scroll();
407 415 return false;
408 416 }
409 417 },
410 418 's' : {
411 419 help : 'save notebook',
412 420 help_index : 'fa',
413 421 handler : function (event) {
414 422 IPython.notebook.save_checkpoint();
415 423 return false;
416 424 }
417 425 },
418 426 'ctrl+j' : {
419 427 help : 'move cell down',
420 428 help_index : 'eb',
421 429 handler : function (event) {
422 430 IPython.notebook.move_cell_down();
423 431 return false;
424 432 }
425 433 },
426 434 'ctrl+k' : {
427 435 help : 'move cell up',
428 436 help_index : 'ea',
429 437 handler : function (event) {
430 438 IPython.notebook.move_cell_up();
431 439 return false;
432 440 }
433 441 },
434 442 'l' : {
435 443 help : 'toggle line numbers',
436 444 help_index : 'ga',
437 445 handler : function (event) {
438 446 IPython.notebook.cell_toggle_line_numbers();
439 447 return false;
440 448 }
441 449 },
442 450 'i' : {
443 451 help : 'interrupt kernel (press twice)',
444 452 help_index : 'ha',
445 453 count: 2,
446 454 handler : function (event) {
447 455 IPython.notebook.kernel.interrupt();
448 456 return false;
449 457 }
450 458 },
451 459 '0' : {
452 460 help : 'restart kernel (press twice)',
453 461 help_index : 'hb',
454 462 count: 2,
455 463 handler : function (event) {
456 464 IPython.notebook.restart_kernel();
457 465 return false;
458 466 }
459 467 },
460 468 'h' : {
461 469 help : 'keyboard shortcuts',
462 470 help_index : 'ge',
463 471 handler : function (event) {
464 472 IPython.quick_help.show_keyboard_shortcuts();
465 473 return false;
466 474 }
467 475 },
468 476 'z' : {
469 477 help : 'undo last delete',
470 478 help_index : 'ei',
471 479 handler : function (event) {
472 480 IPython.notebook.undelete_cell();
473 481 return false;
474 482 }
475 483 },
476 484 'shift+m' : {
477 485 help : 'merge cell below',
478 486 help_index : 'ek',
479 487 handler : function (event) {
480 488 IPython.notebook.merge_cell_below();
481 489 return false;
482 490 }
483 491 },
484 492 'q' : {
485 493 help : 'close pager',
486 494 help_index : 'gd',
487 495 handler : function (event) {
488 496 IPython.pager.collapse();
489 497 return false;
490 498 }
491 499 },
492 500 };
493 501
494 502
495 503 // Main keyboard manager for the notebook
496 504
497 505 var ShortcutManager = IPython.keyboard.ShortcutManager;
498 506 var keycodes = IPython.keyboard.keycodes;
499 507
500 508 var KeyboardManager = function () {
501 509 this.mode = 'command';
502 510 this.enabled = true;
503 511 this.bind_events();
504 512 this.command_shortcuts = new ShortcutManager();
505 513 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
506 514 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
507 515 this.edit_shortcuts = new ShortcutManager();
508 516 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
509 517 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
510 518 };
511 519
512 520 KeyboardManager.prototype.bind_events = function () {
513 521 var that = this;
514 522 $(document).keydown(function (event) {
515 523 return that.handle_keydown(event);
516 524 });
517 525 };
518 526
519 527 KeyboardManager.prototype.handle_keydown = function (event) {
520 528 var notebook = IPython.notebook;
521 529
522 530 if (event.which === keycodes.esc) {
523 531 // Intercept escape at highest level to avoid closing
524 532 // websocket connection with firefox
525 533 event.preventDefault();
526 534 }
527 535
528 536 if (!this.enabled) {
529 537 if (event.which === keycodes.esc) {
530 538 // ESC
531 539 notebook.command_mode();
532 540 return false;
533 541 }
534 542 return true;
535 543 }
536 544
537 545 if (this.mode === 'edit') {
538 546 return this.edit_shortcuts.call_handler(event);
539 547 } else if (this.mode === 'command') {
540 548 return this.command_shortcuts.call_handler(event);
541 549 }
542 550 return true;
543 551 };
544 552
545 553 KeyboardManager.prototype.edit_mode = function () {
546 554 this.last_mode = this.mode;
547 555 this.mode = 'edit';
548 556 };
549 557
550 558 KeyboardManager.prototype.command_mode = function () {
551 559 this.last_mode = this.mode;
552 560 this.mode = 'command';
553 561 };
554 562
555 563 KeyboardManager.prototype.enable = function () {
556 564 this.enabled = true;
557 565 };
558 566
559 567 KeyboardManager.prototype.disable = function () {
560 568 this.enabled = false;
561 569 };
562 570
563 571 KeyboardManager.prototype.register_events = function (e) {
564 572 var that = this;
565 573 var handle_focus = function () {
566 574 that.disable();
567 575 };
568 576 var handle_blur = function () {
569 577 that.enable();
570 578 };
571 579 e.on('focusin', handle_focus);
572 580 e.on('focusout', handle_blur);
573 581 // TODO: Very strange. The focusout event does not seem fire for the
574 582 // bootstrap textboxes on FF25&26... This works around that by
575 583 // registering focus and blur events recursively on all inputs within
576 584 // registered element.
577 585 e.find('input').blur(handle_blur);
578 586 e.on('DOMNodeInserted', function (event) {
579 587 var target = $(event.target);
580 588 if (target.is('input')) {
581 589 target.blur(handle_blur);
582 590 } else {
583 591 target.find('input').blur(handle_blur);
584 592 }
585 593 });
586 594 // There are times (raw_input) where we remove the element from the DOM before
587 595 // focusout is called. In this case we bind to the remove event of jQueryUI,
588 596 // which gets triggered upon removal, iff it is focused at the time.
589 597 // is_focused must be used to check for the case where an element within
590 598 // the element being removed is focused.
591 599 e.on('remove', function () {
592 600 if (IPython.utils.is_focused(e[0])) {
593 601 that.enable();
594 602 }
595 603 });
596 604 };
597 605
598 606
599 607 IPython.default_common_shortcuts = default_common_shortcuts;
600 608 IPython.default_edit_shortcuts = default_edit_shortcuts;
601 609 IPython.default_command_shortcuts = default_command_shortcuts;
602 610 IPython.KeyboardManager = KeyboardManager;
603 611
604 612 return IPython;
605 613
606 614 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now