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