##// END OF EJS Templates
Basic notebook saving and loading....
Brian Granger -
Show More
@@ -126,7 +126,7 b' class NotebookRootHandler(web.RequestHandler):'
126
126
127 def get(self):
127 def get(self):
128 files = os.listdir(os.getcwd())
128 files = os.listdir(os.getcwd())
129 files = [file for file in files if file.endswith(".nb")]
129 files = [file for file in files if file.endswith(".ipynb")]
130 self.write(json.dumps(files))
130 self.write(json.dumps(files))
131
131
132
132
@@ -135,7 +135,9 b' class NotebookHandler(web.RequestHandler):'
135 SUPPORTED_METHODS = ("GET", "DELETE", "PUT")
135 SUPPORTED_METHODS = ("GET", "DELETE", "PUT")
136
136
137 def find_path(self, filename):
137 def find_path(self, filename):
138 filename = urllib.unquote(filename) + ".nb"
138 filename = urllib.unquote(filename)
139 if not filename.endswith('.ipynb'):
140 raise web.HTTPError(400)
139 path = os.path.join(os.getcwd(), filename)
141 path = os.path.join(os.getcwd(), filename)
140 return path
142 return path
141
143
@@ -1,26 +1,6 b''
1 var IPYTHON = {};
1 var IPYTHON = {};
2
2
3
3
4
5 // $.get("/notebooks/number2.nb",function (data, status, xhr) {console.log(data);});
6 //
7 // settings = {
8 // processData : false,
9 // cache : false,
10 // type : "DELETE",
11 // success : function (data, status, xhr) {console.log(data);}
12 // }
13 // $.ajax("/notebooks/number2.nb",settings)
14 //
15 // settings = {
16 // processData : false,
17 // cache : false,
18 // type : "PUT",
19 // success : function (data, status, xhr) {console.log(data);}
20 // }
21 // $.ajax("/notebooks/number2.nb",settings)
22
23
24 //============================================================================
4 //============================================================================
25 // Utilities
5 // Utilities
26 //============================================================================
6 //============================================================================
@@ -82,6 +62,7 b' function fixConsole(txt) {'
82 return txt.trim()
62 return txt.trim()
83 }
63 }
84
64
65
85 //============================================================================
66 //============================================================================
86 // Notebook
67 // Notebook
87 //============================================================================
68 //============================================================================
@@ -94,6 +75,10 b' var Notebook = function (selector) {'
94 this.next_prompt_number = 1;
75 this.next_prompt_number = 1;
95 this.kernel = null;
76 this.kernel = null;
96 this.msg_cell_map = {};
77 this.msg_cell_map = {};
78 this.filename = null;
79 this.notebook_load_re = /%notebook load/
80 this.notebook_save_re = /%notebook save/
81 this.notebook_filename_re = /(\w)+.ipynb/
97 this.bind_events();
82 this.bind_events();
98 this.start_kernel();
83 this.start_kernel();
99 };
84 };
@@ -113,12 +98,29 b' Notebook.prototype.bind_events = function () {'
113 // The focus is not quite working here.
98 // The focus is not quite working here.
114 var cell = that.selected_cell();
99 var cell = that.selected_cell();
115 var cell_index = that.find_cell_index(cell);
100 var cell_index = that.find_cell_index(cell);
101 // TODO: the logic here needs to be moved into appropriate
102 // methods of Notebook.
116 if (cell instanceof CodeCell) {
103 if (cell instanceof CodeCell) {
117 event.preventDefault();
104 event.preventDefault();
118 cell.clear_output();
105 cell.clear_output();
119 cell.hide_output_prompt();
106 cell.hide_output_prompt();
120 var msg_id = that.kernel.execute(cell.get_code());
107 var code = cell.get_code();
121 that.msg_cell_map[msg_id] = cell.cell_id;
108 if (that.notebook_load_re.test(code)) {
109 var code_parts = code.split(' ');
110 if (code_parts.length === 3) {
111 that.load_notebook(code_parts[2]);
112 };
113 } else if (that.notebook_save_re.test(code)) {
114 var code_parts = code.split(' ');
115 if (code_parts.length === 3) {
116 that.save_notebook(code_parts[2]);
117 } else {
118 that.save_notebook()
119 };
120 } else {
121 var msg_id = that.kernel.execute(cell.get_code());
122 that.msg_cell_map[msg_id] = cell.cell_id;
123 };
122 if (cell_index === (that.ncells()-1)) {
124 if (cell_index === (that.ncells()-1)) {
123 that.insert_code_cell_after();
125 that.insert_code_cell_after();
124 } else {
126 } else {
@@ -129,7 +131,7 b' Notebook.prototype.bind_events = function () {'
129 event.preventDefault();
131 event.preventDefault();
130 var cell = that.selected_cell();
132 var cell = that.selected_cell();
131 if (cell instanceof CodeCell) {
133 if (cell instanceof CodeCell) {
132 var ta = cell.element.find("textarea.input_area");
134 var ta = cell.element.find("textarea.input_textarea");
133 ta.val(ta.val() + " ");
135 ta.val(ta.val() + " ");
134 };
136 };
135 };
137 };
@@ -386,8 +388,7 b' Notebook.prototype.text_to_code = function (index) {'
386 if (source_cell instanceof TextCell) {
388 if (source_cell instanceof TextCell) {
387 this.insert_code_cell_after(i);
389 this.insert_code_cell_after(i);
388 var target_cell = this.cells()[i+1];
390 var target_cell = this.cells()[i+1];
389 var text = source_element.find("textarea.text_cell_input").val();
391 target_cell.set_code(source_cell.get_text());
390 target_cell.element.find("textarea.input_area").val(text);
391 source_element.remove();
392 source_element.remove();
392 };
393 };
393 };
394 };
@@ -401,12 +402,9 b' Notebook.prototype.code_to_text = function (index) {'
401 if (source_cell instanceof CodeCell) {
402 if (source_cell instanceof CodeCell) {
402 this.insert_text_cell_after(i);
403 this.insert_text_cell_after(i);
403 var target_cell = this.cells()[i+1];
404 var target_cell = this.cells()[i+1];
404 var text = source_element.find("textarea.input_area").val();
405 var text = source_cell.get_code();
405 if (text === "") {text = target_cell.placeholder;};
406 if (text === "") {text = target_cell.placeholder;};
406 target_cell.element.find("textarea.text_cell_input").val(text);
407 target_cell.set_text(text);
407 target_cell.element.find("textarea.text_cell_input").html(text);
408 target_cell.element.find("div.text_cell_render").html(text);
409
410 source_element.remove();
408 source_element.remove();
411 };
409 };
412 };
410 };
@@ -476,6 +474,94 b' Notebook.prototype._handle_execute_reply = function (reply, cell) {'
476 };
474 };
477
475
478
476
477 // Persistance and loading
478
479
480 Notebook.prototype.fromJSON = function (data) {
481 var ncells = this.ncells();
482 for (var i=0; i<ncells; i++) {
483 // Always delete cell 0 as they get renumbered as they are deleted.
484 this.delete_cell(0);
485 };
486 var new_cells = data.cells;
487 ncells = new_cells.length;
488 var cell_data = null;
489 for (var i=0; i<ncells; i++) {
490 cell_data = new_cells[i];
491 if (cell_data.cell_type == 'code') {
492 this.insert_code_cell_after();
493 this.selected_cell().fromJSON(cell_data);
494 } else if (cell_data.cell_type === 'text') {
495 this.insert_text_cell_after();
496 this.selected_cell().fromJSON(cell_data);
497 };
498 };
499 };
500
501
502 Notebook.prototype.toJSON = function () {
503 var cells = this.cells();
504 var ncells = cells.length;
505 cell_array = new Array(ncells);
506 for (var i=0; i<ncells; i++) {
507 cell_array[i] = cells[i].toJSON();
508 };
509 json = {
510 cells : cell_array
511 };
512 return json
513 };
514
515
516 Notebook.prototype.test_filename = function (filename) {
517 if (this.notebook_filename_re.test(filename)) {
518 return true;
519 } else {
520 var bad_filename = $('<div/>');
521 bad_filename.html(
522 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
523 );
524 bad_filename.dialog({title: 'Invalid filename', modal: true});
525 return false;
526 };
527 };
528
529 Notebook.prototype.save_notebook = function (filename) {
530 this.filename = filename || this.filename || '';
531 if (this.filename === '') {
532 var no_filename = $('<div/>');
533 no_filename.html(
534 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
535 );
536 no_filename.dialog({title: 'Missing filename', modal: true});
537 return;
538 }
539 if (!this.test_filename(this.filename)) {return;}
540 var thedata = this.toJSON();
541 var settings = {
542 processData : false,
543 cache : false,
544 type : "PUT",
545 data : JSON.stringify(thedata),
546 success : function (data, status, xhr) {console.log(data);}
547 };
548 $.ajax("/notebooks/" + this.filename, settings);
549 };
550
551
552 Notebook.prototype.load_notebook = function (filename) {
553 if (!this.test_filename(filename)) {return;}
554 var that = this;
555 $.getJSON("/notebooks/" + filename,
556 function (data, status, xhr) {
557 that.fromJSON(data);
558 that.filename = filename;
559 that.kernel.restart();
560 }
561 );
562 }
563
564
479 //============================================================================
565 //============================================================================
480 // Cell
566 // Cell
481 //============================================================================
567 //============================================================================
@@ -620,16 +706,32 b' CodeCell.prototype.set_output_prompt = function (number) {'
620 this.element.find('div.output_prompt').html('Out[' + n + ']:');
706 this.element.find('div.output_prompt').html('Out[' + n + ']:');
621 };
707 };
622
708
709
623 CodeCell.prototype.hide_output_prompt = function () {
710 CodeCell.prototype.hide_output_prompt = function () {
624 this.element.find('div.output_prompt').hide();
711 this.element.find('div.output_prompt').hide();
625 };
712 };
626
713
714
627 CodeCell.prototype.show_output_prompt = function () {
715 CodeCell.prototype.show_output_prompt = function () {
628 this.element.find('div.output_prompt').show();
716 this.element.find('div.output_prompt').show();
629 };
717 };
630
718
719
631 CodeCell.prototype.get_code = function () {
720 CodeCell.prototype.get_code = function () {
632 return this.element.find("textarea.input_area").val();
721 return this.element.find("textarea.input_textarea").val();
722 };
723
724
725 CodeCell.prototype.set_code = function (code) {
726 return this.element.find("textarea.input_textarea").val(code);
727 };
728
729
730 CodeCell.prototype.fromJSON = function (data) {
731 if (data.cell_type === 'code') {
732 this.set_code(data.code);
733 this.set_input_prompt(data.prompt_number);
734 };
633 };
735 };
634
736
635
737
@@ -640,6 +742,7 b' CodeCell.prototype.toJSON = function () {'
640 prompt_number : this.input_prompt_number
742 prompt_number : this.input_prompt_number
641 };
743 };
642 };
744 };
745
643 //============================================================================
746 //============================================================================
644 // TextCell
747 // TextCell
645 //============================================================================
748 //============================================================================
@@ -714,6 +817,32 b' TextCell.prototype.config_mathjax = function () {'
714 };
817 };
715
818
716
819
820 TextCell.prototype.get_text = function() {
821 return this.element.find("textarea.text_cell_input").val();
822 };
823
824
825 TextCell.prototype.set_text = function(text) {
826 this.element.find("textarea.text_cell_input").val(text);
827 this.element.find("textarea.text_cell_input").html(text);
828 this.element.find("div.text_cell_render").html(text);
829 };
830
831
832 TextCell.prototype.fromJSON = function (data) {
833 if (data.cell_type === 'text') {
834 this.set_text(data.text);
835 };
836 }
837
838
839 TextCell.prototype.toJSON = function () {
840 return {
841 cell_type : 'text',
842 text : this.get_text(),
843 };
844 };
845
717 //============================================================================
846 //============================================================================
718 // On document ready
847 // On document ready
719 //============================================================================
848 //============================================================================
@@ -21,7 +21,7 b''
21 <div id="wrapper">
21 <div id="wrapper">
22
22
23 <div id="header">
23 <div id="header">
24 <span id="ipython_notebook"><h1>|I|Python Notebook</h1></span>
24 <span id="ipython_notebook"><h1>[I]:Python Notebook</h1></span>
25 </div>
25 </div>
26
26
27
27
General Comments 0
You need to be logged in to leave comments. Login now