##// END OF EJS Templates
Pop output now removes a specific output
Jonathan Frederic -
Show More
@@ -1,570 +1,573
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3 /**
3 /**
4 *
4 *
5 *
5 *
6 * @module codecell
6 * @module codecell
7 * @namespace codecell
7 * @namespace codecell
8 * @class CodeCell
8 * @class CodeCell
9 */
9 */
10
10
11
11
12 define([
12 define([
13 'base/js/namespace',
13 'base/js/namespace',
14 'jquery',
14 'jquery',
15 'base/js/utils',
15 'base/js/utils',
16 'base/js/keyboard',
16 'base/js/keyboard',
17 'notebook/js/cell',
17 'notebook/js/cell',
18 'notebook/js/outputarea',
18 'notebook/js/outputarea',
19 'notebook/js/completer',
19 'notebook/js/completer',
20 'notebook/js/celltoolbar',
20 'notebook/js/celltoolbar',
21 'codemirror/lib/codemirror',
21 'codemirror/lib/codemirror',
22 'codemirror/mode/python/python',
22 'codemirror/mode/python/python',
23 'notebook/js/codemirror-ipython'
23 'notebook/js/codemirror-ipython'
24 ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) {
24 ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) {
25 "use strict";
25 "use strict";
26
26
27 var Cell = cell.Cell;
27 var Cell = cell.Cell;
28
28
29 /* local util for codemirror */
29 /* local util for codemirror */
30 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
30 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
31
31
32 /**
32 /**
33 *
33 *
34 * function to delete until previous non blanking space character
34 * function to delete until previous non blanking space character
35 * or first multiple of 4 tabstop.
35 * or first multiple of 4 tabstop.
36 * @private
36 * @private
37 */
37 */
38 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
38 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
39 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
39 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
40 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
40 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
41 var cur = cm.getCursor(), line = cm.getLine(cur.line);
41 var cur = cm.getCursor(), line = cm.getLine(cur.line);
42 var tabsize = cm.getOption('tabSize');
42 var tabsize = cm.getOption('tabSize');
43 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
43 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
44 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
44 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
45 var select = cm.getRange(from,cur);
45 var select = cm.getRange(from,cur);
46 if( select.match(/^\ +$/) !== null){
46 if( select.match(/^\ +$/) !== null){
47 cm.replaceRange("",from,cur);
47 cm.replaceRange("",from,cur);
48 } else {
48 } else {
49 cm.deleteH(-1,"char");
49 cm.deleteH(-1,"char");
50 }
50 }
51 };
51 };
52
52
53 var keycodes = keyboard.keycodes;
53 var keycodes = keyboard.keycodes;
54
54
55 var CodeCell = function (kernel, options) {
55 var CodeCell = function (kernel, options) {
56 // Constructor
56 // Constructor
57 //
57 //
58 // A Cell conceived to write code.
58 // A Cell conceived to write code.
59 //
59 //
60 // Parameters:
60 // Parameters:
61 // kernel: Kernel instance
61 // kernel: Kernel instance
62 // The kernel doesn't have to be set at creation time, in that case
62 // The kernel doesn't have to be set at creation time, in that case
63 // it will be null and set_kernel has to be called later.
63 // it will be null and set_kernel has to be called later.
64 // options: dictionary
64 // options: dictionary
65 // Dictionary of keyword arguments.
65 // Dictionary of keyword arguments.
66 // events: $(Events) instance
66 // events: $(Events) instance
67 // config: dictionary
67 // config: dictionary
68 // keyboard_manager: KeyboardManager instance
68 // keyboard_manager: KeyboardManager instance
69 // notebook: Notebook instance
69 // notebook: Notebook instance
70 // tooltip: Tooltip instance
70 // tooltip: Tooltip instance
71 this.kernel = kernel || null;
71 this.kernel = kernel || null;
72 this.notebook = options.notebook;
72 this.notebook = options.notebook;
73 this.collapsed = false;
73 this.collapsed = false;
74 this.events = options.events;
74 this.events = options.events;
75 this.tooltip = options.tooltip;
75 this.tooltip = options.tooltip;
76 this.config = options.config;
76 this.config = options.config;
77
77
78 // create all attributed in constructor function
78 // create all attributed in constructor function
79 // even if null for V8 VM optimisation
79 // even if null for V8 VM optimisation
80 this.input_prompt_number = null;
80 this.input_prompt_number = null;
81 this.celltoolbar = null;
81 this.celltoolbar = null;
82 this.output_area = null;
82 this.output_area = null;
83 // Keep a stack of the 'active' output areas (where active means the
83 // Keep a stack of the 'active' output areas (where active means the
84 // output area that recieves output). When a user activates an output
84 // output area that recieves output). When a user activates an output
85 // area, it gets pushed to the stack. Then, when the output area is
85 // area, it gets pushed to the stack. Then, when the output area is
86 // deactivated, it's popped from the stack. When the stack is empty,
86 // deactivated, it's popped from the stack. When the stack is empty,
87 // the cell's output area is used.
87 // the cell's output area is used.
88 this.active_output_area = [];
88 this.active_output_area = [];
89 this.last_msg_id = null;
89 this.last_msg_id = null;
90 this.completer = null;
90 this.completer = null;
91
91
92
92
93 var config = utils.mergeopt(CodeCell, this.config);
93 var config = utils.mergeopt(CodeCell, this.config);
94 Cell.apply(this,[{
94 Cell.apply(this,[{
95 config: config,
95 config: config,
96 keyboard_manager: options.keyboard_manager,
96 keyboard_manager: options.keyboard_manager,
97 events: this.events}]);
97 events: this.events}]);
98
98
99 // Attributes we want to override in this subclass.
99 // Attributes we want to override in this subclass.
100 this.cell_type = "code";
100 this.cell_type = "code";
101
101
102 var that = this;
102 var that = this;
103 this.element.focusout(
103 this.element.focusout(
104 function() { that.auto_highlight(); }
104 function() { that.auto_highlight(); }
105 );
105 );
106 };
106 };
107
107
108 CodeCell.options_default = {
108 CodeCell.options_default = {
109 cm_config : {
109 cm_config : {
110 extraKeys: {
110 extraKeys: {
111 "Tab" : "indentMore",
111 "Tab" : "indentMore",
112 "Shift-Tab" : "indentLess",
112 "Shift-Tab" : "indentLess",
113 "Backspace" : "delSpaceToPrevTabStop",
113 "Backspace" : "delSpaceToPrevTabStop",
114 "Cmd-/" : "toggleComment",
114 "Cmd-/" : "toggleComment",
115 "Ctrl-/" : "toggleComment"
115 "Ctrl-/" : "toggleComment"
116 },
116 },
117 mode: 'ipython',
117 mode: 'ipython',
118 theme: 'ipython',
118 theme: 'ipython',
119 matchBrackets: true
119 matchBrackets: true
120 }
120 }
121 };
121 };
122
122
123 CodeCell.msg_cells = {};
123 CodeCell.msg_cells = {};
124
124
125 CodeCell.prototype = Object.create(Cell.prototype);
125 CodeCell.prototype = Object.create(Cell.prototype);
126
126
127 /**
127 /**
128 * @method get_output_area
128 * @method get_output_area
129 */
129 */
130 CodeCell.prototype.get_output_area = function () {
130 CodeCell.prototype.get_output_area = function () {
131 if (this.active_output_area && this.active_output_area.length > 0) {
131 if (this.active_output_area && this.active_output_area.length > 0) {
132 return this.active_output_area[this.active_output_area.length-1];
132 return this.active_output_area[this.active_output_area.length-1];
133 } else {
133 } else {
134 return this.output_area;
134 return this.output_area;
135 }
135 }
136 };
136 };
137
137
138 /**
138 /**
139 * @method push_output_area
139 * @method push_output_area
140 */
140 */
141 CodeCell.prototype.push_output_area = function (output_area) {
141 CodeCell.prototype.push_output_area = function (output_area) {
142 this.active_output_area.push(output_area);
142 this.active_output_area.push(output_area);
143 };
143 };
144
144
145 /**
145 /**
146 * @method pop_output_area
146 * @method pop_output_area
147 */
147 */
148 CodeCell.prototype.pop_output_area = function () {
148 CodeCell.prototype.pop_output_area = function (output_area) {
149 this.active_output_area.pop();
149 var index = this.active_output_area.lastIndexOf(output_area);
150 if (index > -1) {
151 this.active_output_area.splice(index, 1);
152 }
150 };
153 };
151
154
152 /**
155 /**
153 * @method auto_highlight
156 * @method auto_highlight
154 */
157 */
155 CodeCell.prototype.auto_highlight = function () {
158 CodeCell.prototype.auto_highlight = function () {
156 this._auto_highlight(this.config.cell_magic_highlight);
159 this._auto_highlight(this.config.cell_magic_highlight);
157 };
160 };
158
161
159 /** @method create_element */
162 /** @method create_element */
160 CodeCell.prototype.create_element = function () {
163 CodeCell.prototype.create_element = function () {
161 Cell.prototype.create_element.apply(this, arguments);
164 Cell.prototype.create_element.apply(this, arguments);
162
165
163 var cell = $('<div></div>').addClass('cell code_cell');
166 var cell = $('<div></div>').addClass('cell code_cell');
164 cell.attr('tabindex','2');
167 cell.attr('tabindex','2');
165
168
166 var input = $('<div></div>').addClass('input');
169 var input = $('<div></div>').addClass('input');
167 var prompt = $('<div/>').addClass('prompt input_prompt');
170 var prompt = $('<div/>').addClass('prompt input_prompt');
168 var inner_cell = $('<div/>').addClass('inner_cell');
171 var inner_cell = $('<div/>').addClass('inner_cell');
169 this.celltoolbar = new celltoolbar.CellToolbar({
172 this.celltoolbar = new celltoolbar.CellToolbar({
170 cell: this,
173 cell: this,
171 notebook: this.notebook});
174 notebook: this.notebook});
172 inner_cell.append(this.celltoolbar.element);
175 inner_cell.append(this.celltoolbar.element);
173 var input_area = $('<div/>').addClass('input_area');
176 var input_area = $('<div/>').addClass('input_area');
174 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
177 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
175 this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this))
178 this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this))
176 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
179 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
177 inner_cell.append(input_area);
180 inner_cell.append(input_area);
178 input.append(prompt).append(inner_cell);
181 input.append(prompt).append(inner_cell);
179
182
180 var widget_area = $('<div/>')
183 var widget_area = $('<div/>')
181 .addClass('widget-area')
184 .addClass('widget-area')
182 .hide();
185 .hide();
183 this.widget_area = widget_area;
186 this.widget_area = widget_area;
184 var widget_prompt = $('<div/>')
187 var widget_prompt = $('<div/>')
185 .addClass('prompt')
188 .addClass('prompt')
186 .appendTo(widget_area);
189 .appendTo(widget_area);
187 var widget_subarea = $('<div/>')
190 var widget_subarea = $('<div/>')
188 .addClass('widget-subarea')
191 .addClass('widget-subarea')
189 .appendTo(widget_area);
192 .appendTo(widget_area);
190 this.widget_subarea = widget_subarea;
193 this.widget_subarea = widget_subarea;
191 var widget_clear_buton = $('<button />')
194 var widget_clear_buton = $('<button />')
192 .addClass('close')
195 .addClass('close')
193 .html('&times;')
196 .html('&times;')
194 .click(function() {
197 .click(function() {
195 widget_area.slideUp('', function(){ widget_subarea.html(''); });
198 widget_area.slideUp('', function(){ widget_subarea.html(''); });
196 })
199 })
197 .appendTo(widget_prompt);
200 .appendTo(widget_prompt);
198
201
199 var output = $('<div></div>');
202 var output = $('<div></div>');
200 cell.append(input).append(widget_area).append(output);
203 cell.append(input).append(widget_area).append(output);
201 this.element = cell;
204 this.element = cell;
202 this.output_area = new outputarea.OutputArea({
205 this.output_area = new outputarea.OutputArea({
203 selector: output,
206 selector: output,
204 prompt_area: true,
207 prompt_area: true,
205 events: this.events,
208 events: this.events,
206 keyboard_manager: this.keyboard_manager});
209 keyboard_manager: this.keyboard_manager});
207 this.completer = new completer.Completer(this, this.events);
210 this.completer = new completer.Completer(this, this.events);
208 };
211 };
209
212
210 /** @method bind_events */
213 /** @method bind_events */
211 CodeCell.prototype.bind_events = function () {
214 CodeCell.prototype.bind_events = function () {
212 Cell.prototype.bind_events.apply(this);
215 Cell.prototype.bind_events.apply(this);
213 var that = this;
216 var that = this;
214
217
215 this.element.focusout(
218 this.element.focusout(
216 function() { that.auto_highlight(); }
219 function() { that.auto_highlight(); }
217 );
220 );
218 };
221 };
219
222
220
223
221 /**
224 /**
222 * This method gets called in CodeMirror's onKeyDown/onKeyPress
225 * This method gets called in CodeMirror's onKeyDown/onKeyPress
223 * handlers and is used to provide custom key handling. Its return
226 * handlers and is used to provide custom key handling. Its return
224 * value is used to determine if CodeMirror should ignore the event:
227 * value is used to determine if CodeMirror should ignore the event:
225 * true = ignore, false = don't ignore.
228 * true = ignore, false = don't ignore.
226 * @method handle_codemirror_keyevent
229 * @method handle_codemirror_keyevent
227 */
230 */
228 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
231 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
229
232
230 var that = this;
233 var that = this;
231 // whatever key is pressed, first, cancel the tooltip request before
234 // whatever key is pressed, first, cancel the tooltip request before
232 // they are sent, and remove tooltip if any, except for tab again
235 // they are sent, and remove tooltip if any, except for tab again
233 var tooltip_closed = null;
236 var tooltip_closed = null;
234 if (event.type === 'keydown' && event.which != keycodes.tab ) {
237 if (event.type === 'keydown' && event.which != keycodes.tab ) {
235 tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
238 tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
236 }
239 }
237
240
238 var cur = editor.getCursor();
241 var cur = editor.getCursor();
239 if (event.keyCode === keycodes.enter){
242 if (event.keyCode === keycodes.enter){
240 this.auto_highlight();
243 this.auto_highlight();
241 }
244 }
242
245
243 if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
246 if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
244 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
247 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
245 // browser and keyboard layout !
248 // browser and keyboard layout !
246 // Pressing '(' , request tooltip, don't forget to reappend it
249 // Pressing '(' , request tooltip, don't forget to reappend it
247 // The second argument says to hide the tooltip if the docstring
250 // The second argument says to hide the tooltip if the docstring
248 // is actually empty
251 // is actually empty
249 this.tooltip.pending(that, true);
252 this.tooltip.pending(that, true);
250 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
253 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
251 // If tooltip is active, cancel it. The call to
254 // If tooltip is active, cancel it. The call to
252 // remove_and_cancel_tooltip above doesn't pass, force=true.
255 // remove_and_cancel_tooltip above doesn't pass, force=true.
253 // Because of this it won't actually close the tooltip
256 // Because of this it won't actually close the tooltip
254 // if it is in sticky mode. Thus, we have to check again if it is open
257 // if it is in sticky mode. Thus, we have to check again if it is open
255 // and close it with force=true.
258 // and close it with force=true.
256 if (!this.tooltip._hidden) {
259 if (!this.tooltip._hidden) {
257 this.tooltip.remove_and_cancel_tooltip(true);
260 this.tooltip.remove_and_cancel_tooltip(true);
258 }
261 }
259 // If we closed the tooltip, don't let CM or the global handlers
262 // If we closed the tooltip, don't let CM or the global handlers
260 // handle this event.
263 // handle this event.
261 event.codemirrorIgnore = true;
264 event.codemirrorIgnore = true;
262 event.preventDefault();
265 event.preventDefault();
263 return true;
266 return true;
264 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
267 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
265 if (editor.somethingSelected() || editor.getSelections().length !== 1){
268 if (editor.somethingSelected() || editor.getSelections().length !== 1){
266 var anchor = editor.getCursor("anchor");
269 var anchor = editor.getCursor("anchor");
267 var head = editor.getCursor("head");
270 var head = editor.getCursor("head");
268 if( anchor.line != head.line){
271 if( anchor.line != head.line){
269 return false;
272 return false;
270 }
273 }
271 }
274 }
272 this.tooltip.request(that);
275 this.tooltip.request(that);
273 event.codemirrorIgnore = true;
276 event.codemirrorIgnore = true;
274 event.preventDefault();
277 event.preventDefault();
275 return true;
278 return true;
276 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
279 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
277 // Tab completion.
280 // Tab completion.
278 this.tooltip.remove_and_cancel_tooltip();
281 this.tooltip.remove_and_cancel_tooltip();
279
282
280 // completion does not work on multicursor, it might be possible though in some cases
283 // completion does not work on multicursor, it might be possible though in some cases
281 if (editor.somethingSelected() || editor.getSelections().length > 1) {
284 if (editor.somethingSelected() || editor.getSelections().length > 1) {
282 return false;
285 return false;
283 }
286 }
284 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
287 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
285 if (pre_cursor.trim() === "") {
288 if (pre_cursor.trim() === "") {
286 // Don't autocomplete if the part of the line before the cursor
289 // Don't autocomplete if the part of the line before the cursor
287 // is empty. In this case, let CodeMirror handle indentation.
290 // is empty. In this case, let CodeMirror handle indentation.
288 return false;
291 return false;
289 } else {
292 } else {
290 event.codemirrorIgnore = true;
293 event.codemirrorIgnore = true;
291 event.preventDefault();
294 event.preventDefault();
292 this.completer.startCompletion();
295 this.completer.startCompletion();
293 return true;
296 return true;
294 }
297 }
295 }
298 }
296
299
297 // keyboard event wasn't one of those unique to code cells, let's see
300 // keyboard event wasn't one of those unique to code cells, let's see
298 // if it's one of the generic ones (i.e. check edit mode shortcuts)
301 // if it's one of the generic ones (i.e. check edit mode shortcuts)
299 return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
302 return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
300 };
303 };
301
304
302 // Kernel related calls.
305 // Kernel related calls.
303
306
304 CodeCell.prototype.set_kernel = function (kernel) {
307 CodeCell.prototype.set_kernel = function (kernel) {
305 this.kernel = kernel;
308 this.kernel = kernel;
306 };
309 };
307
310
308 /**
311 /**
309 * Execute current code cell to the kernel
312 * Execute current code cell to the kernel
310 * @method execute
313 * @method execute
311 */
314 */
312 CodeCell.prototype.execute = function () {
315 CodeCell.prototype.execute = function () {
313 if (!this.kernel || !this.kernel.is_connected()) {
316 if (!this.kernel || !this.kernel.is_connected()) {
314 console.log("Can't execute, kernel is not connected.");
317 console.log("Can't execute, kernel is not connected.");
315 return;
318 return;
316 }
319 }
317
320
318 this.get_output_area().clear_output();
321 this.get_output_area().clear_output();
319
322
320 // Clear widget area
323 // Clear widget area
321 this.widget_subarea.html('');
324 this.widget_subarea.html('');
322 this.widget_subarea.height('');
325 this.widget_subarea.height('');
323 this.widget_area.height('');
326 this.widget_area.height('');
324 this.widget_area.hide();
327 this.widget_area.hide();
325
328
326 this.set_input_prompt('*');
329 this.set_input_prompt('*');
327 this.element.addClass("running");
330 this.element.addClass("running");
328 if (this.last_msg_id) {
331 if (this.last_msg_id) {
329 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
332 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
330 }
333 }
331 var callbacks = this.get_callbacks();
334 var callbacks = this.get_callbacks();
332
335
333 var old_msg_id = this.last_msg_id;
336 var old_msg_id = this.last_msg_id;
334 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
337 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
335 if (old_msg_id) {
338 if (old_msg_id) {
336 delete CodeCell.msg_cells[old_msg_id];
339 delete CodeCell.msg_cells[old_msg_id];
337 }
340 }
338 CodeCell.msg_cells[this.last_msg_id] = this;
341 CodeCell.msg_cells[this.last_msg_id] = this;
339 this.render();
342 this.render();
340 };
343 };
341
344
342 /**
345 /**
343 * Construct the default callbacks for
346 * Construct the default callbacks for
344 * @method get_callbacks
347 * @method get_callbacks
345 */
348 */
346 CodeCell.prototype.get_callbacks = function () {
349 CodeCell.prototype.get_callbacks = function () {
347 var that = this;
350 var that = this;
348 return {
351 return {
349 shell : {
352 shell : {
350 reply : $.proxy(this._handle_execute_reply, this),
353 reply : $.proxy(this._handle_execute_reply, this),
351 payload : {
354 payload : {
352 set_next_input : $.proxy(this._handle_set_next_input, this),
355 set_next_input : $.proxy(this._handle_set_next_input, this),
353 page : $.proxy(this._open_with_pager, this)
356 page : $.proxy(this._open_with_pager, this)
354 }
357 }
355 },
358 },
356 iopub : {
359 iopub : {
357 output : function() {
360 output : function() {
358 var output_area = that.get_output_area();
361 var output_area = that.get_output_area();
359 output_area.handle_output.apply(output_area, arguments);
362 output_area.handle_output.apply(output_area, arguments);
360 },
363 },
361 clear_output : function() {
364 clear_output : function() {
362 var output_area = that.get_output_area();
365 var output_area = that.get_output_area();
363 output_area.handle_clear_output.apply(output_area, arguments);
366 output_area.handle_clear_output.apply(output_area, arguments);
364 },
367 },
365 },
368 },
366 input : $.proxy(this._handle_input_request, this)
369 input : $.proxy(this._handle_input_request, this)
367 };
370 };
368 };
371 };
369
372
370 CodeCell.prototype._open_with_pager = function (payload) {
373 CodeCell.prototype._open_with_pager = function (payload) {
371 this.events.trigger('open_with_text.Pager', payload);
374 this.events.trigger('open_with_text.Pager', payload);
372 };
375 };
373
376
374 /**
377 /**
375 * @method _handle_execute_reply
378 * @method _handle_execute_reply
376 * @private
379 * @private
377 */
380 */
378 CodeCell.prototype._handle_execute_reply = function (msg) {
381 CodeCell.prototype._handle_execute_reply = function (msg) {
379 this.set_input_prompt(msg.content.execution_count);
382 this.set_input_prompt(msg.content.execution_count);
380 this.element.removeClass("running");
383 this.element.removeClass("running");
381 this.events.trigger('set_dirty.Notebook', {value: true});
384 this.events.trigger('set_dirty.Notebook', {value: true});
382 };
385 };
383
386
384 /**
387 /**
385 * @method _handle_set_next_input
388 * @method _handle_set_next_input
386 * @private
389 * @private
387 */
390 */
388 CodeCell.prototype._handle_set_next_input = function (payload) {
391 CodeCell.prototype._handle_set_next_input = function (payload) {
389 var data = {'cell': this, 'text': payload.text};
392 var data = {'cell': this, 'text': payload.text};
390 this.events.trigger('set_next_input.Notebook', data);
393 this.events.trigger('set_next_input.Notebook', data);
391 };
394 };
392
395
393 /**
396 /**
394 * @method _handle_input_request
397 * @method _handle_input_request
395 * @private
398 * @private
396 */
399 */
397 CodeCell.prototype._handle_input_request = function (msg) {
400 CodeCell.prototype._handle_input_request = function (msg) {
398 this.get_output_area().append_raw_input(msg);
401 this.get_output_area().append_raw_input(msg);
399 };
402 };
400
403
401
404
402 // Basic cell manipulation.
405 // Basic cell manipulation.
403
406
404 CodeCell.prototype.select = function () {
407 CodeCell.prototype.select = function () {
405 var cont = Cell.prototype.select.apply(this);
408 var cont = Cell.prototype.select.apply(this);
406 if (cont) {
409 if (cont) {
407 this.code_mirror.refresh();
410 this.code_mirror.refresh();
408 this.auto_highlight();
411 this.auto_highlight();
409 }
412 }
410 return cont;
413 return cont;
411 };
414 };
412
415
413 CodeCell.prototype.render = function () {
416 CodeCell.prototype.render = function () {
414 var cont = Cell.prototype.render.apply(this);
417 var cont = Cell.prototype.render.apply(this);
415 // Always execute, even if we are already in the rendered state
418 // Always execute, even if we are already in the rendered state
416 return cont;
419 return cont;
417 };
420 };
418
421
419 CodeCell.prototype.select_all = function () {
422 CodeCell.prototype.select_all = function () {
420 var start = {line: 0, ch: 0};
423 var start = {line: 0, ch: 0};
421 var nlines = this.code_mirror.lineCount();
424 var nlines = this.code_mirror.lineCount();
422 var last_line = this.code_mirror.getLine(nlines-1);
425 var last_line = this.code_mirror.getLine(nlines-1);
423 var end = {line: nlines-1, ch: last_line.length};
426 var end = {line: nlines-1, ch: last_line.length};
424 this.code_mirror.setSelection(start, end);
427 this.code_mirror.setSelection(start, end);
425 };
428 };
426
429
427
430
428 CodeCell.prototype.collapse_output = function () {
431 CodeCell.prototype.collapse_output = function () {
429 this.output_area.collapse();
432 this.output_area.collapse();
430 };
433 };
431
434
432
435
433 CodeCell.prototype.expand_output = function () {
436 CodeCell.prototype.expand_output = function () {
434 this.output_area.expand();
437 this.output_area.expand();
435 this.output_area.unscroll_area();
438 this.output_area.unscroll_area();
436 };
439 };
437
440
438 CodeCell.prototype.scroll_output = function () {
441 CodeCell.prototype.scroll_output = function () {
439 this.output_area.expand();
442 this.output_area.expand();
440 this.output_area.scroll_if_long();
443 this.output_area.scroll_if_long();
441 };
444 };
442
445
443 CodeCell.prototype.toggle_output = function () {
446 CodeCell.prototype.toggle_output = function () {
444 this.output_area.toggle_output();
447 this.output_area.toggle_output();
445 };
448 };
446
449
447 CodeCell.prototype.toggle_output_scroll = function () {
450 CodeCell.prototype.toggle_output_scroll = function () {
448 this.output_area.toggle_scroll();
451 this.output_area.toggle_scroll();
449 };
452 };
450
453
451
454
452 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
455 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
453 var ns;
456 var ns;
454 if (prompt_value === undefined || prompt_value === null) {
457 if (prompt_value === undefined || prompt_value === null) {
455 ns = "&nbsp;";
458 ns = "&nbsp;";
456 } else {
459 } else {
457 ns = encodeURIComponent(prompt_value);
460 ns = encodeURIComponent(prompt_value);
458 }
461 }
459 return 'In&nbsp;[' + ns + ']:';
462 return 'In&nbsp;[' + ns + ']:';
460 };
463 };
461
464
462 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
465 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
463 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
466 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
464 for(var i=1; i < lines_number; i++) {
467 for(var i=1; i < lines_number; i++) {
465 html.push(['...:']);
468 html.push(['...:']);
466 }
469 }
467 return html.join('<br/>');
470 return html.join('<br/>');
468 };
471 };
469
472
470 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
473 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
471
474
472
475
473 CodeCell.prototype.set_input_prompt = function (number) {
476 CodeCell.prototype.set_input_prompt = function (number) {
474 var nline = 1;
477 var nline = 1;
475 if (this.code_mirror !== undefined) {
478 if (this.code_mirror !== undefined) {
476 nline = this.code_mirror.lineCount();
479 nline = this.code_mirror.lineCount();
477 }
480 }
478 this.input_prompt_number = number;
481 this.input_prompt_number = number;
479 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
482 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
480 // This HTML call is okay because the user contents are escaped.
483 // This HTML call is okay because the user contents are escaped.
481 this.element.find('div.input_prompt').html(prompt_html);
484 this.element.find('div.input_prompt').html(prompt_html);
482 };
485 };
483
486
484
487
485 CodeCell.prototype.clear_input = function () {
488 CodeCell.prototype.clear_input = function () {
486 this.code_mirror.setValue('');
489 this.code_mirror.setValue('');
487 };
490 };
488
491
489
492
490 CodeCell.prototype.get_text = function () {
493 CodeCell.prototype.get_text = function () {
491 return this.code_mirror.getValue();
494 return this.code_mirror.getValue();
492 };
495 };
493
496
494
497
495 CodeCell.prototype.set_text = function (code) {
498 CodeCell.prototype.set_text = function (code) {
496 return this.code_mirror.setValue(code);
499 return this.code_mirror.setValue(code);
497 };
500 };
498
501
499
502
500 CodeCell.prototype.clear_output = function (wait) {
503 CodeCell.prototype.clear_output = function (wait) {
501 this.get_output_area().clear_output(wait);
504 this.get_output_area().clear_output(wait);
502 this.set_input_prompt();
505 this.set_input_prompt();
503 };
506 };
504
507
505
508
506 // JSON serialization
509 // JSON serialization
507
510
508 CodeCell.prototype.fromJSON = function (data) {
511 CodeCell.prototype.fromJSON = function (data) {
509 Cell.prototype.fromJSON.apply(this, arguments);
512 Cell.prototype.fromJSON.apply(this, arguments);
510 if (data.cell_type === 'code') {
513 if (data.cell_type === 'code') {
511 if (data.source !== undefined) {
514 if (data.source !== undefined) {
512 this.set_text(data.source);
515 this.set_text(data.source);
513 // make this value the starting point, so that we can only undo
516 // make this value the starting point, so that we can only undo
514 // to this state, instead of a blank cell
517 // to this state, instead of a blank cell
515 this.code_mirror.clearHistory();
518 this.code_mirror.clearHistory();
516 this.auto_highlight();
519 this.auto_highlight();
517 }
520 }
518 this.set_input_prompt(data.execution_count);
521 this.set_input_prompt(data.execution_count);
519 this.output_area.trusted = data.metadata.trusted || false;
522 this.output_area.trusted = data.metadata.trusted || false;
520 this.output_area.fromJSON(data.outputs);
523 this.output_area.fromJSON(data.outputs);
521 if (data.metadata.collapsed !== undefined) {
524 if (data.metadata.collapsed !== undefined) {
522 if (data.metadata.collapsed) {
525 if (data.metadata.collapsed) {
523 this.collapse_output();
526 this.collapse_output();
524 } else {
527 } else {
525 this.expand_output();
528 this.expand_output();
526 }
529 }
527 }
530 }
528 }
531 }
529 };
532 };
530
533
531
534
532 CodeCell.prototype.toJSON = function () {
535 CodeCell.prototype.toJSON = function () {
533 var data = Cell.prototype.toJSON.apply(this);
536 var data = Cell.prototype.toJSON.apply(this);
534 data.source = this.get_text();
537 data.source = this.get_text();
535 // is finite protect against undefined and '*' value
538 // is finite protect against undefined and '*' value
536 if (isFinite(this.input_prompt_number)) {
539 if (isFinite(this.input_prompt_number)) {
537 data.execution_count = this.input_prompt_number;
540 data.execution_count = this.input_prompt_number;
538 } else {
541 } else {
539 data.execution_count = null;
542 data.execution_count = null;
540 }
543 }
541 var outputs = this.output_area.toJSON();
544 var outputs = this.output_area.toJSON();
542 data.outputs = outputs;
545 data.outputs = outputs;
543 data.metadata.trusted = this.output_area.trusted;
546 data.metadata.trusted = this.output_area.trusted;
544 data.metadata.collapsed = this.output_area.collapsed;
547 data.metadata.collapsed = this.output_area.collapsed;
545 return data;
548 return data;
546 };
549 };
547
550
548 /**
551 /**
549 * handle cell level logic when a cell is unselected
552 * handle cell level logic when a cell is unselected
550 * @method unselect
553 * @method unselect
551 * @return is the action being taken
554 * @return is the action being taken
552 */
555 */
553 CodeCell.prototype.unselect = function () {
556 CodeCell.prototype.unselect = function () {
554 var cont = Cell.prototype.unselect.apply(this);
557 var cont = Cell.prototype.unselect.apply(this);
555 if (cont) {
558 if (cont) {
556 // When a code cell is usnelected, make sure that the corresponding
559 // When a code cell is usnelected, make sure that the corresponding
557 // tooltip and completer to that cell is closed.
560 // tooltip and completer to that cell is closed.
558 this.tooltip.remove_and_cancel_tooltip(true);
561 this.tooltip.remove_and_cancel_tooltip(true);
559 if (this.completer !== null) {
562 if (this.completer !== null) {
560 this.completer.close();
563 this.completer.close();
561 }
564 }
562 }
565 }
563 return cont;
566 return cont;
564 };
567 };
565
568
566 // Backwards compatability.
569 // Backwards compatability.
567 IPython.CodeCell = CodeCell;
570 IPython.CodeCell = CodeCell;
568
571
569 return {'CodeCell': CodeCell};
572 return {'CodeCell': CodeCell};
570 });
573 });
General Comments 0
You need to be logged in to leave comments. Login now