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