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