##// END OF EJS Templates
Added new short key for cell execution
Zoltán Vörös -
Show More
@@ -1,1287 +1,1291 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-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 // Notebook
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var utils = IPython.utils;
15 15 var key = IPython.utils.keycodes;
16 16
17 17 var Notebook = function (selector) {
18 18 this.read_only = IPython.read_only;
19 19 this.element = $(selector);
20 20 this.element.scroll();
21 21 this.element.data("notebook", this);
22 22 this.next_prompt_number = 1;
23 23 this.kernel = null;
24 24 this.clipboard = null;
25 25 this.paste_enabled = false;
26 26 this.dirty = false;
27 27 this.metadata = {};
28 28 // single worksheet for now
29 29 this.worksheet_metadata = {};
30 30 this.control_key_active = false;
31 31 this.notebook_id = null;
32 32 this.notebook_name = null;
33 33 this.notebook_name_blacklist_re = /[\/\\:]/;
34 34 this.nbformat = 3 // Increment this when changing the nbformat
35 35 this.nbformat_minor = 0 // Increment this when changing the nbformat
36 36 this.style();
37 37 this.create_elements();
38 38 this.bind_events();
39 39 };
40 40
41 41
42 42 Notebook.prototype.style = function () {
43 43 $('div#notebook').addClass('border-box-sizing');
44 44 };
45 45
46 46
47 47 Notebook.prototype.create_elements = function () {
48 48 // We add this end_space div to the end of the notebook div to:
49 49 // i) provide a margin between the last cell and the end of the notebook
50 50 // ii) to prevent the div from scrolling up when the last cell is being
51 51 // edited, but is too low on the page, which browsers will do automatically.
52 52 var that = this;
53 53 var end_space = $('<div/>').addClass('end_space').height("30%");
54 54 end_space.dblclick(function (e) {
55 55 if (that.read_only) return;
56 56 var ncells = that.ncells();
57 57 that.insert_cell_below('code',ncells-1);
58 58 });
59 59 this.element.append(end_space);
60 60 $('div#notebook').addClass('border-box-sizing');
61 61 };
62 62
63 63
64 64 Notebook.prototype.bind_events = function () {
65 65 var that = this;
66 66
67 67 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
68 68 var index = that.find_cell_index(data.cell);
69 69 var new_cell = that.insert_cell_below('code',index);
70 70 new_cell.set_text(data.text);
71 71 that.dirty = true;
72 72 });
73 73
74 74 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
75 75 that.dirty = data.value;
76 76 });
77 77
78 78 $([IPython.events]).on('select.Cell', function (event, data) {
79 79 var index = that.find_cell_index(data.cell);
80 80 that.select(index);
81 81 });
82 82
83 83
84 84 $(document).keydown(function (event) {
85 85 // console.log(event);
86 86 if (that.read_only) return true;
87 87
88 88 // Save (CTRL+S) or (AppleKey+S)
89 89 //metaKey = applekey on mac
90 90 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
91 91 that.save_notebook();
92 92 event.preventDefault();
93 93 return false;
94 94 } else if (event.which === key.ESC) {
95 95 // Intercept escape at highest level to avoid closing
96 96 // websocket connection with firefox
97 97 event.preventDefault();
98 98 } else if (event.which === key.SHIFT) {
99 99 // ignore shift keydown
100 100 return true;
101 101 }
102 102 if (event.which === key.UPARROW && !event.shiftKey) {
103 103 var cell = that.get_selected_cell();
104 104 if (cell.at_top()) {
105 105 event.preventDefault();
106 106 that.select_prev();
107 107 };
108 108 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
109 109 var cell = that.get_selected_cell();
110 110 if (cell.at_bottom()) {
111 111 event.preventDefault();
112 112 that.select_next();
113 113 };
114 114 } else if (event.which === key.ENTER && event.shiftKey) {
115 115 that.execute_selected_cell();
116 116 return false;
117 } else if (event.which === key.ENTER && event.altKey) {
118 that.execute_selected_cell();
119 that.insert_cell_above('code');
120 return false;
117 121 } else if (event.which === key.ENTER && event.ctrlKey) {
118 122 that.execute_selected_cell({terminal:true});
119 123 return false;
120 124 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
121 125 that.control_key_active = true;
122 126 return false;
123 127 } else if (event.which === 88 && that.control_key_active) {
124 128 // Cut selected cell = x
125 129 that.cut_cell();
126 130 that.control_key_active = false;
127 131 return false;
128 132 } else if (event.which === 67 && that.control_key_active) {
129 133 // Copy selected cell = c
130 134 that.copy_cell();
131 135 that.control_key_active = false;
132 136 return false;
133 137 } else if (event.which === 86 && that.control_key_active) {
134 138 // Paste selected cell = v
135 139 that.paste_cell();
136 140 that.control_key_active = false;
137 141 return false;
138 142 } else if (event.which === 68 && that.control_key_active) {
139 143 // Delete selected cell = d
140 144 that.delete_cell();
141 145 that.control_key_active = false;
142 146 return false;
143 147 } else if (event.which === 65 && that.control_key_active) {
144 148 // Insert code cell above selected = a
145 149 that.insert_cell_above('code');
146 150 that.control_key_active = false;
147 151 return false;
148 152 } else if (event.which === 66 && that.control_key_active) {
149 153 // Insert code cell below selected = b
150 154 that.insert_cell_below('code');
151 155 that.control_key_active = false;
152 156 return false;
153 157 } else if (event.which === 89 && that.control_key_active) {
154 158 // To code = y
155 159 that.to_code();
156 160 that.control_key_active = false;
157 161 return false;
158 162 } else if (event.which === 77 && that.control_key_active) {
159 163 // To markdown = m
160 164 that.to_markdown();
161 165 that.control_key_active = false;
162 166 return false;
163 167 } else if (event.which === 84 && that.control_key_active) {
164 168 // To Raw = t
165 169 that.to_raw();
166 170 that.control_key_active = false;
167 171 return false;
168 172 } else if (event.which === 49 && that.control_key_active) {
169 173 // To Heading 1 = 1
170 174 that.to_heading(undefined, 1);
171 175 that.control_key_active = false;
172 176 return false;
173 177 } else if (event.which === 50 && that.control_key_active) {
174 178 // To Heading 2 = 2
175 179 that.to_heading(undefined, 2);
176 180 that.control_key_active = false;
177 181 return false;
178 182 } else if (event.which === 51 && that.control_key_active) {
179 183 // To Heading 3 = 3
180 184 that.to_heading(undefined, 3);
181 185 that.control_key_active = false;
182 186 return false;
183 187 } else if (event.which === 52 && that.control_key_active) {
184 188 // To Heading 4 = 4
185 189 that.to_heading(undefined, 4);
186 190 that.control_key_active = false;
187 191 return false;
188 192 } else if (event.which === 53 && that.control_key_active) {
189 193 // To Heading 5 = 5
190 194 that.to_heading(undefined, 5);
191 195 that.control_key_active = false;
192 196 return false;
193 197 } else if (event.which === 54 && that.control_key_active) {
194 198 // To Heading 6 = 6
195 199 that.to_heading(undefined, 6);
196 200 that.control_key_active = false;
197 201 return false;
198 202 } else if (event.which === 79 && that.control_key_active) {
199 203 // Toggle output = o
200 204 if (event.shiftKey){
201 205 that.toggle_output_scroll();
202 206 } else {
203 207 that.toggle_output();
204 208 }
205 209 that.control_key_active = false;
206 210 return false;
207 211 } else if (event.which === 83 && that.control_key_active) {
208 212 // Save notebook = s
209 213 that.save_notebook();
210 214 that.control_key_active = false;
211 215 return false;
212 216 } else if (event.which === 74 && that.control_key_active) {
213 217 // Move cell down = j
214 218 that.move_cell_down();
215 219 that.control_key_active = false;
216 220 return false;
217 221 } else if (event.which === 75 && that.control_key_active) {
218 222 // Move cell up = k
219 223 that.move_cell_up();
220 224 that.control_key_active = false;
221 225 return false;
222 226 } else if (event.which === 80 && that.control_key_active) {
223 227 // Select previous = p
224 228 that.select_prev();
225 229 that.control_key_active = false;
226 230 return false;
227 231 } else if (event.which === 78 && that.control_key_active) {
228 232 // Select next = n
229 233 that.select_next();
230 234 that.control_key_active = false;
231 235 return false;
232 236 } else if (event.which === 76 && that.control_key_active) {
233 237 // Toggle line numbers = l
234 238 that.cell_toggle_line_numbers();
235 239 that.control_key_active = false;
236 240 return false;
237 241 } else if (event.which === 73 && that.control_key_active) {
238 242 // Interrupt kernel = i
239 243 that.kernel.interrupt();
240 244 that.control_key_active = false;
241 245 return false;
242 246 } else if (event.which === 190 && that.control_key_active) {
243 247 // Restart kernel = . # matches qt console
244 248 that.restart_kernel();
245 249 that.control_key_active = false;
246 250 return false;
247 251 } else if (event.which === 72 && that.control_key_active) {
248 252 // Show keyboard shortcuts = h
249 253 IPython.quick_help.show_keyboard_shortcuts();
250 254 that.control_key_active = false;
251 255 return false;
252 256 } else if (that.control_key_active) {
253 257 that.control_key_active = false;
254 258 return true;
255 259 };
256 260 return true;
257 261 });
258 262
259 263 var collapse_time = function(time){
260 264 var app_height = $('div#main_app').height(); // content height
261 265 var splitter_height = $('div#pager_splitter').outerHeight(true);
262 266 var new_height = app_height - splitter_height;
263 267 that.element.animate({height : new_height + 'px'}, time);
264 268 }
265 269
266 270 this.element.bind('collapse_pager', function (event,extrap) {
267 271 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
268 272 collapse_time(time);
269 273 });
270 274
271 275 var expand_time = function(time) {
272 276 var app_height = $('div#main_app').height(); // content height
273 277 var splitter_height = $('div#pager_splitter').outerHeight(true);
274 278 var pager_height = $('div#pager').outerHeight(true);
275 279 var new_height = app_height - pager_height - splitter_height;
276 280 that.element.animate({height : new_height + 'px'}, time);
277 281 }
278 282
279 283 this.element.bind('expand_pager', function (event, extrap) {
280 284 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
281 285 expand_time(time);
282 286 });
283 287
284 288 $(window).bind('beforeunload', function () {
285 289 // TODO: Make killing the kernel configurable.
286 290 var kill_kernel = false;
287 291 if (kill_kernel) {
288 292 that.kernel.kill();
289 293 }
290 294 if (that.dirty && ! that.read_only) {
291 295 return "You have unsaved changes that will be lost if you leave this page.";
292 296 };
293 297 // Null is the *only* return value that will make the browser not
294 298 // pop up the "don't leave" dialog.
295 299 return null;
296 300 });
297 301 };
298 302
299 303
300 304 Notebook.prototype.scroll_to_bottom = function () {
301 305 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
302 306 };
303 307
304 308
305 309 Notebook.prototype.scroll_to_top = function () {
306 310 this.element.animate({scrollTop:0}, 0);
307 311 };
308 312
309 313
310 314 // Cell indexing, retrieval, etc.
311 315
312 316 Notebook.prototype.get_cell_elements = function () {
313 317 return this.element.children("div.cell");
314 318 };
315 319
316 320
317 321 Notebook.prototype.get_cell_element = function (index) {
318 322 var result = null;
319 323 var e = this.get_cell_elements().eq(index);
320 324 if (e.length !== 0) {
321 325 result = e;
322 326 }
323 327 return result;
324 328 };
325 329
326 330
327 331 Notebook.prototype.ncells = function (cell) {
328 332 return this.get_cell_elements().length;
329 333 };
330 334
331 335
332 336 // TODO: we are often calling cells as cells()[i], which we should optimize
333 337 // to cells(i) or a new method.
334 338 Notebook.prototype.get_cells = function () {
335 339 return this.get_cell_elements().toArray().map(function (e) {
336 340 return $(e).data("cell");
337 341 });
338 342 };
339 343
340 344
341 345 Notebook.prototype.get_cell = function (index) {
342 346 var result = null;
343 347 var ce = this.get_cell_element(index);
344 348 if (ce !== null) {
345 349 result = ce.data('cell');
346 350 }
347 351 return result;
348 352 }
349 353
350 354
351 355 Notebook.prototype.get_next_cell = function (cell) {
352 356 var result = null;
353 357 var index = this.find_cell_index(cell);
354 358 if (index !== null && index < this.ncells()) {
355 359 result = this.get_cell(index+1);
356 360 }
357 361 return result;
358 362 }
359 363
360 364
361 365 Notebook.prototype.get_prev_cell = function (cell) {
362 366 var result = null;
363 367 var index = this.find_cell_index(cell);
364 368 if (index !== null && index > 1) {
365 369 result = this.get_cell(index-1);
366 370 }
367 371 return result;
368 372 }
369 373
370 374 Notebook.prototype.find_cell_index = function (cell) {
371 375 var result = null;
372 376 this.get_cell_elements().filter(function (index) {
373 377 if ($(this).data("cell") === cell) {
374 378 result = index;
375 379 };
376 380 });
377 381 return result;
378 382 };
379 383
380 384
381 385 Notebook.prototype.index_or_selected = function (index) {
382 386 var i;
383 387 if (index === undefined || index === null) {
384 388 i = this.get_selected_index();
385 389 if (i === null) {
386 390 i = 0;
387 391 }
388 392 } else {
389 393 i = index;
390 394 }
391 395 return i;
392 396 };
393 397
394 398
395 399 Notebook.prototype.get_selected_cell = function () {
396 400 var index = this.get_selected_index();
397 401 return this.get_cell(index);
398 402 };
399 403
400 404
401 405 Notebook.prototype.is_valid_cell_index = function (index) {
402 406 if (index !== null && index >= 0 && index < this.ncells()) {
403 407 return true;
404 408 } else {
405 409 return false;
406 410 };
407 411 }
408 412
409 413 Notebook.prototype.get_selected_index = function () {
410 414 var result = null;
411 415 this.get_cell_elements().filter(function (index) {
412 416 if ($(this).data("cell").selected === true) {
413 417 result = index;
414 418 };
415 419 });
416 420 return result;
417 421 };
418 422
419 423
420 424 // Cell selection.
421 425
422 426 Notebook.prototype.select = function (index) {
423 427 if (index !== undefined && index >= 0 && index < this.ncells()) {
424 428 sindex = this.get_selected_index()
425 429 if (sindex !== null && index !== sindex) {
426 430 this.get_cell(sindex).unselect();
427 431 };
428 432 var cell = this.get_cell(index)
429 433 cell.select();
430 434 if (cell.cell_type === 'heading') {
431 435 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
432 436 {'cell_type':cell.cell_type,level:cell.level}
433 437 );
434 438 } else {
435 439 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
436 440 {'cell_type':cell.cell_type}
437 441 );
438 442 };
439 443 };
440 444 return this;
441 445 };
442 446
443 447
444 448 Notebook.prototype.select_next = function () {
445 449 var index = this.get_selected_index();
446 450 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
447 451 this.select(index+1);
448 452 };
449 453 return this;
450 454 };
451 455
452 456
453 457 Notebook.prototype.select_prev = function () {
454 458 var index = this.get_selected_index();
455 459 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
456 460 this.select(index-1);
457 461 };
458 462 return this;
459 463 };
460 464
461 465
462 466 // Cell movement
463 467
464 468 Notebook.prototype.move_cell_up = function (index) {
465 469 var i = this.index_or_selected();
466 470 if (i !== null && i < this.ncells() && i > 0) {
467 471 var pivot = this.get_cell_element(i-1);
468 472 var tomove = this.get_cell_element(i);
469 473 if (pivot !== null && tomove !== null) {
470 474 tomove.detach();
471 475 pivot.before(tomove);
472 476 this.select(i-1);
473 477 };
474 478 };
475 479 this.dirty = true;
476 480 return this;
477 481 };
478 482
479 483
480 484 Notebook.prototype.move_cell_down = function (index) {
481 485 var i = this.index_or_selected();
482 486 if (i !== null && i < (this.ncells()-1) && i >= 0) {
483 487 var pivot = this.get_cell_element(i+1);
484 488 var tomove = this.get_cell_element(i);
485 489 if (pivot !== null && tomove !== null) {
486 490 tomove.detach();
487 491 pivot.after(tomove);
488 492 this.select(i+1);
489 493 };
490 494 };
491 495 this.dirty = true;
492 496 return this;
493 497 };
494 498
495 499
496 500 Notebook.prototype.sort_cells = function () {
497 501 // This is not working right now. Calling this will actually crash
498 502 // the browser. I think there is an infinite loop in here...
499 503 var ncells = this.ncells();
500 504 var sindex = this.get_selected_index();
501 505 var swapped;
502 506 do {
503 507 swapped = false;
504 508 for (var i=1; i<ncells; i++) {
505 509 current = this.get_cell(i);
506 510 previous = this.get_cell(i-1);
507 511 if (previous.input_prompt_number > current.input_prompt_number) {
508 512 this.move_cell_up(i);
509 513 swapped = true;
510 514 };
511 515 };
512 516 } while (swapped);
513 517 this.select(sindex);
514 518 return this;
515 519 };
516 520
517 521 // Insertion, deletion.
518 522
519 523 Notebook.prototype.delete_cell = function (index) {
520 524 var i = this.index_or_selected(index);
521 525 if (this.is_valid_cell_index(i)) {
522 526 var ce = this.get_cell_element(i);
523 527 ce.remove();
524 528 if (i === (this.ncells())) {
525 529 this.select(i-1);
526 530 } else {
527 531 this.select(i);
528 532 };
529 533 this.dirty = true;
530 534 };
531 535 return this;
532 536 };
533 537
534 538
535 539 Notebook.prototype.insert_cell_below = function (type, index) {
536 540 // type = ('code','html','markdown')
537 541 // index = cell index or undefined to insert below selected
538 542 index = this.index_or_selected(index);
539 543 var cell = null;
540 544 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
541 545 if (type === 'code') {
542 546 cell = new IPython.CodeCell(this.kernel);
543 547 cell.set_input_prompt();
544 548 } else if (type === 'markdown') {
545 549 cell = new IPython.MarkdownCell();
546 550 } else if (type === 'html') {
547 551 cell = new IPython.HTMLCell();
548 552 } else if (type === 'raw') {
549 553 cell = new IPython.RawCell();
550 554 } else if (type === 'heading') {
551 555 cell = new IPython.HeadingCell();
552 556 };
553 557 if (cell !== null) {
554 558 if (this.ncells() === 0) {
555 559 this.element.find('div.end_space').before(cell.element);
556 560 } else if (this.is_valid_cell_index(index)) {
557 561 this.get_cell_element(index).after(cell.element);
558 562 };
559 563 cell.render();
560 564 this.select(this.find_cell_index(cell));
561 565 this.dirty = true;
562 566 return cell;
563 567 };
564 568 };
565 569 return cell;
566 570 };
567 571
568 572
569 573 Notebook.prototype.insert_cell_above = function (type, index) {
570 574 // type = ('code','html','markdown')
571 575 // index = cell index or undefined to insert above selected
572 576 index = this.index_or_selected(index);
573 577 var cell = null;
574 578 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
575 579 if (type === 'code') {
576 580 cell = new IPython.CodeCell(this.kernel);
577 581 cell.set_input_prompt();
578 582 } else if (type === 'markdown') {
579 583 cell = new IPython.MarkdownCell();
580 584 } else if (type === 'html') {
581 585 cell = new IPython.HTMLCell();
582 586 } else if (type === 'raw') {
583 587 cell = new IPython.RawCell();
584 588 } else if (type === 'heading') {
585 589 cell = new IPython.HeadingCell();
586 590 };
587 591 if (cell !== null) {
588 592 if (this.ncells() === 0) {
589 593 this.element.find('div.end_space').before(cell.element);
590 594 } else if (this.is_valid_cell_index(index)) {
591 595 this.get_cell_element(index).before(cell.element);
592 596 };
593 597 cell.render();
594 598 this.select(this.find_cell_index(cell));
595 599 this.dirty = true;
596 600 return cell;
597 601 };
598 602 };
599 603 return cell;
600 604 };
601 605
602 606
603 607 Notebook.prototype.to_code = function (index) {
604 608 var i = this.index_or_selected(index);
605 609 if (this.is_valid_cell_index(i)) {
606 610 var source_element = this.get_cell_element(i);
607 611 var source_cell = source_element.data("cell");
608 612 if (!(source_cell instanceof IPython.CodeCell)) {
609 613 target_cell = this.insert_cell_below('code',i);
610 614 var text = source_cell.get_text();
611 615 if (text === source_cell.placeholder) {
612 616 text = '';
613 617 }
614 618 target_cell.set_text(text);
615 619 // make this value the starting point, so that we can only undo
616 620 // to this state, instead of a blank cell
617 621 target_cell.code_mirror.clearHistory();
618 622 source_element.remove();
619 623 this.dirty = true;
620 624 };
621 625 };
622 626 };
623 627
624 628
625 629 Notebook.prototype.to_markdown = function (index) {
626 630 var i = this.index_or_selected(index);
627 631 if (this.is_valid_cell_index(i)) {
628 632 var source_element = this.get_cell_element(i);
629 633 var source_cell = source_element.data("cell");
630 634 if (!(source_cell instanceof IPython.MarkdownCell)) {
631 635 target_cell = this.insert_cell_below('markdown',i);
632 636 var text = source_cell.get_text();
633 637 if (text === source_cell.placeholder) {
634 638 text = '';
635 639 };
636 640 // The edit must come before the set_text.
637 641 target_cell.edit();
638 642 target_cell.set_text(text);
639 643 // make this value the starting point, so that we can only undo
640 644 // to this state, instead of a blank cell
641 645 target_cell.code_mirror.clearHistory();
642 646 source_element.remove();
643 647 this.dirty = true;
644 648 };
645 649 };
646 650 };
647 651
648 652
649 653 Notebook.prototype.to_html = function (index) {
650 654 var i = this.index_or_selected(index);
651 655 if (this.is_valid_cell_index(i)) {
652 656 var source_element = this.get_cell_element(i);
653 657 var source_cell = source_element.data("cell");
654 658 var target_cell = null;
655 659 if (!(source_cell instanceof IPython.HTMLCell)) {
656 660 target_cell = this.insert_cell_below('html',i);
657 661 var text = source_cell.get_text();
658 662 if (text === source_cell.placeholder) {
659 663 text = '';
660 664 };
661 665 // The edit must come before the set_text.
662 666 target_cell.edit();
663 667 target_cell.set_text(text);
664 668 // make this value the starting point, so that we can only undo
665 669 // to this state, instead of a blank cell
666 670 target_cell.code_mirror.clearHistory();
667 671 source_element.remove();
668 672 this.dirty = true;
669 673 };
670 674 };
671 675 };
672 676
673 677
674 678 Notebook.prototype.to_raw = function (index) {
675 679 var i = this.index_or_selected(index);
676 680 if (this.is_valid_cell_index(i)) {
677 681 var source_element = this.get_cell_element(i);
678 682 var source_cell = source_element.data("cell");
679 683 var target_cell = null;
680 684 if (!(source_cell instanceof IPython.RawCell)) {
681 685 target_cell = this.insert_cell_below('raw',i);
682 686 var text = source_cell.get_text();
683 687 if (text === source_cell.placeholder) {
684 688 text = '';
685 689 };
686 690 // The edit must come before the set_text.
687 691 target_cell.edit();
688 692 target_cell.set_text(text);
689 693 // make this value the starting point, so that we can only undo
690 694 // to this state, instead of a blank cell
691 695 target_cell.code_mirror.clearHistory();
692 696 source_element.remove();
693 697 this.dirty = true;
694 698 };
695 699 };
696 700 };
697 701
698 702
699 703 Notebook.prototype.to_heading = function (index, level) {
700 704 level = level || 1;
701 705 var i = this.index_or_selected(index);
702 706 if (this.is_valid_cell_index(i)) {
703 707 var source_element = this.get_cell_element(i);
704 708 var source_cell = source_element.data("cell");
705 709 var target_cell = null;
706 710 if (source_cell instanceof IPython.HeadingCell) {
707 711 source_cell.set_level(level);
708 712 } else {
709 713 target_cell = this.insert_cell_below('heading',i);
710 714 var text = source_cell.get_text();
711 715 if (text === source_cell.placeholder) {
712 716 text = '';
713 717 };
714 718 // The edit must come before the set_text.
715 719 target_cell.set_level(level);
716 720 target_cell.edit();
717 721 target_cell.set_text(text);
718 722 // make this value the starting point, so that we can only undo
719 723 // to this state, instead of a blank cell
720 724 target_cell.code_mirror.clearHistory();
721 725 source_element.remove();
722 726 this.dirty = true;
723 727 };
724 728 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
725 729 {'cell_type':'heading',level:level}
726 730 );
727 731 };
728 732 };
729 733
730 734
731 735 // Cut/Copy/Paste
732 736
733 737 Notebook.prototype.enable_paste = function () {
734 738 var that = this;
735 739 if (!this.paste_enabled) {
736 740 $('#paste_cell').removeClass('ui-state-disabled')
737 741 .on('click', function () {that.paste_cell();});
738 742 $('#paste_cell_above').removeClass('ui-state-disabled')
739 743 .on('click', function () {that.paste_cell_above();});
740 744 $('#paste_cell_below').removeClass('ui-state-disabled')
741 745 .on('click', function () {that.paste_cell_below();});
742 746 this.paste_enabled = true;
743 747 };
744 748 };
745 749
746 750
747 751 Notebook.prototype.disable_paste = function () {
748 752 if (this.paste_enabled) {
749 753 $('#paste_cell').addClass('ui-state-disabled').off('click');
750 754 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
751 755 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
752 756 this.paste_enabled = false;
753 757 };
754 758 };
755 759
756 760
757 761 Notebook.prototype.cut_cell = function () {
758 762 this.copy_cell();
759 763 this.delete_cell();
760 764 }
761 765
762 766 Notebook.prototype.copy_cell = function () {
763 767 var cell = this.get_selected_cell();
764 768 this.clipboard = cell.toJSON();
765 769 this.enable_paste();
766 770 };
767 771
768 772
769 773 Notebook.prototype.paste_cell = function () {
770 774 if (this.clipboard !== null && this.paste_enabled) {
771 775 var cell_data = this.clipboard;
772 776 var new_cell = this.insert_cell_above(cell_data.cell_type);
773 777 new_cell.fromJSON(cell_data);
774 778 old_cell = this.get_next_cell(new_cell);
775 779 this.delete_cell(this.find_cell_index(old_cell));
776 780 this.select(this.find_cell_index(new_cell));
777 781 };
778 782 };
779 783
780 784
781 785 Notebook.prototype.paste_cell_above = function () {
782 786 if (this.clipboard !== null && this.paste_enabled) {
783 787 var cell_data = this.clipboard;
784 788 var new_cell = this.insert_cell_above(cell_data.cell_type);
785 789 new_cell.fromJSON(cell_data);
786 790 };
787 791 };
788 792
789 793
790 794 Notebook.prototype.paste_cell_below = function () {
791 795 if (this.clipboard !== null && this.paste_enabled) {
792 796 var cell_data = this.clipboard;
793 797 var new_cell = this.insert_cell_below(cell_data.cell_type);
794 798 new_cell.fromJSON(cell_data);
795 799 };
796 800 };
797 801
798 802
799 803 // Split/merge
800 804
801 805 Notebook.prototype.split_cell = function () {
802 806 // Todo: implement spliting for other cell types.
803 807 var cell = this.get_selected_cell();
804 808 if (cell.is_splittable()) {
805 809 texta = cell.get_pre_cursor();
806 810 textb = cell.get_post_cursor();
807 811 if (cell instanceof IPython.CodeCell) {
808 812 cell.set_text(texta);
809 813 var new_cell = this.insert_cell_below('code');
810 814 new_cell.set_text(textb);
811 815 } else if (cell instanceof IPython.MarkdownCell) {
812 816 cell.set_text(texta);
813 817 cell.render();
814 818 var new_cell = this.insert_cell_below('markdown');
815 819 new_cell.edit(); // editor must be visible to call set_text
816 820 new_cell.set_text(textb);
817 821 new_cell.render();
818 822 } else if (cell instanceof IPython.HTMLCell) {
819 823 cell.set_text(texta);
820 824 cell.render();
821 825 var new_cell = this.insert_cell_below('html');
822 826 new_cell.edit(); // editor must be visible to call set_text
823 827 new_cell.set_text(textb);
824 828 new_cell.render();
825 829 };
826 830 };
827 831 };
828 832
829 833
830 834 Notebook.prototype.merge_cell_above = function () {
831 835 var index = this.get_selected_index();
832 836 var cell = this.get_cell(index);
833 837 if (index > 0) {
834 838 upper_cell = this.get_cell(index-1);
835 839 upper_text = upper_cell.get_text();
836 840 text = cell.get_text();
837 841 if (cell instanceof IPython.CodeCell) {
838 842 cell.set_text(upper_text+'\n'+text);
839 843 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
840 844 cell.edit();
841 845 cell.set_text(upper_text+'\n'+text);
842 846 cell.render();
843 847 };
844 848 this.delete_cell(index-1);
845 849 this.select(this.find_cell_index(cell));
846 850 };
847 851 };
848 852
849 853
850 854 Notebook.prototype.merge_cell_below = function () {
851 855 var index = this.get_selected_index();
852 856 var cell = this.get_cell(index);
853 857 if (index < this.ncells()-1) {
854 858 lower_cell = this.get_cell(index+1);
855 859 lower_text = lower_cell.get_text();
856 860 text = cell.get_text();
857 861 if (cell instanceof IPython.CodeCell) {
858 862 cell.set_text(text+'\n'+lower_text);
859 863 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
860 864 cell.edit();
861 865 cell.set_text(text+'\n'+lower_text);
862 866 cell.render();
863 867 };
864 868 this.delete_cell(index+1);
865 869 this.select(this.find_cell_index(cell));
866 870 };
867 871 };
868 872
869 873
870 874 // Cell collapsing and output clearing
871 875
872 876 Notebook.prototype.collapse = function (index) {
873 877 var i = this.index_or_selected(index);
874 878 this.get_cell(i).collapse();
875 879 this.dirty = true;
876 880 };
877 881
878 882
879 883 Notebook.prototype.expand = function (index) {
880 884 var i = this.index_or_selected(index);
881 885 this.get_cell(i).expand();
882 886 this.dirty = true;
883 887 };
884 888
885 889
886 890 Notebook.prototype.toggle_output = function (index) {
887 891 var i = this.index_or_selected(index);
888 892 this.get_cell(i).toggle_output();
889 893 this.dirty = true;
890 894 };
891 895
892 896
893 897 Notebook.prototype.toggle_output_scroll = function (index) {
894 898 var i = this.index_or_selected(index);
895 899 this.get_cell(i).toggle_output_scroll();
896 900 };
897 901
898 902
899 903 Notebook.prototype.collapse_all_output = function () {
900 904 var ncells = this.ncells();
901 905 var cells = this.get_cells();
902 906 for (var i=0; i<ncells; i++) {
903 907 if (cells[i] instanceof IPython.CodeCell) {
904 908 cells[i].output_area.collapse();
905 909 }
906 910 };
907 911 // this should not be set if the `collapse` key is removed from nbformat
908 912 this.dirty = true;
909 913 };
910 914
911 915
912 916 Notebook.prototype.scroll_all_output = function () {
913 917 var ncells = this.ncells();
914 918 var cells = this.get_cells();
915 919 for (var i=0; i<ncells; i++) {
916 920 if (cells[i] instanceof IPython.CodeCell) {
917 921 cells[i].output_area.expand();
918 922 cells[i].output_area.scroll_if_long(20);
919 923 }
920 924 };
921 925 // this should not be set if the `collapse` key is removed from nbformat
922 926 this.dirty = true;
923 927 };
924 928
925 929
926 930 Notebook.prototype.expand_all_output = function () {
927 931 var ncells = this.ncells();
928 932 var cells = this.get_cells();
929 933 for (var i=0; i<ncells; i++) {
930 934 if (cells[i] instanceof IPython.CodeCell) {
931 935 cells[i].output_area.expand();
932 936 cells[i].output_area.unscroll_area();
933 937 }
934 938 };
935 939 // this should not be set if the `collapse` key is removed from nbformat
936 940 this.dirty = true;
937 941 };
938 942
939 943
940 944 Notebook.prototype.clear_all_output = function () {
941 945 var ncells = this.ncells();
942 946 var cells = this.get_cells();
943 947 for (var i=0; i<ncells; i++) {
944 948 if (cells[i] instanceof IPython.CodeCell) {
945 949 cells[i].clear_output(true,true,true);
946 950 // Make all In[] prompts blank, as well
947 951 // TODO: make this configurable (via checkbox?)
948 952 cells[i].set_input_prompt();
949 953 }
950 954 };
951 955 this.dirty = true;
952 956 };
953 957
954 958
955 959 // Other cell functions: line numbers, ...
956 960
957 961 Notebook.prototype.cell_toggle_line_numbers = function() {
958 962 this.get_selected_cell().toggle_line_numbers();
959 963 };
960 964
961 965 // Kernel related things
962 966
963 967 Notebook.prototype.start_kernel = function () {
964 968 var base_url = $('body').data('baseKernelUrl') + "kernels";
965 969 this.kernel = new IPython.Kernel(base_url);
966 970 this.kernel.start(this.notebook_id);
967 971 // Now that the kernel has been created, tell the CodeCells about it.
968 972 var ncells = this.ncells();
969 973 for (var i=0; i<ncells; i++) {
970 974 var cell = this.get_cell(i);
971 975 if (cell instanceof IPython.CodeCell) {
972 976 cell.set_kernel(this.kernel)
973 977 };
974 978 };
975 979 };
976 980
977 981
978 982 Notebook.prototype.restart_kernel = function () {
979 983 var that = this;
980 984 var dialog = $('<div/>');
981 985 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
982 986 $(document).append(dialog);
983 987 dialog.dialog({
984 988 resizable: false,
985 989 modal: true,
986 990 title: "Restart kernel or continue running?",
987 991 closeText: '',
988 992 buttons : {
989 993 "Restart": function () {
990 994 that.kernel.restart();
991 995 $(this).dialog('close');
992 996 },
993 997 "Continue running": function () {
994 998 $(this).dialog('close');
995 999 }
996 1000 }
997 1001 });
998 1002 };
999 1003
1000 1004
1001 1005 Notebook.prototype.execute_selected_cell = function (options) {
1002 1006 // add_new: should a new cell be added if we are at the end of the nb
1003 1007 // terminal: execute in terminal mode, which stays in the current cell
1004 1008 default_options = {terminal: false, add_new: true};
1005 1009 $.extend(default_options, options);
1006 1010 var that = this;
1007 1011 var cell = that.get_selected_cell();
1008 1012 var cell_index = that.find_cell_index(cell);
1009 1013 if (cell instanceof IPython.CodeCell) {
1010 1014 cell.execute();
1011 1015 } else if (cell instanceof IPython.HTMLCell) {
1012 1016 cell.render();
1013 1017 }
1014 1018 if (default_options.terminal) {
1015 1019 cell.select_all();
1016 1020 } else {
1017 1021 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1018 1022 that.insert_cell_below('code');
1019 1023 // If we are adding a new cell at the end, scroll down to show it.
1020 1024 that.scroll_to_bottom();
1021 1025 } else {
1022 1026 that.select(cell_index+1);
1023 1027 };
1024 1028 };
1025 1029 this.dirty = true;
1026 1030 };
1027 1031
1028 1032
1029 1033 Notebook.prototype.execute_all_cells = function () {
1030 1034 var ncells = this.ncells();
1031 1035 for (var i=0; i<ncells; i++) {
1032 1036 this.select(i);
1033 1037 this.execute_selected_cell({add_new:false});
1034 1038 };
1035 1039 this.scroll_to_bottom();
1036 1040 };
1037 1041
1038 1042 // Persistance and loading
1039 1043
1040 1044 Notebook.prototype.get_notebook_id = function () {
1041 1045 return this.notebook_id;
1042 1046 };
1043 1047
1044 1048
1045 1049 Notebook.prototype.get_notebook_name = function () {
1046 1050 return this.notebook_name;
1047 1051 };
1048 1052
1049 1053
1050 1054 Notebook.prototype.set_notebook_name = function (name) {
1051 1055 this.notebook_name = name;
1052 1056 };
1053 1057
1054 1058
1055 1059 Notebook.prototype.test_notebook_name = function (nbname) {
1056 1060 nbname = nbname || '';
1057 1061 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1058 1062 return true;
1059 1063 } else {
1060 1064 return false;
1061 1065 };
1062 1066 };
1063 1067
1064 1068
1065 1069 Notebook.prototype.fromJSON = function (data) {
1066 1070 var ncells = this.ncells();
1067 1071 var i;
1068 1072 for (i=0; i<ncells; i++) {
1069 1073 // Always delete cell 0 as they get renumbered as they are deleted.
1070 1074 this.delete_cell(0);
1071 1075 };
1072 1076 // Save the metadata and name.
1073 1077 this.metadata = data.metadata;
1074 1078 this.notebook_name = data.metadata.name;
1075 1079 // Only handle 1 worksheet for now.
1076 1080 var worksheet = data.worksheets[0];
1077 1081 if (worksheet !== undefined) {
1078 1082 if (worksheet.metadata) {
1079 1083 this.worksheet_metadata = worksheet.metadata;
1080 1084 }
1081 1085 var new_cells = worksheet.cells;
1082 1086 ncells = new_cells.length;
1083 1087 var cell_data = null;
1084 1088 var new_cell = null;
1085 1089 for (i=0; i<ncells; i++) {
1086 1090 cell_data = new_cells[i];
1087 1091 // VERSIONHACK: plaintext -> raw
1088 1092 // handle never-released plaintext name for raw cells
1089 1093 if (cell_data.cell_type === 'plaintext'){
1090 1094 cell_data.cell_type = 'raw';
1091 1095 }
1092 1096
1093 1097 new_cell = this.insert_cell_below(cell_data.cell_type);
1094 1098 new_cell.fromJSON(cell_data);
1095 1099 };
1096 1100 };
1097 1101 if (data.worksheets.length > 1) {
1098 1102 var dialog = $('<div/>');
1099 1103 dialog.html("This notebook has " + data.worksheets.length + " worksheets, " +
1100 1104 "but this version of IPython can only handle the first. " +
1101 1105 "If you save this notebook, worksheets after the first will be lost."
1102 1106 );
1103 1107 this.element.append(dialog);
1104 1108 dialog.dialog({
1105 1109 resizable: false,
1106 1110 modal: true,
1107 1111 title: "Multiple worksheets",
1108 1112 closeText: "",
1109 1113 close: function(event, ui) {$(this).dialog('destroy').remove();},
1110 1114 buttons : {
1111 1115 "OK": function () {
1112 1116 $(this).dialog('close');
1113 1117 }
1114 1118 },
1115 1119 width: 400
1116 1120 });
1117 1121 }
1118 1122 };
1119 1123
1120 1124
1121 1125 Notebook.prototype.toJSON = function () {
1122 1126 var cells = this.get_cells();
1123 1127 var ncells = cells.length;
1124 1128 var cell_array = new Array(ncells);
1125 1129 for (var i=0; i<ncells; i++) {
1126 1130 cell_array[i] = cells[i].toJSON();
1127 1131 };
1128 1132 var data = {
1129 1133 // Only handle 1 worksheet for now.
1130 1134 worksheets : [{
1131 1135 cells: cell_array,
1132 1136 metadata: this.worksheet_metadata
1133 1137 }],
1134 1138 metadata : this.metadata
1135 1139 };
1136 1140 return data;
1137 1141 };
1138 1142
1139 1143 Notebook.prototype.save_notebook = function () {
1140 1144 // We may want to move the name/id/nbformat logic inside toJSON?
1141 1145 var data = this.toJSON();
1142 1146 data.metadata.name = this.notebook_name;
1143 1147 data.nbformat = this.nbformat;
1144 1148 data.nbformat_minor = this.nbformat_minor;
1145 1149 // We do the call with settings so we can set cache to false.
1146 1150 var settings = {
1147 1151 processData : false,
1148 1152 cache : false,
1149 1153 type : "PUT",
1150 1154 data : JSON.stringify(data),
1151 1155 headers : {'Content-Type': 'application/json'},
1152 1156 success : $.proxy(this.save_notebook_success,this),
1153 1157 error : $.proxy(this.save_notebook_error,this)
1154 1158 };
1155 1159 $([IPython.events]).trigger('notebook_saving.Notebook');
1156 1160 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1157 1161 $.ajax(url, settings);
1158 1162 };
1159 1163
1160 1164
1161 1165 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1162 1166 this.dirty = false;
1163 1167 $([IPython.events]).trigger('notebook_saved.Notebook');
1164 1168 };
1165 1169
1166 1170
1167 1171 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1168 1172 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1169 1173 };
1170 1174
1171 1175
1172 1176 Notebook.prototype.load_notebook = function (notebook_id) {
1173 1177 var that = this;
1174 1178 this.notebook_id = notebook_id;
1175 1179 // We do the call with settings so we can set cache to false.
1176 1180 var settings = {
1177 1181 processData : false,
1178 1182 cache : false,
1179 1183 type : "GET",
1180 1184 dataType : "json",
1181 1185 success : $.proxy(this.load_notebook_success,this),
1182 1186 error : $.proxy(this.load_notebook_error,this),
1183 1187 };
1184 1188 $([IPython.events]).trigger('notebook_loading.Notebook');
1185 1189 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1186 1190 $.ajax(url, settings);
1187 1191 };
1188 1192
1189 1193
1190 1194 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1191 1195 this.fromJSON(data);
1192 1196 if (this.ncells() === 0) {
1193 1197 this.insert_cell_below('code');
1194 1198 };
1195 1199 this.dirty = false;
1196 1200 this.select(0);
1197 1201 this.scroll_to_top();
1198 1202 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1199 1203 msg = "This notebook has been converted from an older " +
1200 1204 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1201 1205 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1202 1206 "newer notebook format will be used and older verions of IPython " +
1203 1207 "may not be able to read it. To keep the older version, close the " +
1204 1208 "notebook without saving it.";
1205 1209 var dialog = $('<div/>');
1206 1210 dialog.html(msg);
1207 1211 this.element.append(dialog);
1208 1212 dialog.dialog({
1209 1213 resizable: false,
1210 1214 modal: true,
1211 1215 title: "Notebook converted",
1212 1216 closeText: "",
1213 1217 close: function(event, ui) {$(this).dialog('destroy').remove();},
1214 1218 buttons : {
1215 1219 "OK": function () {
1216 1220 $(this).dialog('close');
1217 1221 }
1218 1222 },
1219 1223 width: 400
1220 1224 });
1221 1225 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1222 1226 var that = this;
1223 1227 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1224 1228 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1225 1229 msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1226 1230 this_vs + ". You can still work with this notebook, but some features " +
1227 1231 "introduced in later notebook versions may not be available."
1228 1232
1229 1233 var dialog = $('<div/>');
1230 1234 dialog.html(msg);
1231 1235 this.element.append(dialog);
1232 1236 dialog.dialog({
1233 1237 resizable: false,
1234 1238 modal: true,
1235 1239 title: "Newer Notebook",
1236 1240 closeText: "",
1237 1241 close: function(event, ui) {$(this).dialog('destroy').remove();},
1238 1242 buttons : {
1239 1243 "OK": function () {
1240 1244 $(this).dialog('close');
1241 1245 }
1242 1246 },
1243 1247 width: 400
1244 1248 });
1245 1249
1246 1250 }
1247 1251 // Create the kernel after the notebook is completely loaded to prevent
1248 1252 // code execution upon loading, which is a security risk.
1249 1253 if (! this.read_only) {
1250 1254 this.start_kernel();
1251 1255 }
1252 1256 $([IPython.events]).trigger('notebook_loaded.Notebook');
1253 1257 };
1254 1258
1255 1259
1256 1260 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1257 1261 if (xhr.status === 500) {
1258 1262 msg = "An error occurred while loading this notebook. Most likely " +
1259 1263 "this notebook is in a newer format than is supported by this " +
1260 1264 "version of IPython. This version can load notebook formats " +
1261 1265 "v"+this.nbformat+" or earlier.";
1262 1266 var dialog = $('<div/>');
1263 1267 dialog.html(msg);
1264 1268 this.element.append(dialog);
1265 1269 dialog.dialog({
1266 1270 resizable: false,
1267 1271 modal: true,
1268 1272 title: "Error loading notebook",
1269 1273 closeText: "",
1270 1274 close: function(event, ui) {$(this).dialog('destroy').remove();},
1271 1275 buttons : {
1272 1276 "OK": function () {
1273 1277 $(this).dialog('close');
1274 1278 }
1275 1279 },
1276 1280 width: 400
1277 1281 });
1278 1282 }
1279 1283 }
1280 1284
1281 1285 IPython.Notebook = Notebook;
1282 1286
1283 1287
1284 1288 return IPython;
1285 1289
1286 1290 }(IPython));
1287 1291
@@ -1,71 +1,72 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-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 // QuickHelp button
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var QuickHelp = function (selector) {
15 15 };
16 16
17 17 QuickHelp.prototype.show_keyboard_shortcuts = function () {
18 18 // toggles display of keyboard shortcut dialog
19 19 var that = this;
20 20 if ( this.shortcut_dialog ){
21 21 // if dialog is already shown, close it
22 22 this.shortcut_dialog.dialog("close");
23 23 this.shortcut_dialog = null;
24 24 return;
25 25 }
26 26 var dialog = $('<div/>');
27 27 this.shortcut_dialog = dialog;
28 28 var shortcuts = [
29 29 {key: 'Shift-Enter', help: 'run cell'},
30 30 {key: 'Ctrl-Enter', help: 'run cell in-place'},
31 {key: 'Alt-Enter', help: 'run cell, insert below'},
31 32 {key: 'Ctrl-m x', help: 'cut cell'},
32 33 {key: 'Ctrl-m c', help: 'copy cell'},
33 34 {key: 'Ctrl-m v', help: 'paste cell'},
34 35 {key: 'Ctrl-m d', help: 'delete cell'},
35 36 {key: 'Ctrl-m a', help: 'insert cell above'},
36 37 {key: 'Ctrl-m b', help: 'insert cell below'},
37 38 {key: 'Ctrl-m o', help: 'toggle output'},
38 39 {key: 'Ctrl-m O', help: 'toggle output scroll'},
39 40 {key: 'Ctrl-m l', help: 'toggle line numbers'},
40 41 {key: 'Ctrl-m s', help: 'save notebook'},
41 42 {key: 'Ctrl-m j', help: 'move cell down'},
42 43 {key: 'Ctrl-m k', help: 'move cell up'},
43 44 {key: 'Ctrl-m y', help: 'code cell'},
44 45 {key: 'Ctrl-m m', help: 'markdown cell'},
45 46 {key: 'Ctrl-m t', help: 'raw cell'},
46 47 {key: 'Ctrl-m 1-6', help: 'heading 1-6 cell'},
47 48 {key: 'Ctrl-m p', help: 'select previous'},
48 49 {key: 'Ctrl-m n', help: 'select next'},
49 50 {key: 'Ctrl-m i', help: 'interrupt kernel'},
50 51 {key: 'Ctrl-m .', help: 'restart kernel'},
51 52 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
52 53 ];
53 54 for (var i=0; i<shortcuts.length; i++) {
54 55 dialog.append($('<div>').
55 56 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
56 57 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
57 58 );
58 59 };
59 60 dialog.bind('dialogclose', function(event) {
60 61 // dialog has been closed, allow it to be drawn again.
61 62 that.shortcut_dialog = null;
62 63 });
63 64 dialog.dialog({title: 'Keyboard shortcuts', closeText: ''});
64 65 };
65 66
66 67 // Set module variables
67 68 IPython.QuickHelp = QuickHelp;
68 69
69 70 return IPython;
70 71
71 72 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now