##// END OF EJS Templates
Adding tracebacks, evalue and etype to the nbformat and notebook.
Brian E. Granger -
Show More
@@ -1,212 +1,195 b''
1 """Tornado handlers for the notebook."""
1 """Tornado handlers for the notebook."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 import json
7 import json
8 import logging
8 import logging
9 import os
9 import os
10 import urllib
10 import urllib
11
11
12 from tornado import web
12 from tornado import web
13 from tornado import websocket
13 from tornado import websocket
14
14
15 try:
15 try:
16 from docutils.core import publish_string
16 from docutils.core import publish_string
17 except ImportError:
17 except ImportError:
18 publish_string = None
18 publish_string = None
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Top-level handlers
22 # Top-level handlers
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25
25
26 class NBBrowserHandler(web.RequestHandler):
26 class NBBrowserHandler(web.RequestHandler):
27 def get(self):
27 def get(self):
28 nbm = self.application.notebook_manager
28 nbm = self.application.notebook_manager
29 project = nbm.notebook_dir
29 project = nbm.notebook_dir
30 self.render('nbbrowser.html', project=project)
30 self.render('nbbrowser.html', project=project)
31
31
32
32
33 class NewHandler(web.RequestHandler):
33 class NewHandler(web.RequestHandler):
34 def get(self):
34 def get(self):
35 notebook_id = self.application.notebook_manager.new_notebook()
35 notebook_id = self.application.notebook_manager.new_notebook()
36 self.render('notebook.html', notebook_id=notebook_id)
36 self.render('notebook.html', notebook_id=notebook_id)
37
37
38
38
39 class NamedNotebookHandler(web.RequestHandler):
39 class NamedNotebookHandler(web.RequestHandler):
40 def get(self, notebook_id):
40 def get(self, notebook_id):
41 nbm = self.application.notebook_manager
41 nbm = self.application.notebook_manager
42 if not nbm.notebook_exists(notebook_id):
42 if not nbm.notebook_exists(notebook_id):
43 raise web.HTTPError(404)
43 raise web.HTTPError(404)
44 self.render('notebook.html', notebook_id=notebook_id)
44 self.render('notebook.html', notebook_id=notebook_id)
45
45
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Kernel handlers
48 # Kernel handlers
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 class MainKernelHandler(web.RequestHandler):
52 class MainKernelHandler(web.RequestHandler):
53
53
54 def get(self):
54 def get(self):
55 rkm = self.application.routing_kernel_manager
55 rkm = self.application.routing_kernel_manager
56 self.finish(json.dumps(rkm.kernel_ids))
56 self.finish(json.dumps(rkm.kernel_ids))
57
57
58 def post(self):
58 def post(self):
59 rkm = self.application.routing_kernel_manager
59 rkm = self.application.routing_kernel_manager
60 notebook_id = self.get_argument('notebook', default=None)
60 notebook_id = self.get_argument('notebook', default=None)
61 kernel_id = rkm.start_kernel(notebook_id)
61 kernel_id = rkm.start_kernel(notebook_id)
62 self.set_header('Location', '/'+kernel_id)
62 self.set_header('Location', '/'+kernel_id)
63 self.finish(json.dumps(kernel_id))
63 self.finish(json.dumps(kernel_id))
64
64
65
65
66 class KernelHandler(web.RequestHandler):
66 class KernelHandler(web.RequestHandler):
67
67
68 SUPPORTED_METHODS = ('DELETE')
68 SUPPORTED_METHODS = ('DELETE')
69
69
70 def delete(self, kernel_id):
70 def delete(self, kernel_id):
71 rkm = self.application.routing_kernel_manager
71 rkm = self.application.routing_kernel_manager
72 rkm.kill_kernel(kernel_id)
72 rkm.kill_kernel(kernel_id)
73 self.set_status(204)
73 self.set_status(204)
74 self.finish()
74 self.finish()
75
75
76
76
77 class KernelActionHandler(web.RequestHandler):
77 class KernelActionHandler(web.RequestHandler):
78
78
79 def post(self, kernel_id, action):
79 def post(self, kernel_id, action):
80 rkm = self.application.routing_kernel_manager
80 rkm = self.application.routing_kernel_manager
81 if action == 'interrupt':
81 if action == 'interrupt':
82 rkm.interrupt_kernel(kernel_id)
82 rkm.interrupt_kernel(kernel_id)
83 self.set_status(204)
83 self.set_status(204)
84 if action == 'restart':
84 if action == 'restart':
85 new_kernel_id = rkm.restart_kernel(kernel_id)
85 new_kernel_id = rkm.restart_kernel(kernel_id)
86 self.write(json.dumps(new_kernel_id))
86 self.write(json.dumps(new_kernel_id))
87 self.finish()
87 self.finish()
88
88
89
89
90 class ZMQStreamHandler(websocket.WebSocketHandler):
90 class ZMQStreamHandler(websocket.WebSocketHandler):
91
91
92 def initialize(self, stream_name):
92 def initialize(self, stream_name):
93 self.stream_name = stream_name
93 self.stream_name = stream_name
94
94
95 def open(self, kernel_id):
95 def open(self, kernel_id):
96 rkm = self.application.routing_kernel_manager
96 rkm = self.application.routing_kernel_manager
97 self.router = rkm.get_router(kernel_id, self.stream_name)
97 self.router = rkm.get_router(kernel_id, self.stream_name)
98 self.client_id = self.router.register_client(self)
98 self.client_id = self.router.register_client(self)
99
99
100 def on_message(self, msg):
100 def on_message(self, msg):
101 self.router.forward_msg(self.client_id, msg)
101 self.router.forward_msg(self.client_id, msg)
102
102
103 def on_close(self):
103 def on_close(self):
104 self.router.unregister_client(self.client_id)
104 self.router.unregister_client(self.client_id)
105
105
106
106
107 #-----------------------------------------------------------------------------
107 #-----------------------------------------------------------------------------
108 # Notebook web service handlers
108 # Notebook web service handlers
109 #-----------------------------------------------------------------------------
109 #-----------------------------------------------------------------------------
110
110
111 class NotebookRootHandler(web.RequestHandler):
111 class NotebookRootHandler(web.RequestHandler):
112
112
113 def get(self):
113 def get(self):
114 nbm = self.application.notebook_manager
114 nbm = self.application.notebook_manager
115 files = nbm.list_notebooks()
115 files = nbm.list_notebooks()
116 self.finish(json.dumps(files))
116 self.finish(json.dumps(files))
117
117
118 def post(self):
118 def post(self):
119 nbm = self.application.notebook_manager
119 nbm = self.application.notebook_manager
120 body = self.request.body.strip()
120 body = self.request.body.strip()
121 format = self.get_argument('format', default='json')
121 format = self.get_argument('format', default='json')
122 name = self.get_argument('name', default=None)
122 name = self.get_argument('name', default=None)
123 if body:
123 if body:
124 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
124 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
125 else:
125 else:
126 notebook_id = nbm.new_notebook()
126 notebook_id = nbm.new_notebook()
127 self.set_header('Location', '/'+notebook_id)
127 self.set_header('Location', '/'+notebook_id)
128 self.finish(json.dumps(notebook_id))
128 self.finish(json.dumps(notebook_id))
129
129
130
130
131 class NotebookHandler(web.RequestHandler):
131 class NotebookHandler(web.RequestHandler):
132
132
133 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
133 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
134
134
135 def get(self, notebook_id):
135 def get(self, notebook_id):
136 nbm = self.application.notebook_manager
136 nbm = self.application.notebook_manager
137 format = self.get_argument('format', default='json')
137 format = self.get_argument('format', default='json')
138 last_mod, name, data = nbm.get_notebook(notebook_id, format)
138 last_mod, name, data = nbm.get_notebook(notebook_id, format)
139 if format == u'json':
139 if format == u'json':
140 self.set_header('Content-Type', 'application/json')
140 self.set_header('Content-Type', 'application/json')
141 self.set_header('Content-Disposition','attachment; filename=%s.json' % name)
141 self.set_header('Content-Disposition','attachment; filename=%s.json' % name)
142 elif format == u'xml':
142 elif format == u'xml':
143 self.set_header('Content-Type', 'application/xml')
143 self.set_header('Content-Type', 'application/xml')
144 self.set_header('Content-Disposition','attachment; filename=%s.ipynb' % name)
144 self.set_header('Content-Disposition','attachment; filename=%s.ipynb' % name)
145 elif format == u'py':
145 elif format == u'py':
146 self.set_header('Content-Type', 'application/x-python')
146 self.set_header('Content-Type', 'application/x-python')
147 self.set_header('Content-Disposition','attachment; filename=%s.py' % name)
147 self.set_header('Content-Disposition','attachment; filename=%s.py' % name)
148 self.set_header('Last-Modified', last_mod)
148 self.set_header('Last-Modified', last_mod)
149 self.finish(data)
149 self.finish(data)
150
150
151 def put(self, notebook_id):
151 def put(self, notebook_id):
152 nbm = self.application.notebook_manager
152 nbm = self.application.notebook_manager
153 format = self.get_argument('format', default='json')
153 format = self.get_argument('format', default='json')
154 name = self.get_argument('name', default=None)
154 name = self.get_argument('name', default=None)
155 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
155 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
156 self.set_status(204)
156 self.set_status(204)
157 self.finish()
157 self.finish()
158
158
159 def delete(self, notebook_id):
159 def delete(self, notebook_id):
160 nbm = self.application.notebook_manager
160 nbm = self.application.notebook_manager
161 nbm.delete_notebook(notebook_id)
161 nbm.delete_notebook(notebook_id)
162 self.set_status(204)
162 self.set_status(204)
163 self.finish()
163 self.finish()
164
164
165 #-----------------------------------------------------------------------------
165 #-----------------------------------------------------------------------------
166 # RST web service handlers
166 # RST web service handlers
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168
168
169 _rst_header = """========
170 Heading1
171 ========
172
173 Heading2
174 ========
175
176 Heading3
177 --------
178
179 Heading4
180 ^^^^^^^^
181
182 """
183
169
184 class RSTHandler(web.RequestHandler):
170 class RSTHandler(web.RequestHandler):
185
171
186 def post(self):
172 def post(self):
187 if publish_string is None:
173 if publish_string is None:
188 raise web.HTTPError(503)
174 raise web.HTTPError(503)
189 body = self.request.body.strip()
175 body = self.request.body.strip()
190 source = _rst_header + body
176 source = body
191 template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
177 # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
192 print template_path
178 print template_path
193 defaults = {'file_insertion_enabled': 0,
179 defaults = {'file_insertion_enabled': 0,
194 'raw_enabled': 0,
180 'raw_enabled': 0,
195 '_disable_config': 1,
181 '_disable_config': 1,
196 'stylesheet_path': 0,
182 'stylesheet_path': 0,
197 'initial_header_level': 3,
183 # 'template': template_path
198 'template': template_path
199 }
184 }
200 try:
185 try:
201 html = publish_string(source, writer_name='html',
186 html = publish_string(source, writer_name='html',
202 settings_overrides=defaults
187 settings_overrides=defaults
203 )
188 )
204 except:
189 except:
205 raise web.HTTPError(400)
190 raise web.HTTPError(400)
206 print html
191 print html
207 # html = '\n'.join(html.split('\n')[7:-3])
208 # print html
209 self.set_header('Content-Type', 'text/html')
192 self.set_header('Content-Type', 'text/html')
210 self.finish(html)
193 self.finish(html)
211
194
212
195
@@ -1,421 +1,421 b''
1
1
2 //============================================================================
2 //============================================================================
3 // CodeCell
3 // CodeCell
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var utils = IPython.utils;
8 var utils = IPython.utils;
9
9
10 var CodeCell = function (notebook) {
10 var CodeCell = function (notebook) {
11 this.code_mirror = null;
11 this.code_mirror = null;
12 this.input_prompt_number = ' ';
12 this.input_prompt_number = ' ';
13 this.is_completing = false;
13 this.is_completing = false;
14 this.completion_cursor = null;
14 this.completion_cursor = null;
15 this.outputs = [];
15 this.outputs = [];
16 this.collapsed = false;
16 this.collapsed = false;
17 IPython.Cell.apply(this, arguments);
17 IPython.Cell.apply(this, arguments);
18 };
18 };
19
19
20
20
21 CodeCell.prototype = new IPython.Cell();
21 CodeCell.prototype = new IPython.Cell();
22
22
23
23
24 CodeCell.prototype.create_element = function () {
24 CodeCell.prototype.create_element = function () {
25 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
25 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
26 var input = $('<div></div>').addClass('input hbox');
26 var input = $('<div></div>').addClass('input hbox');
27 input.append($('<div/>').addClass('prompt input_prompt'));
27 input.append($('<div/>').addClass('prompt input_prompt'));
28 var input_area = $('<div/>').addClass('input_area box-flex1');
28 var input_area = $('<div/>').addClass('input_area box-flex1');
29 this.code_mirror = CodeMirror(input_area.get(0), {
29 this.code_mirror = CodeMirror(input_area.get(0), {
30 indentUnit : 4,
30 indentUnit : 4,
31 mode: 'python',
31 mode: 'python',
32 theme: 'ipython',
32 theme: 'ipython',
33 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
33 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
34 });
34 });
35 input.append(input_area);
35 input.append(input_area);
36 var output = $('<div></div>').addClass('output vbox');
36 var output = $('<div></div>').addClass('output vbox');
37 cell.append(input).append(output);
37 cell.append(input).append(output);
38 this.element = cell;
38 this.element = cell;
39 this.collapse()
39 this.collapse()
40 };
40 };
41
41
42
42
43 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
43 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
44 // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and
44 // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and
45 // is used to provide custom key handling. Its return value is used to determine
45 // is used to provide custom key handling. Its return value is used to determine
46 // if CodeMirror should ignore the event: true = ignore, false = don't ignore.
46 // if CodeMirror should ignore the event: true = ignore, false = don't ignore.
47 if (event.keyCode === 13 && event.shiftKey) {
47 if (event.keyCode === 13 && event.shiftKey) {
48 // Always ignore shift-enter in CodeMirror as we handle it.
48 // Always ignore shift-enter in CodeMirror as we handle it.
49 return true;
49 return true;
50 } else if (event.keyCode === 9) {
50 } else if (event.keyCode === 9) {
51 var cur = editor.getCursor();
51 var cur = editor.getCursor();
52 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim();
52 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim();
53 if (pre_cursor === "") {
53 if (pre_cursor === "") {
54 // Don't autocomplete if the part of the line before the cursor is empty.
54 // Don't autocomplete if the part of the line before the cursor is empty.
55 // In this case, let CodeMirror handle indentation.
55 // In this case, let CodeMirror handle indentation.
56 return false;
56 return false;
57 } else {
57 } else {
58 // Autocomplete the current line.
58 // Autocomplete the current line.
59 event.stop();
59 event.stop();
60 var line = editor.getLine(cur.line);
60 var line = editor.getLine(cur.line);
61 this.is_completing = true;
61 this.is_completing = true;
62 this.completion_cursor = cur;
62 this.completion_cursor = cur;
63 IPython.notebook.complete_cell(this, line, cur.ch);
63 IPython.notebook.complete_cell(this, line, cur.ch);
64 return true;
64 return true;
65 }
65 }
66 } else if (event.keyCode === 8 && event.type == 'keydown') {
66 } else if (event.keyCode === 8 && event.type == 'keydown') {
67 // If backspace and the line ends with 4 spaces, remove them.
67 // If backspace and the line ends with 4 spaces, remove them.
68 var cur = editor.getCursor();
68 var cur = editor.getCursor();
69 var line = editor.getLine(cur.line);
69 var line = editor.getLine(cur.line);
70 var ending = line.slice(-4);
70 var ending = line.slice(-4);
71 if (ending === ' ') {
71 if (ending === ' ') {
72 editor.replaceRange('',
72 editor.replaceRange('',
73 {line: cur.line, ch: cur.ch-4},
73 {line: cur.line, ch: cur.ch-4},
74 {line: cur.line, ch: cur.ch}
74 {line: cur.line, ch: cur.ch}
75 );
75 );
76 event.stop();
76 event.stop();
77 return true;
77 return true;
78 } else {
78 } else {
79 return false;
79 return false;
80 };
80 };
81 } else {
81 } else {
82 if (this.is_completing && this.completion_cursor !== editor.getCursor()) {
82 if (this.is_completing && this.completion_cursor !== editor.getCursor()) {
83 this.is_completing = false;
83 this.is_completing = false;
84 this.completion_cursor = null;
84 this.completion_cursor = null;
85 }
85 }
86 return false;
86 return false;
87 };
87 };
88 };
88 };
89
89
90
90
91 CodeCell.prototype.finish_completing = function (matched_text, matches) {
91 CodeCell.prototype.finish_completing = function (matched_text, matches) {
92 if (!this.is_completing || matches.length === 0) {return;}
92 if (!this.is_completing || matches.length === 0) {return;}
93 // console.log("Got matches", matched_text, matches);
93 // console.log("Got matches", matched_text, matches);
94
94
95 var that = this;
95 var that = this;
96 var cur = this.completion_cursor;
96 var cur = this.completion_cursor;
97 var complete = $('<div/>').addClass('completions');
97 var complete = $('<div/>').addClass('completions');
98 var select = $('<select/>').attr('multiple','true');
98 var select = $('<select/>').attr('multiple','true');
99 for (var i=0; i<matches.length; ++i) {
99 for (var i=0; i<matches.length; ++i) {
100 select.append($('<option/>').text(matches[i]));
100 select.append($('<option/>').text(matches[i]));
101 }
101 }
102 select.children().first().attr('selected','true');
102 select.children().first().attr('selected','true');
103 select.attr('size',Math.min(10,matches.length));
103 select.attr('size',Math.min(10,matches.length));
104 var pos = this.code_mirror.cursorCoords();
104 var pos = this.code_mirror.cursorCoords();
105 complete.css('left',pos.x+'px');
105 complete.css('left',pos.x+'px');
106 complete.css('top',pos.yBot+'px');
106 complete.css('top',pos.yBot+'px');
107 complete.append(select);
107 complete.append(select);
108
108
109 $('body').append(complete);
109 $('body').append(complete);
110 var done = false;
110 var done = false;
111
111
112 var insert = function (selected_text) {
112 var insert = function (selected_text) {
113 that.code_mirror.replaceRange(
113 that.code_mirror.replaceRange(
114 selected_text,
114 selected_text,
115 {line: cur.line, ch: (cur.ch-matched_text.length)},
115 {line: cur.line, ch: (cur.ch-matched_text.length)},
116 {line: cur.line, ch: cur.ch}
116 {line: cur.line, ch: cur.ch}
117 );
117 );
118 };
118 };
119
119
120 var close = function () {
120 var close = function () {
121 if (done) return;
121 if (done) return;
122 done = true;
122 done = true;
123 complete.remove();
123 complete.remove();
124 that.is_completing = false;
124 that.is_completing = false;
125 that.completion_cursor = null;
125 that.completion_cursor = null;
126 };
126 };
127
127
128 var pick = function () {
128 var pick = function () {
129 insert(select.val()[0]);
129 insert(select.val()[0]);
130 close();
130 close();
131 setTimeout(function(){that.code_mirror.focus();}, 50);
131 setTimeout(function(){that.code_mirror.focus();}, 50);
132 };
132 };
133
133
134 select.blur(close);
134 select.blur(close);
135 select.keydown(function (event) {
135 select.keydown(function (event) {
136 var code = event.which;
136 var code = event.which;
137 if (code === 13 || code === 32) {
137 if (code === 13 || code === 32) {
138 // Pressing SPACE or ENTER will cause a pick
138 // Pressing SPACE or ENTER will cause a pick
139 event.stopPropagation();
139 event.stopPropagation();
140 event.preventDefault();
140 event.preventDefault();
141 pick();
141 pick();
142 } else if (code === 38 || code === 40) {
142 } else if (code === 38 || code === 40) {
143 // We don't want the document keydown handler to handle UP/DOWN,
143 // We don't want the document keydown handler to handle UP/DOWN,
144 // but we want the default action.
144 // but we want the default action.
145 event.stopPropagation();
145 event.stopPropagation();
146 } else {
146 } else {
147 // All other key presses simple exit completion.
147 // All other key presses simple exit completion.
148 event.stopPropagation();
148 event.stopPropagation();
149 event.preventDefault();
149 event.preventDefault();
150 close();
150 close();
151 that.code_mirror.focus();
151 that.code_mirror.focus();
152 }
152 }
153 });
153 });
154 // Double click also causes a pick.
154 // Double click also causes a pick.
155 select.dblclick(pick);
155 select.dblclick(pick);
156 select.focus();
156 select.focus();
157 };
157 };
158
158
159
159
160 CodeCell.prototype.select = function () {
160 CodeCell.prototype.select = function () {
161 IPython.Cell.prototype.select.apply(this);
161 IPython.Cell.prototype.select.apply(this);
162 // Todo: this dance is needed because as of CodeMirror 2.12, focus is
162 // Todo: this dance is needed because as of CodeMirror 2.12, focus is
163 // not causing the cursor to blink if the editor is empty initially.
163 // not causing the cursor to blink if the editor is empty initially.
164 // While this seems to fix the issue, this should be fixed
164 // While this seems to fix the issue, this should be fixed
165 // in CodeMirror proper.
165 // in CodeMirror proper.
166 var s = this.code_mirror.getValue();
166 var s = this.code_mirror.getValue();
167 if (s === '') this.code_mirror.setValue('.');
167 if (s === '') this.code_mirror.setValue('.');
168 this.code_mirror.focus();
168 this.code_mirror.focus();
169 if (s === '') this.code_mirror.setValue('');
169 if (s === '') this.code_mirror.setValue('');
170 };
170 };
171
171
172
172
173 CodeCell.prototype.append_output = function (json) {
173 CodeCell.prototype.append_output = function (json) {
174 this.expand();
174 this.expand();
175 if (json.output_type === 'pyout') {
175 if (json.output_type === 'pyout') {
176 this.append_pyout(json);
176 this.append_pyout(json);
177 } else if (json.output_type === 'pyerr') {
177 } else if (json.output_type === 'pyerr') {
178 this.append_pyerr(json);
178 this.append_pyerr(json);
179 } else if (json.output_type === 'display_data') {
179 } else if (json.output_type === 'display_data') {
180 this.append_display_data(json);
180 this.append_display_data(json);
181 } else if (json.output_type === 'stream') {
181 } else if (json.output_type === 'stream') {
182 this.append_stream(json);
182 this.append_stream(json);
183 };
183 };
184 this.outputs.push(json);
184 this.outputs.push(json);
185 };
185 };
186
186
187
187
188 CodeCell.prototype.append_pyout = function (json) {
188 CodeCell.prototype.append_pyout = function (json) {
189 n = json.prompt_number || ' ';
189 n = json.prompt_number || ' ';
190 var toinsert = $("<div/>").addClass("output_pyout hbox");
190 var toinsert = $("<div/>").addClass("output_pyout hbox");
191 toinsert.append($('<div/>').
191 toinsert.append($('<div/>').
192 addClass('prompt output_prompt').
192 addClass('prompt output_prompt').
193 html('Out[' + n + ']:')
193 html('Out[' + n + ']:')
194 );
194 );
195 this.append_mime_type(json, toinsert).addClass('output_area');
195 this.append_mime_type(json, toinsert).addClass('output_area');
196 toinsert.children().last().addClass("box_flex1 pyout_area");
196 toinsert.children().last().addClass("box_flex1 pyout_area");
197 this.element.find("div.output").append(toinsert);
197 this.element.find("div.output").append(toinsert);
198 // If we just output latex, typeset it.
198 // If we just output latex, typeset it.
199 if (json.latex !== undefined) {
199 if (json.latex !== undefined) {
200 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
200 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
201 };
201 };
202 };
202 };
203
203
204
204
205 CodeCell.prototype.append_pyerr = function (json) {
205 CodeCell.prototype.append_pyerr = function (json) {
206 var tb = json.traceback;
206 var tb = json.traceback;
207 if (tb !== undefined) {
207 if (tb !== undefined && tb.length > 0) {
208 var s = '';
208 var s = '';
209 var len = tb.length;
209 var len = tb.length;
210 for (var i=0; i<len; i++) {
210 for (var i=0; i<len; i++) {
211 s = s + tb[i] + '\n';
211 s = s + tb[i] + '\n';
212 }
212 }
213 s = s + '\n';
213 s = s + '\n';
214 this.append_text(s).addClass('output_area');
214 this.append_text(s).addClass('output_area');
215 };
215 };
216 };
216 };
217
217
218
218
219 CodeCell.prototype.append_stream = function (json) {
219 CodeCell.prototype.append_stream = function (json) {
220 this.append_text(json.text).addClass('output_area');
220 this.append_text(json.text).addClass('output_area');
221 };
221 };
222
222
223
223
224 CodeCell.prototype.append_display_data = function (json) {
224 CodeCell.prototype.append_display_data = function (json) {
225 this.append_mime_type(json).addClass('output_area');
225 this.append_mime_type(json).addClass('output_area');
226 };
226 };
227
227
228
228
229 CodeCell.prototype.append_mime_type = function (json, element) {
229 CodeCell.prototype.append_mime_type = function (json, element) {
230 if (json.html !== undefined) {
230 if (json.html !== undefined) {
231 this.append_html(json.html, element);
231 this.append_html(json.html, element);
232 } else if (json.latex !== undefined) {
232 } else if (json.latex !== undefined) {
233 this.append_latex(json.latex, element);
233 this.append_latex(json.latex, element);
234 // If it is undefined, then we just appended to div.output, which
234 // If it is undefined, then we just appended to div.output, which
235 // makes the latex visible and we can typeset it. The typesetting
235 // makes the latex visible and we can typeset it. The typesetting
236 // has to be done after the latex is on the page.
236 // has to be done after the latex is on the page.
237 if (element === undefined) {
237 if (element === undefined) {
238 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
238 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
239 };
239 };
240 } else if (json.svg !== undefined) {
240 } else if (json.svg !== undefined) {
241 this.append_svg(json.svg, element);
241 this.append_svg(json.svg, element);
242 } else if (json.png !== undefined) {
242 } else if (json.png !== undefined) {
243 this.append_png(json.png, element);
243 this.append_png(json.png, element);
244 } else if (json.jpeg !== undefined) {
244 } else if (json.jpeg !== undefined) {
245 this.append_jpeg(json.jpeg, element);
245 this.append_jpeg(json.jpeg, element);
246 } else if (json.text !== undefined) {
246 } else if (json.text !== undefined) {
247 this.append_text(json.text, element);
247 this.append_text(json.text, element);
248 };
248 };
249 return element;
249 return element;
250 };
250 };
251
251
252
252
253 CodeCell.prototype.append_html = function (html, element) {
253 CodeCell.prototype.append_html = function (html, element) {
254 element = element || this.element.find("div.output");
254 element = element || this.element.find("div.output");
255 var toinsert = $("<div/>").addClass("output_html");
255 var toinsert = $("<div/>").addClass("output_html");
256 toinsert.append(html);
256 toinsert.append(html);
257 element.append(toinsert);
257 element.append(toinsert);
258 return element;
258 return element;
259 }
259 }
260
260
261
261
262 CodeCell.prototype.append_text = function (data, element) {
262 CodeCell.prototype.append_text = function (data, element) {
263 element = element || this.element.find("div.output");
263 element = element || this.element.find("div.output");
264 var toinsert = $("<div/>").addClass("output_stream");
264 var toinsert = $("<div/>").addClass("output_stream");
265 toinsert.append($("<pre/>").html(utils.fixConsole(data)));
265 toinsert.append($("<pre/>").html(data));
266 element.append(toinsert);
266 element.append(toinsert);
267 return element;
267 return element;
268 };
268 };
269
269
270
270
271 CodeCell.prototype.append_svg = function (svg, element) {
271 CodeCell.prototype.append_svg = function (svg, element) {
272 element = element || this.element.find("div.output");
272 element = element || this.element.find("div.output");
273 var toinsert = $("<div/>").addClass("output_svg");
273 var toinsert = $("<div/>").addClass("output_svg");
274 toinsert.append(svg);
274 toinsert.append(svg);
275 element.append(toinsert);
275 element.append(toinsert);
276 return element;
276 return element;
277 };
277 };
278
278
279
279
280 CodeCell.prototype.append_png = function (png, element) {
280 CodeCell.prototype.append_png = function (png, element) {
281 element = element || this.element.find("div.output");
281 element = element || this.element.find("div.output");
282 var toinsert = $("<div/>").addClass("output_png");
282 var toinsert = $("<div/>").addClass("output_png");
283 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
283 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
284 element.append(toinsert);
284 element.append(toinsert);
285 return element;
285 return element;
286 };
286 };
287
287
288
288
289 CodeCell.prototype.append_jpeg = function (jpeg, element) {
289 CodeCell.prototype.append_jpeg = function (jpeg, element) {
290 element = element || this.element.find("div.output");
290 element = element || this.element.find("div.output");
291 var toinsert = $("<div/>").addClass("output_jpeg");
291 var toinsert = $("<div/>").addClass("output_jpeg");
292 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
292 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
293 element.append(toinsert);
293 element.append(toinsert);
294 return element;
294 return element;
295 };
295 };
296
296
297
297
298 CodeCell.prototype.append_latex = function (latex, element) {
298 CodeCell.prototype.append_latex = function (latex, element) {
299 // This method cannot do the typesetting because the latex first has to
299 // This method cannot do the typesetting because the latex first has to
300 // be on the page.
300 // be on the page.
301 element = element || this.element.find("div.output");
301 element = element || this.element.find("div.output");
302 var toinsert = $("<div/>").addClass("output_latex");
302 var toinsert = $("<div/>").addClass("output_latex");
303 toinsert.append(latex);
303 toinsert.append(latex);
304 element.append(toinsert);
304 element.append(toinsert);
305 return element;
305 return element;
306 }
306 }
307
307
308
308
309 CodeCell.prototype.clear_output = function () {
309 CodeCell.prototype.clear_output = function () {
310 this.element.find("div.output").html("");
310 this.element.find("div.output").html("");
311 this.outputs = [];
311 this.outputs = [];
312 };
312 };
313
313
314
314
315 CodeCell.prototype.clear_input = function () {
315 CodeCell.prototype.clear_input = function () {
316 this.code_mirror.setValue('');
316 this.code_mirror.setValue('');
317 };
317 };
318
318
319
319
320 CodeCell.prototype.collapse = function () {
320 CodeCell.prototype.collapse = function () {
321 if (!this.collapsed) {
321 if (!this.collapsed) {
322 this.element.find('div.output').hide();
322 this.element.find('div.output').hide();
323 this.collapsed = true;
323 this.collapsed = true;
324 };
324 };
325 };
325 };
326
326
327
327
328 CodeCell.prototype.expand = function () {
328 CodeCell.prototype.expand = function () {
329 if (this.collapsed) {
329 if (this.collapsed) {
330 this.element.find('div.output').show();
330 this.element.find('div.output').show();
331 this.collapsed = false;
331 this.collapsed = false;
332 };
332 };
333 };
333 };
334
334
335
335
336 CodeCell.prototype.set_input_prompt = function (number) {
336 CodeCell.prototype.set_input_prompt = function (number) {
337 var n = number || ' ';
337 var n = number || ' ';
338 this.input_prompt_number = n
338 this.input_prompt_number = n
339 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
339 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
340 };
340 };
341
341
342
342
343 CodeCell.prototype.get_code = function () {
343 CodeCell.prototype.get_code = function () {
344 return this.code_mirror.getValue();
344 return this.code_mirror.getValue();
345 };
345 };
346
346
347
347
348 CodeCell.prototype.set_code = function (code) {
348 CodeCell.prototype.set_code = function (code) {
349 return this.code_mirror.setValue(code);
349 return this.code_mirror.setValue(code);
350 };
350 };
351
351
352
352
353 CodeCell.prototype.at_top = function () {
353 CodeCell.prototype.at_top = function () {
354 var cursor = this.code_mirror.getCursor();
354 var cursor = this.code_mirror.getCursor();
355 if (cursor.line === 0) {
355 if (cursor.line === 0) {
356 return true;
356 return true;
357 } else {
357 } else {
358 return false;
358 return false;
359 }
359 }
360 };
360 };
361
361
362
362
363 CodeCell.prototype.at_bottom = function () {
363 CodeCell.prototype.at_bottom = function () {
364 var cursor = this.code_mirror.getCursor();
364 var cursor = this.code_mirror.getCursor();
365 if (cursor.line === (this.code_mirror.lineCount()-1)) {
365 if (cursor.line === (this.code_mirror.lineCount()-1)) {
366 return true;
366 return true;
367 } else {
367 } else {
368 return false;
368 return false;
369 }
369 }
370 };
370 };
371
371
372
372
373 CodeCell.prototype.fromJSON = function (data) {
373 CodeCell.prototype.fromJSON = function (data) {
374 // console.log('Import from JSON:', data);
374 // console.log('Import from JSON:', data);
375 if (data.cell_type === 'code') {
375 if (data.cell_type === 'code') {
376 if (data.input !== undefined) {
376 if (data.input !== undefined) {
377 this.set_code(data.input);
377 this.set_code(data.input);
378 }
378 }
379 if (data.prompt_number !== undefined) {
379 if (data.prompt_number !== undefined) {
380 this.set_input_prompt(data.prompt_number);
380 this.set_input_prompt(data.prompt_number);
381 } else {
381 } else {
382 this.set_input_prompt();
382 this.set_input_prompt();
383 };
383 };
384 var len = data.outputs.length;
384 var len = data.outputs.length;
385 for (var i=0; i<len; i++) {
385 for (var i=0; i<len; i++) {
386 this.append_output(data.outputs[i]);
386 this.append_output(data.outputs[i]);
387 };
387 };
388 if (data.collapsed !== undefined) {
388 if (data.collapsed !== undefined) {
389 if (data.collapsed) {
389 if (data.collapsed) {
390 this.collapse();
390 this.collapse();
391 };
391 };
392 };
392 };
393 };
393 };
394 };
394 };
395
395
396
396
397 CodeCell.prototype.toJSON = function () {
397 CodeCell.prototype.toJSON = function () {
398 var data = {};
398 var data = {};
399 data.input = this.get_code();
399 data.input = this.get_code();
400 data.cell_type = 'code';
400 data.cell_type = 'code';
401 if (this.input_prompt_number !== ' ') {
401 if (this.input_prompt_number !== ' ') {
402 data.prompt_number = this.input_prompt_number
402 data.prompt_number = this.input_prompt_number
403 };
403 };
404 var outputs = [];
404 var outputs = [];
405 var len = this.outputs.length;
405 var len = this.outputs.length;
406 for (var i=0; i<len; i++) {
406 for (var i=0; i<len; i++) {
407 outputs[i] = this.outputs[i];
407 outputs[i] = this.outputs[i];
408 };
408 };
409 data.outputs = outputs;
409 data.outputs = outputs;
410 data.language = 'python';
410 data.language = 'python';
411 data.collapsed = this.collapsed;
411 data.collapsed = this.collapsed;
412 // console.log('Export to JSON:',data);
412 // console.log('Export to JSON:',data);
413 return data;
413 return data;
414 };
414 };
415
415
416
416
417 IPython.CodeCell = CodeCell;
417 IPython.CodeCell = CodeCell;
418
418
419 return IPython;
419 return IPython;
420 }(IPython));
420 }(IPython));
421
421
@@ -1,737 +1,740 b''
1
1
2 //============================================================================
2 //============================================================================
3 // Notebook
3 // Notebook
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var utils = IPython.utils;
8 var utils = IPython.utils;
9
9
10 var Notebook = function (selector) {
10 var Notebook = function (selector) {
11 this.element = $(selector);
11 this.element = $(selector);
12 this.element.scroll();
12 this.element.scroll();
13 this.element.data("notebook", this);
13 this.element.data("notebook", this);
14 this.next_prompt_number = 1;
14 this.next_prompt_number = 1;
15 this.kernel = null;
15 this.kernel = null;
16 this.msg_cell_map = {};
16 this.msg_cell_map = {};
17 this.style();
17 this.style();
18 this.create_elements();
18 this.create_elements();
19 this.bind_events();
19 this.bind_events();
20 };
20 };
21
21
22
22
23 Notebook.prototype.style = function () {
23 Notebook.prototype.style = function () {
24 $('div#notebook').addClass('border-box-sizing');
24 $('div#notebook').addClass('border-box-sizing');
25 };
25 };
26
26
27
27
28 Notebook.prototype.create_elements = function () {
28 Notebook.prototype.create_elements = function () {
29 // We add this end_space div to the end of the notebook div to:
29 // We add this end_space div to the end of the notebook div to:
30 // i) provide a margin between the last cell and the end of the notebook
30 // i) provide a margin between the last cell and the end of the notebook
31 // ii) to prevent the div from scrolling up when the last cell is being
31 // ii) to prevent the div from scrolling up when the last cell is being
32 // edited, but is too low on the page, which browsers will do automatically.
32 // edited, but is too low on the page, which browsers will do automatically.
33 this.element.append($('<div class="end_space"></div>').height(50));
33 this.element.append($('<div class="end_space"></div>').height(50));
34 $('div#notebook').addClass('border-box-sizing');
34 $('div#notebook').addClass('border-box-sizing');
35 };
35 };
36
36
37
37
38 Notebook.prototype.bind_events = function () {
38 Notebook.prototype.bind_events = function () {
39 var that = this;
39 var that = this;
40 $(document).keydown(function (event) {
40 $(document).keydown(function (event) {
41 // console.log(event);
41 // console.log(event);
42 if (event.which === 38) {
42 if (event.which === 38) {
43 var cell = that.selected_cell();
43 var cell = that.selected_cell();
44 if (cell.at_top()) {
44 if (cell.at_top()) {
45 event.preventDefault();
45 event.preventDefault();
46 that.select_prev();
46 that.select_prev();
47 };
47 };
48 } else if (event.which === 40) {
48 } else if (event.which === 40) {
49 var cell = that.selected_cell();
49 var cell = that.selected_cell();
50 if (cell.at_bottom()) {
50 if (cell.at_bottom()) {
51 event.preventDefault();
51 event.preventDefault();
52 that.select_next();
52 that.select_next();
53 };
53 };
54 } else if (event.which === 13 && event.shiftKey) {
54 } else if (event.which === 13 && event.shiftKey) {
55 that.execute_selected_cell();
55 that.execute_selected_cell();
56 return false;
56 return false;
57 } else if (event.which === 13 && event.ctrlKey) {
57 } else if (event.which === 13 && event.ctrlKey) {
58 that.execute_selected_cell({terminal:true});
58 that.execute_selected_cell({terminal:true});
59 return false;
59 return false;
60 };
60 };
61 });
61 });
62
62
63 this.element.bind('collapse_pager', function () {
63 this.element.bind('collapse_pager', function () {
64 var app_height = $('div#main_app').height(); // content height
64 var app_height = $('div#main_app').height(); // content height
65 var splitter_height = $('div#pager_splitter').outerHeight(true);
65 var splitter_height = $('div#pager_splitter').outerHeight(true);
66 var new_height = app_height - splitter_height;
66 var new_height = app_height - splitter_height;
67 that.element.animate({height : new_height + 'px'}, 'fast');
67 that.element.animate({height : new_height + 'px'}, 'fast');
68 });
68 });
69
69
70 this.element.bind('expand_pager', function () {
70 this.element.bind('expand_pager', function () {
71 var app_height = $('div#main_app').height(); // content height
71 var app_height = $('div#main_app').height(); // content height
72 var splitter_height = $('div#pager_splitter').outerHeight(true);
72 var splitter_height = $('div#pager_splitter').outerHeight(true);
73 var pager_height = $('div#pager').outerHeight(true);
73 var pager_height = $('div#pager').outerHeight(true);
74 var new_height = app_height - pager_height - splitter_height;
74 var new_height = app_height - pager_height - splitter_height;
75 that.element.animate({height : new_height + 'px'}, 'fast');
75 that.element.animate({height : new_height + 'px'}, 'fast');
76 });
76 });
77
77
78 this.element.bind('collapse_left_panel', function () {
78 this.element.bind('collapse_left_panel', function () {
79 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
79 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
80 var new_margin = splitter_width;
80 var new_margin = splitter_width;
81 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
81 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
82 });
82 });
83
83
84 this.element.bind('expand_left_panel', function () {
84 this.element.bind('expand_left_panel', function () {
85 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
85 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
86 var left_panel_width = IPython.left_panel.width;
86 var left_panel_width = IPython.left_panel.width;
87 var new_margin = splitter_width + left_panel_width;
87 var new_margin = splitter_width + left_panel_width;
88 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
88 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
89 });
89 });
90 };
90 };
91
91
92
92
93 Notebook.prototype.scroll_to_bottom = function () {
93 Notebook.prototype.scroll_to_bottom = function () {
94 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
94 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
95 };
95 };
96
96
97
97
98 Notebook.prototype.scroll_to_top = function () {
98 Notebook.prototype.scroll_to_top = function () {
99 this.element.animate({scrollTop:0}, 0);
99 this.element.animate({scrollTop:0}, 0);
100 };
100 };
101
101
102
102
103 // Cell indexing, retrieval, etc.
103 // Cell indexing, retrieval, etc.
104
104
105
105
106 Notebook.prototype.cell_elements = function () {
106 Notebook.prototype.cell_elements = function () {
107 return this.element.children("div.cell");
107 return this.element.children("div.cell");
108 }
108 }
109
109
110
110
111 Notebook.prototype.ncells = function (cell) {
111 Notebook.prototype.ncells = function (cell) {
112 return this.cell_elements().length;
112 return this.cell_elements().length;
113 }
113 }
114
114
115
115
116 // TODO: we are often calling cells as cells()[i], which we should optimize
116 // TODO: we are often calling cells as cells()[i], which we should optimize
117 // to cells(i) or a new method.
117 // to cells(i) or a new method.
118 Notebook.prototype.cells = function () {
118 Notebook.prototype.cells = function () {
119 return this.cell_elements().toArray().map(function (e) {
119 return this.cell_elements().toArray().map(function (e) {
120 return $(e).data("cell");
120 return $(e).data("cell");
121 });
121 });
122 }
122 }
123
123
124
124
125 Notebook.prototype.find_cell_index = function (cell) {
125 Notebook.prototype.find_cell_index = function (cell) {
126 var result = null;
126 var result = null;
127 this.cell_elements().filter(function (index) {
127 this.cell_elements().filter(function (index) {
128 if ($(this).data("cell") === cell) {
128 if ($(this).data("cell") === cell) {
129 result = index;
129 result = index;
130 };
130 };
131 });
131 });
132 return result;
132 return result;
133 };
133 };
134
134
135
135
136 Notebook.prototype.index_or_selected = function (index) {
136 Notebook.prototype.index_or_selected = function (index) {
137 return index || this.selected_index() || 0;
137 return index || this.selected_index() || 0;
138 }
138 }
139
139
140
140
141 Notebook.prototype.select = function (index) {
141 Notebook.prototype.select = function (index) {
142 if (index !== undefined && index >= 0 && index < this.ncells()) {
142 if (index !== undefined && index >= 0 && index < this.ncells()) {
143 if (this.selected_index() !== null) {
143 if (this.selected_index() !== null) {
144 this.selected_cell().unselect();
144 this.selected_cell().unselect();
145 };
145 };
146 this.cells()[index].select();
146 this.cells()[index].select();
147 if (index === (this.ncells()-1)) {
147 if (index === (this.ncells()-1)) {
148 this.scroll_to_bottom();
148 this.scroll_to_bottom();
149 };
149 };
150 };
150 };
151 return this;
151 return this;
152 };
152 };
153
153
154
154
155 Notebook.prototype.select_next = function () {
155 Notebook.prototype.select_next = function () {
156 var index = this.selected_index();
156 var index = this.selected_index();
157 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
157 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
158 this.select(index+1);
158 this.select(index+1);
159 };
159 };
160 return this;
160 return this;
161 };
161 };
162
162
163
163
164 Notebook.prototype.select_prev = function () {
164 Notebook.prototype.select_prev = function () {
165 var index = this.selected_index();
165 var index = this.selected_index();
166 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
166 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
167 this.select(index-1);
167 this.select(index-1);
168 };
168 };
169 return this;
169 return this;
170 };
170 };
171
171
172
172
173 Notebook.prototype.selected_index = function () {
173 Notebook.prototype.selected_index = function () {
174 var result = null;
174 var result = null;
175 this.cell_elements().filter(function (index) {
175 this.cell_elements().filter(function (index) {
176 if ($(this).data("cell").selected === true) {
176 if ($(this).data("cell").selected === true) {
177 result = index;
177 result = index;
178 };
178 };
179 });
179 });
180 return result;
180 return result;
181 };
181 };
182
182
183
183
184 Notebook.prototype.cell_for_msg = function (msg_id) {
184 Notebook.prototype.cell_for_msg = function (msg_id) {
185 var cell_id = this.msg_cell_map[msg_id];
185 var cell_id = this.msg_cell_map[msg_id];
186 var result = null;
186 var result = null;
187 this.cell_elements().filter(function (index) {
187 this.cell_elements().filter(function (index) {
188 cell = $(this).data("cell");
188 cell = $(this).data("cell");
189 if (cell.cell_id === cell_id) {
189 if (cell.cell_id === cell_id) {
190 result = cell;
190 result = cell;
191 };
191 };
192 });
192 });
193 return result;
193 return result;
194 };
194 };
195
195
196
196
197 Notebook.prototype.selected_cell = function () {
197 Notebook.prototype.selected_cell = function () {
198 return this.cell_elements().eq(this.selected_index()).data("cell");
198 return this.cell_elements().eq(this.selected_index()).data("cell");
199 }
199 }
200
200
201
201
202 // Cell insertion, deletion and moving.
202 // Cell insertion, deletion and moving.
203
203
204
204
205 Notebook.prototype.delete_cell = function (index) {
205 Notebook.prototype.delete_cell = function (index) {
206 var i = index || this.selected_index();
206 var i = index || this.selected_index();
207 if (i !== null && i >= 0 && i < this.ncells()) {
207 if (i !== null && i >= 0 && i < this.ncells()) {
208 this.cell_elements().eq(i).remove();
208 this.cell_elements().eq(i).remove();
209 if (i === (this.ncells())) {
209 if (i === (this.ncells())) {
210 this.select(i-1);
210 this.select(i-1);
211 } else {
211 } else {
212 this.select(i);
212 this.select(i);
213 };
213 };
214 };
214 };
215 return this;
215 return this;
216 };
216 };
217
217
218
218
219 Notebook.prototype.append_cell = function (cell) {
219 Notebook.prototype.append_cell = function (cell) {
220 this.element.find('div.end_space').before(cell.element);
220 this.element.find('div.end_space').before(cell.element);
221 return this;
221 return this;
222 };
222 };
223
223
224
224
225 Notebook.prototype.insert_cell_after = function (cell, index) {
225 Notebook.prototype.insert_cell_after = function (cell, index) {
226 var ncells = this.ncells();
226 var ncells = this.ncells();
227 if (ncells === 0) {
227 if (ncells === 0) {
228 this.append_cell(cell);
228 this.append_cell(cell);
229 return this;
229 return this;
230 };
230 };
231 if (index >= 0 && index < ncells) {
231 if (index >= 0 && index < ncells) {
232 this.cell_elements().eq(index).after(cell.element);
232 this.cell_elements().eq(index).after(cell.element);
233 };
233 };
234 return this
234 return this
235 };
235 };
236
236
237
237
238 Notebook.prototype.insert_cell_before = function (cell, index) {
238 Notebook.prototype.insert_cell_before = function (cell, index) {
239 var ncells = this.ncells();
239 var ncells = this.ncells();
240 if (ncells === 0) {
240 if (ncells === 0) {
241 this.append_cell(cell);
241 this.append_cell(cell);
242 return this;
242 return this;
243 };
243 };
244 if (index >= 0 && index < ncells) {
244 if (index >= 0 && index < ncells) {
245 this.cell_elements().eq(index).before(cell.element);
245 this.cell_elements().eq(index).before(cell.element);
246 };
246 };
247 return this;
247 return this;
248 };
248 };
249
249
250
250
251 Notebook.prototype.move_cell_up = function (index) {
251 Notebook.prototype.move_cell_up = function (index) {
252 var i = index || this.selected_index();
252 var i = index || this.selected_index();
253 if (i !== null && i < this.ncells() && i > 0) {
253 if (i !== null && i < this.ncells() && i > 0) {
254 var pivot = this.cell_elements().eq(i-1);
254 var pivot = this.cell_elements().eq(i-1);
255 var tomove = this.cell_elements().eq(i);
255 var tomove = this.cell_elements().eq(i);
256 if (pivot !== null && tomove !== null) {
256 if (pivot !== null && tomove !== null) {
257 tomove.detach();
257 tomove.detach();
258 pivot.before(tomove);
258 pivot.before(tomove);
259 this.select(i-1);
259 this.select(i-1);
260 };
260 };
261 };
261 };
262 return this;
262 return this;
263 }
263 }
264
264
265
265
266 Notebook.prototype.move_cell_down = function (index) {
266 Notebook.prototype.move_cell_down = function (index) {
267 var i = index || this.selected_index();
267 var i = index || this.selected_index();
268 if (i !== null && i < (this.ncells()-1) && i >= 0) {
268 if (i !== null && i < (this.ncells()-1) && i >= 0) {
269 var pivot = this.cell_elements().eq(i+1)
269 var pivot = this.cell_elements().eq(i+1)
270 var tomove = this.cell_elements().eq(i)
270 var tomove = this.cell_elements().eq(i)
271 if (pivot !== null && tomove !== null) {
271 if (pivot !== null && tomove !== null) {
272 tomove.detach();
272 tomove.detach();
273 pivot.after(tomove);
273 pivot.after(tomove);
274 this.select(i+1);
274 this.select(i+1);
275 };
275 };
276 };
276 };
277 return this;
277 return this;
278 }
278 }
279
279
280
280
281 Notebook.prototype.sort_cells = function () {
281 Notebook.prototype.sort_cells = function () {
282 var ncells = this.ncells();
282 var ncells = this.ncells();
283 var sindex = this.selected_index();
283 var sindex = this.selected_index();
284 var swapped;
284 var swapped;
285 do {
285 do {
286 swapped = false
286 swapped = false
287 for (var i=1; i<ncells; i++) {
287 for (var i=1; i<ncells; i++) {
288 current = this.cell_elements().eq(i).data("cell");
288 current = this.cell_elements().eq(i).data("cell");
289 previous = this.cell_elements().eq(i-1).data("cell");
289 previous = this.cell_elements().eq(i-1).data("cell");
290 if (previous.input_prompt_number > current.input_prompt_number) {
290 if (previous.input_prompt_number > current.input_prompt_number) {
291 this.move_cell_up(i);
291 this.move_cell_up(i);
292 swapped = true;
292 swapped = true;
293 };
293 };
294 };
294 };
295 } while (swapped);
295 } while (swapped);
296 this.select(sindex);
296 this.select(sindex);
297 return this;
297 return this;
298 };
298 };
299
299
300
300
301 Notebook.prototype.insert_code_cell_before = function (index) {
301 Notebook.prototype.insert_code_cell_before = function (index) {
302 // TODO: Bounds check for i
302 // TODO: Bounds check for i
303 var i = this.index_or_selected(index);
303 var i = this.index_or_selected(index);
304 var cell = new IPython.CodeCell(this);
304 var cell = new IPython.CodeCell(this);
305 cell.set_input_prompt();
305 cell.set_input_prompt();
306 this.insert_cell_before(cell, i);
306 this.insert_cell_before(cell, i);
307 this.select(this.find_cell_index(cell));
307 this.select(this.find_cell_index(cell));
308 return cell;
308 return cell;
309 }
309 }
310
310
311
311
312 Notebook.prototype.insert_code_cell_after = function (index) {
312 Notebook.prototype.insert_code_cell_after = function (index) {
313 // TODO: Bounds check for i
313 // TODO: Bounds check for i
314 var i = this.index_or_selected(index);
314 var i = this.index_or_selected(index);
315 var cell = new IPython.CodeCell(this);
315 var cell = new IPython.CodeCell(this);
316 cell.set_input_prompt();
316 cell.set_input_prompt();
317 this.insert_cell_after(cell, i);
317 this.insert_cell_after(cell, i);
318 this.select(this.find_cell_index(cell));
318 this.select(this.find_cell_index(cell));
319 return cell;
319 return cell;
320 }
320 }
321
321
322
322
323 Notebook.prototype.insert_html_cell_before = function (index) {
323 Notebook.prototype.insert_html_cell_before = function (index) {
324 // TODO: Bounds check for i
324 // TODO: Bounds check for i
325 var i = this.index_or_selected(index);
325 var i = this.index_or_selected(index);
326 var cell = new IPython.HTMLCell(this);
326 var cell = new IPython.HTMLCell(this);
327 cell.config_mathjax();
327 cell.config_mathjax();
328 this.insert_cell_before(cell, i);
328 this.insert_cell_before(cell, i);
329 this.select(this.find_cell_index(cell));
329 this.select(this.find_cell_index(cell));
330 return cell;
330 return cell;
331 }
331 }
332
332
333
333
334 Notebook.prototype.insert_html_cell_after = function (index) {
334 Notebook.prototype.insert_html_cell_after = function (index) {
335 // TODO: Bounds check for i
335 // TODO: Bounds check for i
336 var i = this.index_or_selected(index);
336 var i = this.index_or_selected(index);
337 var cell = new IPython.HTMLCell(this);
337 var cell = new IPython.HTMLCell(this);
338 cell.config_mathjax();
338 cell.config_mathjax();
339 this.insert_cell_after(cell, i);
339 this.insert_cell_after(cell, i);
340 this.select(this.find_cell_index(cell));
340 this.select(this.find_cell_index(cell));
341 return cell;
341 return cell;
342 }
342 }
343
343
344
344
345 Notebook.prototype.insert_markdown_cell_before = function (index) {
345 Notebook.prototype.insert_markdown_cell_before = function (index) {
346 // TODO: Bounds check for i
346 // TODO: Bounds check for i
347 var i = this.index_or_selected(index);
347 var i = this.index_or_selected(index);
348 var cell = new IPython.MarkdownCell(this);
348 var cell = new IPython.MarkdownCell(this);
349 cell.config_mathjax();
349 cell.config_mathjax();
350 this.insert_cell_before(cell, i);
350 this.insert_cell_before(cell, i);
351 this.select(this.find_cell_index(cell));
351 this.select(this.find_cell_index(cell));
352 return cell;
352 return cell;
353 }
353 }
354
354
355
355
356 Notebook.prototype.insert_markdown_cell_after = function (index) {
356 Notebook.prototype.insert_markdown_cell_after = function (index) {
357 // TODO: Bounds check for i
357 // TODO: Bounds check for i
358 var i = this.index_or_selected(index);
358 var i = this.index_or_selected(index);
359 var cell = new IPython.MarkdownCell(this);
359 var cell = new IPython.MarkdownCell(this);
360 cell.config_mathjax();
360 cell.config_mathjax();
361 this.insert_cell_after(cell, i);
361 this.insert_cell_after(cell, i);
362 this.select(this.find_cell_index(cell));
362 this.select(this.find_cell_index(cell));
363 return cell;
363 return cell;
364 }
364 }
365
365
366
366
367 Notebook.prototype.to_code = function (index) {
367 Notebook.prototype.to_code = function (index) {
368 // TODO: Bounds check for i
368 // TODO: Bounds check for i
369 var i = this.index_or_selected(index);
369 var i = this.index_or_selected(index);
370 var source_element = this.cell_elements().eq(i);
370 var source_element = this.cell_elements().eq(i);
371 var source_cell = source_element.data("cell");
371 var source_cell = source_element.data("cell");
372 if (source_cell instanceof IPython.HTMLCell ||
372 if (source_cell instanceof IPython.HTMLCell ||
373 source_cell instanceof IPython.MarkdownCell) {
373 source_cell instanceof IPython.MarkdownCell) {
374 this.insert_code_cell_after(i);
374 this.insert_code_cell_after(i);
375 var target_cell = this.cells()[i+1];
375 var target_cell = this.cells()[i+1];
376 target_cell.set_code(source_cell.get_source());
376 target_cell.set_code(source_cell.get_source());
377 source_element.remove();
377 source_element.remove();
378 };
378 };
379 };
379 };
380
380
381
381
382 Notebook.prototype.to_markdown = function (index) {
382 Notebook.prototype.to_markdown = function (index) {
383 // TODO: Bounds check for i
383 // TODO: Bounds check for i
384 var i = this.index_or_selected(index);
384 var i = this.index_or_selected(index);
385 var source_element = this.cell_elements().eq(i);
385 var source_element = this.cell_elements().eq(i);
386 var source_cell = source_element.data("cell");
386 var source_cell = source_element.data("cell");
387 var target_cell = null;
387 var target_cell = null;
388 if (source_cell instanceof IPython.CodeCell) {
388 if (source_cell instanceof IPython.CodeCell) {
389 this.insert_markdown_cell_after(i);
389 this.insert_markdown_cell_after(i);
390 var target_cell = this.cells()[i+1];
390 var target_cell = this.cells()[i+1];
391 var text = source_cell.get_code();
391 var text = source_cell.get_code();
392 } else if (source_cell instanceof IPython.HTMLCell) {
392 } else if (source_cell instanceof IPython.HTMLCell) {
393 this.insert_markdown_cell_after(i);
393 this.insert_markdown_cell_after(i);
394 var target_cell = this.cells()[i+1];
394 var target_cell = this.cells()[i+1];
395 var text = source_cell.get_source();
395 var text = source_cell.get_source();
396 if (text === source_cell.placeholder) {
396 if (text === source_cell.placeholder) {
397 text = target_cell.placeholder;
397 text = target_cell.placeholder;
398 }
398 }
399 }
399 }
400 if (target_cell !== null) {
400 if (target_cell !== null) {
401 if (text === "") {text = target_cell.placeholder;};
401 if (text === "") {text = target_cell.placeholder;};
402 target_cell.set_source(text);
402 target_cell.set_source(text);
403 source_element.remove();
403 source_element.remove();
404 target_cell.edit();
404 target_cell.edit();
405 }
405 }
406 };
406 };
407
407
408
408
409 Notebook.prototype.to_html = function (index) {
409 Notebook.prototype.to_html = function (index) {
410 // TODO: Bounds check for i
410 // TODO: Bounds check for i
411 var i = this.index_or_selected(index);
411 var i = this.index_or_selected(index);
412 var source_element = this.cell_elements().eq(i);
412 var source_element = this.cell_elements().eq(i);
413 var source_cell = source_element.data("cell");
413 var source_cell = source_element.data("cell");
414 var target_cell = null;
414 var target_cell = null;
415 if (source_cell instanceof IPython.CodeCell) {
415 if (source_cell instanceof IPython.CodeCell) {
416 this.insert_html_cell_after(i);
416 this.insert_html_cell_after(i);
417 var target_cell = this.cells()[i+1];
417 var target_cell = this.cells()[i+1];
418 var text = source_cell.get_code();
418 var text = source_cell.get_code();
419 } else if (source_cell instanceof IPython.MarkdownCell) {
419 } else if (source_cell instanceof IPython.MarkdownCell) {
420 this.insert_html_cell_after(i);
420 this.insert_html_cell_after(i);
421 var target_cell = this.cells()[i+1];
421 var target_cell = this.cells()[i+1];
422 var text = source_cell.get_source();
422 var text = source_cell.get_source();
423 if (text === source_cell.placeholder) {
423 if (text === source_cell.placeholder) {
424 text = target_cell.placeholder;
424 text = target_cell.placeholder;
425 }
425 }
426 }
426 }
427 if (target_cell !== null) {
427 if (target_cell !== null) {
428 if (text === "") {text = target_cell.placeholder;};
428 if (text === "") {text = target_cell.placeholder;};
429 target_cell.set_source(text);
429 target_cell.set_source(text);
430 source_element.remove();
430 source_element.remove();
431 target_cell.edit();
431 target_cell.edit();
432 }
432 }
433 };
433 };
434
434
435
435
436 // Cell collapsing
436 // Cell collapsing
437
437
438 Notebook.prototype.collapse = function (index) {
438 Notebook.prototype.collapse = function (index) {
439 var i = this.index_or_selected(index);
439 var i = this.index_or_selected(index);
440 this.cells()[i].collapse();
440 this.cells()[i].collapse();
441 };
441 };
442
442
443
443
444 Notebook.prototype.expand = function (index) {
444 Notebook.prototype.expand = function (index) {
445 var i = this.index_or_selected(index);
445 var i = this.index_or_selected(index);
446 this.cells()[i].expand();
446 this.cells()[i].expand();
447 };
447 };
448
448
449
449
450 Notebook.prototype.set_autoindent = function (state) {
450 Notebook.prototype.set_autoindent = function (state) {
451 var cells = this.cells();
451 var cells = this.cells();
452 len = cells.length;
452 len = cells.length;
453 for (var i=0; i<len; i++) {
453 for (var i=0; i<len; i++) {
454 cells[i].set_autoindent(state)
454 cells[i].set_autoindent(state)
455 };
455 };
456 };
456 };
457
457
458 // Kernel related things
458 // Kernel related things
459
459
460 Notebook.prototype.start_kernel = function () {
460 Notebook.prototype.start_kernel = function () {
461 this.kernel = new IPython.Kernel();
461 this.kernel = new IPython.Kernel();
462 var notebook_id = IPython.save_widget.get_notebook_id();
462 var notebook_id = IPython.save_widget.get_notebook_id();
463 this.kernel.start_kernel(notebook_id, $.proxy(this.kernel_started, this));
463 this.kernel.start_kernel(notebook_id, $.proxy(this.kernel_started, this));
464 };
464 };
465
465
466
466
467 Notebook.prototype.handle_shell_reply = function (e) {
467 Notebook.prototype.handle_shell_reply = function (e) {
468 reply = $.parseJSON(e.data);
468 reply = $.parseJSON(e.data);
469 var header = reply.header;
469 var header = reply.header;
470 var content = reply.content;
470 var content = reply.content;
471 var msg_type = header.msg_type;
471 var msg_type = header.msg_type;
472 // console.log(reply);
472 // console.log(reply);
473 var cell = this.cell_for_msg(reply.parent_header.msg_id);
473 var cell = this.cell_for_msg(reply.parent_header.msg_id);
474 if (msg_type === "execute_reply") {
474 if (msg_type === "execute_reply") {
475 cell.set_input_prompt(content.execution_count);
475 cell.set_input_prompt(content.execution_count);
476 } else if (msg_type === "complete_reply") {
476 } else if (msg_type === "complete_reply") {
477 cell.finish_completing(content.matched_text, content.matches);
477 cell.finish_completing(content.matched_text, content.matches);
478 };
478 };
479 var payload = content.payload || [];
479 var payload = content.payload || [];
480 this.handle_payload(cell, payload);
480 this.handle_payload(cell, payload);
481 };
481 };
482
482
483
483
484 Notebook.prototype.handle_payload = function (cell, payload) {
484 Notebook.prototype.handle_payload = function (cell, payload) {
485 var l = payload.length;
485 var l = payload.length;
486 for (var i=0; i<l; i++) {
486 for (var i=0; i<l; i++) {
487 if (payload[i].source === 'IPython.zmq.page.page') {
487 if (payload[i].source === 'IPython.zmq.page.page') {
488 IPython.pager.clear();
488 IPython.pager.clear();
489 IPython.pager.expand();
489 IPython.pager.expand();
490 IPython.pager.append_text(payload[i].text);
490 IPython.pager.append_text(payload[i].text);
491 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
491 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
492 var index = this.find_cell_index(cell);
492 var index = this.find_cell_index(cell);
493 var new_cell = this.insert_code_cell_after(index);
493 var new_cell = this.insert_code_cell_after(index);
494 new_cell.set_code(payload[i].text);
494 new_cell.set_code(payload[i].text);
495 }
495 }
496 };
496 };
497 };
497 };
498
498
499
499
500 Notebook.prototype.handle_iopub_reply = function (e) {
500 Notebook.prototype.handle_iopub_reply = function (e) {
501 reply = $.parseJSON(e.data);
501 reply = $.parseJSON(e.data);
502 var content = reply.content;
502 var content = reply.content;
503 // console.log(reply);
503 // console.log(reply);
504 var msg_type = reply.header.msg_type;
504 var msg_type = reply.header.msg_type;
505 var cell = this.cell_for_msg(reply.parent_header.msg_id);
505 var cell = this.cell_for_msg(reply.parent_header.msg_id);
506 var output_types = ['stream','display_data','pyout','pyerr'];
506 var output_types = ['stream','display_data','pyout','pyerr'];
507 if (output_types.indexOf(msg_type) >= 0) {
507 if (output_types.indexOf(msg_type) >= 0) {
508 this.handle_output(cell, msg_type, content);
508 this.handle_output(cell, msg_type, content);
509 } else if (msg_type === "status") {
509 } else if (msg_type === "status") {
510 if (content.execution_state === "busy") {
510 if (content.execution_state === "busy") {
511 IPython.kernel_status_widget.status_busy();
511 IPython.kernel_status_widget.status_busy();
512 } else if (content.execution_state === "idle") {
512 } else if (content.execution_state === "idle") {
513 IPython.kernel_status_widget.status_idle();
513 IPython.kernel_status_widget.status_idle();
514 };
514 };
515 }
515 }
516 };
516 };
517
517
518
518
519 Notebook.prototype.handle_output = function (cell, msg_type, content) {
519 Notebook.prototype.handle_output = function (cell, msg_type, content) {
520 var json = {};
520 var json = {};
521 json.output_type = msg_type;
521 json.output_type = msg_type;
522 if (msg_type === "stream") {
522 if (msg_type === "stream") {
523 json.text = content.data + '\n';
523 json.text = utils.fixConsole(content.data + '\n');
524 } else if (msg_type === "display_data") {
524 } else if (msg_type === "display_data") {
525 json = this.convert_mime_types(json, content.data);
525 json = this.convert_mime_types(json, content.data);
526 } else if (msg_type === "pyout") {
526 } else if (msg_type === "pyout") {
527 json.prompt_number = content.execution_count;
527 json.prompt_number = content.execution_count;
528 json = this.convert_mime_types(json, content.data);
528 json = this.convert_mime_types(json, content.data);
529 } else if (msg_type === "pyerr") {
529 } else if (msg_type === "pyerr") {
530 json.ename = content.ename;
530 json.ename = content.ename;
531 json.evalue = content.evalue;
531 json.evalue = content.evalue;
532 json.traceback = content.traceback;
532 var traceback = [];
533 for (var i=0; i<content.traceback.length; i++) {
534 traceback.push(utils.fixConsole(content.traceback[i]));
535 }
536 json.traceback = traceback;
533 };
537 };
534 cell.append_output(json);
538 cell.append_output(json);
535 };
539 };
536
540
537
541
538 Notebook.prototype.convert_mime_types = function (json, data) {
542 Notebook.prototype.convert_mime_types = function (json, data) {
539 if (data['text/plain'] !== undefined) {
543 if (data['text/plain'] !== undefined) {
540 json.text = data['text/plain'];
544 json.text = utils.fixConsole(data['text/plain']);
541 };
545 };
542 if (data['text/html'] !== undefined) {
546 if (data['text/html'] !== undefined) {
543 json.html = data['text/html'];
547 json.html = data['text/html'];
544 };
548 };
545 if (data['image/svg+xml'] !== undefined) {
549 if (data['image/svg+xml'] !== undefined) {
546 json.svg = data['image/svg+xml'];
550 json.svg = data['image/svg+xml'];
547 };
551 };
548 if (data['image/png'] !== undefined) {
552 if (data['image/png'] !== undefined) {
549 json.png = data['image/png'];
553 json.png = data['image/png'];
550 };
554 };
551 if (data['image/jpeg'] !== undefined) {
555 if (data['image/jpeg'] !== undefined) {
552 json.jpeg = data['image/jpeg'];
556 json.jpeg = data['image/jpeg'];
553 };
557 };
554 if (data['text/latex'] !== undefined) {
558 if (data['text/latex'] !== undefined) {
555 json.latex = data['text/latex'];
559 json.latex = data['text/latex'];
556 };
560 };
557 if (data['application/json'] !== undefined) {
561 if (data['application/json'] !== undefined) {
558 json.json = data['application/json'];
562 json.json = data['application/json'];
559 };
563 };
560 if (data['application/javascript'] !== undefined) {
564 if (data['application/javascript'] !== undefined) {
561 json.javascript = data['application/javascript'];
565 json.javascript = data['application/javascript'];
562 }
566 }
563 return json;
567 return json;
564 };
568 };
565
569
566 Notebook.prototype.kernel_started = function () {
570 Notebook.prototype.kernel_started = function () {
567 console.log("Kernel started: ", this.kernel.kernel_id);
571 console.log("Kernel started: ", this.kernel.kernel_id);
568 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
572 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
569 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
573 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
570 };
574 };
571
575
572
576
573 Notebook.prototype.execute_selected_cell = function (options) {
577 Notebook.prototype.execute_selected_cell = function (options) {
574 // add_new: should a new cell be added if we are at the end of the nb
578 // add_new: should a new cell be added if we are at the end of the nb
575 // terminal: execute in terminal mode, which stays in the current cell
579 // terminal: execute in terminal mode, which stays in the current cell
576 default_options = {terminal: false, add_new: true}
580 default_options = {terminal: false, add_new: true}
577 $.extend(default_options, options)
581 $.extend(default_options, options)
578 var that = this;
582 var that = this;
579 var cell = that.selected_cell();
583 var cell = that.selected_cell();
580 var cell_index = that.find_cell_index(cell);
584 var cell_index = that.find_cell_index(cell);
581 if (cell instanceof IPython.CodeCell) {
585 if (cell instanceof IPython.CodeCell) {
582 cell.clear_output();
586 cell.clear_output();
583 var code = cell.get_code();
587 var code = cell.get_code();
584 var msg_id = that.kernel.execute(cell.get_code());
588 var msg_id = that.kernel.execute(cell.get_code());
585 that.msg_cell_map[msg_id] = cell.cell_id;
589 that.msg_cell_map[msg_id] = cell.cell_id;
586 } else if (cell instanceof IPython.HTMLCell) {
590 } else if (cell instanceof IPython.HTMLCell) {
587 cell.render();
591 cell.render();
588 }
592 }
589 if (default_options.terminal) {
593 if (default_options.terminal) {
590 cell.clear_input();
594 cell.clear_input();
591 } else {
595 } else {
592 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
596 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
593 that.insert_code_cell_after();
597 that.insert_code_cell_after();
594 // If we are adding a new cell at the end, scroll down to show it.
598 // If we are adding a new cell at the end, scroll down to show it.
595 that.scroll_to_bottom();
599 that.scroll_to_bottom();
596 } else {
600 } else {
597 that.select(cell_index+1);
601 that.select(cell_index+1);
598 };
602 };
599 };
603 };
600 };
604 };
601
605
602
606
603 Notebook.prototype.execute_all_cells = function () {
607 Notebook.prototype.execute_all_cells = function () {
604 var ncells = this.ncells();
608 var ncells = this.ncells();
605 for (var i=0; i<ncells; i++) {
609 for (var i=0; i<ncells; i++) {
606 this.select(i);
610 this.select(i);
607 this.execute_selected_cell({add_new:false});
611 this.execute_selected_cell({add_new:false});
608 };
612 };
609 this.scroll_to_bottom();
613 this.scroll_to_bottom();
610 };
614 };
611
615
612
616
613 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
617 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
614 var msg_id = this.kernel.complete(line, cursor_pos);
618 var msg_id = this.kernel.complete(line, cursor_pos);
615 this.msg_cell_map[msg_id] = cell.cell_id;
619 this.msg_cell_map[msg_id] = cell.cell_id;
616 };
620 };
617
621
618 // Persistance and loading
622 // Persistance and loading
619
623
620
624
621 Notebook.prototype.fromJSON = function (data) {
625 Notebook.prototype.fromJSON = function (data) {
622 var ncells = this.ncells();
626 var ncells = this.ncells();
623 for (var i=0; i<ncells; i++) {
627 for (var i=0; i<ncells; i++) {
624 // Always delete cell 0 as they get renumbered as they are deleted.
628 // Always delete cell 0 as they get renumbered as they are deleted.
625 this.delete_cell(0);
629 this.delete_cell(0);
626 };
630 };
627 // Only handle 1 worksheet for now.
631 // Only handle 1 worksheet for now.
628 var worksheet = data.worksheets[0];
632 var worksheet = data.worksheets[0];
629 if (worksheet !== undefined) {
633 if (worksheet !== undefined) {
630 var new_cells = worksheet.cells;
634 var new_cells = worksheet.cells;
631 ncells = new_cells.length;
635 ncells = new_cells.length;
632 var cell_data = null;
636 var cell_data = null;
633 var new_cell = null;
637 var new_cell = null;
634 for (var i=0; i<ncells; i++) {
638 for (var i=0; i<ncells; i++) {
635 cell_data = new_cells[i];
639 cell_data = new_cells[i];
636 if (cell_data.cell_type == 'code') {
640 if (cell_data.cell_type == 'code') {
637 new_cell = this.insert_code_cell_after();
641 new_cell = this.insert_code_cell_after();
638 new_cell.fromJSON(cell_data);
642 new_cell.fromJSON(cell_data);
639 } else if (cell_data.cell_type === 'html') {
643 } else if (cell_data.cell_type === 'html') {
640 new_cell = this.insert_html_cell_after();
644 new_cell = this.insert_html_cell_after();
641 new_cell.fromJSON(cell_data);
645 new_cell.fromJSON(cell_data);
642 } else if (cell_data.cell_type === 'markdown') {
646 } else if (cell_data.cell_type === 'markdown') {
643 new_cell = this.insert_markdown_cell_after();
647 new_cell = this.insert_markdown_cell_after();
644 new_cell.fromJSON(cell_data);
648 new_cell.fromJSON(cell_data);
645 };
649 };
646 };
650 };
647 };
651 };
648 };
652 };
649
653
650
654
651 Notebook.prototype.toJSON = function () {
655 Notebook.prototype.toJSON = function () {
652 var cells = this.cells();
656 var cells = this.cells();
653 var ncells = cells.length;
657 var ncells = cells.length;
654 cell_array = new Array(ncells);
658 cell_array = new Array(ncells);
655 for (var i=0; i<ncells; i++) {
659 for (var i=0; i<ncells; i++) {
656 cell_array[i] = cells[i].toJSON();
660 cell_array[i] = cells[i].toJSON();
657 };
661 };
658 data = {
662 data = {
659 // Only handle 1 worksheet for now.
663 // Only handle 1 worksheet for now.
660 worksheets : [{cells:cell_array}]
664 worksheets : [{cells:cell_array}]
661 }
665 }
662 return data
666 return data
663 };
667 };
664
668
665 Notebook.prototype.save_notebook = function () {
669 Notebook.prototype.save_notebook = function () {
666 if (IPython.save_widget.test_notebook_name()) {
670 if (IPython.save_widget.test_notebook_name()) {
667 var notebook_id = IPython.save_widget.get_notebook_id();
671 var notebook_id = IPython.save_widget.get_notebook_id();
668 var nbname = IPython.save_widget.get_notebook_name();
672 var nbname = IPython.save_widget.get_notebook_name();
669 // We may want to move the name/id/nbformat logic inside toJSON?
673 // We may want to move the name/id/nbformat logic inside toJSON?
670 var data = this.toJSON();
674 var data = this.toJSON();
671 data.name = nbname;
675 data.name = nbname;
672 data.nbformat = 2;
676 data.nbformat = 2;
673 data.id = notebook_id
677 data.id = notebook_id
674 // We do the call with settings so we can set cache to false.
678 // We do the call with settings so we can set cache to false.
675 var settings = {
679 var settings = {
676 processData : false,
680 processData : false,
677 cache : false,
681 cache : false,
678 type : "PUT",
682 type : "PUT",
679 data : JSON.stringify(data),
683 data : JSON.stringify(data),
680 headers : {'Content-Type': 'application/json'},
684 headers : {'Content-Type': 'application/json'},
681 success : $.proxy(this.notebook_saved,this)
685 success : $.proxy(this.notebook_saved,this)
682 };
686 };
683 IPython.save_widget.status_saving();
687 IPython.save_widget.status_saving();
684 $.ajax("/notebooks/" + notebook_id, settings);
688 $.ajax("/notebooks/" + notebook_id, settings);
685 };
689 };
686 };
690 };
687
691
688
692
689 Notebook.prototype.notebook_saved = function (data, status, xhr) {
693 Notebook.prototype.notebook_saved = function (data, status, xhr) {
690 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
694 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
691 // IPython.save_widget.status_save();
692 }
695 }
693
696
694
697
695 Notebook.prototype.load_notebook = function (callback) {
698 Notebook.prototype.load_notebook = function (callback) {
696 var that = this;
699 var that = this;
697 var notebook_id = IPython.save_widget.get_notebook_id();
700 var notebook_id = IPython.save_widget.get_notebook_id();
698 // We do the call with settings so we can set cache to false.
701 // We do the call with settings so we can set cache to false.
699 var settings = {
702 var settings = {
700 processData : false,
703 processData : false,
701 cache : false,
704 cache : false,
702 type : "GET",
705 type : "GET",
703 dataType : "json",
706 dataType : "json",
704 success : function (data, status, xhr) {
707 success : function (data, status, xhr) {
705 that.notebook_loaded(data, status, xhr);
708 that.notebook_loaded(data, status, xhr);
706 if (callback !== undefined) {
709 if (callback !== undefined) {
707 callback();
710 callback();
708 };
711 };
709 }
712 }
710 };
713 };
711 IPython.save_widget.status_loading();
714 IPython.save_widget.status_loading();
712 $.ajax("/notebooks/" + notebook_id, settings);
715 $.ajax("/notebooks/" + notebook_id, settings);
713 }
716 }
714
717
715
718
716 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
719 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
717 this.fromJSON(data);
720 this.fromJSON(data);
718 if (this.ncells() === 0) {
721 if (this.ncells() === 0) {
719 this.insert_code_cell_after();
722 this.insert_code_cell_after();
720 };
723 };
721 IPython.save_widget.status_save();
724 IPython.save_widget.status_save();
722 IPython.save_widget.set_notebook_name(data.name);
725 IPython.save_widget.set_notebook_name(data.name);
723 this.start_kernel();
726 this.start_kernel();
724 // fromJSON always selects the last cell inserted. We need to wait
727 // fromJSON always selects the last cell inserted. We need to wait
725 // until that is done before scrolling to the top.
728 // until that is done before scrolling to the top.
726 setTimeout(function () {
729 setTimeout(function () {
727 IPython.notebook.select(0);
730 IPython.notebook.select(0);
728 IPython.notebook.scroll_to_top();
731 IPython.notebook.scroll_to_top();
729 }, 50);
732 }, 50);
730 };
733 };
731
734
732 IPython.Notebook = Notebook;
735 IPython.Notebook = Notebook;
733
736
734 return IPython;
737 return IPython;
735
738
736 }(IPython));
739 }(IPython));
737
740
@@ -1,122 +1,136 b''
1 """The basic dict based notebook format."""
1 """The basic dict based notebook format."""
2
2
3 import pprint
3 import pprint
4 import uuid
4 import uuid
5
5
6 from IPython.utils.ipstruct import Struct
6 from IPython.utils.ipstruct import Struct
7
7
8
8
9 class NotebookNode(Struct):
9 class NotebookNode(Struct):
10 pass
10 pass
11
11
12
12
13 def from_dict(d):
13 def from_dict(d):
14 if isinstance(d, dict):
14 if isinstance(d, dict):
15 newd = NotebookNode()
15 newd = NotebookNode()
16 for k,v in d.items():
16 for k,v in d.items():
17 newd[k] = from_dict(v)
17 newd[k] = from_dict(v)
18 return newd
18 return newd
19 elif isinstance(d, (tuple, list)):
19 elif isinstance(d, (tuple, list)):
20 return [from_dict(i) for i in d]
20 return [from_dict(i) for i in d]
21 else:
21 else:
22 return d
22 return d
23
23
24
24
25 def new_output(output_type=None, output_text=None, output_png=None,
25 def new_output(output_type=None, output_text=None, output_png=None,
26 output_html=None, output_svg=None, output_latex=None, output_json=None,
26 output_html=None, output_svg=None, output_latex=None, output_json=None,
27 output_javascript=None, output_jpeg=None, prompt_number=None):
27 output_javascript=None, output_jpeg=None, prompt_number=None,
28 etype=None, evalue=None, traceback=None):
28 """Create a new code cell with input and output"""
29 """Create a new code cell with input and output"""
29 output = NotebookNode()
30 output = NotebookNode()
30 if output_type is not None:
31 if output_type is not None:
31 output.output_type = unicode(output_type)
32 output.output_type = unicode(output_type)
32 if output_text is not None:
33
33 output.text = unicode(output_text)
34 if output_type != 'pyerr':
34 if output_png is not None:
35 if output_text is not None:
35 output.png = bytes(output_png)
36 output.text = unicode(output_text)
36 if output_jpeg is not None:
37 if output_png is not None:
37 output.jpeg = bytes(output_jpeg)
38 output.png = bytes(output_png)
38 if output_html is not None:
39 if output_jpeg is not None:
39 output.html = unicode(output_html)
40 output.jpeg = bytes(output_jpeg)
40 if output_svg is not None:
41 if output_html is not None:
41 output.svg = unicode(output_svg)
42 output.html = unicode(output_html)
42 if output_latex is not None:
43 if output_svg is not None:
43 output.latex = unicode(output_latex)
44 output.svg = unicode(output_svg)
44 if output_json is not None:
45 if output_latex is not None:
45 output.json = unicode(output_json)
46 output.latex = unicode(output_latex)
46 if output_javascript is not None:
47 if output_json is not None:
47 output.javascript = unicode(output_javascript)
48 output.json = unicode(output_json)
48 if prompt_number is not None:
49 if output_javascript is not None:
49 output.prompt_number = int(prompt_number)
50 output.javascript = unicode(output_javascript)
51
52 if output_type == u'pyout':
53 if prompt_number is not None:
54 output.prompt_number = int(prompt_number)
55
56 if output_type == u'pyerr':
57 if etype is not None:
58 output.etype = unicode(etype)
59 if evalue is not None:
60 output.evalue = unicode(evalue)
61 if traceback is not None:
62 output.traceback = [unicode(frame) for frame in list(traceback)]
63
50 return output
64 return output
51
65
52
66
53 def new_code_cell(input=None, prompt_number=None, outputs=None,
67 def new_code_cell(input=None, prompt_number=None, outputs=None,
54 language=u'python', collapsed=False):
68 language=u'python', collapsed=False):
55 """Create a new code cell with input and output"""
69 """Create a new code cell with input and output"""
56 cell = NotebookNode()
70 cell = NotebookNode()
57 cell.cell_type = u'code'
71 cell.cell_type = u'code'
58 if language is not None:
72 if language is not None:
59 cell.language = unicode(language)
73 cell.language = unicode(language)
60 if input is not None:
74 if input is not None:
61 cell.input = unicode(input)
75 cell.input = unicode(input)
62 if prompt_number is not None:
76 if prompt_number is not None:
63 cell.prompt_number = int(prompt_number)
77 cell.prompt_number = int(prompt_number)
64 if outputs is None:
78 if outputs is None:
65 cell.outputs = []
79 cell.outputs = []
66 else:
80 else:
67 cell.outputs = outputs
81 cell.outputs = outputs
68 if collapsed is not None:
82 if collapsed is not None:
69 cell.collapsed = bool(collapsed)
83 cell.collapsed = bool(collapsed)
70
84
71 return cell
85 return cell
72
86
73 def new_text_cell(cell_type, source=None, rendered=None):
87 def new_text_cell(cell_type, source=None, rendered=None):
74 """Create a new text cell."""
88 """Create a new text cell."""
75 cell = NotebookNode()
89 cell = NotebookNode()
76 if source is not None:
90 if source is not None:
77 cell.source = unicode(source)
91 cell.source = unicode(source)
78 if rendered is not None:
92 if rendered is not None:
79 cell.rendered = unicode(rendered)
93 cell.rendered = unicode(rendered)
80 cell.cell_type = cell_type
94 cell.cell_type = cell_type
81 return cell
95 return cell
82
96
83
97
84 def new_worksheet(name=None, cells=None):
98 def new_worksheet(name=None, cells=None):
85 """Create a worksheet by name with with a list of cells."""
99 """Create a worksheet by name with with a list of cells."""
86 ws = NotebookNode()
100 ws = NotebookNode()
87 if name is not None:
101 if name is not None:
88 ws.name = unicode(name)
102 ws.name = unicode(name)
89 if cells is None:
103 if cells is None:
90 ws.cells = []
104 ws.cells = []
91 else:
105 else:
92 ws.cells = list(cells)
106 ws.cells = list(cells)
93 return ws
107 return ws
94
108
95
109
96 def new_notebook(name=None, id=None, worksheets=None, author=None, email=None,
110 def new_notebook(name=None, id=None, worksheets=None, author=None, email=None,
97 created=None, saved=None, license=None):
111 created=None, saved=None, license=None):
98 """Create a notebook by name, id and a list of worksheets."""
112 """Create a notebook by name, id and a list of worksheets."""
99 nb = NotebookNode()
113 nb = NotebookNode()
100 nb.nbformat = 2
114 nb.nbformat = 2
101 if name is not None:
115 if name is not None:
102 nb.name = unicode(name)
116 nb.name = unicode(name)
103 if id is None:
117 if id is None:
104 nb.id = unicode(uuid.uuid4())
118 nb.id = unicode(uuid.uuid4())
105 else:
119 else:
106 nb.id = unicode(id)
120 nb.id = unicode(id)
107 if worksheets is None:
121 if worksheets is None:
108 nb.worksheets = []
122 nb.worksheets = []
109 else:
123 else:
110 nb.worksheets = list(worksheets)
124 nb.worksheets = list(worksheets)
111 if author is not None:
125 if author is not None:
112 nb.author = unicode(author)
126 nb.author = unicode(author)
113 if email is not None:
127 if email is not None:
114 nb.email = unicode(email)
128 nb.email = unicode(email)
115 if created is not None:
129 if created is not None:
116 nb.created = unicode(created)
130 nb.created = unicode(created)
117 if saved is not None:
131 if saved is not None:
118 nb.saved = unicode(saved)
132 nb.saved = unicode(saved)
119 if license is not None:
133 if license is not None:
120 nb.license = unicode(license)
134 nb.license = unicode(license)
121 return nb
135 return nb
122
136
@@ -1,210 +1,228 b''
1 """Read and write notebook files as XML."""
1 """Read and write notebook files as XML."""
2
2
3 from base64 import encodestring, decodestring
3 from base64 import encodestring, decodestring
4 from xml.etree import ElementTree as ET
4 from xml.etree import ElementTree as ET
5
5
6 from .rwbase import NotebookReader, NotebookWriter
6 from .rwbase import NotebookReader, NotebookWriter
7 from .nbbase import (
7 from .nbbase import (
8 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
8 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
9 )
9 )
10
10
11 def indent(elem, level=0):
11 def indent(elem, level=0):
12 i = "\n" + level*" "
12 i = "\n" + level*" "
13 if len(elem):
13 if len(elem):
14 if not elem.text or not elem.text.strip():
14 if not elem.text or not elem.text.strip():
15 elem.text = i + " "
15 elem.text = i + " "
16 if not elem.tail or not elem.tail.strip():
16 if not elem.tail or not elem.tail.strip():
17 elem.tail = i
17 elem.tail = i
18 for elem in elem:
18 for elem in elem:
19 indent(elem, level+1)
19 indent(elem, level+1)
20 if not elem.tail or not elem.tail.strip():
20 if not elem.tail or not elem.tail.strip():
21 elem.tail = i
21 elem.tail = i
22 else:
22 else:
23 if level and (not elem.tail or not elem.tail.strip()):
23 if level and (not elem.tail or not elem.tail.strip()):
24 elem.tail = i
24 elem.tail = i
25
25
26
26
27 def _get_text(e, tag):
27 def _get_text(e, tag):
28 sub_e = e.find(tag)
28 sub_e = e.find(tag)
29 if sub_e is None:
29 if sub_e is None:
30 return None
30 return None
31 else:
31 else:
32 return sub_e.text
32 return sub_e.text
33
33
34
34
35 def _set_text(nbnode, attr, parent, tag):
35 def _set_text(nbnode, attr, parent, tag):
36 if attr in nbnode:
36 if attr in nbnode:
37 e = ET.SubElement(parent, tag)
37 e = ET.SubElement(parent, tag)
38 e.text = nbnode[attr]
38 e.text = nbnode[attr]
39
39
40
40
41 def _get_int(e, tag):
41 def _get_int(e, tag):
42 sub_e = e.find(tag)
42 sub_e = e.find(tag)
43 if sub_e is None:
43 if sub_e is None:
44 return None
44 return None
45 else:
45 else:
46 return int(sub_e.text)
46 return int(sub_e.text)
47
47
48
48
49 def _set_int(nbnode, attr, parent, tag):
49 def _set_int(nbnode, attr, parent, tag):
50 if attr in nbnode:
50 if attr in nbnode:
51 e = ET.SubElement(parent, tag)
51 e = ET.SubElement(parent, tag)
52 e.text = unicode(nbnode[attr])
52 e.text = unicode(nbnode[attr])
53
53
54
54
55 def _get_bool(e, tag):
55 def _get_bool(e, tag):
56 sub_e = e.find(tag)
56 sub_e = e.find(tag)
57 if sub_e is None:
57 if sub_e is None:
58 return None
58 return None
59 else:
59 else:
60 return bool(int(sub_e.text))
60 return bool(int(sub_e.text))
61
61
62
62
63 def _set_bool(nbnode, attr, parent, tag):
63 def _set_bool(nbnode, attr, parent, tag):
64 if attr in nbnode:
64 if attr in nbnode:
65 e = ET.SubElement(parent, tag)
65 e = ET.SubElement(parent, tag)
66 if nbnode[attr]:
66 if nbnode[attr]:
67 e.text = u'1'
67 e.text = u'1'
68 else:
68 else:
69 e.text = u'0'
69 e.text = u'0'
70
70
71
71
72 def _get_binary(e, tag):
72 def _get_binary(e, tag):
73 sub_e = e.find(tag)
73 sub_e = e.find(tag)
74 if sub_e is None:
74 if sub_e is None:
75 return None
75 return None
76 else:
76 else:
77 return decodestring(sub_e.text)
77 return decodestring(sub_e.text)
78
78
79
79
80 def _set_binary(nbnode, attr, parent, tag):
80 def _set_binary(nbnode, attr, parent, tag):
81 if attr in nbnode:
81 if attr in nbnode:
82 e = ET.SubElement(parent, tag)
82 e = ET.SubElement(parent, tag)
83 e.text = encodestring(nbnode[attr])
83 e.text = encodestring(nbnode[attr])
84
84
85
85
86 class XMLReader(NotebookReader):
86 class XMLReader(NotebookReader):
87
87
88 def reads(self, s, **kwargs):
88 def reads(self, s, **kwargs):
89 root = ET.fromstring(s)
89 root = ET.fromstring(s)
90 return self.to_notebook(root, **kwargs)
90 return self.to_notebook(root, **kwargs)
91
91
92 def to_notebook(self, root, **kwargs):
92 def to_notebook(self, root, **kwargs):
93 nbname = _get_text(root,'name')
93 nbname = _get_text(root,u'name')
94 nbid = _get_text(root,'id')
94 nbid = _get_text(root,u'id')
95 nbauthor = _get_text(root,'author')
95 nbauthor = _get_text(root,u'author')
96 nbemail = _get_text(root,'email')
96 nbemail = _get_text(root,u'email')
97 nblicense = _get_text(root,'license')
97 nblicense = _get_text(root,u'license')
98 nbcreated = _get_text(root,'created')
98 nbcreated = _get_text(root,u'created')
99 nbsaved = _get_text(root,'saved')
99 nbsaved = _get_text(root,u'saved')
100
100
101 worksheets = []
101 worksheets = []
102 for ws_e in root.find('worksheets').getiterator('worksheet'):
102 for ws_e in root.find(u'worksheets').getiterator(u'worksheet'):
103 wsname = _get_text(ws_e,'name')
103 wsname = _get_text(ws_e,u'name')
104 cells = []
104 cells = []
105 for cell_e in ws_e.find('cells').getiterator():
105 for cell_e in ws_e.find(u'cells').getiterator():
106 if cell_e.tag == 'codecell':
106 if cell_e.tag == u'codecell':
107 input = _get_text(cell_e,'input')
107 input = _get_text(cell_e,u'input')
108 prompt_number = _get_int(cell_e,'prompt_number')
108 prompt_number = _get_int(cell_e,u'prompt_number')
109 collapsed = _get_bool(cell_e,'collapsed')
109 collapsed = _get_bool(cell_e,u'collapsed')
110 language = _get_text(cell_e,'language')
110 language = _get_text(cell_e,u'language')
111 outputs = []
111 outputs = []
112 for output_e in cell_e.find('outputs').getiterator('output'):
112 for output_e in cell_e.find(u'outputs').getiterator(u'output'):
113 out_prompt_number = _get_int(output_e,'prompt_number')
113 output_type = _get_text(output_e,u'output_type')
114 output_type = _get_text(output_e,'output_type')
114 output_text = _get_text(output_e,u'text')
115 output_text = _get_text(output_e,'text')
115 output_png = _get_binary(output_e,u'png')
116 output_png = _get_binary(output_e,'png')
116 output_jpeg = _get_binary(output_e,u'jpeg')
117 output_jpeg = _get_binary(output_e,'jpeg')
117 output_svg = _get_text(output_e,u'svg')
118 output_svg = _get_text(output_e,'svg')
118 output_html = _get_text(output_e,u'html')
119 output_html = _get_text(output_e,'html')
119 output_latex = _get_text(output_e,u'latex')
120 output_latex = _get_text(output_e,'latex')
120 output_json = _get_text(output_e,u'json')
121 output_json = _get_text(output_e,'json')
121 output_javascript = _get_text(output_e,u'javascript')
122 output_javascript = _get_text(output_e,'javascript')
122
123 out_prompt_number = _get_int(output_e,u'prompt_number')
124 etype = _get_text(output_e,u'etype')
125 evalue = _get_text(output_e,u'evalue')
126 traceback = []
127 traceback_e = output_e.find(u'traceback')
128 if traceback_e is not None:
129 for frame_e in traceback_e.getiterator(u'frame'):
130 traceback.append(frame_e.text)
131 if len(traceback) == 0:
132 traceback = None
123 output = new_output(output_type=output_type,output_png=output_png,
133 output = new_output(output_type=output_type,output_png=output_png,
124 output_text=output_text, output_svg=output_svg,
134 output_text=output_text, output_svg=output_svg,
125 output_html=output_html, output_latex=output_latex,
135 output_html=output_html, output_latex=output_latex,
126 output_json=output_json, output_javascript=output_javascript,
136 output_json=output_json, output_javascript=output_javascript,
127 output_jpeg=output_jpeg, prompt_number=out_prompt_number
137 output_jpeg=output_jpeg, prompt_number=out_prompt_number,
138 etype=etype, evalue=evalue, traceback=traceback
128 )
139 )
129 outputs.append(output)
140 outputs.append(output)
130 cc = new_code_cell(input=input,prompt_number=prompt_number,
141 cc = new_code_cell(input=input,prompt_number=prompt_number,
131 language=language,outputs=outputs,collapsed=collapsed)
142 language=language,outputs=outputs,collapsed=collapsed)
132 cells.append(cc)
143 cells.append(cc)
133 if cell_e.tag == 'htmlcell':
144 if cell_e.tag == u'htmlcell':
134 source = _get_text(cell_e,'source')
145 source = _get_text(cell_e,u'source')
135 rendered = _get_text(cell_e,'rendered')
146 rendered = _get_text(cell_e,u'rendered')
136 cells.append(new_text_cell(u'html', source=source, rendered=rendered))
147 cells.append(new_text_cell(u'html', source=source, rendered=rendered))
137 if cell_e.tag == 'markdowncell':
148 if cell_e.tag == u'markdowncell':
138 source = _get_text(cell_e,'source')
149 source = _get_text(cell_e,u'source')
139 rendered = _get_text(cell_e,'rendered')
150 rendered = _get_text(cell_e,u'rendered')
140 cells.append(new_text_cell(u'markdown', source=source, rendered=rendered))
151 cells.append(new_text_cell(u'markdown', source=source, rendered=rendered))
141 ws = new_worksheet(name=wsname,cells=cells)
152 ws = new_worksheet(name=wsname,cells=cells)
142 worksheets.append(ws)
153 worksheets.append(ws)
143
154
144 nb = new_notebook(name=nbname,id=nbid,worksheets=worksheets,author=nbauthor,
155 nb = new_notebook(name=nbname,id=nbid,worksheets=worksheets,author=nbauthor,
145 email=nbemail,license=nblicense,saved=nbsaved,created=nbcreated)
156 email=nbemail,license=nblicense,saved=nbsaved,created=nbcreated)
146 return nb
157 return nb
147
158
148
159
149 class XMLWriter(NotebookWriter):
160 class XMLWriter(NotebookWriter):
150
161
151 def writes(self, nb, **kwargs):
162 def writes(self, nb, **kwargs):
152 nb_e = ET.Element('notebook')
163 nb_e = ET.Element(u'notebook')
153 _set_text(nb,'name',nb_e,'name')
164 _set_text(nb,u'name',nb_e,u'name')
154 _set_text(nb,'id',nb_e,'id')
165 _set_text(nb,u'id',nb_e,u'id')
155 _set_text(nb,'author',nb_e,'author')
166 _set_text(nb,u'author',nb_e,u'author')
156 _set_text(nb,'email',nb_e,'email')
167 _set_text(nb,u'email',nb_e,u'email')
157 _set_text(nb,'license',nb_e,'license')
168 _set_text(nb,u'license',nb_e,u'license')
158 _set_text(nb,'created',nb_e,'created')
169 _set_text(nb,u'created',nb_e,u'created')
159 _set_text(nb,'saved',nb_e,'saved')
170 _set_text(nb,u'saved',nb_e,u'saved')
160 _set_int(nb,'nbformat',nb_e,'nbformat')
171 _set_int(nb,u'nbformat',nb_e,u'nbformat')
161 wss_e = ET.SubElement(nb_e,'worksheets')
172 wss_e = ET.SubElement(nb_e,u'worksheets')
162 for ws in nb.worksheets:
173 for ws in nb.worksheets:
163 ws_e = ET.SubElement(wss_e, 'worksheet')
174 ws_e = ET.SubElement(wss_e, u'worksheet')
164 _set_text(ws,'name',ws_e,'name')
175 _set_text(ws,u'name',ws_e,u'name')
165 cells_e = ET.SubElement(ws_e,'cells')
176 cells_e = ET.SubElement(ws_e,u'cells')
166 for cell in ws.cells:
177 for cell in ws.cells:
167 cell_type = cell.cell_type
178 cell_type = cell.cell_type
168 if cell_type == 'code':
179 if cell_type == u'code':
169 cell_e = ET.SubElement(cells_e, 'codecell')
180 cell_e = ET.SubElement(cells_e, u'codecell')
170 _set_text(cell,'input',cell_e,'input')
181 _set_text(cell,u'input',cell_e,u'input')
171 _set_text(cell,'language',cell_e,'language')
182 _set_text(cell,u'language',cell_e,u'language')
172 _set_int(cell,'prompt_number',cell_e,'prompt_number')
183 _set_int(cell,u'prompt_number',cell_e,u'prompt_number')
173 _set_bool(cell,'collapsed',cell_e,'collapsed')
184 _set_bool(cell,u'collapsed',cell_e,u'collapsed')
174 outputs_e = ET.SubElement(cell_e, 'outputs')
185 outputs_e = ET.SubElement(cell_e, u'outputs')
175 for output in cell.outputs:
186 for output in cell.outputs:
176 output_e = ET.SubElement(outputs_e, 'output')
187 output_e = ET.SubElement(outputs_e, u'output')
177 _set_int(output,'prompt_number',output_e,'prompt_number')
188 _set_text(output,u'output_type',output_e,u'output_type')
178 _set_text(output,'output_type',output_e,'output_type')
189 _set_text(output,u'text',output_e,u'text')
179 _set_text(output,'text',output_e,'text')
190 _set_binary(output,u'png',output_e,u'png')
180 _set_binary(output,'png',output_e,'png')
191 _set_binary(output,u'jpeg',output_e,u'jpeg')
181 _set_binary(output,'jpeg',output_e,'jpeg')
192 _set_text(output,u'html',output_e,u'html')
182 _set_text(output,'html',output_e,'html')
193 _set_text(output,u'svg',output_e,u'svg')
183 _set_text(output,'svg',output_e,'svg')
194 _set_text(output,u'latex',output_e,u'latex')
184 _set_text(output,'latex',output_e,'latex')
195 _set_text(output,u'json',output_e,u'json')
185 _set_text(output,'json',output_e,'json')
196 _set_text(output,u'javascript',output_e,u'javascript')
186 _set_text(output,'javascript',output_e,'javascript')
197 _set_int(output,u'prompt_number',output_e,u'prompt_number')
187 elif cell_type == 'html':
198 _set_text(output,u'etype',output_e,u'etype')
188 cell_e = ET.SubElement(cells_e, 'htmlcell')
199 _set_text(output,u'evalue',output_e,u'evalue')
189 _set_text(cell,'source',cell_e,'source')
200 if u'traceback' in output:
190 _set_text(cell,'rendered',cell_e,'rendered')
201 tb_e = ET.SubElement(output_e, u'traceback')
191 elif cell_type == 'markdown':
202 for frame in output.traceback:
192 cell_e = ET.SubElement(cells_e, 'markdowncell')
203 frame_e = ET.SubElement(tb_e, u'frame')
193 _set_text(cell,'source',cell_e,'source')
204 frame_e.text = frame
194 _set_text(cell,'rendered',cell_e,'rendered')
205 elif cell_type == u'html':
206 cell_e = ET.SubElement(cells_e, u'htmlcell')
207 _set_text(cell,u'source',cell_e,u'source')
208 _set_text(cell,u'rendered',cell_e,u'rendered')
209 elif cell_type == u'markdown':
210 cell_e = ET.SubElement(cells_e, u'markdowncell')
211 _set_text(cell,u'source',cell_e,u'source')
212 _set_text(cell,u'rendered',cell_e,u'rendered')
195
213
196 indent(nb_e)
214 indent(nb_e)
197 txt = ET.tostring(nb_e, encoding="utf-8")
215 txt = ET.tostring(nb_e, encoding="utf-8")
198 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
216 txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
199 return txt
217 return txt
200
218
201
219
202 _reader = XMLReader()
220 _reader = XMLReader()
203 _writer = XMLWriter()
221 _writer = XMLWriter()
204
222
205 reads = _reader.reads
223 reads = _reader.reads
206 read = _reader.read
224 read = _reader.read
207 to_notebook = _reader.to_notebook
225 to_notebook = _reader.to_notebook
208 write = _writer.write
226 write = _writer.write
209 writes = _writer.writes
227 writes = _writer.writes
210
228
@@ -1,98 +1,102 b''
1 from ..nbbase import (
1 from ..nbbase import (
2 NotebookNode,
2 NotebookNode,
3 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
3 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
4 )
4 )
5
5
6
6
7
7
8 ws = new_worksheet(name='worksheet1')
8 ws = new_worksheet(name='worksheet1')
9
9
10 ws.cells.append(new_text_cell(
10 ws.cells.append(new_text_cell(
11 u'html',
11 u'html',
12 source='Some NumPy Examples',
12 source='Some NumPy Examples',
13 rendered='Some NumPy Examples'
13 rendered='Some NumPy Examples'
14 ))
14 ))
15
15
16
16
17 ws.cells.append(new_code_cell(
17 ws.cells.append(new_code_cell(
18 input='import numpy',
18 input='import numpy',
19 prompt_number=1,
19 prompt_number=1,
20 collapsed=False
20 collapsed=False
21 ))
21 ))
22
22
23 ws.cells.append(new_text_cell(
23 ws.cells.append(new_text_cell(
24 u'markdown',
24 u'markdown',
25 source='A random array',
25 source='A random array',
26 rendered='A random array'
26 rendered='A random array'
27 ))
27 ))
28
28
29 ws.cells.append(new_code_cell(
29 ws.cells.append(new_code_cell(
30 input='a = numpy.random.rand(100)',
30 input='a = numpy.random.rand(100)',
31 prompt_number=2,
31 prompt_number=2,
32 collapsed=True
32 collapsed=True
33 ))
33 ))
34
34
35 ws.cells.append(new_code_cell(
35 ws.cells.append(new_code_cell(
36 input='print a',
36 input='print a',
37 prompt_number=3,
37 prompt_number=3,
38 collapsed=False,
38 collapsed=False,
39 outputs=[new_output(
39 outputs=[new_output(
40 output_type=u'pyout',
40 output_type=u'pyout',
41 output_text=u'<array a>',
41 output_text=u'<array a>',
42 output_html=u'The HTML rep',
42 output_html=u'The HTML rep',
43 output_latex=u'$a$',
43 output_latex=u'$a$',
44 output_png=b'data',
44 output_png=b'data',
45 output_jpeg=b'data',
45 output_jpeg=b'data',
46 output_svg=u'<svg>',
46 output_svg=u'<svg>',
47 output_json=u'json data',
47 output_json=u'json data',
48 output_javascript=u'var i=0;',
48 output_javascript=u'var i=0;',
49 prompt_number=3
49 prompt_number=3
50 ),new_output(
50 ),new_output(
51 output_type=u'display_data',
51 output_type=u'display_data',
52 output_text=u'<array a>',
52 output_text=u'<array a>',
53 output_html=u'The HTML rep',
53 output_html=u'The HTML rep',
54 output_latex=u'$a$',
54 output_latex=u'$a$',
55 output_png=b'data',
55 output_png=b'data',
56 output_jpeg=b'data',
56 output_jpeg=b'data',
57 output_svg=u'<svg>',
57 output_svg=u'<svg>',
58 output_json=u'json data',
58 output_json=u'json data',
59 output_javascript=u'var i=0;',
59 output_javascript=u'var i=0;'
60 prompt_number=4
60 ),new_output(
61 output_type=u'pyerr',
62 etype=u'NameError',
63 evalue=u'NameError was here',
64 traceback=[u'frame 0', u'frame 1', u'frame 2']
61 )]
65 )]
62 ))
66 ))
63
67
64 nb0 = new_notebook(
68 nb0 = new_notebook(
65 name='nb0',
69 name='nb0',
66 worksheets=[ws, new_worksheet(name='worksheet2')],
70 worksheets=[ws, new_worksheet(name='worksheet2')],
67 author='Bart Simpson',
71 author='Bart Simpson',
68 email='bsimple@fox.com',
72 email='bsimpson@fox.com',
69 saved='ISO8601_goes_here',
73 saved='ISO8601_goes_here',
70 created='ISO8601_goes_here',
74 created='ISO8601_goes_here',
71 license='BSD'
75 license='BSD'
72 )
76 )
73
77
74 nb0_py = """# <nbformat>2</nbformat>
78 nb0_py = """# <nbformat>2</nbformat>
75
79
76 # <htmlcell>
80 # <htmlcell>
77
81
78 # Some NumPy Examples
82 # Some NumPy Examples
79
83
80 # <codecell>
84 # <codecell>
81
85
82 import numpy
86 import numpy
83
87
84 # <markdowncell>
88 # <markdowncell>
85
89
86 # A random array
90 # A random array
87
91
88 # <codecell>
92 # <codecell>
89
93
90 a = numpy.random.rand(100)
94 a = numpy.random.rand(100)
91
95
92 # <codecell>
96 # <codecell>
93
97
94 print a
98 print a
95
99
96 """
100 """
97
101
98
102
@@ -1,82 +1,90 b''
1 from unittest import TestCase
1 from unittest import TestCase
2
2
3 from ..nbbase import (
3 from ..nbbase import (
4 NotebookNode,
4 NotebookNode,
5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
6 )
6 )
7
7
8 class TestCell(TestCase):
8 class TestCell(TestCase):
9
9
10 def test_empty_code_cell(self):
10 def test_empty_code_cell(self):
11 cc = new_code_cell()
11 cc = new_code_cell()
12 self.assertEquals(cc.cell_type,'code')
12 self.assertEquals(cc.cell_type,'code')
13 self.assertEquals('input' not in cc, True)
13 self.assertEquals('input' not in cc, True)
14 self.assertEquals('prompt_number' not in cc, True)
14 self.assertEquals('prompt_number' not in cc, True)
15 self.assertEquals(cc.outputs, [])
15 self.assertEquals(cc.outputs, [])
16 self.assertEquals(cc.collapsed, False)
16 self.assertEquals(cc.collapsed, False)
17
17
18 def test_code_cell(self):
18 def test_code_cell(self):
19 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
19 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
20 cc.outputs = [new_output(output_type='pyout',
20 cc.outputs = [new_output(output_type='pyout',
21 output_svg='foo',output_text='10',prompt_number=0)]
21 output_svg='foo',output_text='10',prompt_number=0)]
22 self.assertEquals(cc.input, u'a=10')
22 self.assertEquals(cc.input, u'a=10')
23 self.assertEquals(cc.prompt_number, 0)
23 self.assertEquals(cc.prompt_number, 0)
24 self.assertEquals(cc.language, u'python')
24 self.assertEquals(cc.language, u'python')
25 self.assertEquals(cc.outputs[0].svg, u'foo')
25 self.assertEquals(cc.outputs[0].svg, u'foo')
26 self.assertEquals(cc.outputs[0].text, u'10')
26 self.assertEquals(cc.outputs[0].text, u'10')
27 self.assertEquals(cc.outputs[0].prompt_number, 0)
27 self.assertEquals(cc.outputs[0].prompt_number, 0)
28 self.assertEquals(cc.collapsed, True)
28 self.assertEquals(cc.collapsed, True)
29
29
30 def test_pyerr(self):
31 o = new_output(output_type=u'pyerr', etype=u'NameError',
32 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
33 )
34 self.assertEquals(o.output_type, u'pyerr')
35 self.assertEquals(o.etype, u'NameError')
36 self.assertEquals(o.evalue, u'Name not found')
37 self.assertEquals(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
30
38
31 def test_empty_html_cell(self):
39 def test_empty_html_cell(self):
32 tc = new_text_cell(u'html')
40 tc = new_text_cell(u'html')
33 self.assertEquals(tc.cell_type, u'html')
41 self.assertEquals(tc.cell_type, u'html')
34 self.assertEquals('source' not in tc, True)
42 self.assertEquals('source' not in tc, True)
35 self.assertEquals('rendered' not in tc, True)
43 self.assertEquals('rendered' not in tc, True)
36
44
37 def test_html_cell(self):
45 def test_html_cell(self):
38 tc = new_text_cell(u'html', 'hi', 'hi')
46 tc = new_text_cell(u'html', 'hi', 'hi')
39 self.assertEquals(tc.source, u'hi')
47 self.assertEquals(tc.source, u'hi')
40 self.assertEquals(tc.rendered, u'hi')
48 self.assertEquals(tc.rendered, u'hi')
41
49
42 def test_empty_markdown_cell(self):
50 def test_empty_markdown_cell(self):
43 tc = new_text_cell(u'markdown')
51 tc = new_text_cell(u'markdown')
44 self.assertEquals(tc.cell_type, u'markdown')
52 self.assertEquals(tc.cell_type, u'markdown')
45 self.assertEquals('source' not in tc, True)
53 self.assertEquals('source' not in tc, True)
46 self.assertEquals('rendered' not in tc, True)
54 self.assertEquals('rendered' not in tc, True)
47
55
48 def test_markdown_cell(self):
56 def test_markdown_cell(self):
49 tc = new_text_cell(u'markdown', 'hi', 'hi')
57 tc = new_text_cell(u'markdown', 'hi', 'hi')
50 self.assertEquals(tc.source, u'hi')
58 self.assertEquals(tc.source, u'hi')
51 self.assertEquals(tc.rendered, u'hi')
59 self.assertEquals(tc.rendered, u'hi')
52
60
53
61
54 class TestWorksheet(TestCase):
62 class TestWorksheet(TestCase):
55
63
56 def test_empty_worksheet(self):
64 def test_empty_worksheet(self):
57 ws = new_worksheet()
65 ws = new_worksheet()
58 self.assertEquals(ws.cells,[])
66 self.assertEquals(ws.cells,[])
59 self.assertEquals('name' not in ws, True)
67 self.assertEquals('name' not in ws, True)
60
68
61 def test_worksheet(self):
69 def test_worksheet(self):
62 cells = [new_code_cell(), new_text_cell(u'html')]
70 cells = [new_code_cell(), new_text_cell(u'html')]
63 ws = new_worksheet(cells=cells,name='foo')
71 ws = new_worksheet(cells=cells,name='foo')
64 self.assertEquals(ws.cells,cells)
72 self.assertEquals(ws.cells,cells)
65 self.assertEquals(ws.name,u'foo')
73 self.assertEquals(ws.name,u'foo')
66
74
67 class TestNotebook(TestCase):
75 class TestNotebook(TestCase):
68
76
69 def test_empty_notebook(self):
77 def test_empty_notebook(self):
70 nb = new_notebook()
78 nb = new_notebook()
71 self.assertEquals('id' in nb, True)
79 self.assertEquals('id' in nb, True)
72 self.assertEquals(nb.worksheets, [])
80 self.assertEquals(nb.worksheets, [])
73 self.assertEquals('name' not in nb, True)
81 self.assertEquals('name' not in nb, True)
74 self.assertEquals(nb.nbformat,2)
82 self.assertEquals(nb.nbformat,2)
75
83
76 def test_notebook(self):
84 def test_notebook(self):
77 worksheets = [new_worksheet(),new_worksheet()]
85 worksheets = [new_worksheet(),new_worksheet()]
78 nb = new_notebook(name='foo',worksheets=worksheets)
86 nb = new_notebook(name='foo',worksheets=worksheets)
79 self.assertEquals(nb.name,u'foo')
87 self.assertEquals(nb.name,u'foo')
80 self.assertEquals(nb.worksheets,worksheets)
88 self.assertEquals(nb.worksheets,worksheets)
81 self.assertEquals(nb.nbformat,2)
89 self.assertEquals(nb.nbformat,2)
82
90
General Comments 0
You need to be logged in to leave comments. Login now