##// END OF EJS Templates
show_keyboard_shortcuts -> toggle_keyboard_shortcuts...
MinRK -
Show More
@@ -1,972 +1,985
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
16 16 var Notebook = function (selector) {
17 17 this.element = $(selector);
18 18 this.element.scroll();
19 19 this.element.data("notebook", this);
20 20 this.next_prompt_number = 1;
21 21 this.kernel = null;
22 22 this.dirty = false;
23 23 this.msg_cell_map = {};
24 24 this.metadata = {};
25 25 this.control_key_active = false;
26 26 this.style();
27 27 this.create_elements();
28 28 this.bind_events();
29 29 };
30 30
31 31
32 32 Notebook.prototype.style = function () {
33 33 $('div#notebook').addClass('border-box-sizing');
34 34 };
35 35
36 36
37 37 Notebook.prototype.create_elements = function () {
38 38 // We add this end_space div to the end of the notebook div to:
39 39 // i) provide a margin between the last cell and the end of the notebook
40 40 // ii) to prevent the div from scrolling up when the last cell is being
41 41 // edited, but is too low on the page, which browsers will do automatically.
42 42 var that = this;
43 43 var end_space = $('<div class="end_space"></div>').height(150);
44 44 end_space.dblclick(function (e) {
45 45 var ncells = that.ncells();
46 46 that.insert_code_cell_below(ncells-1);
47 47 });
48 48 this.element.append(end_space);
49 49 $('div#notebook').addClass('border-box-sizing');
50 50 };
51 51
52 52
53 53 Notebook.prototype.bind_events = function () {
54 54 var that = this;
55 55 $(document).keydown(function (event) {
56 56 // console.log(event);
57 57 if (event.which === 38) {
58 58 var cell = that.selected_cell();
59 59 if (cell.at_top()) {
60 60 event.preventDefault();
61 61 that.select_prev();
62 62 };
63 63 } else if (event.which === 40) {
64 64 var cell = that.selected_cell();
65 65 if (cell.at_bottom()) {
66 66 event.preventDefault();
67 67 that.select_next();
68 68 };
69 69 } else if (event.which === 13 && event.shiftKey) {
70 70 that.execute_selected_cell();
71 71 return false;
72 72 } else if (event.which === 13 && event.ctrlKey) {
73 73 that.execute_selected_cell({terminal:true});
74 74 return false;
75 75 } else if (event.which === 77 && event.ctrlKey) {
76 76 that.control_key_active = true;
77 77 return false;
78 78 } else if (event.which === 68 && that.control_key_active) {
79 79 // Delete selected cell = d
80 80 that.delete_cell();
81 81 that.control_key_active = false;
82 82 return false;
83 83 } else if (event.which === 65 && that.control_key_active) {
84 84 // Insert code cell above selected = a
85 85 that.insert_code_cell_above();
86 86 that.control_key_active = false;
87 87 return false;
88 88 } else if (event.which === 66 && that.control_key_active) {
89 89 // Insert code cell below selected = b
90 90 that.insert_code_cell_below();
91 91 that.control_key_active = false;
92 92 return false;
93 93 } else if (event.which === 67 && that.control_key_active) {
94 94 // To code = c
95 95 that.to_code();
96 96 that.control_key_active = false;
97 97 return false;
98 98 } else if (event.which === 77 && that.control_key_active) {
99 99 // To markdown = m
100 100 that.to_markdown();
101 101 that.control_key_active = false;
102 102 return false;
103 103 } else if (event.which === 84 && that.control_key_active) {
104 104 // Toggle output = t
105 105 that.toggle_output();
106 106 that.control_key_active = false;
107 107 return false;
108 108 } else if (event.which === 83 && that.control_key_active) {
109 109 // Save notebook = s
110 110 IPython.save_widget.save_notebook();
111 111 that.control_key_active = false;
112 112 return false;
113 113 } else if (event.which === 74 && that.control_key_active) {
114 114 // Move cell down = j
115 115 that.move_cell_down();
116 116 that.control_key_active = false;
117 117 return false;
118 118 } else if (event.which === 75 && that.control_key_active) {
119 119 // Move cell up = k
120 120 that.move_cell_up();
121 121 that.control_key_active = false;
122 122 return false;
123 123 } else if (event.which === 80 && that.control_key_active) {
124 124 // Select previous = p
125 125 that.select_prev();
126 126 that.control_key_active = false;
127 127 return false;
128 128 } else if (event.which === 78 && that.control_key_active) {
129 129 // Select next = n
130 130 that.select_next();
131 131 that.control_key_active = false;
132 132 return false;
133 133 } else if (event.which === 76 && that.control_key_active) {
134 134 // Toggle line numbers = l
135 135 that.cell_toggle_line_numbers();
136 136 that.control_key_active = false;
137 137 return false;
138 138 } else if (event.which === 73 && that.control_key_active) {
139 139 // Interrupt kernel = i
140 140 IPython.notebook.kernel.interrupt();
141 141 that.control_key_active = false;
142 142 return false;
143 143 } else if (event.which === 190 && that.control_key_active) {
144 144 // Restart kernel = . # matches qt console
145 145 IPython.notebook.restart_kernel();
146 146 that.control_key_active = false;
147 147 return false;
148 148 } else if (event.which === 72 && that.control_key_active) {
149 149 // Show keyboard shortcuts = h
150 that.show_keyboard_shortcuts();
150 that.toggle_keyboard_shortcuts();
151 151 that.control_key_active = false;
152 152 return false;
153 153 } else if (that.control_key_active) {
154 154 that.control_key_active = false;
155 155 return true;
156 156 };
157 157 });
158 158
159 159 this.element.bind('collapse_pager', function () {
160 160 var app_height = $('div#main_app').height(); // content height
161 161 var splitter_height = $('div#pager_splitter').outerHeight(true);
162 162 var new_height = app_height - splitter_height;
163 163 that.element.animate({height : new_height + 'px'}, 'fast');
164 164 });
165 165
166 166 this.element.bind('expand_pager', function () {
167 167 var app_height = $('div#main_app').height(); // content height
168 168 var splitter_height = $('div#pager_splitter').outerHeight(true);
169 169 var pager_height = $('div#pager').outerHeight(true);
170 170 var new_height = app_height - pager_height - splitter_height;
171 171 that.element.animate({height : new_height + 'px'}, 'fast');
172 172 });
173 173
174 174 this.element.bind('collapse_left_panel', function () {
175 175 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
176 176 var new_margin = splitter_width;
177 177 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
178 178 });
179 179
180 180 this.element.bind('expand_left_panel', function () {
181 181 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
182 182 var left_panel_width = IPython.left_panel.width;
183 183 var new_margin = splitter_width + left_panel_width;
184 184 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
185 185 });
186 186
187 187 $(window).bind('beforeunload', function () {
188 188 var kill_kernel = $('#kill_kernel').prop('checked');
189 189 if (kill_kernel) {
190 190 that.kernel.kill();
191 191 }
192 192 if (that.dirty) {
193 193 return "You have unsaved changes that will be lost if you leave this page.";
194 194 };
195 195 });
196 196 };
197 197
198 198
199 Notebook.prototype.show_keyboard_shortcuts = function () {
199 Notebook.prototype.toggle_keyboard_shortcuts = function () {
200 // toggles display of keyboard shortcut dialog
201 var that = this;
202 if ( this.shortcut_dialog ){
203 // if dialog is already shown, close it
204 this.shortcut_dialog.dialog("close");
205 this.shortcut_dialog = null;
206 return;
207 }
200 208 var dialog = $('<div/>');
209 this.shortcut_dialog = dialog;
201 210 var shortcuts = [
202 211 {key: 'Shift-Enter', help: 'run cell'},
203 212 {key: 'Ctrl-Enter', help: 'run cell in-place'},
204 213 {key: 'Ctrl-m d', help: 'delete cell'},
205 214 {key: 'Ctrl-m a', help: 'insert cell above'},
206 215 {key: 'Ctrl-m b', help: 'insert cell below'},
207 216 {key: 'Ctrl-m t', help: 'toggle output'},
208 217 {key: 'Ctrl-m l', help: 'toggle line numbers'},
209 218 {key: 'Ctrl-m s', help: 'save notebook'},
210 219 {key: 'Ctrl-m j', help: 'move cell down'},
211 220 {key: 'Ctrl-m k', help: 'move cell up'},
212 221 {key: 'Ctrl-m c', help: 'code cell'},
213 222 {key: 'Ctrl-m m', help: 'markdown cell'},
214 223 {key: 'Ctrl-m p', help: 'select previous'},
215 224 {key: 'Ctrl-m n', help: 'select next'},
216 225 {key: 'Ctrl-m i', help: 'interrupt kernel'},
217 226 {key: 'Ctrl-m .', help: 'restart kernel'},
218 227 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
219 228 ];
220 229 for (var i=0; i<shortcuts.length; i++) {
221 230 dialog.append($('<div>').
222 231 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
223 232 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
224 233 );
225 234 };
235 dialog.bind('dialogclose', function(event) {
236 // dialog has been closed, allow it to be drawn again.
237 that.shortcut_dialog = null;
238 });
226 239 dialog.dialog({title: 'Keyboard shortcuts'});
227 240 };
228 241
229 242
230 243 Notebook.prototype.scroll_to_bottom = function () {
231 244 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
232 245 };
233 246
234 247
235 248 Notebook.prototype.scroll_to_top = function () {
236 249 this.element.animate({scrollTop:0}, 0);
237 250 };
238 251
239 252
240 253 // Cell indexing, retrieval, etc.
241 254
242 255
243 256 Notebook.prototype.cell_elements = function () {
244 257 return this.element.children("div.cell");
245 258 }
246 259
247 260
248 261 Notebook.prototype.ncells = function (cell) {
249 262 return this.cell_elements().length;
250 263 }
251 264
252 265
253 266 // TODO: we are often calling cells as cells()[i], which we should optimize
254 267 // to cells(i) or a new method.
255 268 Notebook.prototype.cells = function () {
256 269 return this.cell_elements().toArray().map(function (e) {
257 270 return $(e).data("cell");
258 271 });
259 272 }
260 273
261 274
262 275 Notebook.prototype.find_cell_index = function (cell) {
263 276 var result = null;
264 277 this.cell_elements().filter(function (index) {
265 278 if ($(this).data("cell") === cell) {
266 279 result = index;
267 280 };
268 281 });
269 282 return result;
270 283 };
271 284
272 285
273 286 Notebook.prototype.index_or_selected = function (index) {
274 287 return index || this.selected_index() || 0;
275 288 }
276 289
277 290
278 291 Notebook.prototype.select = function (index) {
279 292 if (index !== undefined && index >= 0 && index < this.ncells()) {
280 293 if (this.selected_index() !== null) {
281 294 this.selected_cell().unselect();
282 295 };
283 296 this.cells()[index].select();
284 297 };
285 298 return this;
286 299 };
287 300
288 301
289 302 Notebook.prototype.select_next = function () {
290 303 var index = this.selected_index();
291 304 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
292 305 this.select(index+1);
293 306 };
294 307 return this;
295 308 };
296 309
297 310
298 311 Notebook.prototype.select_prev = function () {
299 312 var index = this.selected_index();
300 313 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
301 314 this.select(index-1);
302 315 };
303 316 return this;
304 317 };
305 318
306 319
307 320 Notebook.prototype.selected_index = function () {
308 321 var result = null;
309 322 this.cell_elements().filter(function (index) {
310 323 if ($(this).data("cell").selected === true) {
311 324 result = index;
312 325 };
313 326 });
314 327 return result;
315 328 };
316 329
317 330
318 331 Notebook.prototype.cell_for_msg = function (msg_id) {
319 332 var cell_id = this.msg_cell_map[msg_id];
320 333 var result = null;
321 334 this.cell_elements().filter(function (index) {
322 335 cell = $(this).data("cell");
323 336 if (cell.cell_id === cell_id) {
324 337 result = cell;
325 338 };
326 339 });
327 340 return result;
328 341 };
329 342
330 343
331 344 Notebook.prototype.selected_cell = function () {
332 345 return this.cell_elements().eq(this.selected_index()).data("cell");
333 346 }
334 347
335 348
336 349 // Cell insertion, deletion and moving.
337 350
338 351
339 352 Notebook.prototype.delete_cell = function (index) {
340 353 var i = index || this.selected_index();
341 354 if (i !== null && i >= 0 && i < this.ncells()) {
342 355 this.cell_elements().eq(i).remove();
343 356 if (i === (this.ncells())) {
344 357 this.select(i-1);
345 358 } else {
346 359 this.select(i);
347 360 };
348 361 };
349 362 this.dirty = true;
350 363 return this;
351 364 };
352 365
353 366
354 367 Notebook.prototype.append_cell = function (cell) {
355 368 this.element.find('div.end_space').before(cell.element);
356 369 this.dirty = true;
357 370 return this;
358 371 };
359 372
360 373
361 374 Notebook.prototype.insert_cell_below = function (cell, index) {
362 375 var ncells = this.ncells();
363 376 if (ncells === 0) {
364 377 this.append_cell(cell);
365 378 return this;
366 379 };
367 380 if (index >= 0 && index < ncells) {
368 381 this.cell_elements().eq(index).after(cell.element);
369 382 };
370 383 this.dirty = true;
371 384 return this
372 385 };
373 386
374 387
375 388 Notebook.prototype.insert_cell_above = function (cell, index) {
376 389 var ncells = this.ncells();
377 390 if (ncells === 0) {
378 391 this.append_cell(cell);
379 392 return this;
380 393 };
381 394 if (index >= 0 && index < ncells) {
382 395 this.cell_elements().eq(index).before(cell.element);
383 396 };
384 397 this.dirty = true;
385 398 return this;
386 399 };
387 400
388 401
389 402 Notebook.prototype.move_cell_up = function (index) {
390 403 var i = index || this.selected_index();
391 404 if (i !== null && i < this.ncells() && i > 0) {
392 405 var pivot = this.cell_elements().eq(i-1);
393 406 var tomove = this.cell_elements().eq(i);
394 407 if (pivot !== null && tomove !== null) {
395 408 tomove.detach();
396 409 pivot.before(tomove);
397 410 this.select(i-1);
398 411 };
399 412 };
400 413 this.dirty = true;
401 414 return this;
402 415 }
403 416
404 417
405 418 Notebook.prototype.move_cell_down = function (index) {
406 419 var i = index || this.selected_index();
407 420 if (i !== null && i < (this.ncells()-1) && i >= 0) {
408 421 var pivot = this.cell_elements().eq(i+1)
409 422 var tomove = this.cell_elements().eq(i)
410 423 if (pivot !== null && tomove !== null) {
411 424 tomove.detach();
412 425 pivot.after(tomove);
413 426 this.select(i+1);
414 427 };
415 428 };
416 429 this.dirty = true;
417 430 return this;
418 431 }
419 432
420 433
421 434 Notebook.prototype.sort_cells = function () {
422 435 var ncells = this.ncells();
423 436 var sindex = this.selected_index();
424 437 var swapped;
425 438 do {
426 439 swapped = false
427 440 for (var i=1; i<ncells; i++) {
428 441 current = this.cell_elements().eq(i).data("cell");
429 442 previous = this.cell_elements().eq(i-1).data("cell");
430 443 if (previous.input_prompt_number > current.input_prompt_number) {
431 444 this.move_cell_up(i);
432 445 swapped = true;
433 446 };
434 447 };
435 448 } while (swapped);
436 449 this.select(sindex);
437 450 return this;
438 451 };
439 452
440 453
441 454 Notebook.prototype.insert_code_cell_above = function (index) {
442 455 // TODO: Bounds check for i
443 456 var i = this.index_or_selected(index);
444 457 var cell = new IPython.CodeCell(this);
445 458 cell.set_input_prompt();
446 459 this.insert_cell_above(cell, i);
447 460 this.select(this.find_cell_index(cell));
448 461 return cell;
449 462 }
450 463
451 464
452 465 Notebook.prototype.insert_code_cell_below = function (index) {
453 466 // TODO: Bounds check for i
454 467 var i = this.index_or_selected(index);
455 468 var cell = new IPython.CodeCell(this);
456 469 cell.set_input_prompt();
457 470 this.insert_cell_below(cell, i);
458 471 this.select(this.find_cell_index(cell));
459 472 return cell;
460 473 }
461 474
462 475
463 476 Notebook.prototype.insert_html_cell_above = function (index) {
464 477 // TODO: Bounds check for i
465 478 var i = this.index_or_selected(index);
466 479 var cell = new IPython.HTMLCell(this);
467 480 cell.config_mathjax();
468 481 this.insert_cell_above(cell, i);
469 482 this.select(this.find_cell_index(cell));
470 483 return cell;
471 484 }
472 485
473 486
474 487 Notebook.prototype.insert_html_cell_below = function (index) {
475 488 // TODO: Bounds check for i
476 489 var i = this.index_or_selected(index);
477 490 var cell = new IPython.HTMLCell(this);
478 491 cell.config_mathjax();
479 492 this.insert_cell_below(cell, i);
480 493 this.select(this.find_cell_index(cell));
481 494 return cell;
482 495 }
483 496
484 497
485 498 Notebook.prototype.insert_markdown_cell_above = function (index) {
486 499 // TODO: Bounds check for i
487 500 var i = this.index_or_selected(index);
488 501 var cell = new IPython.MarkdownCell(this);
489 502 cell.config_mathjax();
490 503 this.insert_cell_above(cell, i);
491 504 this.select(this.find_cell_index(cell));
492 505 return cell;
493 506 }
494 507
495 508
496 509 Notebook.prototype.insert_markdown_cell_below = function (index) {
497 510 // TODO: Bounds check for i
498 511 var i = this.index_or_selected(index);
499 512 var cell = new IPython.MarkdownCell(this);
500 513 cell.config_mathjax();
501 514 this.insert_cell_below(cell, i);
502 515 this.select(this.find_cell_index(cell));
503 516 return cell;
504 517 }
505 518
506 519
507 520 Notebook.prototype.to_code = function (index) {
508 521 // TODO: Bounds check for i
509 522 var i = this.index_or_selected(index);
510 523 var source_element = this.cell_elements().eq(i);
511 524 var source_cell = source_element.data("cell");
512 525 if (source_cell instanceof IPython.HTMLCell ||
513 526 source_cell instanceof IPython.MarkdownCell) {
514 527 this.insert_code_cell_below(i);
515 528 var target_cell = this.cells()[i+1];
516 529 target_cell.set_code(source_cell.get_source());
517 530 source_element.remove();
518 531 target_cell.select();
519 532 };
520 533 this.dirty = true;
521 534 };
522 535
523 536
524 537 Notebook.prototype.to_markdown = function (index) {
525 538 // TODO: Bounds check for i
526 539 var i = this.index_or_selected(index);
527 540 var source_element = this.cell_elements().eq(i);
528 541 var source_cell = source_element.data("cell");
529 542 var target_cell = null;
530 543 if (source_cell instanceof IPython.CodeCell) {
531 544 this.insert_markdown_cell_below(i);
532 545 var target_cell = this.cells()[i+1];
533 546 var text = source_cell.get_code();
534 547 } else if (source_cell instanceof IPython.HTMLCell) {
535 548 this.insert_markdown_cell_below(i);
536 549 var target_cell = this.cells()[i+1];
537 550 var text = source_cell.get_source();
538 551 if (text === source_cell.placeholder) {
539 552 text = target_cell.placeholder;
540 553 }
541 554 }
542 555 if (target_cell !== null) {
543 556 if (text === "") {text = target_cell.placeholder;};
544 557 target_cell.set_source(text);
545 558 source_element.remove();
546 559 target_cell.edit();
547 560 }
548 561 this.dirty = true;
549 562 };
550 563
551 564
552 565 Notebook.prototype.to_html = function (index) {
553 566 // TODO: Bounds check for i
554 567 var i = this.index_or_selected(index);
555 568 var source_element = this.cell_elements().eq(i);
556 569 var source_cell = source_element.data("cell");
557 570 var target_cell = null;
558 571 if (source_cell instanceof IPython.CodeCell) {
559 572 this.insert_html_cell_below(i);
560 573 var target_cell = this.cells()[i+1];
561 574 var text = source_cell.get_code();
562 575 } else if (source_cell instanceof IPython.MarkdownCell) {
563 576 this.insert_html_cell_below(i);
564 577 var target_cell = this.cells()[i+1];
565 578 var text = source_cell.get_source();
566 579 if (text === source_cell.placeholder) {
567 580 text = target_cell.placeholder;
568 581 }
569 582 }
570 583 if (target_cell !== null) {
571 584 if (text === "") {text = target_cell.placeholder;};
572 585 target_cell.set_source(text);
573 586 source_element.remove();
574 587 target_cell.edit();
575 588 }
576 589 this.dirty = true;
577 590 };
578 591
579 592
580 593 // Cell collapsing and output clearing
581 594
582 595 Notebook.prototype.collapse = function (index) {
583 596 var i = this.index_or_selected(index);
584 597 this.cells()[i].collapse();
585 598 this.dirty = true;
586 599 };
587 600
588 601
589 602 Notebook.prototype.expand = function (index) {
590 603 var i = this.index_or_selected(index);
591 604 this.cells()[i].expand();
592 605 this.dirty = true;
593 606 };
594 607
595 608
596 609 Notebook.prototype.toggle_output = function (index) {
597 610 var i = this.index_or_selected(index);
598 611 this.cells()[i].toggle_output();
599 612 this.dirty = true;
600 613 };
601 614
602 615
603 616 Notebook.prototype.set_autoindent = function (state) {
604 617 var cells = this.cells();
605 618 len = cells.length;
606 619 for (var i=0; i<len; i++) {
607 620 cells[i].set_autoindent(state)
608 621 };
609 622 };
610 623
611 624
612 625 Notebook.prototype.clear_all_output = function () {
613 626 var ncells = this.ncells();
614 627 var cells = this.cells();
615 628 for (var i=0; i<ncells; i++) {
616 629 if (cells[i] instanceof IPython.CodeCell) {
617 630 cells[i].clear_output();
618 631 }
619 632 };
620 633 this.dirty = true;
621 634 };
622 635
623 636 // Other cell functions: line numbers, ...
624 637
625 638 Notebook.prototype.cell_toggle_line_numbers = function() {
626 639 this.selected_cell().toggle_line_numbers()
627 640 };
628 641
629 642 // Kernel related things
630 643
631 644 Notebook.prototype.start_kernel = function () {
632 645 this.kernel = new IPython.Kernel();
633 646 var notebook_id = IPython.save_widget.get_notebook_id();
634 647 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
635 648 };
636 649
637 650
638 651 Notebook.prototype.restart_kernel = function () {
639 652 var that = this;
640 653 var notebook_id = IPython.save_widget.get_notebook_id();
641 654
642 655 var dialog = $('<div/>');
643 656 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
644 657 $(document).append(dialog);
645 658 dialog.dialog({
646 659 resizable: false,
647 660 modal: true,
648 661 title: "Restart kernel or continue running?",
649 662 buttons : {
650 663 "Restart": function () {
651 664 that.kernel.restart($.proxy(that.kernel_started, that));
652 665 $(this).dialog('close');
653 666 },
654 667 "Continue running": function () {
655 668 $(this).dialog('close');
656 669 }
657 670 }
658 671 });
659 672 };
660 673
661 674
662 675 Notebook.prototype.kernel_started = function () {
663 676 console.log("Kernel started: ", this.kernel.kernel_id);
664 677 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
665 678 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
666 679 };
667 680
668 681
669 682 Notebook.prototype.handle_shell_reply = function (e) {
670 683 reply = $.parseJSON(e.data);
671 684 var header = reply.header;
672 685 var content = reply.content;
673 686 var msg_type = header.msg_type;
674 687 // console.log(reply);
675 688 var cell = this.cell_for_msg(reply.parent_header.msg_id);
676 689 if (msg_type === "execute_reply") {
677 690 cell.set_input_prompt(content.execution_count);
678 691 this.dirty = true;
679 692 } else if (msg_type === "complete_reply") {
680 693 cell.finish_completing(content.matched_text, content.matches);
681 694 };
682 695 var payload = content.payload || [];
683 696 this.handle_payload(cell, payload);
684 697 };
685 698
686 699
687 700 Notebook.prototype.handle_payload = function (cell, payload) {
688 701 var l = payload.length;
689 702 for (var i=0; i<l; i++) {
690 703 if (payload[i].source === 'IPython.zmq.page.page') {
691 704 if (payload[i].text.trim() !== '') {
692 705 IPython.pager.clear();
693 706 IPython.pager.expand();
694 707 IPython.pager.append_text(payload[i].text);
695 708 }
696 709 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
697 710 var index = this.find_cell_index(cell);
698 711 var new_cell = this.insert_code_cell_below(index);
699 712 new_cell.set_code(payload[i].text);
700 713 this.dirty = true;
701 714 }
702 715 };
703 716 };
704 717
705 718
706 719 Notebook.prototype.handle_iopub_reply = function (e) {
707 720 reply = $.parseJSON(e.data);
708 721 var content = reply.content;
709 722 // console.log(reply);
710 723 var msg_type = reply.header.msg_type;
711 724 var cell = this.cell_for_msg(reply.parent_header.msg_id);
712 725 var output_types = ['stream','display_data','pyout','pyerr'];
713 726 if (output_types.indexOf(msg_type) >= 0) {
714 727 this.handle_output(cell, msg_type, content);
715 728 } else if (msg_type === 'status') {
716 729 if (content.execution_state === 'busy') {
717 730 IPython.kernel_status_widget.status_busy();
718 731 } else if (content.execution_state === 'idle') {
719 732 IPython.kernel_status_widget.status_idle();
720 733 } else if (content.execution_state === 'dead') {
721 734 this.handle_status_dead();
722 735 };
723 736 }
724 737 };
725 738
726 739
727 740 Notebook.prototype.handle_status_dead = function () {
728 741 var that = this;
729 742 this.kernel.stop_channels();
730 743 var dialog = $('<div/>');
731 744 dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.');
732 745 $(document).append(dialog);
733 746 dialog.dialog({
734 747 resizable: false,
735 748 modal: true,
736 749 title: "Dead kernel",
737 750 buttons : {
738 751 "Restart": function () {
739 752 that.start_kernel();
740 753 $(this).dialog('close');
741 754 },
742 755 "Continue running": function () {
743 756 $(this).dialog('close');
744 757 }
745 758 }
746 759 });
747 760 };
748 761
749 762
750 763 Notebook.prototype.handle_output = function (cell, msg_type, content) {
751 764 var json = {};
752 765 json.output_type = msg_type;
753 766 if (msg_type === "stream") {
754 767 json.text = utils.fixConsole(content.data);
755 768 json.stream = content.name;
756 769 } else if (msg_type === "display_data") {
757 770 json = this.convert_mime_types(json, content.data);
758 771 } else if (msg_type === "pyout") {
759 772 json.prompt_number = content.execution_count;
760 773 json = this.convert_mime_types(json, content.data);
761 774 } else if (msg_type === "pyerr") {
762 775 json.ename = content.ename;
763 776 json.evalue = content.evalue;
764 777 var traceback = [];
765 778 for (var i=0; i<content.traceback.length; i++) {
766 779 traceback.push(utils.fixConsole(content.traceback[i]));
767 780 }
768 781 json.traceback = traceback;
769 782 };
770 783 cell.append_output(json);
771 784 this.dirty = true;
772 785 };
773 786
774 787
775 788 Notebook.prototype.convert_mime_types = function (json, data) {
776 789 if (data['text/plain'] !== undefined) {
777 790 json.text = utils.fixConsole(data['text/plain']);
778 791 };
779 792 if (data['text/html'] !== undefined) {
780 793 json.html = data['text/html'];
781 794 };
782 795 if (data['image/svg+xml'] !== undefined) {
783 796 json.svg = data['image/svg+xml'];
784 797 };
785 798 if (data['image/png'] !== undefined) {
786 799 json.png = data['image/png'];
787 800 };
788 801 if (data['image/jpeg'] !== undefined) {
789 802 json.jpeg = data['image/jpeg'];
790 803 };
791 804 if (data['text/latex'] !== undefined) {
792 805 json.latex = data['text/latex'];
793 806 };
794 807 if (data['application/json'] !== undefined) {
795 808 json.json = data['application/json'];
796 809 };
797 810 if (data['application/javascript'] !== undefined) {
798 811 json.javascript = data['application/javascript'];
799 812 }
800 813 return json;
801 814 };
802 815
803 816
804 817 Notebook.prototype.execute_selected_cell = function (options) {
805 818 // add_new: should a new cell be added if we are at the end of the nb
806 819 // terminal: execute in terminal mode, which stays in the current cell
807 820 default_options = {terminal: false, add_new: true}
808 821 $.extend(default_options, options)
809 822 var that = this;
810 823 var cell = that.selected_cell();
811 824 var cell_index = that.find_cell_index(cell);
812 825 if (cell instanceof IPython.CodeCell) {
813 826 cell.clear_output();
814 827 var code = cell.get_code();
815 828 var msg_id = that.kernel.execute(cell.get_code());
816 829 that.msg_cell_map[msg_id] = cell.cell_id;
817 830 } else if (cell instanceof IPython.HTMLCell) {
818 831 cell.render();
819 832 }
820 833 if (default_options.terminal) {
821 834 cell.select_all();
822 835 } else {
823 836 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
824 837 that.insert_code_cell_below();
825 838 // If we are adding a new cell at the end, scroll down to show it.
826 839 that.scroll_to_bottom();
827 840 } else {
828 841 that.select(cell_index+1);
829 842 };
830 843 };
831 844 this.dirty = true;
832 845 };
833 846
834 847
835 848 Notebook.prototype.execute_all_cells = function () {
836 849 var ncells = this.ncells();
837 850 for (var i=0; i<ncells; i++) {
838 851 this.select(i);
839 852 this.execute_selected_cell({add_new:false});
840 853 };
841 854 this.scroll_to_bottom();
842 855 };
843 856
844 857
845 858 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
846 859 var msg_id = this.kernel.complete(line, cursor_pos);
847 860 this.msg_cell_map[msg_id] = cell.cell_id;
848 861 };
849 862
850 863 // Persistance and loading
851 864
852 865
853 866 Notebook.prototype.fromJSON = function (data) {
854 867 var ncells = this.ncells();
855 868 for (var i=0; i<ncells; i++) {
856 869 // Always delete cell 0 as they get renumbered as they are deleted.
857 870 this.delete_cell(0);
858 871 };
859 872 // Save the metadata
860 873 this.metadata = data.metadata;
861 874 // Only handle 1 worksheet for now.
862 875 var worksheet = data.worksheets[0];
863 876 if (worksheet !== undefined) {
864 877 var new_cells = worksheet.cells;
865 878 ncells = new_cells.length;
866 879 var cell_data = null;
867 880 var new_cell = null;
868 881 for (var i=0; i<ncells; i++) {
869 882 cell_data = new_cells[i];
870 883 if (cell_data.cell_type == 'code') {
871 884 new_cell = this.insert_code_cell_below();
872 885 new_cell.fromJSON(cell_data);
873 886 } else if (cell_data.cell_type === 'html') {
874 887 new_cell = this.insert_html_cell_below();
875 888 new_cell.fromJSON(cell_data);
876 889 } else if (cell_data.cell_type === 'markdown') {
877 890 new_cell = this.insert_markdown_cell_below();
878 891 new_cell.fromJSON(cell_data);
879 892 };
880 893 };
881 894 };
882 895 };
883 896
884 897
885 898 Notebook.prototype.toJSON = function () {
886 899 var cells = this.cells();
887 900 var ncells = cells.length;
888 901 cell_array = new Array(ncells);
889 902 for (var i=0; i<ncells; i++) {
890 903 cell_array[i] = cells[i].toJSON();
891 904 };
892 905 data = {
893 906 // Only handle 1 worksheet for now.
894 907 worksheets : [{cells:cell_array}],
895 908 metadata : this.metadata
896 909 }
897 910 return data
898 911 };
899 912
900 913 Notebook.prototype.save_notebook = function () {
901 914 if (IPython.save_widget.test_notebook_name()) {
902 915 var notebook_id = IPython.save_widget.get_notebook_id();
903 916 var nbname = IPython.save_widget.get_notebook_name();
904 917 // We may want to move the name/id/nbformat logic inside toJSON?
905 918 var data = this.toJSON();
906 919 data.metadata.name = nbname;
907 920 data.nbformat = 2;
908 921 // We do the call with settings so we can set cache to false.
909 922 var settings = {
910 923 processData : false,
911 924 cache : false,
912 925 type : "PUT",
913 926 data : JSON.stringify(data),
914 927 headers : {'Content-Type': 'application/json'},
915 928 success : $.proxy(this.notebook_saved,this)
916 929 };
917 930 IPython.save_widget.status_saving();
918 931 $.ajax("/notebooks/" + notebook_id, settings);
919 932 };
920 933 };
921 934
922 935
923 936 Notebook.prototype.notebook_saved = function (data, status, xhr) {
924 937 this.dirty = false;
925 938 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
926 939 }
927 940
928 941
929 942 Notebook.prototype.load_notebook = function (callback) {
930 943 var that = this;
931 944 var notebook_id = IPython.save_widget.get_notebook_id();
932 945 // We do the call with settings so we can set cache to false.
933 946 var settings = {
934 947 processData : false,
935 948 cache : false,
936 949 type : "GET",
937 950 dataType : "json",
938 951 success : function (data, status, xhr) {
939 952 that.notebook_loaded(data, status, xhr);
940 953 if (callback !== undefined) {
941 954 callback();
942 955 };
943 956 }
944 957 };
945 958 IPython.save_widget.status_loading();
946 959 $.ajax("/notebooks/" + notebook_id, settings);
947 960 }
948 961
949 962
950 963 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
951 964 this.fromJSON(data);
952 965 if (this.ncells() === 0) {
953 966 this.insert_code_cell_below();
954 967 };
955 968 IPython.save_widget.status_save();
956 969 IPython.save_widget.set_notebook_name(data.metadata.name);
957 970 this.start_kernel();
958 971 this.dirty = false;
959 972 // fromJSON always selects the last cell inserted. We need to wait
960 973 // until that is done before scrolling to the top.
961 974 setTimeout(function () {
962 975 IPython.notebook.select(0);
963 976 IPython.notebook.scroll_to_top();
964 977 }, 50);
965 978 };
966 979
967 980 IPython.Notebook = Notebook;
968 981
969 982 return IPython;
970 983
971 984 }(IPython));
972 985
@@ -1,39 +1,39
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 this.selector = selector;
16 16 if (this.selector !== undefined) {
17 17 this.element = $(selector);
18 18 this.style();
19 19 this.bind_events();
20 20 }
21 21 };
22 22
23 23 QuickHelp.prototype.style = function () {
24 24 this.element.find('button#quick_help').button();
25 25 };
26 26
27 27 QuickHelp.prototype.bind_events = function () {
28 28 var that = this;
29 29 this.element.find("button#quick_help").click(function () {
30 IPython.notebook.show_keyboard_shortcuts();
30 IPython.notebook.toggle_keyboard_shortcuts();
31 31 });
32 32 };
33 33
34 34 // Set module variables
35 35 IPython.QuickHelp = QuickHelp;
36 36
37 37 return IPython;
38 38
39 39 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now