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