##// END OF EJS Templates
put OutputArea map at the end
Matthias BUSSONNIER -
Show More
@@ -1,843 +1,843
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008 The IPython Development Team
2 // Copyright (C) 2008 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // OutputArea
9 // OutputArea
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule OutputArea
15 * @submodule OutputArea
16 */
16 */
17 var IPython = (function (IPython) {
17 var IPython = (function (IPython) {
18 "use strict";
18 "use strict";
19
19
20 var utils = IPython.utils;
20 var utils = IPython.utils;
21
21
22 /**
22 /**
23 * @class OutputArea
23 * @class OutputArea
24 *
24 *
25 * @constructor
25 * @constructor
26 */
26 */
27
27
28 var OutputArea = function (selector, prompt_area) {
28 var OutputArea = function (selector, prompt_area) {
29 this.selector = selector;
29 this.selector = selector;
30 this.wrapper = $(selector);
30 this.wrapper = $(selector);
31 this.outputs = [];
31 this.outputs = [];
32 this.collapsed = false;
32 this.collapsed = false;
33 this.scrolled = false;
33 this.scrolled = false;
34 this.clear_queued = null;
34 this.clear_queued = null;
35 if (prompt_area === undefined) {
35 if (prompt_area === undefined) {
36 this.prompt_area = true;
36 this.prompt_area = true;
37 } else {
37 } else {
38 this.prompt_area = prompt_area;
38 this.prompt_area = prompt_area;
39 }
39 }
40 this.create_elements();
40 this.create_elements();
41 this.style();
41 this.style();
42 this.bind_events();
42 this.bind_events();
43 };
43 };
44
44
45 /**
46 * Class properties
47 **/
48
49 /**
50 * Threshold to trigger autoscroll when the OutputArea is resized,
51 * typically when new outputs are added.
52 *
53 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
54 * unless it is < 0, in which case autoscroll will never be triggered
55 *
56 * @property auto_scroll_threshold
57 * @type Number
58 * @default 100
59 *
60 **/
61 OutputArea.auto_scroll_threshold = 100;
62
63 /**
64 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
65 * shorter than this are never scrolled.
66 *
67 * @property minimum_scroll_threshold
68 * @type Number
69 * @default 20
70 *
71 **/
72 OutputArea.minimum_scroll_threshold = 20;
73
74
75
76 OutputArea.mime_map = {
77 "text/plain" : "text",
78 "text/html" : "html",
79 "image/svg+xml" : "svg",
80 "image/png" : "png",
81 "image/jpeg" : "jpeg",
82 "text/latex" : "latex",
83 "application/json" : "json",
84 "application/javascript" : "javascript",
85 };
86
87 OutputArea.mime_map_r = {
88 "text" : "text/plain",
89 "html" : "text/html",
90 "svg" : "image/svg+xml",
91 "png" : "image/png",
92 "jpeg" : "image/jpeg",
93 "latex" : "text/latex",
94 "json" : "application/json",
95 "javascript" : "application/javascript",
96 };
97
98 OutputArea.display_order = [
99 'application/javascript',
100 'text/html',
101 'text/latex',
102 'image/svg+xml',
103 'image/png',
104 'image/jpeg',
105 'text/plain'
106 ];
107
108 OutputArea.append_map = {
109 "text/plain" : OutputArea.prototype.append_text,
110 "text/html" : OutputArea.prototype.append_html,
111 "image/svg+xml" : OutputArea.prototype.append_svg,
112 "image/png" : OutputArea.prototype.append_png,
113 "image/jpeg" : OutputArea.prototype.append_jpeg,
114 "text/latex" : OutputArea.prototype.append_latex,
115 "application/json" : OutputArea.prototype.append_json,
116 "application/javascript" : OutputArea.prototype.append_javascript,
117 };
118
45
119 /**
46 /**
120 * Class prototypes
47 * Class prototypes
121 **/
48 **/
122
49
123 OutputArea.prototype.create_elements = function () {
50 OutputArea.prototype.create_elements = function () {
124 this.element = $("<div/>");
51 this.element = $("<div/>");
125 this.collapse_button = $("<div/>");
52 this.collapse_button = $("<div/>");
126 this.prompt_overlay = $("<div/>");
53 this.prompt_overlay = $("<div/>");
127 this.wrapper.append(this.prompt_overlay);
54 this.wrapper.append(this.prompt_overlay);
128 this.wrapper.append(this.element);
55 this.wrapper.append(this.element);
129 this.wrapper.append(this.collapse_button);
56 this.wrapper.append(this.collapse_button);
130 };
57 };
131
58
132
59
133 OutputArea.prototype.style = function () {
60 OutputArea.prototype.style = function () {
134 this.collapse_button.hide();
61 this.collapse_button.hide();
135 this.prompt_overlay.hide();
62 this.prompt_overlay.hide();
136
63
137 this.wrapper.addClass('output_wrapper');
64 this.wrapper.addClass('output_wrapper');
138 this.element.addClass('output');
65 this.element.addClass('output');
139
66
140 this.collapse_button.addClass("btn output_collapsed");
67 this.collapse_button.addClass("btn output_collapsed");
141 this.collapse_button.attr('title', 'click to expand output');
68 this.collapse_button.attr('title', 'click to expand output');
142 this.collapse_button.text('. . .');
69 this.collapse_button.text('. . .');
143
70
144 this.prompt_overlay.addClass('out_prompt_overlay prompt');
71 this.prompt_overlay.addClass('out_prompt_overlay prompt');
145 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
72 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
146
73
147 this.collapse();
74 this.collapse();
148 };
75 };
149
76
150 /**
77 /**
151 * Should the OutputArea scroll?
78 * Should the OutputArea scroll?
152 * Returns whether the height (in lines) exceeds a threshold.
79 * Returns whether the height (in lines) exceeds a threshold.
153 *
80 *
154 * @private
81 * @private
155 * @method _should_scroll
82 * @method _should_scroll
156 * @param [lines=100]{Integer}
83 * @param [lines=100]{Integer}
157 * @return {Bool}
84 * @return {Bool}
158 *
85 *
159 */
86 */
160 OutputArea.prototype._should_scroll = function (lines) {
87 OutputArea.prototype._should_scroll = function (lines) {
161 if (lines <=0 ){ return }
88 if (lines <=0 ){ return }
162 if (!lines) {
89 if (!lines) {
163 lines = 100;
90 lines = 100;
164 }
91 }
165 // line-height from http://stackoverflow.com/questions/1185151
92 // line-height from http://stackoverflow.com/questions/1185151
166 var fontSize = this.element.css('font-size');
93 var fontSize = this.element.css('font-size');
167 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
94 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
168
95
169 return (this.element.height() > lines * lineHeight);
96 return (this.element.height() > lines * lineHeight);
170 };
97 };
171
98
172
99
173 OutputArea.prototype.bind_events = function () {
100 OutputArea.prototype.bind_events = function () {
174 var that = this;
101 var that = this;
175 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
102 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
176 this.prompt_overlay.click(function () { that.toggle_scroll(); });
103 this.prompt_overlay.click(function () { that.toggle_scroll(); });
177
104
178 this.element.resize(function () {
105 this.element.resize(function () {
179 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
106 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
180 if ( IPython.utils.browser[0] === "Firefox" ) {
107 if ( IPython.utils.browser[0] === "Firefox" ) {
181 return;
108 return;
182 }
109 }
183 // maybe scroll output,
110 // maybe scroll output,
184 // if it's grown large enough and hasn't already been scrolled.
111 // if it's grown large enough and hasn't already been scrolled.
185 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
112 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
186 that.scroll_area();
113 that.scroll_area();
187 }
114 }
188 });
115 });
189 this.collapse_button.click(function () {
116 this.collapse_button.click(function () {
190 that.expand();
117 that.expand();
191 });
118 });
192 };
119 };
193
120
194
121
195 OutputArea.prototype.collapse = function () {
122 OutputArea.prototype.collapse = function () {
196 if (!this.collapsed) {
123 if (!this.collapsed) {
197 this.element.hide();
124 this.element.hide();
198 this.prompt_overlay.hide();
125 this.prompt_overlay.hide();
199 if (this.element.html()){
126 if (this.element.html()){
200 this.collapse_button.show();
127 this.collapse_button.show();
201 }
128 }
202 this.collapsed = true;
129 this.collapsed = true;
203 }
130 }
204 };
131 };
205
132
206
133
207 OutputArea.prototype.expand = function () {
134 OutputArea.prototype.expand = function () {
208 if (this.collapsed) {
135 if (this.collapsed) {
209 this.collapse_button.hide();
136 this.collapse_button.hide();
210 this.element.show();
137 this.element.show();
211 this.prompt_overlay.show();
138 this.prompt_overlay.show();
212 this.collapsed = false;
139 this.collapsed = false;
213 }
140 }
214 };
141 };
215
142
216
143
217 OutputArea.prototype.toggle_output = function () {
144 OutputArea.prototype.toggle_output = function () {
218 if (this.collapsed) {
145 if (this.collapsed) {
219 this.expand();
146 this.expand();
220 } else {
147 } else {
221 this.collapse();
148 this.collapse();
222 }
149 }
223 };
150 };
224
151
225
152
226 OutputArea.prototype.scroll_area = function () {
153 OutputArea.prototype.scroll_area = function () {
227 this.element.addClass('output_scroll');
154 this.element.addClass('output_scroll');
228 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
155 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
229 this.scrolled = true;
156 this.scrolled = true;
230 };
157 };
231
158
232
159
233 OutputArea.prototype.unscroll_area = function () {
160 OutputArea.prototype.unscroll_area = function () {
234 this.element.removeClass('output_scroll');
161 this.element.removeClass('output_scroll');
235 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
162 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
236 this.scrolled = false;
163 this.scrolled = false;
237 };
164 };
238
165
239 /**
166 /**
240 *
167 *
241 * Scroll OutputArea if height supperior than a threshold (in lines).
168 * Scroll OutputArea if height supperior than a threshold (in lines).
242 *
169 *
243 * Threshold is a maximum number of lines. If unspecified, defaults to
170 * Threshold is a maximum number of lines. If unspecified, defaults to
244 * OutputArea.minimum_scroll_threshold.
171 * OutputArea.minimum_scroll_threshold.
245 *
172 *
246 * Negative threshold will prevent the OutputArea from ever scrolling.
173 * Negative threshold will prevent the OutputArea from ever scrolling.
247 *
174 *
248 * @method scroll_if_long
175 * @method scroll_if_long
249 *
176 *
250 * @param [lines=20]{Number} Default to 20 if not set,
177 * @param [lines=20]{Number} Default to 20 if not set,
251 * behavior undefined for value of `0`.
178 * behavior undefined for value of `0`.
252 *
179 *
253 **/
180 **/
254 OutputArea.prototype.scroll_if_long = function (lines) {
181 OutputArea.prototype.scroll_if_long = function (lines) {
255 var n = lines | OutputArea.minimum_scroll_threshold;
182 var n = lines | OutputArea.minimum_scroll_threshold;
256 if(n <= 0){
183 if(n <= 0){
257 return
184 return
258 }
185 }
259
186
260 if (this._should_scroll(n)) {
187 if (this._should_scroll(n)) {
261 // only allow scrolling long-enough output
188 // only allow scrolling long-enough output
262 this.scroll_area();
189 this.scroll_area();
263 }
190 }
264 };
191 };
265
192
266
193
267 OutputArea.prototype.toggle_scroll = function () {
194 OutputArea.prototype.toggle_scroll = function () {
268 if (this.scrolled) {
195 if (this.scrolled) {
269 this.unscroll_area();
196 this.unscroll_area();
270 } else {
197 } else {
271 // only allow scrolling long-enough output
198 // only allow scrolling long-enough output
272 this.scroll_if_long();
199 this.scroll_if_long();
273 }
200 }
274 };
201 };
275
202
276
203
277 // typeset with MathJax if MathJax is available
204 // typeset with MathJax if MathJax is available
278 OutputArea.prototype.typeset = function () {
205 OutputArea.prototype.typeset = function () {
279 if (window.MathJax){
206 if (window.MathJax){
280 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
207 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
281 }
208 }
282 };
209 };
283
210
284
211
285 OutputArea.prototype.handle_output = function (msg) {
212 OutputArea.prototype.handle_output = function (msg) {
286 var json = {};
213 var json = {};
287 var msg_type = json.output_type = msg.header.msg_type;
214 var msg_type = json.output_type = msg.header.msg_type;
288 var content = msg.content;
215 var content = msg.content;
289 if (msg_type === "stream") {
216 if (msg_type === "stream") {
290 json.text = content.data;
217 json.text = content.data;
291 json.stream = content.name;
218 json.stream = content.name;
292 } else if (msg_type === "display_data") {
219 } else if (msg_type === "display_data") {
293 json = content.data;
220 json = content.data;
294 json.output_type = msg_type;
221 json.output_type = msg_type;
295 json.metadata = content.metadata;
222 json.metadata = content.metadata;
296 } else if (msg_type === "pyout") {
223 } else if (msg_type === "pyout") {
297 json = content.data;
224 json = content.data;
298 json.output_type = msg_type;
225 json.output_type = msg_type;
299 json.metadata = content.metadata;
226 json.metadata = content.metadata;
300 json.prompt_number = content.execution_count;
227 json.prompt_number = content.execution_count;
301 } else if (msg_type === "pyerr") {
228 } else if (msg_type === "pyerr") {
302 json.ename = content.ename;
229 json.ename = content.ename;
303 json.evalue = content.evalue;
230 json.evalue = content.evalue;
304 json.traceback = content.traceback;
231 json.traceback = content.traceback;
305 }
232 }
306 this.append_output(json);
233 this.append_output(json);
307 };
234 };
308
235
309
236
310 OutputArea.prototype.rename_keys = function (data, key_map) {
237 OutputArea.prototype.rename_keys = function (data, key_map) {
311 var remapped = {};
238 var remapped = {};
312 for (var key in data) {
239 for (var key in data) {
313 var new_key = key_map[key] || key;
240 var new_key = key_map[key] || key;
314 remapped[new_key] = data[key];
241 remapped[new_key] = data[key];
315 }
242 }
316 return remapped;
243 return remapped;
317 };
244 };
318
245
319
246
320 OutputArea.output_types = [
247 OutputArea.output_types = [
321 'application/javascript',
248 'application/javascript',
322 'text/html',
249 'text/html',
323 'text/latex',
250 'text/latex',
324 'image/svg+xml',
251 'image/svg+xml',
325 'image/png',
252 'image/png',
326 'image/jpeg',
253 'image/jpeg',
327 'text/plain'
254 'text/plain'
328 ];
255 ];
329
256
330 OutputArea.prototype.validate_output = function (json) {
257 OutputArea.prototype.validate_output = function (json) {
331 // scrub invalid outputs
258 // scrub invalid outputs
332 // TODO: right now everything is a string, but JSON really shouldn't be.
259 // TODO: right now everything is a string, but JSON really shouldn't be.
333 // nbformat 4 will fix that.
260 // nbformat 4 will fix that.
334 $.map(OutputArea.output_types, function(key){
261 $.map(OutputArea.output_types, function(key){
335 if (json[key] !== undefined && typeof json[key] !== 'string') {
262 if (json[key] !== undefined && typeof json[key] !== 'string') {
336 console.log("Invalid type for " + key, json[key]);
263 console.log("Invalid type for " + key, json[key]);
337 delete json[key];
264 delete json[key];
338 }
265 }
339 });
266 });
340 return json;
267 return json;
341 };
268 };
342
269
343 OutputArea.prototype.append_output = function (json) {
270 OutputArea.prototype.append_output = function (json) {
344 this.expand();
271 this.expand();
345 // Clear the output if clear is queued.
272 // Clear the output if clear is queued.
346 var needs_height_reset = false;
273 var needs_height_reset = false;
347 if (this.clear_queued) {
274 if (this.clear_queued) {
348 this.clear_output(false);
275 this.clear_output(false);
349 needs_height_reset = true;
276 needs_height_reset = true;
350 }
277 }
351
278
352 // validate output data types
279 // validate output data types
353 json = this.validate_output(json);
280 json = this.validate_output(json);
354
281
355 if (json.output_type === 'pyout') {
282 if (json.output_type === 'pyout') {
356 this.append_pyout(json);
283 this.append_pyout(json);
357 } else if (json.output_type === 'pyerr') {
284 } else if (json.output_type === 'pyerr') {
358 this.append_pyerr(json);
285 this.append_pyerr(json);
359 } else if (json.output_type === 'display_data') {
286 } else if (json.output_type === 'display_data') {
360 this.append_display_data(json);
287 this.append_display_data(json);
361 } else if (json.output_type === 'stream') {
288 } else if (json.output_type === 'stream') {
362 this.append_stream(json);
289 this.append_stream(json);
363 }
290 }
364 this.outputs.push(json);
291 this.outputs.push(json);
365
292
366 // Only reset the height to automatic if the height is currently
293 // Only reset the height to automatic if the height is currently
367 // fixed (done by wait=True flag on clear_output).
294 // fixed (done by wait=True flag on clear_output).
368 if (needs_height_reset) {
295 if (needs_height_reset) {
369 this.element.height('');
296 this.element.height('');
370 }
297 }
371
298
372 var that = this;
299 var that = this;
373 setTimeout(function(){that.element.trigger('resize');}, 100);
300 setTimeout(function(){that.element.trigger('resize');}, 100);
374 };
301 };
375
302
376
303
377 OutputArea.prototype.create_output_area = function () {
304 OutputArea.prototype.create_output_area = function () {
378 var oa = $("<div/>").addClass("output_area");
305 var oa = $("<div/>").addClass("output_area");
379 if (this.prompt_area) {
306 if (this.prompt_area) {
380 oa.append($('<div/>').addClass('prompt'));
307 oa.append($('<div/>').addClass('prompt'));
381 }
308 }
382 return oa;
309 return oa;
383 };
310 };
384
311
385
312
386 function _get_metadata_key(metadata, key, mime) {
313 function _get_metadata_key(metadata, key, mime) {
387 var mime_md = metadata[mime];
314 var mime_md = metadata[mime];
388 // mime-specific higher priority
315 // mime-specific higher priority
389 if (mime_md && mime_md[key] !== undefined) {
316 if (mime_md && mime_md[key] !== undefined) {
390 return mime_md[key];
317 return mime_md[key];
391 }
318 }
392 // fallback on global
319 // fallback on global
393 return metadata[key];
320 return metadata[key];
394 }
321 }
395
322
396 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
323 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
397 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
324 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
398 if (_get_metadata_key(md, 'isolated', mime)) {
325 if (_get_metadata_key(md, 'isolated', mime)) {
399 // Create an iframe to isolate the subarea from the rest of the
326 // Create an iframe to isolate the subarea from the rest of the
400 // document
327 // document
401 var iframe = $('<iframe/>').addClass('box-flex1');
328 var iframe = $('<iframe/>').addClass('box-flex1');
402 iframe.css({'height':1, 'width':'100%', 'display':'block'});
329 iframe.css({'height':1, 'width':'100%', 'display':'block'});
403 iframe.attr('frameborder', 0);
330 iframe.attr('frameborder', 0);
404 iframe.attr('scrolling', 'auto');
331 iframe.attr('scrolling', 'auto');
405
332
406 // Once the iframe is loaded, the subarea is dynamically inserted
333 // Once the iframe is loaded, the subarea is dynamically inserted
407 iframe.on('load', function() {
334 iframe.on('load', function() {
408 // Workaround needed by Firefox, to properly render svg inside
335 // Workaround needed by Firefox, to properly render svg inside
409 // iframes, see http://stackoverflow.com/questions/10177190/
336 // iframes, see http://stackoverflow.com/questions/10177190/
410 // svg-dynamically-added-to-iframe-does-not-render-correctly
337 // svg-dynamically-added-to-iframe-does-not-render-correctly
411 this.contentDocument.open();
338 this.contentDocument.open();
412
339
413 // Insert the subarea into the iframe
340 // Insert the subarea into the iframe
414 // We must directly write the html. When using Jquery's append
341 // We must directly write the html. When using Jquery's append
415 // method, javascript is evaluated in the parent document and
342 // method, javascript is evaluated in the parent document and
416 // not in the iframe document.
343 // not in the iframe document.
417 this.contentDocument.write(subarea.html());
344 this.contentDocument.write(subarea.html());
418
345
419 this.contentDocument.close();
346 this.contentDocument.close();
420
347
421 var body = this.contentDocument.body;
348 var body = this.contentDocument.body;
422 // Adjust the iframe height automatically
349 // Adjust the iframe height automatically
423 iframe.height(body.scrollHeight + 'px');
350 iframe.height(body.scrollHeight + 'px');
424 });
351 });
425
352
426 // Elements should be appended to the inner subarea and not to the
353 // Elements should be appended to the inner subarea and not to the
427 // iframe
354 // iframe
428 iframe.append = function(that) {
355 iframe.append = function(that) {
429 subarea.append(that);
356 subarea.append(that);
430 };
357 };
431
358
432 return iframe;
359 return iframe;
433 } else {
360 } else {
434 return subarea;
361 return subarea;
435 }
362 }
436 }
363 }
437
364
438
365
439 OutputArea.prototype._append_javascript_error = function (err, element) {
366 OutputArea.prototype._append_javascript_error = function (err, element) {
440 // display a message when a javascript error occurs in display output
367 // display a message when a javascript error occurs in display output
441 var msg = "Javascript error adding output!"
368 var msg = "Javascript error adding output!"
442 if ( element === undefined ) return;
369 if ( element === undefined ) return;
443 element.append(
370 element.append(
444 $('<div/>').html(msg + "<br/>" +
371 $('<div/>').html(msg + "<br/>" +
445 err.toString() +
372 err.toString() +
446 '<br/>See your browser Javascript console for more details.'
373 '<br/>See your browser Javascript console for more details.'
447 ).addClass('js-error')
374 ).addClass('js-error')
448 );
375 );
449 };
376 };
450
377
451 OutputArea.prototype._safe_append = function (toinsert) {
378 OutputArea.prototype._safe_append = function (toinsert) {
452 // safely append an item to the document
379 // safely append an item to the document
453 // this is an object created by user code,
380 // this is an object created by user code,
454 // and may have errors, which should not be raised
381 // and may have errors, which should not be raised
455 // under any circumstances.
382 // under any circumstances.
456 try {
383 try {
457 this.element.append(toinsert);
384 this.element.append(toinsert);
458 } catch(err) {
385 } catch(err) {
459 console.log(err);
386 console.log(err);
460 // Create an actual output_area and output_subarea, which creates
387 // Create an actual output_area and output_subarea, which creates
461 // the prompt area and the proper indentation.
388 // the prompt area and the proper indentation.
462 var toinsert = this.create_output_area();
389 var toinsert = this.create_output_area();
463 var subarea = $('<div/>').addClass('output_subarea');
390 var subarea = $('<div/>').addClass('output_subarea');
464 toinsert.append(subarea);
391 toinsert.append(subarea);
465 this._append_javascript_error(err, subarea);
392 this._append_javascript_error(err, subarea);
466 this.element.append(toinsert);
393 this.element.append(toinsert);
467 }
394 }
468 };
395 };
469
396
470
397
471 OutputArea.prototype.append_pyout = function (json) {
398 OutputArea.prototype.append_pyout = function (json) {
472 var n = json.prompt_number || ' ';
399 var n = json.prompt_number || ' ';
473 var toinsert = this.create_output_area();
400 var toinsert = this.create_output_area();
474 if (this.prompt_area) {
401 if (this.prompt_area) {
475 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
402 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
476 }
403 }
477 this.append_mime_type(json, toinsert);
404 this.append_mime_type(json, toinsert);
478 this._safe_append(toinsert);
405 this._safe_append(toinsert);
479 // If we just output latex, typeset it.
406 // If we just output latex, typeset it.
480 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
407 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
481 this.typeset();
408 this.typeset();
482 }
409 }
483 };
410 };
484
411
485
412
486 OutputArea.prototype.append_pyerr = function (json) {
413 OutputArea.prototype.append_pyerr = function (json) {
487 var tb = json.traceback;
414 var tb = json.traceback;
488 if (tb !== undefined && tb.length > 0) {
415 if (tb !== undefined && tb.length > 0) {
489 var s = '';
416 var s = '';
490 var len = tb.length;
417 var len = tb.length;
491 for (var i=0; i<len; i++) {
418 for (var i=0; i<len; i++) {
492 s = s + tb[i] + '\n';
419 s = s + tb[i] + '\n';
493 }
420 }
494 s = s + '\n';
421 s = s + '\n';
495 var toinsert = this.create_output_area();
422 var toinsert = this.create_output_area();
496 this.append_text(s, {}, toinsert);
423 this.append_text(s, {}, toinsert);
497 this._safe_append(toinsert);
424 this._safe_append(toinsert);
498 }
425 }
499 };
426 };
500
427
501
428
502 OutputArea.prototype.append_stream = function (json) {
429 OutputArea.prototype.append_stream = function (json) {
503 // temporary fix: if stream undefined (json file written prior to this patch),
430 // temporary fix: if stream undefined (json file written prior to this patch),
504 // default to most likely stdout:
431 // default to most likely stdout:
505 if (json.stream == undefined){
432 if (json.stream == undefined){
506 json.stream = 'stdout';
433 json.stream = 'stdout';
507 }
434 }
508 var text = json.text;
435 var text = json.text;
509 var subclass = "output_"+json.stream;
436 var subclass = "output_"+json.stream;
510 if (this.outputs.length > 0){
437 if (this.outputs.length > 0){
511 // have at least one output to consider
438 // have at least one output to consider
512 var last = this.outputs[this.outputs.length-1];
439 var last = this.outputs[this.outputs.length-1];
513 if (last.output_type == 'stream' && json.stream == last.stream){
440 if (last.output_type == 'stream' && json.stream == last.stream){
514 // latest output was in the same stream,
441 // latest output was in the same stream,
515 // so append directly into its pre tag
442 // so append directly into its pre tag
516 // escape ANSI & HTML specials:
443 // escape ANSI & HTML specials:
517 var pre = this.element.find('div.'+subclass).last().find('pre');
444 var pre = this.element.find('div.'+subclass).last().find('pre');
518 var html = utils.fixCarriageReturn(
445 var html = utils.fixCarriageReturn(
519 pre.html() + utils.fixConsole(text));
446 pre.html() + utils.fixConsole(text));
520 pre.html(html);
447 pre.html(html);
521 return;
448 return;
522 }
449 }
523 }
450 }
524
451
525 if (!text.replace("\r", "")) {
452 if (!text.replace("\r", "")) {
526 // text is nothing (empty string, \r, etc.)
453 // text is nothing (empty string, \r, etc.)
527 // so don't append any elements, which might add undesirable space
454 // so don't append any elements, which might add undesirable space
528 return;
455 return;
529 }
456 }
530
457
531 // If we got here, attach a new div
458 // If we got here, attach a new div
532 var toinsert = this.create_output_area();
459 var toinsert = this.create_output_area();
533 this.append_text(text, {}, toinsert, "output_stream "+subclass);
460 this.append_text(text, {}, toinsert, "output_stream "+subclass);
534 this._safe_append(toinsert);
461 this._safe_append(toinsert);
535 };
462 };
536
463
537
464
538 OutputArea.prototype.append_display_data = function (json) {
465 OutputArea.prototype.append_display_data = function (json) {
539 var toinsert = this.create_output_area();
466 var toinsert = this.create_output_area();
540 if (this.append_mime_type(json, toinsert)) {
467 if (this.append_mime_type(json, toinsert)) {
541 this._safe_append(toinsert);
468 this._safe_append(toinsert);
542 // If we just output latex, typeset it.
469 // If we just output latex, typeset it.
543 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
470 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
544 this.typeset();
471 this.typeset();
545 }
472 }
546 }
473 }
547 };
474 };
548
475
549
476
550 OutputArea.prototype.append_mime_type = function (json, element) {
477 OutputArea.prototype.append_mime_type = function (json, element) {
551
478
552 for (var type_i in OutputArea.display_order) {
479 for (var type_i in OutputArea.display_order) {
553 var type = OutputArea.display_order[type_i];
480 var type = OutputArea.display_order[type_i];
554 var append = OutputArea.append_map[type];
481 var append = OutputArea.append_map[type];
555 if ((json[type] !== undefined) && append) {
482 if ((json[type] !== undefined) && append) {
556 var md = json.metadata || {};
483 var md = json.metadata || {};
557 var toinsert = append.apply(this, [json[type], md, element]);
484 var toinsert = append.apply(this, [json[type], md, element]);
558 $([IPython.events]).trigger('output_appended.OutputArea', [type, json[type], md, toinsert]);
485 $([IPython.events]).trigger('output_appended.OutputArea', [type, json[type], md, toinsert]);
559 return true;
486 return true;
560 }
487 }
561 }
488 }
562 return false;
489 return false;
563 };
490 };
564
491
565
492
566 OutputArea.prototype.append_html = function (html, md, element) {
493 OutputArea.prototype.append_html = function (html, md, element) {
567 var type = 'text/html';
494 var type = 'text/html';
568 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
495 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
569 IPython.keyboard_manager.register_events(toinsert);
496 IPython.keyboard_manager.register_events(toinsert);
570 toinsert.append(html);
497 toinsert.append(html);
571 element.append(toinsert);
498 element.append(toinsert);
572 return toinsert;
499 return toinsert;
573 };
500 };
574
501
575
502
576 OutputArea.prototype.append_javascript = function (js, md, element) {
503 OutputArea.prototype.append_javascript = function (js, md, element) {
577 // We just eval the JS code, element appears in the local scope.
504 // We just eval the JS code, element appears in the local scope.
578 var type = 'application/javascript';
505 var type = 'application/javascript';
579 var toinsert = this.create_output_subarea(md, "output_javascript", type);
506 var toinsert = this.create_output_subarea(md, "output_javascript", type);
580 IPython.keyboard_manager.register_events(toinsert);
507 IPython.keyboard_manager.register_events(toinsert);
581 element.append(toinsert);
508 element.append(toinsert);
582 // FIXME TODO : remove `container element for 3.0`
509 // FIXME TODO : remove `container element for 3.0`
583 //backward compat, js should be eval'ed in a context where `container` is defined.
510 //backward compat, js should be eval'ed in a context where `container` is defined.
584 var container = element;
511 var container = element;
585 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
512 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
586 // end backward compat
513 // end backward compat
587 try {
514 try {
588 eval(js);
515 eval(js);
589 } catch(err) {
516 } catch(err) {
590 console.log(err);
517 console.log(err);
591 this._append_javascript_error(err, toinsert);
518 this._append_javascript_error(err, toinsert);
592 }
519 }
593 return toinsert;
520 return toinsert;
594 };
521 };
595
522
596
523
597 OutputArea.prototype.append_text = function (data, md, element, extra_class) {
524 OutputArea.prototype.append_text = function (data, md, element, extra_class) {
598 var type = 'text/plain';
525 var type = 'text/plain';
599 var toinsert = this.create_output_subarea(md, "output_text", type);
526 var toinsert = this.create_output_subarea(md, "output_text", type);
600 // escape ANSI & HTML specials in plaintext:
527 // escape ANSI & HTML specials in plaintext:
601 data = utils.fixConsole(data);
528 data = utils.fixConsole(data);
602 data = utils.fixCarriageReturn(data);
529 data = utils.fixCarriageReturn(data);
603 data = utils.autoLinkUrls(data);
530 data = utils.autoLinkUrls(data);
604 if (extra_class){
531 if (extra_class){
605 toinsert.addClass(extra_class);
532 toinsert.addClass(extra_class);
606 }
533 }
607 toinsert.append($("<pre/>").html(data));
534 toinsert.append($("<pre/>").html(data));
608 element.append(toinsert);
535 element.append(toinsert);
609 return toinsert;
536 return toinsert;
610 };
537 };
611
538
612
539
613 OutputArea.prototype.append_svg = function (svg, md, element) {
540 OutputArea.prototype.append_svg = function (svg, md, element) {
614 var type = 'image/svg+xml';
541 var type = 'image/svg+xml';
615 var toinsert = this.create_output_subarea(md, "output_svg", type);
542 var toinsert = this.create_output_subarea(md, "output_svg", type);
616 toinsert.append(svg);
543 toinsert.append(svg);
617 element.append(toinsert);
544 element.append(toinsert);
618 return toinsert;
545 return toinsert;
619 };
546 };
620
547
621
548
622 OutputArea.prototype._dblclick_to_reset_size = function (img) {
549 OutputArea.prototype._dblclick_to_reset_size = function (img) {
623 // schedule wrapping image in resizable after a delay,
550 // schedule wrapping image in resizable after a delay,
624 // so we don't end up calling resize on a zero-size object
551 // so we don't end up calling resize on a zero-size object
625 var that = this;
552 var that = this;
626 setTimeout(function () {
553 setTimeout(function () {
627 var h0 = img.height();
554 var h0 = img.height();
628 var w0 = img.width();
555 var w0 = img.width();
629 if (!(h0 && w0)) {
556 if (!(h0 && w0)) {
630 // zero size, schedule another timeout
557 // zero size, schedule another timeout
631 that._dblclick_to_reset_size(img);
558 that._dblclick_to_reset_size(img);
632 return;
559 return;
633 }
560 }
634 img.resizable({
561 img.resizable({
635 aspectRatio: true,
562 aspectRatio: true,
636 autoHide: true
563 autoHide: true
637 });
564 });
638 img.dblclick(function () {
565 img.dblclick(function () {
639 // resize wrapper & image together for some reason:
566 // resize wrapper & image together for some reason:
640 img.parent().height(h0);
567 img.parent().height(h0);
641 img.height(h0);
568 img.height(h0);
642 img.parent().width(w0);
569 img.parent().width(w0);
643 img.width(w0);
570 img.width(w0);
644 });
571 });
645 }, 250);
572 }, 250);
646 };
573 };
647
574
648
575
649 OutputArea.prototype.append_png = function (png, md, element) {
576 OutputArea.prototype.append_png = function (png, md, element) {
650 var type = 'image/png';
577 var type = 'image/png';
651 var toinsert = this.create_output_subarea(md, "output_png", type);
578 var toinsert = this.create_output_subarea(md, "output_png", type);
652 var img = $("<img/>");
579 var img = $("<img/>");
653 img[0].setAttribute('src','data:image/png;base64,'+png);
580 img[0].setAttribute('src','data:image/png;base64,'+png);
654 if (md['height']) {
581 if (md['height']) {
655 img[0].setAttribute('height', md['height']);
582 img[0].setAttribute('height', md['height']);
656 }
583 }
657 if (md['width']) {
584 if (md['width']) {
658 img[0].setAttribute('width', md['width']);
585 img[0].setAttribute('width', md['width']);
659 }
586 }
660 this._dblclick_to_reset_size(img);
587 this._dblclick_to_reset_size(img);
661 toinsert.append(img);
588 toinsert.append(img);
662 element.append(toinsert);
589 element.append(toinsert);
663 return toinsert;
590 return toinsert;
664 };
591 };
665
592
666
593
667 OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
594 OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
668 var type = 'image/jpeg';
595 var type = 'image/jpeg';
669 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
596 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
670 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
597 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
671 if (md['height']) {
598 if (md['height']) {
672 img.attr('height', md['height']);
599 img.attr('height', md['height']);
673 }
600 }
674 if (md['width']) {
601 if (md['width']) {
675 img.attr('width', md['width']);
602 img.attr('width', md['width']);
676 }
603 }
677 this._dblclick_to_reset_size(img);
604 this._dblclick_to_reset_size(img);
678 toinsert.append(img);
605 toinsert.append(img);
679 element.append(toinsert);
606 element.append(toinsert);
680 return toinsert;
607 return toinsert;
681 };
608 };
682
609
683
610
684 OutputArea.prototype.append_latex = function (latex, md, element) {
611 OutputArea.prototype.append_latex = function (latex, md, element) {
685 // This method cannot do the typesetting because the latex first has to
612 // This method cannot do the typesetting because the latex first has to
686 // be on the page.
613 // be on the page.
687 var type = 'text/latex';
614 var type = 'text/latex';
688 var toinsert = this.create_output_subarea(md, "output_latex", type);
615 var toinsert = this.create_output_subarea(md, "output_latex", type);
689 toinsert.append(latex);
616 toinsert.append(latex);
690 element.append(toinsert);
617 element.append(toinsert);
691 return toinsert;
618 return toinsert;
692 };
619 };
693
620
694
621
695 OutputArea.prototype.append_raw_input = function (msg) {
622 OutputArea.prototype.append_raw_input = function (msg) {
696 var that = this;
623 var that = this;
697 this.expand();
624 this.expand();
698 var content = msg.content;
625 var content = msg.content;
699 var area = this.create_output_area();
626 var area = this.create_output_area();
700
627
701 // disable any other raw_inputs, if they are left around
628 // disable any other raw_inputs, if they are left around
702 $("div.output_subarea.raw_input").remove();
629 $("div.output_subarea.raw_input").remove();
703
630
704 area.append(
631 area.append(
705 $("<div/>")
632 $("<div/>")
706 .addClass("box-flex1 output_subarea raw_input")
633 .addClass("box-flex1 output_subarea raw_input")
707 .append(
634 .append(
708 $("<span/>")
635 $("<span/>")
709 .addClass("input_prompt")
636 .addClass("input_prompt")
710 .text(content.prompt)
637 .text(content.prompt)
711 )
638 )
712 .append(
639 .append(
713 $("<input/>")
640 $("<input/>")
714 .addClass("raw_input")
641 .addClass("raw_input")
715 .attr('type', 'text')
642 .attr('type', 'text')
716 .attr("size", 47)
643 .attr("size", 47)
717 .keydown(function (event, ui) {
644 .keydown(function (event, ui) {
718 // make sure we submit on enter,
645 // make sure we submit on enter,
719 // and don't re-execute the *cell* on shift-enter
646 // and don't re-execute the *cell* on shift-enter
720 if (event.which === utils.keycodes.ENTER) {
647 if (event.which === utils.keycodes.ENTER) {
721 that._submit_raw_input();
648 that._submit_raw_input();
722 return false;
649 return false;
723 }
650 }
724 })
651 })
725 )
652 )
726 );
653 );
727
654
728 this.element.append(area);
655 this.element.append(area);
729 var raw_input = area.find('input.raw_input');
656 var raw_input = area.find('input.raw_input');
730 // Register events that enable/disable the keyboard manager while raw
657 // Register events that enable/disable the keyboard manager while raw
731 // input is focused.
658 // input is focused.
732 IPython.keyboard_manager.register_events(raw_input);
659 IPython.keyboard_manager.register_events(raw_input);
733 // Note, the following line used to read raw_input.focus().focus().
660 // Note, the following line used to read raw_input.focus().focus().
734 // This seemed to be needed otherwise only the cell would be focused.
661 // This seemed to be needed otherwise only the cell would be focused.
735 // But with the modal UI, this seems to work fine with one call to focus().
662 // But with the modal UI, this seems to work fine with one call to focus().
736 raw_input.focus();
663 raw_input.focus();
737 }
664 }
738
665
739 OutputArea.prototype._submit_raw_input = function (evt) {
666 OutputArea.prototype._submit_raw_input = function (evt) {
740 var container = this.element.find("div.raw_input");
667 var container = this.element.find("div.raw_input");
741 var theprompt = container.find("span.input_prompt");
668 var theprompt = container.find("span.input_prompt");
742 var theinput = container.find("input.raw_input");
669 var theinput = container.find("input.raw_input");
743 var value = theinput.val();
670 var value = theinput.val();
744 var content = {
671 var content = {
745 output_type : 'stream',
672 output_type : 'stream',
746 name : 'stdout',
673 name : 'stdout',
747 text : theprompt.text() + value + '\n'
674 text : theprompt.text() + value + '\n'
748 }
675 }
749 // remove form container
676 // remove form container
750 container.parent().remove();
677 container.parent().remove();
751 // replace with plaintext version in stdout
678 // replace with plaintext version in stdout
752 this.append_output(content, false);
679 this.append_output(content, false);
753 $([IPython.events]).trigger('send_input_reply.Kernel', value);
680 $([IPython.events]).trigger('send_input_reply.Kernel', value);
754 }
681 }
755
682
756
683
757 OutputArea.prototype.handle_clear_output = function (msg) {
684 OutputArea.prototype.handle_clear_output = function (msg) {
758 this.clear_output(msg.content.wait);
685 this.clear_output(msg.content.wait);
759 };
686 };
760
687
761
688
762 OutputArea.prototype.clear_output = function(wait) {
689 OutputArea.prototype.clear_output = function(wait) {
763 if (wait) {
690 if (wait) {
764
691
765 // If a clear is queued, clear before adding another to the queue.
692 // If a clear is queued, clear before adding another to the queue.
766 if (this.clear_queued) {
693 if (this.clear_queued) {
767 this.clear_output(false);
694 this.clear_output(false);
768 };
695 };
769
696
770 this.clear_queued = true;
697 this.clear_queued = true;
771 } else {
698 } else {
772
699
773 // Fix the output div's height if the clear_output is waiting for
700 // Fix the output div's height if the clear_output is waiting for
774 // new output (it is being used in an animation).
701 // new output (it is being used in an animation).
775 if (this.clear_queued) {
702 if (this.clear_queued) {
776 var height = this.element.height();
703 var height = this.element.height();
777 this.element.height(height);
704 this.element.height(height);
778 this.clear_queued = false;
705 this.clear_queued = false;
779 }
706 }
780
707
781 // clear all, no need for logic
708 // clear all, no need for logic
782 this.element.html("");
709 this.element.html("");
783 this.outputs = [];
710 this.outputs = [];
784 this.unscroll_area();
711 this.unscroll_area();
785 return;
712 return;
786 };
713 };
787 };
714 };
788
715
789
716
790 // JSON serialization
717 // JSON serialization
791
718
792 OutputArea.prototype.fromJSON = function (outputs) {
719 OutputArea.prototype.fromJSON = function (outputs) {
793 var len = outputs.length;
720 var len = outputs.length;
794 var data;
721 var data;
795
722
796 // We don't want to display javascript on load, so remove it from the
723 // We don't want to display javascript on load, so remove it from the
797 // display order for the duration of this function call, but be sure to
724 // display order for the duration of this function call, but be sure to
798 // put it back in there so incoming messages that contain javascript
725 // put it back in there so incoming messages that contain javascript
799 // representations get displayed
726 // representations get displayed
800 var js_index = OutputArea.display_order.indexOf('application/javascript');
727 var js_index = OutputArea.display_order.indexOf('application/javascript');
801 OutputArea.display_order.splice(js_index, 1);
728 OutputArea.display_order.splice(js_index, 1);
802
729
803 for (var i=0; i<len; i++) {
730 for (var i=0; i<len; i++) {
804 data = outputs[i];
731 data = outputs[i];
805 var msg_type = data.output_type;
732 var msg_type = data.output_type;
806 if (msg_type === "display_data" || msg_type === "pyout") {
733 if (msg_type === "display_data" || msg_type === "pyout") {
807 // convert short keys to mime keys
734 // convert short keys to mime keys
808 // TODO: remove mapping of short keys when we update to nbformat 4
735 // TODO: remove mapping of short keys when we update to nbformat 4
809 data = this.rename_keys(data, OutputArea.mime_map_r);
736 data = this.rename_keys(data, OutputArea.mime_map_r);
810 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
737 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
811 }
738 }
812
739
813 this.append_output(data);
740 this.append_output(data);
814 }
741 }
815
742
816 // reinsert javascript into display order, see note above
743 // reinsert javascript into display order, see note above
817 OutputArea.display_order.splice(js_index, 0, 'application/javascript');
744 OutputArea.display_order.splice(js_index, 0, 'application/javascript');
818 };
745 };
819
746
820
747
821 OutputArea.prototype.toJSON = function () {
748 OutputArea.prototype.toJSON = function () {
822 var outputs = [];
749 var outputs = [];
823 var len = this.outputs.length;
750 var len = this.outputs.length;
824 var data;
751 var data;
825 for (var i=0; i<len; i++) {
752 for (var i=0; i<len; i++) {
826 data = this.outputs[i];
753 data = this.outputs[i];
827 var msg_type = data.output_type;
754 var msg_type = data.output_type;
828 if (msg_type === "display_data" || msg_type === "pyout") {
755 if (msg_type === "display_data" || msg_type === "pyout") {
829 // convert mime keys to short keys
756 // convert mime keys to short keys
830 data = this.rename_keys(data, OutputArea.mime_map);
757 data = this.rename_keys(data, OutputArea.mime_map);
831 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
758 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
832 }
759 }
833 outputs[i] = data;
760 outputs[i] = data;
834 }
761 }
835 return outputs;
762 return outputs;
836 };
763 };
837
764
765 /**
766 * Class properties
767 **/
768
769 /**
770 * Threshold to trigger autoscroll when the OutputArea is resized,
771 * typically when new outputs are added.
772 *
773 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
774 * unless it is < 0, in which case autoscroll will never be triggered
775 *
776 * @property auto_scroll_threshold
777 * @type Number
778 * @default 100
779 *
780 **/
781 OutputArea.auto_scroll_threshold = 100;
782
783 /**
784 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
785 * shorter than this are never scrolled.
786 *
787 * @property minimum_scroll_threshold
788 * @type Number
789 * @default 20
790 *
791 **/
792 OutputArea.minimum_scroll_threshold = 20;
793
794
795
796 OutputArea.mime_map = {
797 "text/plain" : "text",
798 "text/html" : "html",
799 "image/svg+xml" : "svg",
800 "image/png" : "png",
801 "image/jpeg" : "jpeg",
802 "text/latex" : "latex",
803 "application/json" : "json",
804 "application/javascript" : "javascript",
805 };
806
807 OutputArea.mime_map_r = {
808 "text" : "text/plain",
809 "html" : "text/html",
810 "svg" : "image/svg+xml",
811 "png" : "image/png",
812 "jpeg" : "image/jpeg",
813 "latex" : "text/latex",
814 "json" : "application/json",
815 "javascript" : "application/javascript",
816 };
817
818 OutputArea.display_order = [
819 'application/javascript',
820 'text/html',
821 'text/latex',
822 'image/svg+xml',
823 'image/png',
824 'image/jpeg',
825 'text/plain'
826 ];
827
828 OutputArea.append_map = {
829 "text/plain" : OutputArea.prototype.append_text,
830 "text/html" : OutputArea.prototype.append_html,
831 "image/svg+xml" : OutputArea.prototype.append_svg,
832 "image/png" : OutputArea.prototype.append_png,
833 "image/jpeg" : OutputArea.prototype.append_jpeg,
834 "text/latex" : OutputArea.prototype.append_latex,
835 "application/json" : OutputArea.prototype.append_json,
836 "application/javascript" : OutputArea.prototype.append_javascript,
837 };
838
838
839 IPython.OutputArea = OutputArea;
839 IPython.OutputArea = OutputArea;
840
840
841 return IPython;
841 return IPython;
842
842
843 }(IPython));
843 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now