##// END OF EJS Templates
Removing left over console.logs.
Brian Granger -
Show More
@@ -1,1195 +1,1193 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
16 16 var Notebook = function (selector) {
17 17 this.read_only = IPython.read_only;
18 18 this.element = $(selector);
19 19 this.element.scroll();
20 20 this.element.data("notebook", this);
21 21 this.next_prompt_number = 1;
22 22 this.kernel = null;
23 23 this.clipboard = null;
24 24 this.paste_enabled = false;
25 25 this.dirty = false;
26 26 this.msg_cell_map = {};
27 27 this.metadata = {};
28 28 this.control_key_active = false;
29 29 this.style();
30 30 this.create_elements();
31 31 this.bind_events();
32 32 this.set_tooltipontab(true);
33 33 this.set_smartcompleter(true);
34 34 this.set_timebeforetooltip(1200);
35 35 this.set_autoindent(true);
36 36 };
37 37
38 38
39 39 Notebook.prototype.style = function () {
40 40 $('div#notebook').addClass('border-box-sizing');
41 41 };
42 42
43 43
44 44 Notebook.prototype.create_elements = function () {
45 45 // We add this end_space div to the end of the notebook div to:
46 46 // i) provide a margin between the last cell and the end of the notebook
47 47 // ii) to prevent the div from scrolling up when the last cell is being
48 48 // edited, but is too low on the page, which browsers will do automatically.
49 49 var that = this;
50 50 var end_space = $('<div class="end_space"></div>').height("30%");
51 51 end_space.dblclick(function (e) {
52 52 if (that.read_only) return;
53 53 var ncells = that.ncells();
54 54 that.insert_code_cell_below(ncells-1);
55 55 });
56 56 this.element.append(end_space);
57 57 $('div#notebook').addClass('border-box-sizing');
58 58 };
59 59
60 60
61 61 Notebook.prototype.bind_events = function () {
62 62 var that = this;
63 63 $(document).keydown(function (event) {
64 64 // console.log(event);
65 65 if (that.read_only) return true;
66 66 if (event.which === 27) {
67 67 // Intercept escape at highest level to avoid closing
68 68 // websocket connection with firefox
69 69 event.preventDefault();
70 70 }
71 71 if (event.which === 38 && !event.shiftKey) {
72 72 var cell = that.selected_cell();
73 73 if (cell.at_top()) {
74 74 event.preventDefault();
75 75 that.select_prev();
76 76 };
77 77 } else if (event.which === 40 && !event.shiftKey) {
78 78 var cell = that.selected_cell();
79 79 if (cell.at_bottom()) {
80 80 event.preventDefault();
81 81 that.select_next();
82 82 };
83 83 } else if (event.which === 13 && event.shiftKey) {
84 84 that.execute_selected_cell();
85 85 return false;
86 86 } else if (event.which === 13 && event.ctrlKey) {
87 87 that.execute_selected_cell({terminal:true});
88 88 return false;
89 89 } else if (event.which === 77 && event.ctrlKey) {
90 90 that.control_key_active = true;
91 91 return false;
92 92 } else if (event.which === 88 && that.control_key_active) {
93 93 // Cut selected cell = x
94 94 that.cut_cell();
95 95 that.control_key_active = false;
96 96 return false;
97 97 } else if (event.which === 67 && that.control_key_active) {
98 98 // Copy selected cell = c
99 99 that.copy_cell();
100 100 that.control_key_active = false;
101 101 return false;
102 102 } else if (event.which === 86 && that.control_key_active) {
103 103 // Paste selected cell = v
104 104 that.paste_cell();
105 105 that.control_key_active = false;
106 106 return false;
107 107 } else if (event.which === 68 && that.control_key_active) {
108 108 // Delete selected cell = d
109 109 that.delete_cell();
110 110 that.control_key_active = false;
111 111 return false;
112 112 } else if (event.which === 65 && that.control_key_active) {
113 113 // Insert code cell above selected = a
114 114 that.insert_code_cell_above();
115 115 that.control_key_active = false;
116 116 return false;
117 117 } else if (event.which === 66 && that.control_key_active) {
118 118 // Insert code cell below selected = b
119 119 that.insert_code_cell_below();
120 120 that.control_key_active = false;
121 121 return false;
122 122 } else if (event.which === 89 && that.control_key_active) {
123 123 // To code = y
124 124 that.to_code();
125 125 that.control_key_active = false;
126 126 return false;
127 127 } else if (event.which === 77 && that.control_key_active) {
128 128 // To markdown = m
129 129 that.to_markdown();
130 130 that.control_key_active = false;
131 131 return false;
132 132 } else if (event.which === 84 && that.control_key_active) {
133 133 // Toggle output = t
134 134 that.toggle_output();
135 135 that.control_key_active = false;
136 136 return false;
137 137 } else if (event.which === 83 && that.control_key_active) {
138 138 // Save notebook = s
139 139 IPython.save_widget.save_notebook();
140 140 that.control_key_active = false;
141 141 return false;
142 142 } else if (event.which === 74 && that.control_key_active) {
143 143 // Move cell down = j
144 144 that.move_cell_down();
145 145 that.control_key_active = false;
146 146 return false;
147 147 } else if (event.which === 75 && that.control_key_active) {
148 148 // Move cell up = k
149 149 that.move_cell_up();
150 150 that.control_key_active = false;
151 151 return false;
152 152 } else if (event.which === 80 && that.control_key_active) {
153 153 // Select previous = p
154 154 that.select_prev();
155 155 that.control_key_active = false;
156 156 return false;
157 157 } else if (event.which === 78 && that.control_key_active) {
158 158 // Select next = n
159 159 that.select_next();
160 160 that.control_key_active = false;
161 161 return false;
162 162 } else if (event.which === 76 && that.control_key_active) {
163 163 // Toggle line numbers = l
164 164 that.cell_toggle_line_numbers();
165 165 that.control_key_active = false;
166 166 return false;
167 167 } else if (event.which === 73 && that.control_key_active) {
168 168 // Interrupt kernel = i
169 169 IPython.notebook.kernel.interrupt();
170 170 that.control_key_active = false;
171 171 return false;
172 172 } else if (event.which === 190 && that.control_key_active) {
173 173 // Restart kernel = . # matches qt console
174 174 IPython.notebook.restart_kernel();
175 175 that.control_key_active = false;
176 176 return false;
177 177 } else if (event.which === 72 && that.control_key_active) {
178 178 // Show keyboard shortcuts = h
179 179 IPython.quick_help.show_keyboard_shortcuts();
180 180 that.control_key_active = false;
181 181 return false;
182 182 } else if (event.which === 69 && that.control_key_active) {
183 183 // Edit in Ace = e
184 184 IPython.fulledit_widget.toggle();
185 185 that.control_key_active = false;
186 186 return false;
187 187 } else if (that.control_key_active) {
188 188 that.control_key_active = false;
189 189 return true;
190 190 };
191 191 return true;
192 192 });
193 193
194 194 this.element.bind('collapse_pager', function () {
195 195 var app_height = $('div#main_app').height(); // content height
196 196 var splitter_height = $('div#pager_splitter').outerHeight(true);
197 197 var new_height = app_height - splitter_height;
198 198 that.element.animate({height : new_height + 'px'}, 'fast');
199 199 });
200 200
201 201 this.element.bind('expand_pager', function () {
202 202 var app_height = $('div#main_app').height(); // content height
203 203 var splitter_height = $('div#pager_splitter').outerHeight(true);
204 204 var pager_height = $('div#pager').outerHeight(true);
205 205 var new_height = app_height - pager_height - splitter_height;
206 206 that.element.animate({height : new_height + 'px'}, 'fast');
207 207 });
208 208
209 209 $(window).bind('beforeunload', function () {
210 210 // TODO: Make killing the kernel configurable.
211 211 var kill_kernel = false;
212 212 if (kill_kernel) {
213 213 that.kernel.kill();
214 214 }
215 215 if (that.dirty && ! that.read_only) {
216 216 return "You have unsaved changes that will be lost if you leave this page.";
217 217 };
218 218 // Null is the *only* return value that will make the browser not
219 219 // pop up the "don't leave" dialog.
220 220 return null;
221 221 });
222 222 };
223 223
224 224
225 225 Notebook.prototype.scroll_to_bottom = function () {
226 226 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
227 227 };
228 228
229 229
230 230 Notebook.prototype.scroll_to_top = function () {
231 231 this.element.animate({scrollTop:0}, 0);
232 232 };
233 233
234 234
235 235 // Cell indexing, retrieval, etc.
236 236
237 237
238 238 Notebook.prototype.cell_elements = function () {
239 239 return this.element.children("div.cell");
240 240 };
241 241
242 242
243 243 Notebook.prototype.ncells = function (cell) {
244 244 return this.cell_elements().length;
245 245 };
246 246
247 247
248 248 // TODO: we are often calling cells as cells()[i], which we should optimize
249 249 // to cells(i) or a new method.
250 250 Notebook.prototype.cells = function () {
251 251 return this.cell_elements().toArray().map(function (e) {
252 252 return $(e).data("cell");
253 253 });
254 254 };
255 255
256 256
257 257 Notebook.prototype.find_cell_index = function (cell) {
258 258 var result = null;
259 259 this.cell_elements().filter(function (index) {
260 260 if ($(this).data("cell") === cell) {
261 261 result = index;
262 262 };
263 263 });
264 264 return result;
265 265 };
266 266
267 267
268 268 Notebook.prototype.index_or_selected = function (index) {
269 269 var i;
270 270 if (index === undefined) {
271 271 i = this.selected_index();
272 272 if (i === null) {
273 273 i = 0;
274 274 }
275 275 } else {
276 276 i = index;
277 277 }
278 278 return i;
279 279 };
280 280
281 281
282 282 Notebook.prototype.select = function (index) {
283 283 if (index !== undefined && index >= 0 && index < this.ncells()) {
284 284 if (this.selected_index() !== null) {
285 285 this.selected_cell().unselect();
286 286 };
287 287 this.cells()[index].select();
288 288 };
289 289 return this;
290 290 };
291 291
292 292
293 293 Notebook.prototype.select_next = function () {
294 294 var index = this.selected_index();
295 295 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
296 296 this.select(index+1);
297 297 };
298 298 return this;
299 299 };
300 300
301 301
302 302 Notebook.prototype.select_prev = function () {
303 303 var index = this.selected_index();
304 304 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
305 305 this.select(index-1);
306 306 };
307 307 return this;
308 308 };
309 309
310 310
311 311 Notebook.prototype.selected_index = function () {
312 312 var result = null;
313 313 this.cell_elements().filter(function (index) {
314 314 if ($(this).data("cell").selected === true) {
315 315 result = index;
316 316 };
317 317 });
318 318 return result;
319 319 };
320 320
321 321
322 322 Notebook.prototype.cell_for_msg = function (msg_id) {
323 323 var cell_id = this.msg_cell_map[msg_id];
324 324 var result = null;
325 325 this.cell_elements().filter(function (index) {
326 326 cell = $(this).data("cell");
327 327 if (cell.cell_id === cell_id) {
328 328 result = cell;
329 329 };
330 330 });
331 331 return result;
332 332 };
333 333
334 334
335 335 Notebook.prototype.selected_cell = function () {
336 336 return this.cell_elements().eq(this.selected_index()).data("cell");
337 337 };
338 338
339 339
340 340 // Cell insertion, deletion and moving.
341 341
342 342 Notebook.prototype.delete_cell = function (index) {
343 343 var i = this.index_or_selected(index);
344 344 if (i !== null && i >= 0 && i < this.ncells()) {
345 345 this.cell_elements().eq(i).remove();
346 346 if (i === (this.ncells())) {
347 347 this.select(i-1);
348 348 } else {
349 349 this.select(i);
350 350 };
351 351 };
352 352 this.dirty = true;
353 353 return this;
354 354 };
355 355
356 356
357 357 Notebook.prototype.append_cell = function (cell) {
358 358 this.element.find('div.end_space').before(cell.element);
359 359 this.dirty = true;
360 360 return this;
361 361 };
362 362
363 363
364 364 Notebook.prototype.insert_cell_below = function (cell, index) {
365 365 var ncells = this.ncells();
366 366 if (ncells === 0) {
367 367 this.append_cell(cell);
368 368 return this;
369 369 };
370 370 if (index >= 0 && index < ncells) {
371 371 this.cell_elements().eq(index).after(cell.element);
372 372 };
373 373 this.dirty = true;
374 374 return this;
375 375 };
376 376
377 377
378 378 Notebook.prototype.insert_cell_above = function (cell, index) {
379 379 var ncells = this.ncells();
380 380 if (ncells === 0) {
381 381 this.append_cell(cell);
382 382 return this;
383 383 };
384 384 if (index >= 0 && index < ncells) {
385 385 this.cell_elements().eq(index).before(cell.element);
386 386 };
387 387 this.dirty = true;
388 388 return this;
389 389 };
390 390
391 391
392 392 Notebook.prototype.move_cell_up = function (index) {
393 393 var i = index || this.selected_index();
394 394 if (i !== null && i < this.ncells() && i > 0) {
395 395 var pivot = this.cell_elements().eq(i-1);
396 396 var tomove = this.cell_elements().eq(i);
397 397 if (pivot !== null && tomove !== null) {
398 398 tomove.detach();
399 399 pivot.before(tomove);
400 400 this.select(i-1);
401 401 };
402 402 };
403 403 this.dirty = true;
404 404 return this;
405 405 };
406 406
407 407
408 408 Notebook.prototype.move_cell_down = function (index) {
409 409 var i = index || this.selected_index();
410 410 if (i !== null && i < (this.ncells()-1) && i >= 0) {
411 411 var pivot = this.cell_elements().eq(i+1);
412 412 var tomove = this.cell_elements().eq(i);
413 413 if (pivot !== null && tomove !== null) {
414 414 tomove.detach();
415 415 pivot.after(tomove);
416 416 this.select(i+1);
417 417 };
418 418 };
419 419 this.dirty = true;
420 420 return this;
421 421 };
422 422
423 423
424 424 Notebook.prototype.sort_cells = function () {
425 425 var ncells = this.ncells();
426 426 var sindex = this.selected_index();
427 427 var swapped;
428 428 do {
429 429 swapped = false;
430 430 for (var i=1; i<ncells; i++) {
431 431 current = this.cell_elements().eq(i).data("cell");
432 432 previous = this.cell_elements().eq(i-1).data("cell");
433 433 if (previous.input_prompt_number > current.input_prompt_number) {
434 434 this.move_cell_up(i);
435 435 swapped = true;
436 436 };
437 437 };
438 438 } while (swapped);
439 439 this.select(sindex);
440 440 return this;
441 441 };
442 442
443 443
444 444 Notebook.prototype.insert_code_cell_above = function (index) {
445 445 // TODO: Bounds check for i
446 446 var i = this.index_or_selected(index);
447 447 var cell = new IPython.CodeCell(this);
448 448 cell.set_input_prompt();
449 449 this.insert_cell_above(cell, i);
450 450 this.select(this.find_cell_index(cell));
451 451 return cell;
452 452 };
453 453
454 454
455 455 Notebook.prototype.insert_code_cell_below = function (index) {
456 456 // TODO: Bounds check for i
457 457 var i = this.index_or_selected(index);
458 458 var cell = new IPython.CodeCell(this);
459 459 cell.set_input_prompt();
460 460 this.insert_cell_below(cell, i);
461 461 this.select(this.find_cell_index(cell));
462 462 return cell;
463 463 };
464 464
465 465
466 466 Notebook.prototype.insert_html_cell_above = function (index) {
467 467 // TODO: Bounds check for i
468 468 var i = this.index_or_selected(index);
469 469 var cell = new IPython.HTMLCell(this);
470 470 cell.config_mathjax();
471 471 this.insert_cell_above(cell, i);
472 472 this.select(this.find_cell_index(cell));
473 473 return cell;
474 474 };
475 475
476 476
477 477 Notebook.prototype.insert_html_cell_below = function (index) {
478 478 // TODO: Bounds check for i
479 479 var i = this.index_or_selected(index);
480 480 var cell = new IPython.HTMLCell(this);
481 481 cell.config_mathjax();
482 482 this.insert_cell_below(cell, i);
483 483 this.select(this.find_cell_index(cell));
484 484 return cell;
485 485 };
486 486
487 487
488 488 Notebook.prototype.insert_markdown_cell_above = function (index) {
489 489 // TODO: Bounds check for i
490 490 var i = this.index_or_selected(index);
491 491 var cell = new IPython.MarkdownCell(this);
492 492 cell.config_mathjax();
493 493 this.insert_cell_above(cell, i);
494 494 this.select(this.find_cell_index(cell));
495 495 return cell;
496 496 };
497 497
498 498
499 499 Notebook.prototype.insert_markdown_cell_below = function (index) {
500 500 // TODO: Bounds check for i
501 501 var i = this.index_or_selected(index);
502 502 var cell = new IPython.MarkdownCell(this);
503 503 cell.config_mathjax();
504 504 this.insert_cell_below(cell, i);
505 505 this.select(this.find_cell_index(cell));
506 506 return cell;
507 507 };
508 508
509 509
510 510 Notebook.prototype.to_code = function (index) {
511 511 // TODO: Bounds check for i
512 512 var i = this.index_or_selected(index);
513 513 var source_element = this.cell_elements().eq(i);
514 514 var source_cell = source_element.data("cell");
515 515 if (source_cell instanceof IPython.HTMLCell ||
516 516 source_cell instanceof IPython.MarkdownCell) {
517 517 this.insert_code_cell_below(i);
518 518 var target_cell = this.cells()[i+1];
519 519 target_cell.set_code(source_cell.get_source());
520 520 source_element.remove();
521 521 target_cell.select();
522 522 };
523 523 this.dirty = true;
524 524 };
525 525
526 526
527 527 Notebook.prototype.to_markdown = function (index) {
528 528 // TODO: Bounds check for i
529 529 var i = this.index_or_selected(index);
530 530 var source_element = this.cell_elements().eq(i);
531 531 var source_cell = source_element.data("cell");
532 532 var target_cell = null;
533 533 if (source_cell instanceof IPython.CodeCell) {
534 534 this.insert_markdown_cell_below(i);
535 535 target_cell = this.cells()[i+1];
536 536 var text = source_cell.get_code();
537 537 } else if (source_cell instanceof IPython.HTMLCell) {
538 538 this.insert_markdown_cell_below(i);
539 539 target_cell = this.cells()[i+1];
540 540 var text = source_cell.get_source();
541 541 if (text === source_cell.placeholder) {
542 542 text = target_cell.placeholder;
543 543 }
544 544 }
545 545 if (target_cell !== null) {
546 546 if (text === "") {text = target_cell.placeholder;};
547 547 target_cell.set_source(text);
548 548 source_element.remove();
549 549 target_cell.edit();
550 550 }
551 551 this.dirty = true;
552 552 };
553 553
554 554
555 555 Notebook.prototype.to_html = function (index) {
556 556 // TODO: Bounds check for i
557 557 var i = this.index_or_selected(index);
558 558 var source_element = this.cell_elements().eq(i);
559 559 var source_cell = source_element.data("cell");
560 560 var target_cell = null;
561 561 if (source_cell instanceof IPython.CodeCell) {
562 562 this.insert_html_cell_below(i);
563 563 target_cell = this.cells()[i+1];
564 564 var text = source_cell.get_code();
565 565 } else if (source_cell instanceof IPython.MarkdownCell) {
566 566 this.insert_html_cell_below(i);
567 567 target_cell = this.cells()[i+1];
568 568 var text = source_cell.get_source();
569 569 if (text === source_cell.placeholder) {
570 570 text = target_cell.placeholder;
571 571 }
572 572 }
573 573 if (target_cell !== null) {
574 574 if (text === "") {text = target_cell.placeholder;};
575 575 target_cell.set_source(text);
576 576 source_element.remove();
577 577 target_cell.edit();
578 578 }
579 579 this.dirty = true;
580 580 };
581 581
582 582
583 583 // Copy/Paste/Merge/Split
584 584
585 585 Notebook.prototype.enable_paste = function () {
586 586 var that = this;
587 587 if (!this.paste_enabled) {
588 588 $('#paste_cell').removeClass('ui-state-disabled')
589 589 .on('click', function () {that.paste_cell();});
590 590 $('#paste_cell_above').removeClass('ui-state-disabled')
591 591 .on('click', function () {that.paste_cell_above();});
592 592 $('#paste_cell_below').removeClass('ui-state-disabled')
593 593 .on('click', function () {that.paste_cell_below();});
594 594 this.paste_enabled = true;
595 595 };
596 596 };
597 597
598 598
599 599 Notebook.prototype.disable_paste = function () {
600 600 if (this.paste_enabled) {
601 601 $('#paste_cell').addClass('ui-state-disabled').off('click');
602 602 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
603 603 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
604 604 this.paste_enabled = false;
605 605 };
606 606 };
607 607
608 608
609 609 Notebook.prototype.cut_cell = function () {
610 console.log('cut_cell');
611 610 this.copy_cell();
612 611 this.delete_cell();
613 612 }
614 613
615 614 Notebook.prototype.copy_cell = function () {
616 615 var cell = this.selected_cell();
617 616 this.clipboard = cell.toJSON();
618 617 this.enable_paste();
619 618 };
620 619
621 620
622 621 Notebook.prototype.paste_cell = function () {
623 console.log('paste_cell');
624 622 if (this.clipboard !== null && this.paste_enabled) {
625 623 var cell_data = this.clipboard;
626 624 if (cell_data.cell_type == 'code') {
627 625 new_cell = this.insert_code_cell_above();
628 626 new_cell.fromJSON(cell_data);
629 627 } else if (cell_data.cell_type === 'html') {
630 628 new_cell = this.insert_html_cell_above();
631 629 new_cell.fromJSON(cell_data);
632 630 } else if (cell_data.cell_type === 'markdown') {
633 631 new_cell = this.insert_markdown_cell_above();
634 632 new_cell.fromJSON(cell_data);
635 633 };
636 634 this.select_next();
637 635 this.delete_cell();
638 636 };
639 637 };
640 638
641 639
642 640 Notebook.prototype.paste_cell_above = function () {
643 641 if (this.clipboard !== null && this.paste_enabled) {
644 642 var cell_data = this.clipboard;
645 643 if (cell_data.cell_type == 'code') {
646 644 new_cell = this.insert_code_cell_above();
647 645 new_cell.fromJSON(cell_data);
648 646 } else if (cell_data.cell_type === 'html') {
649 647 new_cell = this.insert_html_cell_above();
650 648 new_cell.fromJSON(cell_data);
651 649 } else if (cell_data.cell_type === 'markdown') {
652 650 new_cell = this.insert_markdown_cell_above();
653 651 new_cell.fromJSON(cell_data);
654 652 };
655 653 };
656 654 };
657 655
658 656
659 657 Notebook.prototype.paste_cell_below = function () {
660 658 if (this.clipboard !== null && this.paste_enabled) {
661 659 var cell_data = this.clipboard;
662 660 if (cell_data.cell_type == 'code') {
663 661 new_cell = this.insert_code_cell_below();
664 662 new_cell.fromJSON(cell_data);
665 663 } else if (cell_data.cell_type === 'html') {
666 664 new_cell = this.insert_html_cell_below();
667 665 new_cell.fromJSON(cell_data);
668 666 } else if (cell_data.cell_type === 'markdown') {
669 667 new_cell = this.insert_markdown_cell_below();
670 668 new_cell.fromJSON(cell_data);
671 669 };
672 670 };
673 671 };
674 672
675 673
676 674 Notebook.prototype.split_cell = function () {
677 675 // Todo: implement spliting for other cell types.
678 676 var cell = this.selected_cell();
679 677 if (cell instanceof IPython.CodeCell) {
680 678 var cursor = cell.code_mirror.getCursor();
681 679 var last_line_num = cell.code_mirror.lineCount()-1;
682 680 var last_line_len = cell.code_mirror.getLine(last_line_num).length;
683 681 var end = {line:last_line_num, ch:last_line_len}
684 682 var texta = cell.code_mirror.getRange({line:0,ch:0}, cursor);
685 683 var textb = cell.code_mirror.getRange(cursor, end);
686 684 texta = texta.replace(/^\n+/, '').replace(/\n+$/, '');
687 685 textb = textb.replace(/^\n+/, '').replace(/\n+$/, '');
688 686 cell.set_code(texta);
689 687 var new_cell = this.insert_code_cell_below();
690 688 new_cell.set_code(textb);
691 689 };
692 690 };
693 691
694 692
695 693 Notebook.prototype.merge_cell_above = function () {
696 694 // Todo: implement merging for other cell types.
697 695 var cell = this.selected_cell();
698 696 var index = this.selected_index();
699 697 if (index > 0) {
700 698 upper_cell = this.cells()[index-1];
701 699 lower_cell = this.cells()[index];
702 700 if (upper_cell instanceof IPython.CodeCell && lower_cell instanceof IPython.CodeCell) {
703 701 upper_text = upper_cell.get_code();
704 702 lower_text = lower_cell.get_code();
705 703 lower_cell.set_code(upper_text+'\n'+lower_text);
706 704 this.delete_cell(index-1);
707 705 };
708 706 };
709 707 };
710 708
711 709
712 710 Notebook.prototype.merge_cell_below = function () {
713 711 // Todo: implement merging for other cell types.
714 712 var cell = this.selected_cell();
715 713 var index = this.selected_index();
716 714 if (index < this.ncells()-1) {
717 715 upper_cell = this.cells()[index];
718 716 lower_cell = this.cells()[index+1];
719 717 if (upper_cell instanceof IPython.CodeCell && lower_cell instanceof IPython.CodeCell) {
720 718 upper_text = upper_cell.get_code();
721 719 lower_text = lower_cell.get_code();
722 720 upper_cell.set_code(upper_text+'\n'+lower_text);
723 721 this.delete_cell(index+1);
724 722 };
725 723 };
726 724 };
727 725
728 726 // Cell collapsing and output clearing
729 727
730 728 Notebook.prototype.collapse = function (index) {
731 729 var i = this.index_or_selected(index);
732 730 this.cells()[i].collapse();
733 731 this.dirty = true;
734 732 };
735 733
736 734
737 735 Notebook.prototype.expand = function (index) {
738 736 var i = this.index_or_selected(index);
739 737 this.cells()[i].expand();
740 738 this.dirty = true;
741 739 };
742 740
743 741
744 742 Notebook.prototype.toggle_output = function (index) {
745 743 var i = this.index_or_selected(index);
746 744 this.cells()[i].toggle_output();
747 745 this.dirty = true;
748 746 };
749 747
750 748
751 749 Notebook.prototype.set_timebeforetooltip = function (time) {
752 750 this.time_before_tooltip = time;
753 751 };
754 752
755 753 Notebook.prototype.set_tooltipontab = function (state) {
756 754 this.tooltip_on_tab = state;
757 755 };
758 756
759 757 Notebook.prototype.set_smartcompleter = function (state) {
760 758 this.smart_completer = state;
761 759 };
762 760
763 761 Notebook.prototype.set_autoindent = function (state) {
764 762 var cells = this.cells();
765 763 len = cells.length;
766 764 for (var i=0; i<len; i++) {
767 765 cells[i].set_autoindent(state);
768 766 };
769 767 };
770 768
771 769
772 770 Notebook.prototype.clear_all_output = function () {
773 771 var ncells = this.ncells();
774 772 var cells = this.cells();
775 773 for (var i=0; i<ncells; i++) {
776 774 if (cells[i] instanceof IPython.CodeCell) {
777 775 cells[i].clear_output(true,true,true);
778 776 }
779 777 };
780 778 this.dirty = true;
781 779 };
782 780
783 781 // Other cell functions: line numbers, ...
784 782
785 783 Notebook.prototype.cell_toggle_line_numbers = function() {
786 784 this.selected_cell().toggle_line_numbers();
787 785 };
788 786
789 787 // Kernel related things
790 788
791 789 Notebook.prototype.start_kernel = function () {
792 790 this.kernel = new IPython.Kernel();
793 791 var notebook_id = IPython.save_widget.get_notebook_id();
794 792 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
795 793 };
796 794
797 795
798 796 Notebook.prototype.restart_kernel = function () {
799 797 var that = this;
800 798 var notebook_id = IPython.save_widget.get_notebook_id();
801 799
802 800 var dialog = $('<div/>');
803 801 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
804 802 $(document).append(dialog);
805 803 dialog.dialog({
806 804 resizable: false,
807 805 modal: true,
808 806 title: "Restart kernel or continue running?",
809 807 closeText: '',
810 808 buttons : {
811 809 "Restart": function () {
812 810 that.kernel.restart($.proxy(that.kernel_started, that));
813 811 $(this).dialog('close');
814 812 },
815 813 "Continue running": function () {
816 814 $(this).dialog('close');
817 815 }
818 816 }
819 817 });
820 818 };
821 819
822 820
823 821 Notebook.prototype.kernel_started = function () {
824 822 console.log("Kernel started: ", this.kernel.kernel_id);
825 823 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
826 824 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
827 825 };
828 826
829 827
830 828 Notebook.prototype.handle_shell_reply = function (e) {
831 829 reply = $.parseJSON(e.data);
832 830 var header = reply.header;
833 831 var content = reply.content;
834 832 var msg_type = header.msg_type;
835 833 // console.log(reply);
836 834 var cell = this.cell_for_msg(reply.parent_header.msg_id);
837 835 if (msg_type === "execute_reply") {
838 836 cell.set_input_prompt(content.execution_count);
839 837 cell.element.removeClass("running");
840 838 this.dirty = true;
841 839 } else if (msg_type === "complete_reply") {
842 840 cell.finish_completing(content.matched_text, content.matches);
843 841 } else if (msg_type === "object_info_reply"){
844 842 //console.log('back from object_info_request : ')
845 843 rep = reply.content;
846 844 if(rep.found)
847 845 {
848 846 cell.finish_tooltip(rep);
849 847 }
850 848 } else {
851 849 //console.log("unknown reply:"+msg_type);
852 850 }
853 851 // when having a rely from object_info_reply,
854 852 // no payload so no nned to handle it
855 853 if(typeof(content.payload)!='undefined') {
856 854 var payload = content.payload || [];
857 855 this.handle_payload(cell, payload);
858 856 }
859 857 };
860 858
861 859
862 860 Notebook.prototype.handle_payload = function (cell, payload) {
863 861 var l = payload.length;
864 862 for (var i=0; i<l; i++) {
865 863 if (payload[i].source === 'IPython.zmq.page.page') {
866 864 if (payload[i].text.trim() !== '') {
867 865 IPython.pager.clear();
868 866 IPython.pager.expand();
869 867 IPython.pager.append_text(payload[i].text);
870 868 }
871 869 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
872 870 var index = this.find_cell_index(cell);
873 871 var new_cell = this.insert_code_cell_below(index);
874 872 new_cell.set_code(payload[i].text);
875 873 this.dirty = true;
876 874 }
877 875 };
878 876 };
879 877
880 878
881 879 Notebook.prototype.handle_iopub_reply = function (e) {
882 880 reply = $.parseJSON(e.data);
883 881 var content = reply.content;
884 882 // console.log(reply);
885 883 var msg_type = reply.header.msg_type;
886 884 var cell = this.cell_for_msg(reply.parent_header.msg_id);
887 885 if (msg_type !== 'status' && !cell){
888 886 // message not from this notebook, but should be attached to a cell
889 887 console.log("Received IOPub message not caused by one of my cells");
890 888 console.log(reply);
891 889 return;
892 890 }
893 891 var output_types = ['stream','display_data','pyout','pyerr'];
894 892 if (output_types.indexOf(msg_type) >= 0) {
895 893 this.handle_output(cell, msg_type, content);
896 894 } else if (msg_type === 'status') {
897 895 if (content.execution_state === 'busy') {
898 896 IPython.kernel_status_widget.status_busy();
899 897 } else if (content.execution_state === 'idle') {
900 898 IPython.kernel_status_widget.status_idle();
901 899 } else if (content.execution_state === 'dead') {
902 900 this.handle_status_dead();
903 901 };
904 902 } else if (msg_type === 'clear_output') {
905 903 cell.clear_output(content.stdout, content.stderr, content.other);
906 904 };
907 905 };
908 906
909 907
910 908 Notebook.prototype.handle_status_dead = function () {
911 909 var that = this;
912 910 this.kernel.stop_channels();
913 911 var dialog = $('<div/>');
914 912 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.');
915 913 $(document).append(dialog);
916 914 dialog.dialog({
917 915 resizable: false,
918 916 modal: true,
919 917 title: "Dead kernel",
920 918 buttons : {
921 919 "Restart": function () {
922 920 that.start_kernel();
923 921 $(this).dialog('close');
924 922 },
925 923 "Continue running": function () {
926 924 $(this).dialog('close');
927 925 }
928 926 }
929 927 });
930 928 };
931 929
932 930
933 931 Notebook.prototype.handle_output = function (cell, msg_type, content) {
934 932 var json = {};
935 933 json.output_type = msg_type;
936 934 if (msg_type === "stream") {
937 935 json.text = utils.fixConsole(content.data);
938 936 json.stream = content.name;
939 937 } else if (msg_type === "display_data") {
940 938 json = this.convert_mime_types(json, content.data);
941 939 } else if (msg_type === "pyout") {
942 940 json.prompt_number = content.execution_count;
943 941 json = this.convert_mime_types(json, content.data);
944 942 } else if (msg_type === "pyerr") {
945 943 json.ename = content.ename;
946 944 json.evalue = content.evalue;
947 945 var traceback = [];
948 946 for (var i=0; i<content.traceback.length; i++) {
949 947 traceback.push(utils.fixConsole(content.traceback[i]));
950 948 }
951 949 json.traceback = traceback;
952 950 };
953 951 cell.append_output(json);
954 952 this.dirty = true;
955 953 };
956 954
957 955
958 956 Notebook.prototype.convert_mime_types = function (json, data) {
959 957 if (data['text/plain'] !== undefined) {
960 958 json.text = utils.fixConsole(data['text/plain']);
961 959 };
962 960 if (data['text/html'] !== undefined) {
963 961 json.html = data['text/html'];
964 962 };
965 963 if (data['image/svg+xml'] !== undefined) {
966 964 json.svg = data['image/svg+xml'];
967 965 };
968 966 if (data['image/png'] !== undefined) {
969 967 json.png = data['image/png'];
970 968 };
971 969 if (data['image/jpeg'] !== undefined) {
972 970 json.jpeg = data['image/jpeg'];
973 971 };
974 972 if (data['text/latex'] !== undefined) {
975 973 json.latex = data['text/latex'];
976 974 };
977 975 if (data['application/json'] !== undefined) {
978 976 json.json = data['application/json'];
979 977 };
980 978 if (data['application/javascript'] !== undefined) {
981 979 json.javascript = data['application/javascript'];
982 980 }
983 981 return json;
984 982 };
985 983
986 984
987 985 Notebook.prototype.execute_selected_cell = function (options) {
988 986 // add_new: should a new cell be added if we are at the end of the nb
989 987 // terminal: execute in terminal mode, which stays in the current cell
990 988 default_options = {terminal: false, add_new: true};
991 989 $.extend(default_options, options);
992 990 var that = this;
993 991 var cell = that.selected_cell();
994 992 var cell_index = that.find_cell_index(cell);
995 993 if (cell instanceof IPython.CodeCell) {
996 994 cell.clear_output(true, true, true);
997 995 cell.set_input_prompt('*');
998 996 cell.element.addClass("running");
999 997 var code = cell.get_code();
1000 998 var msg_id = that.kernel.execute(cell.get_code());
1001 999 that.msg_cell_map[msg_id] = cell.cell_id;
1002 1000 } else if (cell instanceof IPython.HTMLCell) {
1003 1001 cell.render();
1004 1002 }
1005 1003 if (default_options.terminal) {
1006 1004 cell.select_all();
1007 1005 } else {
1008 1006 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1009 1007 that.insert_code_cell_below();
1010 1008 // If we are adding a new cell at the end, scroll down to show it.
1011 1009 that.scroll_to_bottom();
1012 1010 } else {
1013 1011 that.select(cell_index+1);
1014 1012 };
1015 1013 };
1016 1014 this.dirty = true;
1017 1015 };
1018 1016
1019 1017
1020 1018 Notebook.prototype.execute_all_cells = function () {
1021 1019 var ncells = this.ncells();
1022 1020 for (var i=0; i<ncells; i++) {
1023 1021 this.select(i);
1024 1022 this.execute_selected_cell({add_new:false});
1025 1023 };
1026 1024 this.scroll_to_bottom();
1027 1025 };
1028 1026
1029 1027
1030 1028 Notebook.prototype.request_tool_tip = function (cell,func) {
1031 1029 // Feel free to shorten this logic if you are better
1032 1030 // than me in regEx
1033 1031 // basicaly you shoul be able to get xxx.xxx.xxx from
1034 1032 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
1035 1033 // remove everything between matchin bracket (need to iterate)
1036 1034 matchBracket = /\([^\(\)]+\)/g;
1037 1035 oldfunc = func;
1038 1036 func = func.replace(matchBracket,"");
1039 1037 while( oldfunc != func )
1040 1038 {
1041 1039 oldfunc = func;
1042 1040 func = func.replace(matchBracket,"");
1043 1041 }
1044 1042 // remove everythin after last open bracket
1045 1043 endBracket = /\([^\(]*$/g;
1046 1044 func = func.replace(endBracket,"");
1047 1045 var re = /[a-zA-Z._]+$/g;
1048 1046 var msg_id = this.kernel.object_info_request(re.exec(func));
1049 1047 if(typeof(msg_id)!='undefined'){
1050 1048 this.msg_cell_map[msg_id] = cell.cell_id;
1051 1049 }
1052 1050 };
1053 1051
1054 1052 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
1055 1053 var msg_id = this.kernel.complete(line, cursor_pos);
1056 1054 this.msg_cell_map[msg_id] = cell.cell_id;
1057 1055 };
1058 1056
1059 1057 // Persistance and loading
1060 1058
1061 1059
1062 1060 Notebook.prototype.fromJSON = function (data) {
1063 1061 var ncells = this.ncells();
1064 1062 var i;
1065 1063 for (i=0; i<ncells; i++) {
1066 1064 // Always delete cell 0 as they get renumbered as they are deleted.
1067 1065 this.delete_cell(0);
1068 1066 };
1069 1067 // Save the metadata
1070 1068 this.metadata = data.metadata;
1071 1069 // Only handle 1 worksheet for now.
1072 1070 var worksheet = data.worksheets[0];
1073 1071 if (worksheet !== undefined) {
1074 1072 var new_cells = worksheet.cells;
1075 1073 ncells = new_cells.length;
1076 1074 var cell_data = null;
1077 1075 var new_cell = null;
1078 1076 for (i=0; i<ncells; i++) {
1079 1077 cell_data = new_cells[i];
1080 1078 if (cell_data.cell_type == 'code') {
1081 1079 new_cell = this.insert_code_cell_below();
1082 1080 new_cell.fromJSON(cell_data);
1083 1081 } else if (cell_data.cell_type === 'html') {
1084 1082 new_cell = this.insert_html_cell_below();
1085 1083 new_cell.fromJSON(cell_data);
1086 1084 } else if (cell_data.cell_type === 'markdown') {
1087 1085 new_cell = this.insert_markdown_cell_below();
1088 1086 new_cell.fromJSON(cell_data);
1089 1087 };
1090 1088 };
1091 1089 };
1092 1090 };
1093 1091
1094 1092
1095 1093 Notebook.prototype.toJSON = function () {
1096 1094 var cells = this.cells();
1097 1095 var ncells = cells.length;
1098 1096 cell_array = new Array(ncells);
1099 1097 for (var i=0; i<ncells; i++) {
1100 1098 cell_array[i] = cells[i].toJSON();
1101 1099 };
1102 1100 data = {
1103 1101 // Only handle 1 worksheet for now.
1104 1102 worksheets : [{cells:cell_array}],
1105 1103 metadata : this.metadata
1106 1104 };
1107 1105 return data;
1108 1106 };
1109 1107
1110 1108 Notebook.prototype.save_notebook = function () {
1111 1109 if (IPython.save_widget.test_notebook_name()) {
1112 1110 var notebook_id = IPython.save_widget.get_notebook_id();
1113 1111 var nbname = IPython.save_widget.get_notebook_name();
1114 1112 // We may want to move the name/id/nbformat logic inside toJSON?
1115 1113 var data = this.toJSON();
1116 1114 data.metadata.name = nbname;
1117 1115 data.nbformat = 2;
1118 1116 // We do the call with settings so we can set cache to false.
1119 1117 var settings = {
1120 1118 processData : false,
1121 1119 cache : false,
1122 1120 type : "PUT",
1123 1121 data : JSON.stringify(data),
1124 1122 headers : {'Content-Type': 'application/json'},
1125 1123 success : $.proxy(this.notebook_saved,this),
1126 1124 error : $.proxy(this.notebook_save_failed,this)
1127 1125 };
1128 1126 IPython.save_widget.status_saving();
1129 1127 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
1130 1128 $.ajax(url, settings);
1131 1129 };
1132 1130 };
1133 1131
1134 1132
1135 1133 Notebook.prototype.notebook_saved = function (data, status, xhr) {
1136 1134 this.dirty = false;
1137 1135 IPython.save_widget.notebook_saved();
1138 1136 IPython.save_widget.status_last_saved();
1139 1137 };
1140 1138
1141 1139
1142 1140 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
1143 1141 IPython.save_widget.status_save_failed();
1144 1142 };
1145 1143
1146 1144
1147 1145 Notebook.prototype.load_notebook = function (callback) {
1148 1146 var that = this;
1149 1147 var notebook_id = IPython.save_widget.get_notebook_id();
1150 1148 // We do the call with settings so we can set cache to false.
1151 1149 var settings = {
1152 1150 processData : false,
1153 1151 cache : false,
1154 1152 type : "GET",
1155 1153 dataType : "json",
1156 1154 success : function (data, status, xhr) {
1157 1155 that.notebook_loaded(data, status, xhr);
1158 1156 if (callback !== undefined) {
1159 1157 callback();
1160 1158 };
1161 1159 }
1162 1160 };
1163 1161 IPython.save_widget.status_loading();
1164 1162 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
1165 1163 $.ajax(url, settings);
1166 1164 };
1167 1165
1168 1166
1169 1167 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
1170 1168 var allowed = xhr.getResponseHeader('Allow');
1171 1169 this.fromJSON(data);
1172 1170 if (this.ncells() === 0) {
1173 1171 this.insert_code_cell_below();
1174 1172 };
1175 1173 IPython.save_widget.status_last_saved();
1176 1174 IPython.save_widget.set_notebook_name(data.metadata.name);
1177 1175 this.dirty = false;
1178 1176 if (! this.read_only) {
1179 1177 this.start_kernel();
1180 1178 }
1181 1179 // fromJSON always selects the last cell inserted. We need to wait
1182 1180 // until that is done before scrolling to the top.
1183 1181 setTimeout(function () {
1184 1182 IPython.notebook.select(0);
1185 1183 IPython.notebook.scroll_to_top();
1186 1184 }, 50);
1187 1185 };
1188 1186
1189 1187 IPython.Notebook = Notebook;
1190 1188
1191 1189
1192 1190 return IPython;
1193 1191
1194 1192 }(IPython));
1195 1193
General Comments 0
You need to be logged in to leave comments. Login now