##// END OF EJS Templates
Fixing bug in prompt_area handling of OutputArea.
Brian Granger -
Show More
@@ -1,290 +1,290
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // CodeCell
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16 var key = IPython.utils.keycodes;
17 17
18 18 var CodeCell = function (kernel) {
19 19 this.kernel = kernel;
20 20 this.code_mirror = null;
21 21 this.input_prompt_number = null;
22 22 this.tooltip_on_tab = true;
23 23 IPython.Cell.apply(this, arguments);
24 24 };
25 25
26 26
27 27 CodeCell.prototype = new IPython.Cell();
28 28
29 29
30 30 CodeCell.prototype.create_element = function () {
31 31 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
32 32 cell.attr('tabindex','2');
33 33 var input = $('<div></div>').addClass('input hbox');
34 34 input.append($('<div/>').addClass('prompt input_prompt'));
35 35 var input_area = $('<div/>').addClass('input_area box-flex1');
36 36 this.code_mirror = CodeMirror(input_area.get(0), {
37 37 indentUnit : 4,
38 38 mode: 'python',
39 39 theme: 'ipython',
40 40 readOnly: this.read_only,
41 41 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
42 42 });
43 43 input.append(input_area);
44 44 var output = $('<div></div>');
45 45 cell.append(input).append(output);
46 46 this.element = cell;
47 this.output_area = new IPython.OutputArea(output, false);
47 this.output_area = new IPython.OutputArea(output, true);
48 48
49 49 // construct a completer only if class exist
50 50 // otherwise no print view
51 51 if (IPython.Completer != undefined )
52 52 {
53 53 this.completer = new IPython.Completer(this);
54 54 }
55 55 };
56 56
57 57 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
58 58 // This method gets called in CodeMirror's onKeyDown/onKeyPress
59 59 // handlers and is used to provide custom key handling. Its return
60 60 // value is used to determine if CodeMirror should ignore the event:
61 61 // true = ignore, false = don't ignore.
62 62
63 63 if (this.read_only){
64 64 return false;
65 65 }
66 66
67 67 var that = this;
68 68 // whatever key is pressed, first, cancel the tooltip request before
69 69 // they are sent, and remove tooltip if any, except for tab again
70 70 if(event.type === 'keydown' && event.which != key.tab ) {
71 71 IPython.tooltip.remove_and_cancel_tooltip();
72 72 };
73 73
74 74 var cur = editor.getCursor();
75 75
76 76 if (event.keyCode === key.enter && (event.shiftKey || event.ctrlKey)) {
77 77 // Always ignore shift-enter in CodeMirror as we handle it.
78 78 return true;
79 79 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
80 80 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
81 81 // browser and keyboard layout !
82 82 // Pressing '(' , request tooltip, don't forget to reappend it
83 83 IPython.tooltip.pending(that);
84 84 } else if (event.which === key.upArrow) {
85 85 // If we are not at the top, let CM handle the up arrow and
86 86 // prevent the global keydown handler from handling it.
87 87 if (!that.at_top()) {
88 88 event.stop();
89 89 return false;
90 90 } else {
91 91 return true;
92 92 };
93 93 } else if (event.which === key.downArrow) {
94 94 // If we are not at the bottom, let CM handle the down arrow and
95 95 // prevent the global keydown handler from handling it.
96 96 if (!that.at_bottom()) {
97 97 event.stop();
98 98 return false;
99 99 } else {
100 100 return true;
101 101 };
102 102 } else if (event.keyCode === key.tab && event.type == 'keydown') {
103 103 // Tab completion.
104 104 //Do not trim here because of tooltip
105 105 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
106 106 if (pre_cursor.trim() === "") {
107 107 // Don't autocomplete if the part of the line before the cursor
108 108 // is empty. In this case, let CodeMirror handle indentation.
109 109 return false;
110 110 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && that.tooltip_on_tab ) {
111 111 IPython.tooltip.request(that);
112 112 // Prevent the event from bubbling up.
113 113 event.stop();
114 114 // Prevent CodeMirror from handling the tab.
115 115 return true;
116 116 } else {
117 117 event.stop();
118 118 this.completer.startCompletion();
119 119 return true;
120 120 };
121 121 } else if (event.keyCode === key.backspace && event.type == 'keydown') {
122 122 // If backspace and the line ends with 4 spaces, remove them.
123 123 var line = editor.getLine(cur.line);
124 124 var ending = line.slice(-4);
125 125 if (ending === ' ') {
126 126 editor.replaceRange('',
127 127 {line: cur.line, ch: cur.ch-4},
128 128 {line: cur.line, ch: cur.ch}
129 129 );
130 130 event.stop();
131 131 return true;
132 132 } else {
133 133 return false;
134 134 };
135 135 } else {
136 136 // keypress/keyup also trigger on TAB press, and we don't want to
137 137 // use those to disable tab completion.
138 138 return false;
139 139 };
140 140 return false;
141 141 };
142 142
143 143 // Kernel related calls.
144 144
145 145 CodeCell.prototype.execute = function () {
146 146 this.output_area.clear_output(true, true, true);
147 147 this.set_input_prompt('*');
148 148 this.element.addClass("running");
149 149 var callbacks = {
150 150 'execute_reply': $.proxy(this._handle_execute_reply, this),
151 151 'output': $.proxy(this.output_area.handle_output, this.output_area),
152 152 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
153 153 'cell': this
154 154 };
155 155 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
156 156 };
157 157
158 158
159 159 CodeCell.prototype._handle_execute_reply = function (content) {
160 160 this.set_input_prompt(content.execution_count);
161 161 this.element.removeClass("running");
162 162 // this.dirty = true;
163 163 }
164 164
165 165 // Basic cell manipulation.
166 166
167 167 CodeCell.prototype.select = function () {
168 168 IPython.Cell.prototype.select.apply(this);
169 169 this.code_mirror.refresh();
170 170 this.code_mirror.focus();
171 171 // We used to need an additional refresh() after the focus, but
172 172 // it appears that this has been fixed in CM. This bug would show
173 173 // up on FF when a newly loaded markdown cell was edited.
174 174 };
175 175
176 176
177 177 CodeCell.prototype.select_all = function () {
178 178 var start = {line: 0, ch: 0};
179 179 var nlines = this.code_mirror.lineCount();
180 180 var last_line = this.code_mirror.getLine(nlines-1);
181 181 var end = {line: nlines-1, ch: last_line.length};
182 182 this.code_mirror.setSelection(start, end);
183 183 };
184 184
185 185
186 186 CodeCell.prototype.collapse = function () {
187 187 this.output_area.collapse();
188 188 };
189 189
190 190
191 191 CodeCell.prototype.expand = function () {
192 192 this.output_area.expand();
193 193 };
194 194
195 195
196 196 CodeCell.prototype.toggle_output = function () {
197 197 this.output_area.toggle_output();
198 198 };
199 199
200 200
201 201 CodeCell.prototype.set_input_prompt = function (number) {
202 202 this.input_prompt_number = number;
203 203 var ns = number || "&nbsp;";
204 204 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
205 205 };
206 206
207 207
208 208 CodeCell.prototype.clear_input = function () {
209 209 this.code_mirror.setValue('');
210 210 };
211 211
212 212
213 213 CodeCell.prototype.get_text = function () {
214 214 return this.code_mirror.getValue();
215 215 };
216 216
217 217
218 218 CodeCell.prototype.set_text = function (code) {
219 219 return this.code_mirror.setValue(code);
220 220 };
221 221
222 222
223 223 CodeCell.prototype.at_top = function () {
224 224 var cursor = this.code_mirror.getCursor();
225 225 if (cursor.line === 0) {
226 226 return true;
227 227 } else {
228 228 return false;
229 229 }
230 230 };
231 231
232 232
233 233 CodeCell.prototype.at_bottom = function () {
234 234 var cursor = this.code_mirror.getCursor();
235 235 if (cursor.line === (this.code_mirror.lineCount()-1)) {
236 236 return true;
237 237 } else {
238 238 return false;
239 239 }
240 240 };
241 241
242 242
243 243 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
244 244 this.output_area.clear_output(stdout, stderr, other);
245 245 };
246 246
247 247
248 248 // JSON serialization
249 249
250 250 CodeCell.prototype.fromJSON = function (data) {
251 251 if (data.cell_type === 'code') {
252 252 if (data.input !== undefined) {
253 253 this.set_text(data.input);
254 254 }
255 255 if (data.prompt_number !== undefined) {
256 256 this.set_input_prompt(data.prompt_number);
257 257 } else {
258 258 this.set_input_prompt();
259 259 };
260 260 this.output_area.fromJSON(data.outputs);
261 261 if (data.collapsed !== undefined) {
262 262 if (data.collapsed) {
263 263 this.collapse();
264 264 } else {
265 265 this.expand();
266 266 };
267 267 };
268 268 };
269 269 };
270 270
271 271
272 272 CodeCell.prototype.toJSON = function () {
273 273 var data = {};
274 274 data.input = this.get_text();
275 275 data.cell_type = 'code';
276 276 if (this.input_prompt_number) {
277 277 data.prompt_number = this.input_prompt_number;
278 278 };
279 279 var outputs = this.output_area.toJSON();
280 280 data.outputs = outputs;
281 281 data.language = 'python';
282 282 data.collapsed = this.collapsed;
283 283 return data;
284 284 };
285 285
286 286
287 287 IPython.CodeCell = CodeCell;
288 288
289 289 return IPython;
290 290 }(IPython));
@@ -1,402 +1,404
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // OutputArea
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16
17 17 var OutputArea = function (selector, prompt_area) {
18 18 this.selector = selector;
19 19 this.element = $(selector);
20 20 this.outputs = [];
21 21 this.collapsed = false;
22 22 this.clear_out_timeout = null;
23 23 if (prompt_area === undefined) {
24 24 this.prompt_area = true;
25 }
25 } else {
26 this.prompt_area = prompt_area;
27 };
26 28 this.style();
27 29 };
28 30
29 31
30 32 OutputArea.prototype.style = function () {
31 33 this.element.addClass('output vbox');
32 34 this.collapse();
33 35 };
34 36
35 37
36 38 OutputArea.prototype.collapse = function () {
37 39 if (!this.collapsed) {
38 40 this.element.hide();
39 41 this.collapsed = true;
40 42 };
41 43 };
42 44
43 45
44 46 OutputArea.prototype.expand = function () {
45 47 if (this.collapsed) {
46 48 this.element.show();
47 49 this.collapsed = false;
48 50 };
49 51 };
50 52
51 53
52 54 OutputArea.prototype.toggle_output = function () {
53 55 if (this.collapsed) {
54 56 this.expand();
55 57 } else {
56 58 this.collapse();
57 59 };
58 60 };
59 61
60 62
61 63 // typeset with MathJax if MathJax is available
62 64 OutputArea.prototype.typeset = function () {
63 65 if (window.MathJax){
64 66 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
65 67 }
66 68 };
67 69
68 70
69 71 OutputArea.prototype.handle_output = function (msg_type, content) {
70 72 var json = {};
71 73 json.output_type = msg_type;
72 74 if (msg_type === "stream") {
73 75 json.text = content.data;
74 76 json.stream = content.name;
75 77 } else if (msg_type === "display_data") {
76 78 json = this.convert_mime_types(json, content.data);
77 79 } else if (msg_type === "pyout") {
78 80 json.prompt_number = content.execution_count;
79 81 json = this.convert_mime_types(json, content.data);
80 82 } else if (msg_type === "pyerr") {
81 83 json.ename = content.ename;
82 84 json.evalue = content.evalue;
83 85 json.traceback = content.traceback;
84 86 };
85 87 // append with dynamic=true
86 88 this.append_output(json, true);
87 89 };
88 90
89 91
90 92 OutputArea.prototype.convert_mime_types = function (json, data) {
91 93 if (data['text/plain'] !== undefined) {
92 94 json.text = data['text/plain'];
93 95 };
94 96 if (data['text/html'] !== undefined) {
95 97 json.html = data['text/html'];
96 98 };
97 99 if (data['image/svg+xml'] !== undefined) {
98 100 json.svg = data['image/svg+xml'];
99 101 };
100 102 if (data['image/png'] !== undefined) {
101 103 json.png = data['image/png'];
102 104 };
103 105 if (data['image/jpeg'] !== undefined) {
104 106 json.jpeg = data['image/jpeg'];
105 107 };
106 108 if (data['text/latex'] !== undefined) {
107 109 json.latex = data['text/latex'];
108 110 };
109 111 if (data['application/json'] !== undefined) {
110 112 json.json = data['application/json'];
111 113 };
112 114 if (data['application/javascript'] !== undefined) {
113 115 json.javascript = data['application/javascript'];
114 116 }
115 117 return json;
116 118 };
117 119
118 120
119 121 OutputArea.prototype.append_output = function (json, dynamic) {
120 122 // If dynamic is true, javascript output will be eval'd.
121 123 this.expand();
122 124 this.flush_clear_timeout();
123 125 if (json.output_type === 'pyout') {
124 126 this.append_pyout(json, dynamic);
125 127 } else if (json.output_type === 'pyerr') {
126 128 this.append_pyerr(json);
127 129 } else if (json.output_type === 'display_data') {
128 130 this.append_display_data(json, dynamic);
129 131 } else if (json.output_type === 'stream') {
130 132 this.append_stream(json);
131 133 };
132 134 this.outputs.push(json);
133 135 };
134 136
135 137
136 138 OutputArea.prototype.create_output_area = function () {
137 139 var oa = $("<div/>").addClass("hbox output_area");
138 140 if (this.prompt_area) {
139 141 oa.append($('<div/>').addClass('prompt'));
140 142 }
141 143 return oa;
142 144 };
143 145
144 146
145 147 OutputArea.prototype.append_pyout = function (json, dynamic) {
146 148 var n = json.prompt_number || ' ';
147 149 var toinsert = this.create_output_area();
148 150 if (this.prompt_area) {
149 151 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
150 152 }
151 153 this.append_mime_type(json, toinsert, dynamic);
152 154 this.element.append(toinsert);
153 155 // If we just output latex, typeset it.
154 156 if ((json.latex !== undefined) || (json.html !== undefined)) {
155 157 this.typeset();
156 158 };
157 159 };
158 160
159 161
160 162 OutputArea.prototype.append_pyerr = function (json) {
161 163 var tb = json.traceback;
162 164 if (tb !== undefined && tb.length > 0) {
163 165 var s = '';
164 166 var len = tb.length;
165 167 for (var i=0; i<len; i++) {
166 168 s = s + tb[i] + '\n';
167 169 }
168 170 s = s + '\n';
169 171 var toinsert = this.create_output_area();
170 172 this.append_text(s, toinsert);
171 173 this.element.append(toinsert);
172 174 };
173 175 };
174 176
175 177
176 178 OutputArea.prototype.append_stream = function (json) {
177 179 // temporary fix: if stream undefined (json file written prior to this patch),
178 180 // default to most likely stdout:
179 181 if (json.stream == undefined){
180 182 json.stream = 'stdout';
181 183 }
182 184 if (!utils.fixConsole(json.text)){
183 185 // fixConsole gives nothing (empty string, \r, etc.)
184 186 // so don't append any elements, which might add undesirable space
185 187 return;
186 188 }
187 189 var subclass = "output_"+json.stream;
188 190 if (this.outputs.length > 0){
189 191 // have at least one output to consider
190 192 var last = this.outputs[this.outputs.length-1];
191 193 if (last.output_type == 'stream' && json.stream == last.stream){
192 194 // latest output was in the same stream,
193 195 // so append directly into its pre tag
194 196 // escape ANSI & HTML specials:
195 197 var text = utils.fixConsole(json.text);
196 198 this.element.find('div.'+subclass).last().find('pre').append(text);
197 199 return;
198 200 }
199 201 }
200 202
201 203 // If we got here, attach a new div
202 204 var toinsert = this.create_output_area();
203 205 this.append_text(json.text, toinsert, "output_stream "+subclass);
204 206 this.element.append(toinsert);
205 207 };
206 208
207 209
208 210 OutputArea.prototype.append_display_data = function (json, dynamic) {
209 211 var toinsert = this.create_output_area();
210 212 this.append_mime_type(json, toinsert, dynamic);
211 213 this.element.append(toinsert);
212 214 // If we just output latex, typeset it.
213 215 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
214 216 this.typeset();
215 217 };
216 218 };
217 219
218 220
219 221 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
220 222 if (json.javascript !== undefined && dynamic) {
221 223 this.append_javascript(json.javascript, element, dynamic);
222 224 } else if (json.html !== undefined) {
223 225 this.append_html(json.html, element);
224 226 } else if (json.latex !== undefined) {
225 227 this.append_latex(json.latex, element);
226 228 } else if (json.svg !== undefined) {
227 229 this.append_svg(json.svg, element);
228 230 } else if (json.png !== undefined) {
229 231 this.append_png(json.png, element);
230 232 } else if (json.jpeg !== undefined) {
231 233 this.append_jpeg(json.jpeg, element);
232 234 } else if (json.text !== undefined) {
233 235 this.append_text(json.text, element);
234 236 };
235 237 };
236 238
237 239
238 240 OutputArea.prototype.append_html = function (html, element) {
239 241 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
240 242 toinsert.append(html);
241 243 element.append(toinsert);
242 244 };
243 245
244 246
245 247 OutputArea.prototype.append_javascript = function (js, container) {
246 248 // We just eval the JS code, element appears in the local scope.
247 249 var element = $("<div/>").addClass("box_flex1 output_subarea");
248 250 var kernel = this.kernel;
249 251 container.append(element);
250 252 // Div for js shouldn't be drawn, as it will add empty height to the area.
251 253 container.hide();
252 254 // If the Javascript appends content to `element` that should be drawn, then
253 255 // it must also call `container.show()`.
254 256 eval(js);
255 257 }
256 258
257 259
258 260 OutputArea.prototype.append_text = function (data, element, extra_class) {
259 261 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
260 262 // escape ANSI & HTML specials in plaintext:
261 263 data = utils.fixConsole(data);
262 264 if (extra_class){
263 265 toinsert.addClass(extra_class);
264 266 }
265 267 toinsert.append($("<pre/>").html(data));
266 268 element.append(toinsert);
267 269 };
268 270
269 271
270 272 OutputArea.prototype.append_svg = function (svg, element) {
271 273 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
272 274 toinsert.append(svg);
273 275 element.append(toinsert);
274 276 };
275 277
276 278
277 279 OutputArea.prototype.append_png = function (png, element) {
278 280 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
279 281 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
280 282 element.append(toinsert);
281 283 };
282 284
283 285
284 286 OutputArea.prototype.append_jpeg = function (jpeg, element) {
285 287 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
286 288 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
287 289 element.append(toinsert);
288 290 };
289 291
290 292
291 293 OutputArea.prototype.append_latex = function (latex, element) {
292 294 // This method cannot do the typesetting because the latex first has to
293 295 // be on the page.
294 296 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
295 297 toinsert.append(latex);
296 298 element.append(toinsert);
297 299 };
298 300
299 301
300 302 OutputArea.prototype.handle_clear_output = function (content) {
301 303 this.clear_output(content.stdout, content.stderr, content.other);
302 304 }
303 305
304 306
305 307 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
306 308 var that = this;
307 309 if (this.clear_out_timeout != null){
308 310 // fire previous pending clear *immediately*
309 311 clearTimeout(this.clear_out_timeout);
310 312 this.clear_out_timeout = null;
311 313 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
312 314 }
313 315 // store flags for flushing the timeout
314 316 this._clear_stdout = stdout;
315 317 this._clear_stderr = stderr;
316 318 this._clear_other = other;
317 319 this.clear_out_timeout = setTimeout(function() {
318 320 // really clear timeout only after a short delay
319 321 // this reduces flicker in 'clear_output; print' cases
320 322 that.clear_out_timeout = null;
321 323 that._clear_stdout = that._clear_stderr = that._clear_other = null;
322 324 that.clear_output_callback(stdout, stderr, other);
323 325 }, 500
324 326 );
325 327 };
326 328
327 329
328 330 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
329 331 var output_div = this.element;
330 332
331 333 if (stdout && stderr && other){
332 334 // clear all, no need for logic
333 335 output_div.html("");
334 336 this.outputs = [];
335 337 return;
336 338 }
337 339 // remove html output
338 340 // each output_subarea that has an identifying class is in an output_area
339 341 // which is the element to be removed.
340 342 if (stdout) {
341 343 output_div.find("div.output_stdout").parent().remove();
342 344 }
343 345 if (stderr) {
344 346 output_div.find("div.output_stderr").parent().remove();
345 347 }
346 348 if (other) {
347 349 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
348 350 }
349 351
350 352 // remove cleared outputs from JSON list:
351 353 for (var i = this.outputs.length - 1; i >= 0; i--) {
352 354 var out = this.outputs[i];
353 355 var output_type = out.output_type;
354 356 if (output_type == "display_data" && other) {
355 357 this.outputs.splice(i,1);
356 358 } else if (output_type == "stream") {
357 359 if (stdout && out.stream == "stdout") {
358 360 this.outputs.splice(i,1);
359 361 } else if (stderr && out.stream == "stderr") {
360 362 this.outputs.splice(i,1);
361 363 }
362 364 }
363 365 }
364 366 };
365 367
366 368
367 369 OutputArea.prototype.flush_clear_timeout = function() {
368 370 var output_div = this.element;
369 371 if (this.clear_out_timeout){
370 372 clearTimeout(this.clear_out_timeout);
371 373 this.clear_out_timeout = null;
372 374 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
373 375 };
374 376 }
375 377
376 378
377 379 // JSON serialization
378 380
379 381 OutputArea.prototype.fromJSON = function (outputs) {
380 382 var len = outputs.length;
381 383 for (var i=0; i<len; i++) {
382 384 // append with dynamic=false.
383 385 this.append_output(outputs[i], false);
384 386 };
385 387 };
386 388
387 389
388 390 OutputArea.prototype.toJSON = function () {
389 391 var outputs = [];
390 392 var len = this.outputs.length;
391 393 for (var i=0; i<len; i++) {
392 394 outputs[i] = this.outputs[i];
393 395 };
394 396 return outputs;
395 397 };
396 398
397 399
398 400 IPython.OutputArea = OutputArea;
399 401
400 402 return IPython;
401 403
402 404 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now