##// END OF EJS Templates
comment more
Matthias BUSSONNIER -
Show More
@@ -1,684 +1,691 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // CodeCell
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16
17 17 var CodeCell = function (notebook) {
18 18 this.code_mirror = null;
19 19 this.input_prompt_number = null;
20 20 this.is_completing = false;
21 21 this.completion_cursor = null;
22 22 this.outputs = [];
23 23 this.collapsed = false;
24 24 this.tooltip_timeout = null;
25 25 this.clear_out_timeout = null;
26 26 IPython.Cell.apply(this, arguments);
27 27 };
28 28
29 29
30 30 CodeCell.prototype = new IPython.Cell();
31 31
32 32
33 33 CodeCell.prototype.create_element = function () {
34 34 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
35 35 cell.attr('tabindex','2');
36 36 var input = $('<div></div>').addClass('input hbox');
37 37 input.append($('<div/>').addClass('prompt input_prompt'));
38 38 var input_area = $('<div/>').addClass('input_area box-flex1');
39 39 this.code_mirror = CodeMirror(input_area.get(0), {
40 40 indentUnit : 4,
41 41 mode: 'python',
42 42 theme: 'ipython',
43 43 readOnly: this.read_only,
44 44 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
45 45 });
46 46 input.append(input_area);
47 47 var output = $('<div></div>').addClass('output vbox');
48 48 cell.append(input).append(output);
49 49 this.element = cell;
50 50 this.collapse();
51 51
52 52 // construct a completer
53 53 // And give it the function to call to get the completion list
54 54 var that = this;
55 55 this.completer = new IPython.Completer(this.code_mirror,function(callback){that.requestCompletion(callback)});
56 56 };
57 57
58 58 //TODO, try to diminish the number of parameters.
59 59 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
60 60 var that = this;
61 61 if (pre_cursor === "" || pre_cursor === "(" ) {
62 62 // don't do anything if line beggin with '(' or is empty
63 63 } else {
64 64 // Will set a timer to request tooltip in `time`
65 65 that.tooltip_timeout = setTimeout(function(){
66 66 IPython.notebook.request_tool_tip(that, pre_cursor)
67 67 },time);
68 68 }
69 69 };
70 70
71 71 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
72 72 // This method gets called in CodeMirror's onKeyDown/onKeyPress
73 73 // handlers and is used to provide custom key handling. Its return
74 74 // value is used to determine if CodeMirror should ignore the event:
75 75 // true = ignore, false = don't ignore.
76 76
77 77 if (this.read_only){
78 78 return false;
79 79 }
80 80
81 81 // note that we are comparing and setting the time to wait at each key press.
82 82 // a better wqy might be to generate a new function on each time change and
83 83 // assign it to CodeCell.prototype.request_tooltip_after_time
84 84 var tooltip_wait_time = this.notebook.time_before_tooltip;
85 85 var tooltip_on_tab = this.notebook.tooltip_on_tab;
86 86 var that = this;
87 87 // whatever key is pressed, first, cancel the tooltip request before
88 88 // they are sent, and remove tooltip if any
89 89 if(event.type === 'keydown' ) {
90 90 that.remove_and_cancel_tooltip();
91 91 };
92 92
93 93
94 94 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
95 95 // Always ignore shift-enter in CodeMirror as we handle it.
96 96 return true;
97 97 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
98 98 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
99 99 // browser and keyboard layout !
100 100 // Pressing '(' , request tooltip, don't forget to reappend it
101 101 var cursor = editor.getCursor();
102 102 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
103 103 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
104 104 } else if (event.which === 38) {
105 105 // If we are not at the top, let CM handle the up arrow and
106 106 // prevent the global keydown handler from handling it.
107 107 if (!that.at_top()) {
108 108 event.stop();
109 109 return false;
110 110 } else {
111 111 return true;
112 112 };
113 113 } else if (event.which === 40) {
114 114 // If we are not at the bottom, let CM handle the down arrow and
115 115 // prevent the global keydown handler from handling it.
116 116 if (!that.at_bottom()) {
117 117 event.stop();
118 118 return false;
119 119 } else {
120 120 return true;
121 121 };
122 122 } else if (event.keyCode === 9 && event.type == 'keydown') {
123 123 // Tab completion.
124 124 var cur = editor.getCursor();
125 125 //Do not trim here because of tooltip
126 126 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
127 127 if (pre_cursor.trim() === "") {
128 128 // Don't autocomplete if the part of the line before the cursor
129 129 // is empty. In this case, let CodeMirror handle indentation.
130 130 return false;
131 131 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
132 132 that.request_tooltip_after_time(pre_cursor,0);
133 133 // Prevent the event from bubbling up.
134 134 event.stop();
135 135 // Prevent CodeMirror from handling the tab.
136 136 return true;
137 137 } else {
138 138 event.stop();
139 139 this.completer.startCompletion();
140 140 return true;
141 141 };
142 142 } else if (event.keyCode === 8 && event.type == 'keydown') {
143 143 // If backspace and the line ends with 4 spaces, remove them.
144 144 var cur = editor.getCursor();
145 145 var line = editor.getLine(cur.line);
146 146 var ending = line.slice(-4);
147 147 if (ending === ' ') {
148 148 editor.replaceRange('',
149 149 {line: cur.line, ch: cur.ch-4},
150 150 {line: cur.line, ch: cur.ch}
151 151 );
152 152 event.stop();
153 153 return true;
154 154 } else {
155 155 return false;
156 156 };
157 157 } else {
158 158 // keypress/keyup also trigger on TAB press, and we don't want to
159 159 // use those to disable tab completion.
160 160 if (this.is_completing && event.keyCode !== 9) {
161 161 var ed_cur = editor.getCursor();
162 162 var cc_cur = this.completion_cursor;
163 163 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
164 164 this.is_completing = false;
165 165 this.completion_cursor = null;
166 166 };
167 167 };
168 168 return false;
169 169 };
170 170 return false;
171 171 };
172 172
173 173 CodeCell.prototype.remove_and_cancel_tooltip = function() {
174 174 // note that we don't handle closing directly inside the calltip
175 175 // as in the completer, because it is not focusable, so won't
176 176 // get the event.
177 177 if (this.tooltip_timeout != null){
178 178 clearTimeout(this.tooltip_timeout);
179 179 $('#tooltip').remove();
180 180 this.tooltip_timeout = null;
181 181 }
182 182 }
183 183
184 184 CodeCell.prototype.finish_tooltip = function (reply) {
185 185 // Extract call tip data; the priority is call, init, main.
186 186 defstring = reply.call_def;
187 187 if (defstring == null) { defstring = reply.init_definition; }
188 188 if (defstring == null) { defstring = reply.definition; }
189 189
190 190 docstring = reply.call_docstring;
191 191 if (docstring == null) { docstring = reply.init_docstring; }
192 192 if (docstring == null) { docstring = reply.docstring; }
193 193 if (docstring == null) { docstring = "<empty docstring>"; }
194 194
195 195 name=reply.name;
196 196
197 197 var that = this;
198 198 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
199 199 // remove to have the tooltip not Limited in X and Y
200 200 tooltip.addClass('smalltooltip');
201 201 var pre=$('<pre/>').html(utils.fixConsole(docstring));
202 202 var expandlink=$('<a/>').attr('href',"#");
203 203 expandlink.addClass("ui-corner-all"); //rounded corner
204 204 expandlink.attr('role',"button");
205 205 //expandlink.addClass('ui-button');
206 206 //expandlink.addClass('ui-state-default');
207 207 var expandspan=$('<span/>').text('Expand');
208 208 expandspan.addClass('ui-icon');
209 209 expandspan.addClass('ui-icon-plus');
210 210 expandlink.append(expandspan);
211 211 expandlink.attr('id','expanbutton');
212 212 expandlink.click(function(){
213 213 tooltip.removeClass('smalltooltip');
214 214 tooltip.addClass('bigtooltip');
215 215 $('#expanbutton').remove();
216 216 setTimeout(function(){that.code_mirror.focus();}, 50);
217 217 });
218 218 var morelink=$('<a/>').attr('href',"#");
219 219 morelink.attr('role',"button");
220 220 morelink.addClass('ui-button');
221 221 //morelink.addClass("ui-corner-all"); //rounded corner
222 222 //morelink.addClass('ui-state-default');
223 223 var morespan=$('<span/>').text('Open in Pager');
224 224 morespan.addClass('ui-icon');
225 225 morespan.addClass('ui-icon-arrowstop-l-n');
226 226 morelink.append(morespan);
227 227 morelink.click(function(){
228 228 var msg_id = IPython.notebook.kernel.execute(name+"?");
229 229 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
230 230 that.remove_and_cancel_tooltip();
231 231 setTimeout(function(){that.code_mirror.focus();}, 50);
232 232 });
233 233
234 234 var closelink=$('<a/>').attr('href',"#");
235 235 closelink.attr('role',"button");
236 236 closelink.addClass('ui-button');
237 237 //closelink.addClass("ui-corner-all"); //rounded corner
238 238 //closelink.adClass('ui-state-default'); // grey background and blue cross
239 239 var closespan=$('<span/>').text('Close');
240 240 closespan.addClass('ui-icon');
241 241 closespan.addClass('ui-icon-close');
242 242 closelink.append(closespan);
243 243 closelink.click(function(){
244 244 that.remove_and_cancel_tooltip();
245 245 setTimeout(function(){that.code_mirror.focus();}, 50);
246 246 });
247 247 //construct the tooltip
248 248 tooltip.append(closelink);
249 249 tooltip.append(expandlink);
250 250 tooltip.append(morelink);
251 251 if(defstring){
252 252 defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
253 253 tooltip.append(defstring_html);
254 254 }
255 255 tooltip.append(pre);
256 256 var pos = this.code_mirror.cursorCoords();
257 257 tooltip.css('left',pos.x+'px');
258 258 tooltip.css('top',pos.yBot+'px');
259 259 $('body').append(tooltip);
260 260
261 261 // issues with cross-closing if multiple tooltip in less than 5sec
262 262 // keep it comented for now
263 263 // setTimeout(that.remove_and_cancel_tooltip, 5000);
264 264 };
265 265
266 266 // As you type completer
267 // this should be called by the completer, that in return will
268 // be reclled by finish_completing
267 269 CodeCell.prototype.requestCompletion= function(callback)
268 270 {
269 271 this._compcallback = callback;
270 272 var cur = this.code_mirror.getCursor();
271 273 var pre_cursor = this.code_mirror.getRange({line:cur.line,ch:0},cur);
272 274 pre_cursor.trim();
273 275 // Autocomplete the current line.
274 276 var line = this.code_mirror.getLine(cur.line);
275 277 this.is_completing = true;
276 278 this.completion_cursor = cur;
279 // one could fork here and directly call finish completing
280 // if kernel is busy
277 281 IPython.notebook.complete_cell(this, line, cur.ch);
278 282 }
279 283
284 // called when completion came back from the kernel. this will inspect the
285 // curent cell for (more) completion merge the resuults with the ones
286 // comming from the kernel and forward it to the completer
280 287 CodeCell.prototype.finish_completing = function (matched_text, matches) {
281 288 // let's build a function that wrap all that stuff into what is needed for the
282 289 // new completer:
283 290 //
284 291 var cur = this.code_mirror.getCursor();
285 292 var res = CodeMirror.contextHint(this.code_mirror);
286 293
287 294 // append the introspection result, in order, at
288 295 // at the beginning of the table and compute the replacement rance
289 296 // from current cursor positon and matched_text length.
290 297 for(var i= matches.length-1; i>=0 ;--i)
291 298 {
292 299 res.unshift(
293 300 {
294 301 str : matches[i],
295 302 type : "introspection",
296 303 from : {line: cur.line, ch: cur.ch-matched_text.length},
297 304 to : {line: cur.line, ch: cur.ch}
298 305 }
299 306 )
300 307 }
301 308 this._compcallback(res);
302 309 };
303 310
304 311
305 312 CodeCell.prototype.select = function () {
306 313 IPython.Cell.prototype.select.apply(this);
307 314 this.code_mirror.refresh();
308 315 this.code_mirror.focus();
309 316 // We used to need an additional refresh() after the focus, but
310 317 // it appears that this has been fixed in CM. This bug would show
311 318 // up on FF when a newly loaded markdown cell was edited.
312 319 };
313 320
314 321
315 322 CodeCell.prototype.select_all = function () {
316 323 var start = {line: 0, ch: 0};
317 324 var nlines = this.code_mirror.lineCount();
318 325 var last_line = this.code_mirror.getLine(nlines-1);
319 326 var end = {line: nlines-1, ch: last_line.length};
320 327 this.code_mirror.setSelection(start, end);
321 328 };
322 329
323 330
324 331 CodeCell.prototype.append_output = function (json, dynamic) {
325 332 // If dynamic is true, javascript output will be eval'd.
326 333 this.expand();
327 334 this.flush_clear_timeout();
328 335 if (json.output_type === 'pyout') {
329 336 this.append_pyout(json, dynamic);
330 337 } else if (json.output_type === 'pyerr') {
331 338 this.append_pyerr(json);
332 339 } else if (json.output_type === 'display_data') {
333 340 this.append_display_data(json, dynamic);
334 341 } else if (json.output_type === 'stream') {
335 342 this.append_stream(json);
336 343 };
337 344 this.outputs.push(json);
338 345 };
339 346
340 347
341 348 CodeCell.prototype.create_output_area = function () {
342 349 var oa = $("<div/>").addClass("hbox output_area");
343 350 oa.append($('<div/>').addClass('prompt'));
344 351 return oa;
345 352 };
346 353
347 354
348 355 CodeCell.prototype.append_pyout = function (json, dynamic) {
349 356 var n = json.prompt_number || ' ';
350 357 var toinsert = this.create_output_area();
351 358 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
352 359 this.append_mime_type(json, toinsert, dynamic);
353 360 this.element.find('div.output').append(toinsert);
354 361 // If we just output latex, typeset it.
355 362 if ((json.latex !== undefined) || (json.html !== undefined)) {
356 363 this.typeset();
357 364 };
358 365 };
359 366
360 367
361 368 CodeCell.prototype.append_pyerr = function (json) {
362 369 var tb = json.traceback;
363 370 if (tb !== undefined && tb.length > 0) {
364 371 var s = '';
365 372 var len = tb.length;
366 373 for (var i=0; i<len; i++) {
367 374 s = s + tb[i] + '\n';
368 375 }
369 376 s = s + '\n';
370 377 var toinsert = this.create_output_area();
371 378 this.append_text(s, toinsert);
372 379 this.element.find('div.output').append(toinsert);
373 380 };
374 381 };
375 382
376 383
377 384 CodeCell.prototype.append_stream = function (json) {
378 385 // temporary fix: if stream undefined (json file written prior to this patch),
379 386 // default to most likely stdout:
380 387 if (json.stream == undefined){
381 388 json.stream = 'stdout';
382 389 }
383 390 if (!utils.fixConsole(json.text)){
384 391 // fixConsole gives nothing (empty string, \r, etc.)
385 392 // so don't append any elements, which might add undesirable space
386 393 return;
387 394 }
388 395 var subclass = "output_"+json.stream;
389 396 if (this.outputs.length > 0){
390 397 // have at least one output to consider
391 398 var last = this.outputs[this.outputs.length-1];
392 399 if (last.output_type == 'stream' && json.stream == last.stream){
393 400 // latest output was in the same stream,
394 401 // so append directly into its pre tag
395 402 // escape ANSI & HTML specials:
396 403 var text = utils.fixConsole(json.text);
397 404 this.element.find('div.'+subclass).last().find('pre').append(text);
398 405 return;
399 406 }
400 407 }
401 408
402 409 // If we got here, attach a new div
403 410 var toinsert = this.create_output_area();
404 411 this.append_text(json.text, toinsert, "output_stream "+subclass);
405 412 this.element.find('div.output').append(toinsert);
406 413 };
407 414
408 415
409 416 CodeCell.prototype.append_display_data = function (json, dynamic) {
410 417 var toinsert = this.create_output_area();
411 418 this.append_mime_type(json, toinsert, dynamic);
412 419 this.element.find('div.output').append(toinsert);
413 420 // If we just output latex, typeset it.
414 421 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
415 422 this.typeset();
416 423 };
417 424 };
418 425
419 426
420 427 CodeCell.prototype.append_mime_type = function (json, element, dynamic) {
421 428 if (json.javascript !== undefined && dynamic) {
422 429 this.append_javascript(json.javascript, element, dynamic);
423 430 } else if (json.html !== undefined) {
424 431 this.append_html(json.html, element);
425 432 } else if (json.latex !== undefined) {
426 433 this.append_latex(json.latex, element);
427 434 } else if (json.svg !== undefined) {
428 435 this.append_svg(json.svg, element);
429 436 } else if (json.png !== undefined) {
430 437 this.append_png(json.png, element);
431 438 } else if (json.jpeg !== undefined) {
432 439 this.append_jpeg(json.jpeg, element);
433 440 } else if (json.text !== undefined) {
434 441 this.append_text(json.text, element);
435 442 };
436 443 };
437 444
438 445
439 446 CodeCell.prototype.append_html = function (html, element) {
440 447 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
441 448 toinsert.append(html);
442 449 element.append(toinsert);
443 450 };
444 451
445 452
446 453 CodeCell.prototype.append_javascript = function (js, container) {
447 454 // We just eval the JS code, element appears in the local scope.
448 455 var element = $("<div/>").addClass("box_flex1 output_subarea");
449 456 container.append(element);
450 457 // Div for js shouldn't be drawn, as it will add empty height to the area.
451 458 container.hide();
452 459 // If the Javascript appends content to `element` that should be drawn, then
453 460 // it must also call `container.show()`.
454 461 eval(js);
455 462 }
456 463
457 464
458 465 CodeCell.prototype.append_text = function (data, element, extra_class) {
459 466 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
460 467 // escape ANSI & HTML specials in plaintext:
461 468 data = utils.fixConsole(data);
462 469 if (extra_class){
463 470 toinsert.addClass(extra_class);
464 471 }
465 472 toinsert.append($("<pre/>").html(data));
466 473 element.append(toinsert);
467 474 };
468 475
469 476
470 477 CodeCell.prototype.append_svg = function (svg, element) {
471 478 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
472 479 toinsert.append(svg);
473 480 element.append(toinsert);
474 481 };
475 482
476 483
477 484 CodeCell.prototype.append_png = function (png, element) {
478 485 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
479 486 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
480 487 element.append(toinsert);
481 488 };
482 489
483 490
484 491 CodeCell.prototype.append_jpeg = function (jpeg, element) {
485 492 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
486 493 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
487 494 element.append(toinsert);
488 495 };
489 496
490 497
491 498 CodeCell.prototype.append_latex = function (latex, element) {
492 499 // This method cannot do the typesetting because the latex first has to
493 500 // be on the page.
494 501 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
495 502 toinsert.append(latex);
496 503 element.append(toinsert);
497 504 };
498 505
499 506
500 507 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
501 508 var that = this;
502 509 if (this.clear_out_timeout != null){
503 510 // fire previous pending clear *immediately*
504 511 clearTimeout(this.clear_out_timeout);
505 512 this.clear_out_timeout = null;
506 513 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
507 514 }
508 515 // store flags for flushing the timeout
509 516 this._clear_stdout = stdout;
510 517 this._clear_stderr = stderr;
511 518 this._clear_other = other;
512 519 this.clear_out_timeout = setTimeout(function(){
513 520 // really clear timeout only after a short delay
514 521 // this reduces flicker in 'clear_output; print' cases
515 522 that.clear_out_timeout = null;
516 523 that._clear_stdout = that._clear_stderr = that._clear_other = null;
517 524 that.clear_output_callback(stdout, stderr, other);
518 525 }, 500
519 526 );
520 527 };
521 528
522 529 CodeCell.prototype.clear_output_callback = function (stdout, stderr, other) {
523 530 var output_div = this.element.find("div.output");
524 531
525 532 if (stdout && stderr && other){
526 533 // clear all, no need for logic
527 534 output_div.html("");
528 535 this.outputs = [];
529 536 return;
530 537 }
531 538 // remove html output
532 539 // each output_subarea that has an identifying class is in an output_area
533 540 // which is the element to be removed.
534 541 if (stdout){
535 542 output_div.find("div.output_stdout").parent().remove();
536 543 }
537 544 if (stderr){
538 545 output_div.find("div.output_stderr").parent().remove();
539 546 }
540 547 if (other){
541 548 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
542 549 }
543 550
544 551 // remove cleared outputs from JSON list:
545 552 for (var i = this.outputs.length - 1; i >= 0; i--){
546 553 var out = this.outputs[i];
547 554 var output_type = out.output_type;
548 555 if (output_type == "display_data" && other){
549 556 this.outputs.splice(i,1);
550 557 }else if (output_type == "stream"){
551 558 if (stdout && out.stream == "stdout"){
552 559 this.outputs.splice(i,1);
553 560 }else if (stderr && out.stream == "stderr"){
554 561 this.outputs.splice(i,1);
555 562 }
556 563 }
557 564 }
558 565 };
559 566
560 567
561 568 CodeCell.prototype.clear_input = function () {
562 569 this.code_mirror.setValue('');
563 570 };
564 571
565 572 CodeCell.prototype.flush_clear_timeout = function() {
566 573 var output_div = this.element.find('div.output');
567 574 if (this.clear_out_timeout){
568 575 clearTimeout(this.clear_out_timeout);
569 576 this.clear_out_timeout = null;
570 577 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
571 578 };
572 579 }
573 580
574 581
575 582 CodeCell.prototype.collapse = function () {
576 583 if (!this.collapsed) {
577 584 this.element.find('div.output').hide();
578 585 this.collapsed = true;
579 586 };
580 587 };
581 588
582 589
583 590 CodeCell.prototype.expand = function () {
584 591 if (this.collapsed) {
585 592 this.element.find('div.output').show();
586 593 this.collapsed = false;
587 594 };
588 595 };
589 596
590 597
591 598 CodeCell.prototype.toggle_output = function () {
592 599 if (this.collapsed) {
593 600 this.expand();
594 601 } else {
595 602 this.collapse();
596 603 };
597 604 };
598 605
599 606 CodeCell.prototype.set_input_prompt = function (number) {
600 607 this.input_prompt_number = number;
601 608 var ns = number || "&nbsp;";
602 609 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
603 610 };
604 611
605 612
606 613 CodeCell.prototype.get_text = function () {
607 614 return this.code_mirror.getValue();
608 615 };
609 616
610 617
611 618 CodeCell.prototype.set_text = function (code) {
612 619 return this.code_mirror.setValue(code);
613 620 };
614 621
615 622
616 623 CodeCell.prototype.at_top = function () {
617 624 var cursor = this.code_mirror.getCursor();
618 625 if (cursor.line === 0) {
619 626 return true;
620 627 } else {
621 628 return false;
622 629 }
623 630 };
624 631
625 632
626 633 CodeCell.prototype.at_bottom = function () {
627 634 var cursor = this.code_mirror.getCursor();
628 635 if (cursor.line === (this.code_mirror.lineCount()-1)) {
629 636 return true;
630 637 } else {
631 638 return false;
632 639 }
633 640 };
634 641
635 642
636 643 CodeCell.prototype.fromJSON = function (data) {
637 644 if (data.cell_type === 'code') {
638 645 if (data.input !== undefined) {
639 646 this.set_text(data.input);
640 647 }
641 648 if (data.prompt_number !== undefined) {
642 649 this.set_input_prompt(data.prompt_number);
643 650 } else {
644 651 this.set_input_prompt();
645 652 };
646 653 var len = data.outputs.length;
647 654 for (var i=0; i<len; i++) {
648 655 // append with dynamic=false.
649 656 this.append_output(data.outputs[i], false);
650 657 };
651 658 if (data.collapsed !== undefined) {
652 659 if (data.collapsed) {
653 660 this.collapse();
654 661 } else {
655 662 this.expand();
656 663 };
657 664 };
658 665 };
659 666 };
660 667
661 668
662 669 CodeCell.prototype.toJSON = function () {
663 670 var data = {};
664 671 data.input = this.get_text();
665 672 data.cell_type = 'code';
666 673 if (this.input_prompt_number) {
667 674 data.prompt_number = this.input_prompt_number;
668 675 };
669 676 var outputs = [];
670 677 var len = this.outputs.length;
671 678 for (var i=0; i<len; i++) {
672 679 outputs[i] = this.outputs[i];
673 680 };
674 681 data.outputs = outputs;
675 682 data.language = 'python';
676 683 data.collapsed = this.collapsed;
677 684 return data;
678 685 };
679 686
680 687
681 688 IPython.CodeCell = CodeCell;
682 689
683 690 return IPython;
684 691 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now