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