##// END OF EJS Templates
support display_pub metadata in js frontend
MinRK -
Show More
@@ -1,606 +1,624 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 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 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var OutputArea = function (selector, prompt_area) {
17 var OutputArea = function (selector, prompt_area) {
18 this.selector = selector;
18 this.selector = selector;
19 this.wrapper = $(selector);
19 this.wrapper = $(selector);
20 this.outputs = [];
20 this.outputs = [];
21 this.collapsed = false;
21 this.collapsed = false;
22 this.scrolled = false;
22 this.scrolled = false;
23 this.clear_out_timeout = null;
23 this.clear_out_timeout = null;
24 if (prompt_area === undefined) {
24 if (prompt_area === undefined) {
25 this.prompt_area = true;
25 this.prompt_area = true;
26 } else {
26 } else {
27 this.prompt_area = prompt_area;
27 this.prompt_area = prompt_area;
28 }
28 }
29 this.create_elements();
29 this.create_elements();
30 this.style();
30 this.style();
31 this.bind_events();
31 this.bind_events();
32 };
32 };
33
33
34 OutputArea.prototype.create_elements = function () {
34 OutputArea.prototype.create_elements = function () {
35 this.element = $("<div/>");
35 this.element = $("<div/>");
36 this.collapse_button = $("<div/>");
36 this.collapse_button = $("<div/>");
37 this.prompt_overlay = $("<div/>");
37 this.prompt_overlay = $("<div/>");
38 this.wrapper.append(this.prompt_overlay);
38 this.wrapper.append(this.prompt_overlay);
39 this.wrapper.append(this.element);
39 this.wrapper.append(this.element);
40 this.wrapper.append(this.collapse_button);
40 this.wrapper.append(this.collapse_button);
41 };
41 };
42
42
43
43
44 OutputArea.prototype.style = function () {
44 OutputArea.prototype.style = function () {
45 this.collapse_button.hide();
45 this.collapse_button.hide();
46 this.prompt_overlay.hide();
46 this.prompt_overlay.hide();
47
47
48 this.wrapper.addClass('output_wrapper');
48 this.wrapper.addClass('output_wrapper');
49 this.element.addClass('output vbox');
49 this.element.addClass('output vbox');
50
50
51 this.collapse_button.button();
51 this.collapse_button.button();
52 this.collapse_button.addClass('output_collapsed vbox');
52 this.collapse_button.addClass('output_collapsed vbox');
53 this.collapse_button.attr('title', 'click to expand output');
53 this.collapse_button.attr('title', 'click to expand output');
54 this.collapse_button.html('. . .');
54 this.collapse_button.html('. . .');
55
55
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
57 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
57 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
58
58
59 this.collapse();
59 this.collapse();
60 };
60 };
61
61
62
62
63 OutputArea.prototype._should_scroll = function (lines) {
63 OutputArea.prototype._should_scroll = function (lines) {
64 if (!lines) {
64 if (!lines) {
65 lines = 100;
65 lines = 100;
66 }
66 }
67 // line-height from http://stackoverflow.com/questions/1185151
67 // line-height from http://stackoverflow.com/questions/1185151
68 var fontSize = this.element.css('font-size');
68 var fontSize = this.element.css('font-size');
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
70
70
71 return (this.element.height() > lines * lineHeight);
71 return (this.element.height() > lines * lineHeight);
72 };
72 };
73
73
74
74
75 OutputArea.prototype.bind_events = function () {
75 OutputArea.prototype.bind_events = function () {
76 var that = this;
76 var that = this;
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
79
79
80 this.element.resize(function () {
80 this.element.resize(function () {
81 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
81 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
82 if ( IPython.utils.browser[0] === "Firefox" ) {
82 if ( IPython.utils.browser[0] === "Firefox" ) {
83 return;
83 return;
84 }
84 }
85 // maybe scroll output,
85 // maybe scroll output,
86 // if it's grown large enough and hasn't already been scrolled.
86 // if it's grown large enough and hasn't already been scrolled.
87 if ( !that.scrolled && that._should_scroll()) {
87 if ( !that.scrolled && that._should_scroll()) {
88 that.scroll_area();
88 that.scroll_area();
89 }
89 }
90 });
90 });
91 this.collapse_button.click(function () {
91 this.collapse_button.click(function () {
92 that.expand();
92 that.expand();
93 });
93 });
94 this.collapse_button.hover(function () {
94 this.collapse_button.hover(function () {
95 $(this).addClass("ui-state-hover");
95 $(this).addClass("ui-state-hover");
96 }, function () {
96 }, function () {
97 $(this).removeClass("ui-state-hover");
97 $(this).removeClass("ui-state-hover");
98 });
98 });
99 };
99 };
100
100
101
101
102 OutputArea.prototype.collapse = function () {
102 OutputArea.prototype.collapse = function () {
103 if (!this.collapsed) {
103 if (!this.collapsed) {
104 this.element.hide();
104 this.element.hide();
105 this.prompt_overlay.hide();
105 this.prompt_overlay.hide();
106 if (this.element.html()){
106 if (this.element.html()){
107 this.collapse_button.show();
107 this.collapse_button.show();
108 }
108 }
109 this.collapsed = true;
109 this.collapsed = true;
110 }
110 }
111 };
111 };
112
112
113
113
114 OutputArea.prototype.expand = function () {
114 OutputArea.prototype.expand = function () {
115 if (this.collapsed) {
115 if (this.collapsed) {
116 this.collapse_button.hide();
116 this.collapse_button.hide();
117 this.element.show();
117 this.element.show();
118 this.prompt_overlay.show();
118 this.prompt_overlay.show();
119 this.collapsed = false;
119 this.collapsed = false;
120 }
120 }
121 };
121 };
122
122
123
123
124 OutputArea.prototype.toggle_output = function () {
124 OutputArea.prototype.toggle_output = function () {
125 if (this.collapsed) {
125 if (this.collapsed) {
126 this.expand();
126 this.expand();
127 } else {
127 } else {
128 this.collapse();
128 this.collapse();
129 }
129 }
130 };
130 };
131
131
132
132
133 OutputArea.prototype.scroll_area = function () {
133 OutputArea.prototype.scroll_area = function () {
134 this.element.addClass('output_scroll');
134 this.element.addClass('output_scroll');
135 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
135 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
136 this.scrolled = true;
136 this.scrolled = true;
137 };
137 };
138
138
139
139
140 OutputArea.prototype.unscroll_area = function () {
140 OutputArea.prototype.unscroll_area = function () {
141 this.element.removeClass('output_scroll');
141 this.element.removeClass('output_scroll');
142 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
142 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
143 this.scrolled = false;
143 this.scrolled = false;
144 };
144 };
145
145
146
146
147 OutputArea.prototype.scroll_if_long = function (lines) {
147 OutputArea.prototype.scroll_if_long = function (lines) {
148 if (this._should_scroll(lines)) {
148 if (this._should_scroll(lines)) {
149 // only allow scrolling long-enough output
149 // only allow scrolling long-enough output
150 this.scroll_area();
150 this.scroll_area();
151 }
151 }
152 };
152 };
153
153
154
154
155 OutputArea.prototype.toggle_scroll = function () {
155 OutputArea.prototype.toggle_scroll = function () {
156 if (this.scrolled) {
156 if (this.scrolled) {
157 this.unscroll_area();
157 this.unscroll_area();
158 } else {
158 } else {
159 // only allow scrolling long-enough output
159 // only allow scrolling long-enough output
160 this.scroll_if_long(20);
160 this.scroll_if_long(20);
161 }
161 }
162 };
162 };
163
163
164
164
165 // typeset with MathJax if MathJax is available
165 // typeset with MathJax if MathJax is available
166 OutputArea.prototype.typeset = function () {
166 OutputArea.prototype.typeset = function () {
167 if (window.MathJax){
167 if (window.MathJax){
168 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
168 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
169 }
169 }
170 };
170 };
171
171
172
172
173 OutputArea.prototype.handle_output = function (msg_type, content) {
173 OutputArea.prototype.handle_output = function (msg_type, content) {
174 var json = {};
174 var json = {};
175 json.output_type = msg_type;
175 json.output_type = msg_type;
176 if (msg_type === "stream") {
176 if (msg_type === "stream") {
177 json.text = content.data;
177 json.text = content.data;
178 json.stream = content.name;
178 json.stream = content.name;
179 } else if (msg_type === "display_data") {
179 } else if (msg_type === "display_data") {
180 json = this.convert_mime_types(json, content.data);
180 json = this.convert_mime_types(json, content.data);
181 json.metadata = this.convert_mime_types({}, content.metadata);
181 } else if (msg_type === "pyout") {
182 } else if (msg_type === "pyout") {
182 json.prompt_number = content.execution_count;
183 json.prompt_number = content.execution_count;
183 json = this.convert_mime_types(json, content.data);
184 json = this.convert_mime_types(json, content.data);
185 json.metadata = this.convert_mime_types({}, content.metadata);
184 } else if (msg_type === "pyerr") {
186 } else if (msg_type === "pyerr") {
185 json.ename = content.ename;
187 json.ename = content.ename;
186 json.evalue = content.evalue;
188 json.evalue = content.evalue;
187 json.traceback = content.traceback;
189 json.traceback = content.traceback;
188 }
190 }
189 // append with dynamic=true
191 // append with dynamic=true
190 this.append_output(json, true);
192 this.append_output(json, true);
191 };
193 };
192
194
193
195
194 OutputArea.prototype.convert_mime_types = function (json, data) {
196 OutputArea.prototype.convert_mime_types = function (json, data) {
195 if (data['text/plain'] !== undefined) {
197 if (data['text/plain'] !== undefined) {
196 json.text = data['text/plain'];
198 json.text = data['text/plain'];
197 }
199 }
198 if (data['text/html'] !== undefined) {
200 if (data['text/html'] !== undefined) {
199 json.html = data['text/html'];
201 json.html = data['text/html'];
200 }
202 }
201 if (data['image/svg+xml'] !== undefined) {
203 if (data['image/svg+xml'] !== undefined) {
202 json.svg = data['image/svg+xml'];
204 json.svg = data['image/svg+xml'];
203 }
205 }
204 if (data['image/png'] !== undefined) {
206 if (data['image/png'] !== undefined) {
205 json.png = data['image/png'];
207 json.png = data['image/png'];
206 }
208 }
207 if (data['image/jpeg'] !== undefined) {
209 if (data['image/jpeg'] !== undefined) {
208 json.jpeg = data['image/jpeg'];
210 json.jpeg = data['image/jpeg'];
209 }
211 }
210 if (data['text/latex'] !== undefined) {
212 if (data['text/latex'] !== undefined) {
211 json.latex = data['text/latex'];
213 json.latex = data['text/latex'];
212 }
214 }
213 if (data['application/json'] !== undefined) {
215 if (data['application/json'] !== undefined) {
214 json.json = data['application/json'];
216 json.json = data['application/json'];
215 }
217 }
216 if (data['application/javascript'] !== undefined) {
218 if (data['application/javascript'] !== undefined) {
217 json.javascript = data['application/javascript'];
219 json.javascript = data['application/javascript'];
218 }
220 }
219 return json;
221 return json;
220 };
222 };
221
223
222
224
223 OutputArea.prototype.append_output = function (json, dynamic) {
225 OutputArea.prototype.append_output = function (json, dynamic) {
224 // If dynamic is true, javascript output will be eval'd.
226 // If dynamic is true, javascript output will be eval'd.
225 this.expand();
227 this.expand();
226 this.flush_clear_timeout();
228 this.flush_clear_timeout();
227 if (json.output_type === 'pyout') {
229 if (json.output_type === 'pyout') {
228 this.append_pyout(json, dynamic);
230 this.append_pyout(json, dynamic);
229 } else if (json.output_type === 'pyerr') {
231 } else if (json.output_type === 'pyerr') {
230 this.append_pyerr(json);
232 this.append_pyerr(json);
231 } else if (json.output_type === 'display_data') {
233 } else if (json.output_type === 'display_data') {
232 this.append_display_data(json, dynamic);
234 this.append_display_data(json, dynamic);
233 } else if (json.output_type === 'stream') {
235 } else if (json.output_type === 'stream') {
234 this.append_stream(json);
236 this.append_stream(json);
235 }
237 }
236 this.outputs.push(json);
238 this.outputs.push(json);
237 var that = this;
239 var that = this;
238 setTimeout(function(){that.element.trigger('resize');}, 100);
240 setTimeout(function(){that.element.trigger('resize');}, 100);
239 };
241 };
240
242
241
243
242 OutputArea.prototype.create_output_area = function () {
244 OutputArea.prototype.create_output_area = function () {
243 var oa = $("<div/>").addClass("output_area");
245 var oa = $("<div/>").addClass("output_area");
244 if (this.prompt_area) {
246 if (this.prompt_area) {
245 oa.append($('<div/>').addClass('prompt'));
247 oa.append($('<div/>').addClass('prompt'));
246 }
248 }
247 return oa;
249 return oa;
248 };
250 };
249
251
250
252
251 OutputArea.prototype.append_pyout = function (json, dynamic) {
253 OutputArea.prototype.append_pyout = function (json, dynamic) {
252 var n = json.prompt_number || ' ';
254 var n = json.prompt_number || ' ';
253 var toinsert = this.create_output_area();
255 var toinsert = this.create_output_area();
254 if (this.prompt_area) {
256 if (this.prompt_area) {
255 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
257 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
256 }
258 }
257 this.append_mime_type(json, toinsert, dynamic);
259 this.append_mime_type(json, toinsert, dynamic);
258 this.element.append(toinsert);
260 this.element.append(toinsert);
259 // If we just output latex, typeset it.
261 // If we just output latex, typeset it.
260 if ((json.latex !== undefined) || (json.html !== undefined)) {
262 if ((json.latex !== undefined) || (json.html !== undefined)) {
261 this.typeset();
263 this.typeset();
262 }
264 }
263 };
265 };
264
266
265
267
266 OutputArea.prototype.append_pyerr = function (json) {
268 OutputArea.prototype.append_pyerr = function (json) {
267 var tb = json.traceback;
269 var tb = json.traceback;
268 if (tb !== undefined && tb.length > 0) {
270 if (tb !== undefined && tb.length > 0) {
269 var s = '';
271 var s = '';
270 var len = tb.length;
272 var len = tb.length;
271 for (var i=0; i<len; i++) {
273 for (var i=0; i<len; i++) {
272 s = s + tb[i] + '\n';
274 s = s + tb[i] + '\n';
273 }
275 }
274 s = s + '\n';
276 s = s + '\n';
275 var toinsert = this.create_output_area();
277 var toinsert = this.create_output_area();
276 this.append_text(s, toinsert);
278 this.append_text(s, {}, toinsert);
277 this.element.append(toinsert);
279 this.element.append(toinsert);
278 }
280 }
279 };
281 };
280
282
281
283
282 OutputArea.prototype.append_stream = function (json) {
284 OutputArea.prototype.append_stream = function (json) {
283 // temporary fix: if stream undefined (json file written prior to this patch),
285 // temporary fix: if stream undefined (json file written prior to this patch),
284 // default to most likely stdout:
286 // default to most likely stdout:
285 if (json.stream == undefined){
287 if (json.stream == undefined){
286 json.stream = 'stdout';
288 json.stream = 'stdout';
287 }
289 }
288 var text = json.text;
290 var text = json.text;
289 var subclass = "output_"+json.stream;
291 var subclass = "output_"+json.stream;
290 if (this.outputs.length > 0){
292 if (this.outputs.length > 0){
291 // have at least one output to consider
293 // have at least one output to consider
292 var last = this.outputs[this.outputs.length-1];
294 var last = this.outputs[this.outputs.length-1];
293 if (last.output_type == 'stream' && json.stream == last.stream){
295 if (last.output_type == 'stream' && json.stream == last.stream){
294 // latest output was in the same stream,
296 // latest output was in the same stream,
295 // so append directly into its pre tag
297 // so append directly into its pre tag
296 // escape ANSI & HTML specials:
298 // escape ANSI & HTML specials:
297 var pre = this.element.find('div.'+subclass).last().find('pre');
299 var pre = this.element.find('div.'+subclass).last().find('pre');
298 var html = utils.fixCarriageReturn(
300 var html = utils.fixCarriageReturn(
299 pre.html() + utils.fixConsole(text));
301 pre.html() + utils.fixConsole(text));
300 pre.html(html);
302 pre.html(html);
301 return;
303 return;
302 }
304 }
303 }
305 }
304
306
305 if (!text.replace("\r", "")) {
307 if (!text.replace("\r", "")) {
306 // text is nothing (empty string, \r, etc.)
308 // text is nothing (empty string, \r, etc.)
307 // so don't append any elements, which might add undesirable space
309 // so don't append any elements, which might add undesirable space
308 return;
310 return;
309 }
311 }
310
312
311 // If we got here, attach a new div
313 // If we got here, attach a new div
312 var toinsert = this.create_output_area();
314 var toinsert = this.create_output_area();
313 this.append_text(text, toinsert, "output_stream "+subclass);
315 this.append_text(text, {}, toinsert, "output_stream "+subclass);
314 this.element.append(toinsert);
316 this.element.append(toinsert);
315 };
317 };
316
318
317
319
318 OutputArea.prototype.append_display_data = function (json, dynamic) {
320 OutputArea.prototype.append_display_data = function (json, dynamic) {
319 var toinsert = this.create_output_area();
321 var toinsert = this.create_output_area();
320 this.append_mime_type(json, toinsert, dynamic);
322 this.append_mime_type(json, toinsert, dynamic);
321 this.element.append(toinsert);
323 this.element.append(toinsert);
322 // If we just output latex, typeset it.
324 // If we just output latex, typeset it.
323 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
325 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
324 this.typeset();
326 this.typeset();
325 }
327 }
326 };
328 };
327
329
328 OutputArea.display_order = ['javascript','html','latex','svg','png','jpeg','text'];
330 OutputArea.display_order = ['javascript','html','latex','svg','png','jpeg','text'];
329
331
330 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
332 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
331 for(var type_i in OutputArea.display_order){
333 for(var type_i in OutputArea.display_order){
332 var type = OutputArea.display_order[type_i];
334 var type = OutputArea.display_order[type_i];
333 if(json[type] != undefined ){
335 if(json[type] != undefined ){
336 var md = {};
337 if (json.metadata && json.metadata[type]) {
338 md = json.metadata[type];
339 };
334 if(type == 'javascript'){
340 if(type == 'javascript'){
335 if (dynamic) {
341 if (dynamic) {
336 this.append_javascript(json.javascript, element, dynamic);
342 this.append_javascript(json.javascript, md, element, dynamic);
337 }
343 }
338 } else {
344 } else {
339 this['append_'+type](json[type], element);
345 this['append_'+type](json[type], md, element);
340 }
346 }
341 return;
347 return;
342 }
348 }
343 }
349 }
344 };
350 };
345
351
346
352
347 OutputArea.prototype.append_html = function (html, element) {
353 OutputArea.prototype.append_html = function (html, md, element) {
348 var toinsert = $("<div/>").addClass("output_subarea output_html rendered_html");
354 var toinsert = $("<div/>").addClass("output_subarea output_html rendered_html");
349 toinsert.append(html);
355 toinsert.append(html);
350 element.append(toinsert);
356 element.append(toinsert);
351 };
357 };
352
358
353
359
354 OutputArea.prototype.append_javascript = function (js, container) {
360 OutputArea.prototype.append_javascript = function (js, md, container) {
355 // We just eval the JS code, element appears in the local scope.
361 // We just eval the JS code, element appears in the local scope.
356 var element = $("<div/>").addClass("output_subarea");
362 var element = $("<div/>").addClass("output_subarea");
357 container.append(element);
363 container.append(element);
358 // Div for js shouldn't be drawn, as it will add empty height to the area.
364 // Div for js shouldn't be drawn, as it will add empty height to the area.
359 container.hide();
365 container.hide();
360 // If the Javascript appends content to `element` that should be drawn, then
366 // If the Javascript appends content to `element` that should be drawn, then
361 // it must also call `container.show()`.
367 // it must also call `container.show()`.
362 try {
368 try {
363 eval(js);
369 eval(js);
364 } catch(err) {
370 } catch(err) {
365 console.log('Error in Javascript!');
371 console.log('Error in Javascript!');
366 console.log(err);
372 console.log(err);
367 container.show();
373 container.show();
368 element.append($('<div/>')
374 element.append($('<div/>')
369 .html("Error in Javascript !<br/>"+
375 .html("Error in Javascript !<br/>"+
370 err.toString()+
376 err.toString()+
371 '<br/>See your browser Javascript console for more details.')
377 '<br/>See your browser Javascript console for more details.')
372 .addClass('js-error')
378 .addClass('js-error')
373 );
379 );
374 }
380 }
375 };
381 };
376
382
377
383
378 OutputArea.prototype.append_text = function (data, element, extra_class) {
384 OutputArea.prototype.append_text = function (data, md, element, extra_class) {
379 var toinsert = $("<div/>").addClass("output_subarea output_text");
385 var toinsert = $("<div/>").addClass("output_subarea output_text");
380 // escape ANSI & HTML specials in plaintext:
386 // escape ANSI & HTML specials in plaintext:
381 data = utils.fixConsole(data);
387 data = utils.fixConsole(data);
382 data = utils.fixCarriageReturn(data);
388 data = utils.fixCarriageReturn(data);
383 data = utils.autoLinkUrls(data);
389 data = utils.autoLinkUrls(data);
384 if (extra_class){
390 if (extra_class){
385 toinsert.addClass(extra_class);
391 toinsert.addClass(extra_class);
386 }
392 }
387 toinsert.append($("<pre/>").html(data));
393 toinsert.append($("<pre/>").html(data));
388 element.append(toinsert);
394 element.append(toinsert);
389 };
395 };
390
396
391
397
392 OutputArea.prototype.append_svg = function (svg, element) {
398 OutputArea.prototype.append_svg = function (svg, md, element) {
393 var toinsert = $("<div/>").addClass("output_subarea output_svg");
399 var toinsert = $("<div/>").addClass("output_subarea output_svg");
394 toinsert.append(svg);
400 toinsert.append(svg);
395 element.append(toinsert);
401 element.append(toinsert);
396 };
402 };
397
403
398
404
399 OutputArea.prototype._dblclick_to_reset_size = function (img) {
405 OutputArea.prototype._dblclick_to_reset_size = function (img) {
400 // schedule wrapping image in resizable after a delay,
406 // schedule wrapping image in resizable after a delay,
401 // so we don't end up calling resize on a zero-size object
407 // so we don't end up calling resize on a zero-size object
402 var that = this;
408 var that = this;
403 setTimeout(function () {
409 setTimeout(function () {
404 var h0 = img.height();
410 var h0 = img.height();
405 var w0 = img.width();
411 var w0 = img.width();
406 if (!(h0 && w0)) {
412 if (!(h0 && w0)) {
407 // zero size, schedule another timeout
413 // zero size, schedule another timeout
408 that._dblclick_to_reset_size(img);
414 that._dblclick_to_reset_size(img);
409 return;
415 return;
410 }
416 }
411 img.resizable({
417 img.resizable({
412 aspectRatio: true,
418 aspectRatio: true,
413 autoHide: true
419 autoHide: true
414 });
420 });
415 img.dblclick(function () {
421 img.dblclick(function () {
416 // resize wrapper & image together for some reason:
422 // resize wrapper & image together for some reason:
417 img.parent().height(h0);
423 img.parent().height(h0);
418 img.height(h0);
424 img.height(h0);
419 img.parent().width(w0);
425 img.parent().width(w0);
420 img.width(w0);
426 img.width(w0);
421 });
427 });
422 }, 250);
428 }, 250);
423 };
429 };
424
430
425
431
426 OutputArea.prototype.append_png = function (png, element) {
432 OutputArea.prototype.append_png = function (png, md, element) {
427 var toinsert = $("<div/>").addClass("output_subarea output_png");
433 var toinsert = $("<div/>").addClass("output_subarea output_png");
428 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
434 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
435 if (md['height']) {
436 img.attr('height', md['height']);
437 }
438 if (md['width']) {
439 img.attr('width', md['width']);
440 }
429 this._dblclick_to_reset_size(img);
441 this._dblclick_to_reset_size(img);
430 toinsert.append(img);
442 toinsert.append(img);
431 element.append(toinsert);
443 element.append(toinsert);
432 };
444 };
433
445
434
446
435 OutputArea.prototype.append_jpeg = function (jpeg, element) {
447 OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
436 var toinsert = $("<div/>").addClass("output_subarea output_jpeg");
448 var toinsert = $("<div/>").addClass("output_subarea output_jpeg");
437 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
449 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
450 if (md['height']) {
451 img.attr('height', md['height']);
452 }
453 if (md['width']) {
454 img.attr('width', md['width']);
455 }
438 this._dblclick_to_reset_size(img);
456 this._dblclick_to_reset_size(img);
439 toinsert.append(img);
457 toinsert.append(img);
440 element.append(toinsert);
458 element.append(toinsert);
441 };
459 };
442
460
443
461
444 OutputArea.prototype.append_latex = function (latex, element) {
462 OutputArea.prototype.append_latex = function (latex, md, element) {
445 // This method cannot do the typesetting because the latex first has to
463 // This method cannot do the typesetting because the latex first has to
446 // be on the page.
464 // be on the page.
447 var toinsert = $("<div/>").addClass("output_subarea output_latex");
465 var toinsert = $("<div/>").addClass("output_subarea output_latex");
448 toinsert.append(latex);
466 toinsert.append(latex);
449 element.append(toinsert);
467 element.append(toinsert);
450 };
468 };
451
469
452 OutputArea.prototype.append_raw_input = function (content) {
470 OutputArea.prototype.append_raw_input = function (content) {
453 var that = this;
471 var that = this;
454 this.expand();
472 this.expand();
455 this.flush_clear_timeout();
473 this.flush_clear_timeout();
456 var area = this.create_output_area();
474 var area = this.create_output_area();
457
475
458 area.append(
476 area.append(
459 $("<div/>")
477 $("<div/>")
460 .addClass("box-flex1 output_subarea raw_input")
478 .addClass("box-flex1 output_subarea raw_input")
461 .append(
479 .append(
462 $("<span/>")
480 $("<span/>")
463 .addClass("input_prompt")
481 .addClass("input_prompt")
464 .text(content.prompt)
482 .text(content.prompt)
465 )
483 )
466 .append(
484 .append(
467 $("<input/>")
485 $("<input/>")
468 .addClass("raw_input")
486 .addClass("raw_input")
469 .attr('type', 'text')
487 .attr('type', 'text')
470 .attr("size", 80)
488 .attr("size", 80)
471 .keydown(function (event, ui) {
489 .keydown(function (event, ui) {
472 // make sure we submit on enter,
490 // make sure we submit on enter,
473 // and don't re-execute the *cell* on shift-enter
491 // and don't re-execute the *cell* on shift-enter
474 if (event.which === utils.keycodes.ENTER) {
492 if (event.which === utils.keycodes.ENTER) {
475 that._submit_raw_input();
493 that._submit_raw_input();
476 return false;
494 return false;
477 }
495 }
478 })
496 })
479 )
497 )
480 );
498 );
481 this.element.append(area);
499 this.element.append(area);
482 area.find("input.raw_input").focus();
500 area.find("input.raw_input").focus();
483 }
501 }
484 OutputArea.prototype._submit_raw_input = function (evt) {
502 OutputArea.prototype._submit_raw_input = function (evt) {
485 var container = this.element.find("div.raw_input");
503 var container = this.element.find("div.raw_input");
486 var theprompt = container.find("span.input_prompt");
504 var theprompt = container.find("span.input_prompt");
487 var theinput = container.find("input.raw_input");
505 var theinput = container.find("input.raw_input");
488 var value = theinput.attr("value");
506 var value = theinput.attr("value");
489 var content = {
507 var content = {
490 output_type : 'stream',
508 output_type : 'stream',
491 name : 'stdout',
509 name : 'stdout',
492 text : theprompt.text() + value + '\n'
510 text : theprompt.text() + value + '\n'
493 }
511 }
494 // remove form container
512 // remove form container
495 container.parent().remove();
513 container.parent().remove();
496 // replace with plaintext version in stdout
514 // replace with plaintext version in stdout
497 this.append_output(content, false);
515 this.append_output(content, false);
498 $([IPython.events]).trigger('send_input_reply.Kernel', value);
516 $([IPython.events]).trigger('send_input_reply.Kernel', value);
499 }
517 }
500
518
501
519
502 OutputArea.prototype.handle_clear_output = function (content) {
520 OutputArea.prototype.handle_clear_output = function (content) {
503 this.clear_output(content.stdout, content.stderr, content.other);
521 this.clear_output(content.stdout, content.stderr, content.other);
504 };
522 };
505
523
506
524
507 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
525 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
508 var that = this;
526 var that = this;
509 if (this.clear_out_timeout != null){
527 if (this.clear_out_timeout != null){
510 // fire previous pending clear *immediately*
528 // fire previous pending clear *immediately*
511 clearTimeout(this.clear_out_timeout);
529 clearTimeout(this.clear_out_timeout);
512 this.clear_out_timeout = null;
530 this.clear_out_timeout = null;
513 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
531 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
514 }
532 }
515 // store flags for flushing the timeout
533 // store flags for flushing the timeout
516 this._clear_stdout = stdout;
534 this._clear_stdout = stdout;
517 this._clear_stderr = stderr;
535 this._clear_stderr = stderr;
518 this._clear_other = other;
536 this._clear_other = other;
519 this.clear_out_timeout = setTimeout(function() {
537 this.clear_out_timeout = setTimeout(function() {
520 // really clear timeout only after a short delay
538 // really clear timeout only after a short delay
521 // this reduces flicker in 'clear_output; print' cases
539 // this reduces flicker in 'clear_output; print' cases
522 that.clear_out_timeout = null;
540 that.clear_out_timeout = null;
523 that._clear_stdout = that._clear_stderr = that._clear_other = null;
541 that._clear_stdout = that._clear_stderr = that._clear_other = null;
524 that.clear_output_callback(stdout, stderr, other);
542 that.clear_output_callback(stdout, stderr, other);
525 }, 500
543 }, 500
526 );
544 );
527 };
545 };
528
546
529
547
530 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
548 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
531 var output_div = this.element;
549 var output_div = this.element;
532
550
533 if (stdout && stderr && other){
551 if (stdout && stderr && other){
534 // clear all, no need for logic
552 // clear all, no need for logic
535 output_div.html("");
553 output_div.html("");
536 this.outputs = [];
554 this.outputs = [];
537 this.unscroll_area();
555 this.unscroll_area();
538 return;
556 return;
539 }
557 }
540 // remove html output
558 // remove html output
541 // each output_subarea that has an identifying class is in an output_area
559 // each output_subarea that has an identifying class is in an output_area
542 // which is the element to be removed.
560 // which is the element to be removed.
543 if (stdout) {
561 if (stdout) {
544 output_div.find("div.output_stdout").parent().remove();
562 output_div.find("div.output_stdout").parent().remove();
545 }
563 }
546 if (stderr) {
564 if (stderr) {
547 output_div.find("div.output_stderr").parent().remove();
565 output_div.find("div.output_stderr").parent().remove();
548 }
566 }
549 if (other) {
567 if (other) {
550 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
568 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
551 }
569 }
552 this.unscroll_area();
570 this.unscroll_area();
553
571
554 // remove cleared outputs from JSON list:
572 // remove cleared outputs from JSON list:
555 for (var i = this.outputs.length - 1; i >= 0; i--) {
573 for (var i = this.outputs.length - 1; i >= 0; i--) {
556 var out = this.outputs[i];
574 var out = this.outputs[i];
557 var output_type = out.output_type;
575 var output_type = out.output_type;
558 if (output_type == "display_data" && other) {
576 if (output_type == "display_data" && other) {
559 this.outputs.splice(i,1);
577 this.outputs.splice(i,1);
560 } else if (output_type == "stream") {
578 } else if (output_type == "stream") {
561 if (stdout && out.stream == "stdout") {
579 if (stdout && out.stream == "stdout") {
562 this.outputs.splice(i,1);
580 this.outputs.splice(i,1);
563 } else if (stderr && out.stream == "stderr") {
581 } else if (stderr && out.stream == "stderr") {
564 this.outputs.splice(i,1);
582 this.outputs.splice(i,1);
565 }
583 }
566 }
584 }
567 }
585 }
568 };
586 };
569
587
570
588
571 OutputArea.prototype.flush_clear_timeout = function() {
589 OutputArea.prototype.flush_clear_timeout = function() {
572 var output_div = this.element;
590 var output_div = this.element;
573 if (this.clear_out_timeout){
591 if (this.clear_out_timeout){
574 clearTimeout(this.clear_out_timeout);
592 clearTimeout(this.clear_out_timeout);
575 this.clear_out_timeout = null;
593 this.clear_out_timeout = null;
576 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
594 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
577 }
595 }
578 };
596 };
579
597
580
598
581 // JSON serialization
599 // JSON serialization
582
600
583 OutputArea.prototype.fromJSON = function (outputs) {
601 OutputArea.prototype.fromJSON = function (outputs) {
584 var len = outputs.length;
602 var len = outputs.length;
585 for (var i=0; i<len; i++) {
603 for (var i=0; i<len; i++) {
586 // append with dynamic=false.
604 // append with dynamic=false.
587 this.append_output(outputs[i], false);
605 this.append_output(outputs[i], false);
588 }
606 }
589 };
607 };
590
608
591
609
592 OutputArea.prototype.toJSON = function () {
610 OutputArea.prototype.toJSON = function () {
593 var outputs = [];
611 var outputs = [];
594 var len = this.outputs.length;
612 var len = this.outputs.length;
595 for (var i=0; i<len; i++) {
613 for (var i=0; i<len; i++) {
596 outputs[i] = this.outputs[i];
614 outputs[i] = this.outputs[i];
597 }
615 }
598 return outputs;
616 return outputs;
599 };
617 };
600
618
601
619
602 IPython.OutputArea = OutputArea;
620 IPython.OutputArea = OutputArea;
603
621
604 return IPython;
622 return IPython;
605
623
606 }(IPython));
624 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now