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