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