##// END OF EJS Templates
forgotten selected_cell -> get_selected_cell...
Matthias BUSSONNIER -
Show More
@@ -1,850 +1,850 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
14 14 var utils = IPython.utils;
15 15
16 16 var CodeCell = function (notebook) {
17 17 this.code_mirror = null;
18 18 this.input_prompt_number = ' ';
19 19 this.is_completing = false;
20 20 this.completion_cursor = null;
21 21 this.outputs = [];
22 22 this.collapsed = false;
23 23 this.tooltip_timeout = null;
24 24 IPython.Cell.apply(this, arguments);
25 25 };
26 26
27 27
28 28 CodeCell.prototype = new IPython.Cell();
29 29
30 30
31 31 CodeCell.prototype.create_element = function () {
32 32 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
33 33 cell.attr('tabindex','2');
34 34 var input = $('<div></div>').addClass('input hbox');
35 35 input.append($('<div/>').addClass('prompt input_prompt'));
36 36 var input_area = $('<div/>').addClass('input_area box-flex1');
37 37 this.code_mirror = CodeMirror(input_area.get(0), {
38 38 indentUnit : 4,
39 39 mode: 'python',
40 40 theme: 'ipython',
41 41 readOnly: this.read_only,
42 42 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
43 43 });
44 44 input.append(input_area);
45 45 var output = $('<div></div>').addClass('output vbox');
46 46 cell.append(input).append(output);
47 47 this.element = cell;
48 48 this.collapse();
49 49 };
50 50
51 51 //TODO, try to diminish the number of parameters.
52 52 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
53 53 var that = this;
54 54 if (pre_cursor === "" || pre_cursor === "(" ) {
55 55 // don't do anything if line beggin with '(' or is empty
56 56 } else {
57 57 // Will set a timer to request tooltip in `time`
58 58 that.tooltip_timeout = setTimeout(function(){
59 59 IPython.notebook.request_tool_tip(that, pre_cursor)
60 60 },time);
61 61 }
62 62 };
63 63
64 64 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
65 65 // This method gets called in CodeMirror's onKeyDown/onKeyPress
66 66 // handlers and is used to provide custom key handling. Its return
67 67 // value is used to determine if CodeMirror should ignore the event:
68 68 // true = ignore, false = don't ignore.
69 69
70 70 if (this.read_only){
71 71 return false;
72 72 }
73 73
74 74 // note that we are comparing and setting the time to wait at each key press.
75 75 // a better wqy might be to generate a new function on each time change and
76 76 // assign it to CodeCell.prototype.request_tooltip_after_time
77 77 tooltip_wait_time = this.notebook.time_before_tooltip;
78 78 tooltip_on_tab = this.notebook.tooltip_on_tab;
79 79 var that = this;
80 80 // whatever key is pressed, first, cancel the tooltip request before
81 81 // they are sent, and remove tooltip if any
82 82 if(event.type === 'keydown' ){
83 83 that.remove_and_cancel_tooltip();
84 84 }
85 85
86 86 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
87 87 // Always ignore shift-enter in CodeMirror as we handle it.
88 88 return true;
89 89 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
90 90 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
91 91 // browser and keyboard layout !
92 92 // Pressing '(' , request tooltip, don't forget to reappend it
93 93 var cursor = editor.getCursor();
94 94 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
95 95 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
96 96 } else if (event.which === 38) {
97 97 // If we are not at the top, let CM handle the up arrow and
98 98 // prevent the global keydown handler from handling it.
99 99 if (!that.at_top()) {
100 100 event.stop();
101 101 return false;
102 102 } else {
103 103 return true;
104 104 };
105 105 } else if (event.which === 40) {
106 106 // If we are not at the bottom, let CM handle the down arrow and
107 107 // prevent the global keydown handler from handling it.
108 108 if (!that.at_bottom()) {
109 109 event.stop();
110 110 return false;
111 111 } else {
112 112 return true;
113 113 };
114 114 } else if (event.keyCode === 9 && event.type == 'keydown') {
115 115 // Tab completion.
116 116 var cur = editor.getCursor();
117 117 //Do not trim here because of tooltip
118 118 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
119 119 if (pre_cursor.trim() === "") {
120 120 // Don't autocomplete if the part of the line before the cursor
121 121 // is empty. In this case, let CodeMirror handle indentation.
122 122 return false;
123 123 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
124 124 that.request_tooltip_after_time(pre_cursor,0);
125 125 } else {
126 126 pre_cursor.trim();
127 127 // Autocomplete the current line.
128 128 event.stop();
129 129 var line = editor.getLine(cur.line);
130 130 this.is_completing = true;
131 131 this.completion_cursor = cur;
132 132 IPython.notebook.complete_cell(this, line, cur.ch);
133 133 return true;
134 134 }
135 135 } else if (event.keyCode === 8 && event.type == 'keydown') {
136 136 // If backspace and the line ends with 4 spaces, remove them.
137 137 var cur = editor.getCursor();
138 138 var line = editor.getLine(cur.line);
139 139 var ending = line.slice(-4);
140 140 if (ending === ' ') {
141 141 editor.replaceRange('',
142 142 {line: cur.line, ch: cur.ch-4},
143 143 {line: cur.line, ch: cur.ch}
144 144 );
145 145 event.stop();
146 146 return true;
147 147 } else {
148 148 return false;
149 149 }
150 150 } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey
151 151 && event.type == 'keydown') {
152 152 // toggle line numbers with Ctrl-Shift-L
153 153 this.toggle_line_numbers();
154 154 }
155 155 else {
156 156 // keypress/keyup also trigger on TAB press, and we don't want to
157 157 // use those to disable tab completion.
158 158 if (this.is_completing && event.keyCode !== 9) {
159 159 var ed_cur = editor.getCursor();
160 160 var cc_cur = this.completion_cursor;
161 161 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
162 162 this.is_completing = false;
163 163 this.completion_cursor = null;
164 164 }
165 165 }
166 166 return false;
167 167 };
168 168 return false;
169 169 };
170 170
171 171 CodeCell.prototype.remove_and_cancel_tooltip = function() {
172 172 // note that we don't handle closing directly inside the calltip
173 173 // as in the completer, because it is not focusable, so won't
174 174 // get the event.
175 175 if (this.tooltip_timeout != null){
176 176 clearTimeout(this.tooltip_timeout);
177 177 $('#tooltip').remove();
178 178 this.tooltip_timeout = null;
179 179 }
180 180 }
181 181
182 182 CodeCell.prototype.finish_tooltip = function (reply) {
183 183 // Extract call tip data; the priority is call, init, main.
184 184 defstring = reply.call_def;
185 185 if (defstring == null) { defstring = reply.init_definition; }
186 186 if (defstring == null) { defstring = reply.definition; }
187 187
188 188 docstring = reply.call_docstring;
189 189 if (docstring == null) { docstring = reply.init_docstring; }
190 190 if (docstring == null) { docstring = reply.docstring; }
191 191 if (docstring == null) { docstring = "<empty docstring>"; }
192 192
193 193 name=reply.name;
194 194
195 195 var that = this;
196 196 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
197 197 // remove to have the tooltip not Limited in X and Y
198 198 tooltip.addClass('smalltooltip');
199 199 var pre=$('<pre/>').html(utils.fixConsole(docstring));
200 200 var expandlink=$('<a/>').attr('href',"#");
201 201 expandlink.addClass("ui-corner-all"); //rounded corner
202 202 expandlink.attr('role',"button");
203 203 //expandlink.addClass('ui-button');
204 204 //expandlink.addClass('ui-state-default');
205 205 var expandspan=$('<span/>').text('Expand');
206 206 expandspan.addClass('ui-icon');
207 207 expandspan.addClass('ui-icon-plus');
208 208 expandlink.append(expandspan);
209 209 expandlink.attr('id','expanbutton');
210 210 expandlink.click(function(){
211 211 tooltip.removeClass('smalltooltip');
212 212 tooltip.addClass('bigtooltip');
213 213 $('#expanbutton').remove();
214 214 setTimeout(function(){that.code_mirror.focus();}, 50);
215 215 });
216 216 var morelink=$('<a/>').attr('href',"#");
217 217 morelink.attr('role',"button");
218 218 morelink.addClass('ui-button');
219 219 //morelink.addClass("ui-corner-all"); //rounded corner
220 220 //morelink.addClass('ui-state-default');
221 221 var morespan=$('<span/>').text('Open in Pager');
222 222 morespan.addClass('ui-icon');
223 223 morespan.addClass('ui-icon-arrowstop-l-n');
224 224 morelink.append(morespan);
225 225 morelink.click(function(){
226 226 var msg_id = IPython.notebook.kernel.execute(name+"?");
227 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.selected_cell().cell_id;
227 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
228 228 that.remove_and_cancel_tooltip();
229 229 setTimeout(function(){that.code_mirror.focus();}, 50);
230 230 });
231 231
232 232 var closelink=$('<a/>').attr('href',"#");
233 233 closelink.attr('role',"button");
234 234 closelink.addClass('ui-button');
235 235 //closelink.addClass("ui-corner-all"); //rounded corner
236 236 //closelink.adClass('ui-state-default'); // grey background and blue cross
237 237 var closespan=$('<span/>').text('Close');
238 238 closespan.addClass('ui-icon');
239 239 closespan.addClass('ui-icon-close');
240 240 closelink.append(closespan);
241 241 closelink.click(function(){
242 242 that.remove_and_cancel_tooltip();
243 243 setTimeout(function(){that.code_mirror.focus();}, 50);
244 244 });
245 245 //construct the tooltip
246 246 tooltip.append(closelink);
247 247 tooltip.append(expandlink);
248 248 tooltip.append(morelink);
249 249 if(defstring){
250 250 defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
251 251 tooltip.append(defstring_html);
252 252 }
253 253 tooltip.append(pre);
254 254 var pos = this.code_mirror.cursorCoords();
255 255 tooltip.css('left',pos.x+'px');
256 256 tooltip.css('top',pos.yBot+'px');
257 257 $('body').append(tooltip);
258 258
259 259 // issues with cross-closing if multiple tooltip in less than 5sec
260 260 // keep it comented for now
261 261 // setTimeout(that.remove_and_cancel_tooltip, 5000);
262 262 };
263 263
264 264 // As you type completer
265 265 CodeCell.prototype.finish_completing = function (matched_text, matches) {
266 266 //return if not completing or nothing to complete
267 267 if (!this.is_completing || matches.length === 0) {return;}
268 268
269 269 // for later readability
270 270 var key = { tab:9,
271 271 esc:27,
272 272 backspace:8,
273 273 space:32,
274 274 shift:16,
275 275 enter:13,
276 276 // _ is 95
277 277 isCompSymbol : function (code)
278 278 {
279 279 return (code > 64 && code <= 90)
280 280 || (code >= 97 && code <= 122)
281 281 || (code == 95)
282 282 },
283 283 dismissAndAppend : function (code)
284 284 {
285 285 chararr = '()[]+-/\\. ,=*'.split("");
286 286 codearr = chararr.map(function(x){return x.charCodeAt(0)});
287 287 return jQuery.inArray(code, codearr) != -1;
288 288 }
289 289
290 290 }
291 291
292 292 // smart completion, sort kwarg ending with '='
293 293 var newm = new Array();
294 294 if(this.notebook.smart_completer)
295 295 {
296 296 kwargs = new Array();
297 297 other = new Array();
298 298 for(var i = 0 ; i<matches.length ; ++i){
299 299 if(matches[i].substr(-1) === '='){
300 300 kwargs.push(matches[i]);
301 301 }else{other.push(matches[i]);}
302 302 }
303 303 newm = kwargs.concat(other);
304 304 matches = newm;
305 305 }
306 306 // end sort kwargs
307 307
308 308 // give common prefix of a array of string
309 309 function sharedStart(A){
310 310 if(A.length == 1){return A[0]}
311 311 if(A.length > 1 ){
312 312 var tem1, tem2, s, A = A.slice(0).sort();
313 313 tem1 = A[0];
314 314 s = tem1.length;
315 315 tem2 = A.pop();
316 316 while(s && tem2.indexOf(tem1) == -1){
317 317 tem1 = tem1.substring(0, --s);
318 318 }
319 319 return tem1;
320 320 }
321 321 return "";
322 322 }
323 323
324 324
325 325 //try to check if the user is typing tab at least twice after a word
326 326 // and completion is "done"
327 327 fallback_on_tooltip_after = 2
328 328 if(matches.length == 1 && matched_text === matches[0])
329 329 {
330 330 if(this.npressed >fallback_on_tooltip_after && this.prevmatch==matched_text)
331 331 {
332 332 this.request_tooltip_after_time(matched_text+'(',0);
333 333 return;
334 334 }
335 335 this.prevmatch = matched_text
336 336 this.npressed = this.npressed+1;
337 337 }
338 338 else
339 339 {
340 340 this.prevmatch = "";
341 341 this.npressed = 0;
342 342 }
343 343 // end fallback on tooltip
344 344 //==================================
345 345 // Real completion logic start here
346 346 var that = this;
347 347 var cur = this.completion_cursor;
348 348 var done = false;
349 349
350 350 // call to dismmiss the completer
351 351 var close = function () {
352 352 if (done) return;
353 353 done = true;
354 354 if (complete != undefined)
355 355 {complete.remove();}
356 356 that.is_completing = false;
357 357 that.completion_cursor = null;
358 358 };
359 359
360 360 // update codemirror with the typed text
361 361 prev = matched_text
362 362 var update = function (inserted_text, event) {
363 363 that.code_mirror.replaceRange(
364 364 inserted_text,
365 365 {line: cur.line, ch: (cur.ch-matched_text.length)},
366 366 {line: cur.line, ch: (cur.ch+prev.length-matched_text.length)}
367 367 );
368 368 prev = inserted_text
369 369 if(event != null){
370 370 event.stopPropagation();
371 371 event.preventDefault();
372 372 }
373 373 };
374 374 // insert the given text and exit the completer
375 375 var insert = function (selected_text, event) {
376 376 update(selected_text)
377 377 close();
378 378 setTimeout(function(){that.code_mirror.focus();}, 50);
379 379 };
380 380
381 381 // insert the curent highlited selection and exit
382 382 var pick = function () {
383 383 insert(select.val()[0],null);
384 384 };
385 385
386 386
387 387 // Define function to clear the completer, refill it with the new
388 388 // matches, update the pseuso typing field. autopick insert match if
389 389 // only one left, in no matches (anymore) dismiss itself by pasting
390 390 // what the user have typed until then
391 391 var complete_with = function(matches,typed_text,autopick,event)
392 392 {
393 393 // If autopick an only one match, past.
394 394 // Used to 'pick' when pressing tab
395 395 if (matches.length < 1) {
396 396 insert(typed_text,event);
397 397 if(event != null){
398 398 event.stopPropagation();
399 399 event.preventDefault();
400 400 }
401 401 } else if (autopick && matches.length == 1) {
402 402 insert(matches[0],event);
403 403 if(event != null){
404 404 event.stopPropagation();
405 405 event.preventDefault();
406 406 }
407 407 }
408 408 //clear the previous completion if any
409 409 update(typed_text,event);
410 410 complete.children().children().remove();
411 411 $('#asyoutype').html("<b>"+matched_text+"</b>"+typed_text.substr(matched_text.length));
412 412 select = $('#asyoutypeselect');
413 413 for (var i = 0; i<matches.length; ++i) {
414 414 select.append($('<option/>').html(matches[i]));
415 415 }
416 416 select.children().first().attr('selected','true');
417 417 }
418 418
419 419 // create html for completer
420 420 var complete = $('<div/>').addClass('completions');
421 421 complete.attr('id','complete');
422 422 complete.append($('<p/>').attr('id', 'asyoutype').html('<b>fixed part</b>user part'));//pseudo input field
423 423
424 424 var select = $('<select/>').attr('multiple','true');
425 425 select.attr('id', 'asyoutypeselect')
426 426 select.attr('size',Math.min(10,matches.length));
427 427 var pos = this.code_mirror.cursorCoords();
428 428
429 429 // TODO: I propose to remove enough horizontal pixel
430 430 // to align the text later
431 431 complete.css('left',pos.x+'px');
432 432 complete.css('top',pos.yBot+'px');
433 433 complete.append(select);
434 434
435 435 $('body').append(complete);
436 436
437 437 // So a first actual completion. see if all the completion start wit
438 438 // the same letter and complete if necessary
439 439 fastForward = sharedStart(matches)
440 440 typed_characters = fastForward.substr(matched_text.length);
441 441 complete_with(matches,matched_text+typed_characters,true,null);
442 442 filterd = matches;
443 443 // Give focus to select, and make it filter the match as the user type
444 444 // by filtering the previous matches. Called by .keypress and .keydown
445 445 var downandpress = function (event,press_or_down) {
446 446 var code = event.which;
447 447 var autopick = false; // auto 'pick' if only one match
448 448 if (press_or_down === 0){
449 449 press = true; down = false; //Are we called from keypress or keydown
450 450 } else if (press_or_down == 1){
451 451 press = false; down = true;
452 452 }
453 453 if (code === key.shift) {
454 454 // nothing on Shift
455 455 return;
456 456 }
457 457 if (key.dismissAndAppend(code) && press) {
458 458 var newchar = String.fromCharCode(code);
459 459 typed_characters = typed_characters+newchar;
460 460 insert(matched_text+typed_characters,event);
461 461 return
462 462 }
463 463 if (code === key.enter) {
464 464 // Pressing ENTER will cause a pick
465 465 event.stopPropagation();
466 466 event.preventDefault();
467 467 pick();
468 468 } else if (code === 38 || code === 40) {
469 469 // We don't want the document keydown handler to handle UP/DOWN,
470 470 // but we want the default action.
471 471 event.stopPropagation();
472 472 } else if ( (code == key.backspace)||(code == key.tab && down) || press || key.isCompSymbol(code)){
473 473 if( key.isCompSymbol(code) && press)
474 474 {
475 475 var newchar = String.fromCharCode(code);
476 476 typed_characters = typed_characters+newchar;
477 477 } else if (code == key.tab) {
478 478 fastForward = sharedStart(filterd)
479 479 ffsub = fastForward.substr(matched_text.length+typed_characters.length);
480 480 typed_characters = typed_characters+ffsub;
481 481 autopick = true;
482 482 } else if (code == key.backspace && down) {
483 483 // cancel if user have erase everything, otherwise decrease
484 484 // what we filter with
485 485 event.preventDefault();
486 486 if (typed_characters.length <= 0)
487 487 {
488 488 insert(matched_text,event)
489 489 return
490 490 }
491 491 typed_characters = typed_characters.substr(0,typed_characters.length-1);
492 492 } else if (press && code != key.backspace && code != key.tab && code != 0){
493 493 insert(matched_text+typed_characters,event);
494 494 return
495 495 } else {
496 496 return
497 497 }
498 498 re = new RegExp("^"+"\%?"+matched_text+typed_characters,"");
499 499 filterd = matches.filter(function(x){return re.test(x)});
500 500 complete_with(filterd,matched_text+typed_characters,autopick,event);
501 501 } else if (code == key.esc) {
502 502 // dismiss the completer and go back to before invoking it
503 503 insert(matched_text,event);
504 504 } else if (press) { // abort only on .keypress or esc
505 505 }
506 506 }
507 507 select.keydown(function (event) {
508 508 downandpress(event,1)
509 509 });
510 510 select.keypress(function (event) {
511 511 downandpress(event,0)
512 512 });
513 513 // Double click also causes a pick.
514 514 // and bind the last actions.
515 515 select.dblclick(pick);
516 516 select.blur(close);
517 517 select.focus();
518 518 };
519 519
520 520
521 521 CodeCell.prototype.toggle_line_numbers = function () {
522 522 if (this.code_mirror.getOption('lineNumbers') == false) {
523 523 this.code_mirror.setOption('lineNumbers', true);
524 524 } else {
525 525 this.code_mirror.setOption('lineNumbers', false);
526 526 }
527 527 this.code_mirror.refresh();
528 528 };
529 529
530 530
531 531 CodeCell.prototype.select = function () {
532 532 IPython.Cell.prototype.select.apply(this);
533 533 // In some cases (inserting a new cell) we need a refresh before and
534 534 // after the focus. Not sure why this is the case.
535 535 this.code_mirror.refresh();
536 536 this.code_mirror.focus();
537 537 this.code_mirror.refresh();
538 538 };
539 539
540 540
541 541 CodeCell.prototype.select_all = function () {
542 542 var start = {line: 0, ch: 0};
543 543 var nlines = this.code_mirror.lineCount();
544 544 var last_line = this.code_mirror.getLine(nlines-1);
545 545 var end = {line: nlines-1, ch: last_line.length};
546 546 this.code_mirror.setSelection(start, end);
547 547 };
548 548
549 549
550 550 CodeCell.prototype.append_output = function (json) {
551 551 this.expand();
552 552 if (json.output_type === 'pyout') {
553 553 this.append_pyout(json);
554 554 } else if (json.output_type === 'pyerr') {
555 555 this.append_pyerr(json);
556 556 } else if (json.output_type === 'display_data') {
557 557 this.append_display_data(json);
558 558 } else if (json.output_type === 'stream') {
559 559 this.append_stream(json);
560 560 };
561 561 this.outputs.push(json);
562 562 };
563 563
564 564
565 565 CodeCell.prototype.create_output_area = function () {
566 566 var oa = $("<div/>").addClass("hbox output_area");
567 567 oa.append($('<div/>').addClass('prompt'));
568 568 return oa;
569 569 };
570 570
571 571
572 572 CodeCell.prototype.append_pyout = function (json) {
573 573 n = json.prompt_number || ' ';
574 574 var toinsert = this.create_output_area();
575 575 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
576 576 this.append_mime_type(json, toinsert);
577 577 this.element.find('div.output').append(toinsert);
578 578 // If we just output latex, typeset it.
579 579 if ((json.latex !== undefined) || (json.html !== undefined)) {
580 580 this.typeset();
581 581 };
582 582 };
583 583
584 584
585 585 CodeCell.prototype.append_pyerr = function (json) {
586 586 var tb = json.traceback;
587 587 if (tb !== undefined && tb.length > 0) {
588 588 var s = '';
589 589 var len = tb.length;
590 590 for (var i=0; i<len; i++) {
591 591 s = s + tb[i] + '\n';
592 592 }
593 593 s = s + '\n';
594 594 var toinsert = this.create_output_area();
595 595 this.append_text(s, toinsert);
596 596 this.element.find('div.output').append(toinsert);
597 597 };
598 598 };
599 599
600 600
601 601 CodeCell.prototype.append_stream = function (json) {
602 602 // temporary fix: if stream undefined (json file written prior to this patch),
603 603 // default to most likely stdout:
604 604 if (json.stream == undefined){
605 605 json.stream = 'stdout';
606 606 }
607 607 var subclass = "output_"+json.stream;
608 608 if (this.outputs.length > 0){
609 609 // have at least one output to consider
610 610 var last = this.outputs[this.outputs.length-1];
611 611 if (last.output_type == 'stream' && json.stream == last.stream){
612 612 // latest output was in the same stream,
613 613 // so append directly into its pre tag
614 614 this.element.find('div.'+subclass).last().find('pre').append(json.text);
615 615 return;
616 616 }
617 617 }
618 618
619 619 // If we got here, attach a new div
620 620 var toinsert = this.create_output_area();
621 621 this.append_text(json.text, toinsert, "output_stream "+subclass);
622 622 this.element.find('div.output').append(toinsert);
623 623 };
624 624
625 625
626 626 CodeCell.prototype.append_display_data = function (json) {
627 627 var toinsert = this.create_output_area();
628 628 this.append_mime_type(json, toinsert);
629 629 this.element.find('div.output').append(toinsert);
630 630 // If we just output latex, typeset it.
631 631 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
632 632 this.typeset();
633 633 };
634 634 };
635 635
636 636
637 637 CodeCell.prototype.append_mime_type = function (json, element) {
638 638 if (json.html !== undefined) {
639 639 this.append_html(json.html, element);
640 640 } else if (json.latex !== undefined) {
641 641 this.append_latex(json.latex, element);
642 642 } else if (json.svg !== undefined) {
643 643 this.append_svg(json.svg, element);
644 644 } else if (json.png !== undefined) {
645 645 this.append_png(json.png, element);
646 646 } else if (json.jpeg !== undefined) {
647 647 this.append_jpeg(json.jpeg, element);
648 648 } else if (json.text !== undefined) {
649 649 this.append_text(json.text, element);
650 650 };
651 651 };
652 652
653 653
654 654 CodeCell.prototype.append_html = function (html, element) {
655 655 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
656 656 toinsert.append(html);
657 657 element.append(toinsert);
658 658 };
659 659
660 660
661 661 CodeCell.prototype.append_text = function (data, element, extra_class) {
662 662 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
663 663 if (extra_class){
664 664 toinsert.addClass(extra_class);
665 665 }
666 666 toinsert.append($("<pre/>").html(data));
667 667 element.append(toinsert);
668 668 };
669 669
670 670
671 671 CodeCell.prototype.append_svg = function (svg, element) {
672 672 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
673 673 toinsert.append(svg);
674 674 element.append(toinsert);
675 675 };
676 676
677 677
678 678 CodeCell.prototype.append_png = function (png, element) {
679 679 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
680 680 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
681 681 element.append(toinsert);
682 682 };
683 683
684 684
685 685 CodeCell.prototype.append_jpeg = function (jpeg, element) {
686 686 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
687 687 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
688 688 element.append(toinsert);
689 689 };
690 690
691 691
692 692 CodeCell.prototype.append_latex = function (latex, element) {
693 693 // This method cannot do the typesetting because the latex first has to
694 694 // be on the page.
695 695 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
696 696 toinsert.append(latex);
697 697 element.append(toinsert);
698 698 };
699 699
700 700
701 701 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
702 702 var output_div = this.element.find("div.output");
703 703 if (stdout && stderr && other){
704 704 // clear all, no need for logic
705 705 output_div.html("");
706 706 this.outputs = [];
707 707 return;
708 708 }
709 709 // remove html output
710 710 // each output_subarea that has an identifying class is in an output_area
711 711 // which is the element to be removed.
712 712 if (stdout){
713 713 output_div.find("div.output_stdout").parent().remove();
714 714 }
715 715 if (stderr){
716 716 output_div.find("div.output_stderr").parent().remove();
717 717 }
718 718 if (other){
719 719 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
720 720 }
721 721
722 722 // remove cleared outputs from JSON list:
723 723 for (var i = this.outputs.length - 1; i >= 0; i--){
724 724 var out = this.outputs[i];
725 725 var output_type = out.output_type;
726 726 if (output_type == "display_data" && other){
727 727 this.outputs.splice(i,1);
728 728 }else if (output_type == "stream"){
729 729 if (stdout && out.stream == "stdout"){
730 730 this.outputs.splice(i,1);
731 731 }else if (stderr && out.stream == "stderr"){
732 732 this.outputs.splice(i,1);
733 733 }
734 734 }
735 735 }
736 736 };
737 737
738 738
739 739 CodeCell.prototype.clear_input = function () {
740 740 this.code_mirror.setValue('');
741 741 };
742 742
743 743
744 744 CodeCell.prototype.collapse = function () {
745 745 if (!this.collapsed) {
746 746 this.element.find('div.output').hide();
747 747 this.collapsed = true;
748 748 };
749 749 };
750 750
751 751
752 752 CodeCell.prototype.expand = function () {
753 753 if (this.collapsed) {
754 754 this.element.find('div.output').show();
755 755 this.collapsed = false;
756 756 };
757 757 };
758 758
759 759
760 760 CodeCell.prototype.toggle_output = function () {
761 761 if (this.collapsed) {
762 762 this.expand();
763 763 } else {
764 764 this.collapse();
765 765 };
766 766 };
767 767
768 768 CodeCell.prototype.set_input_prompt = function (number) {
769 769 var n = number || '&nbsp;';
770 770 this.input_prompt_number = n;
771 771 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
772 772 };
773 773
774 774
775 775 CodeCell.prototype.get_text = function () {
776 776 return this.code_mirror.getValue();
777 777 };
778 778
779 779
780 780 CodeCell.prototype.set_text = function (code) {
781 781 return this.code_mirror.setValue(code);
782 782 };
783 783
784 784
785 785 CodeCell.prototype.at_top = function () {
786 786 var cursor = this.code_mirror.getCursor();
787 787 if (cursor.line === 0) {
788 788 return true;
789 789 } else {
790 790 return false;
791 791 }
792 792 };
793 793
794 794
795 795 CodeCell.prototype.at_bottom = function () {
796 796 var cursor = this.code_mirror.getCursor();
797 797 if (cursor.line === (this.code_mirror.lineCount()-1)) {
798 798 return true;
799 799 } else {
800 800 return false;
801 801 }
802 802 };
803 803
804 804
805 805 CodeCell.prototype.fromJSON = function (data) {
806 806 if (data.cell_type === 'code') {
807 807 if (data.input !== undefined) {
808 808 this.set_text(data.input);
809 809 }
810 810 if (data.prompt_number !== undefined) {
811 811 this.set_input_prompt(data.prompt_number);
812 812 } else {
813 813 this.set_input_prompt();
814 814 };
815 815 var len = data.outputs.length;
816 816 for (var i=0; i<len; i++) {
817 817 this.append_output(data.outputs[i]);
818 818 };
819 819 if (data.collapsed !== undefined) {
820 820 if (data.collapsed) {
821 821 this.collapse();
822 822 };
823 823 };
824 824 };
825 825 };
826 826
827 827
828 828 CodeCell.prototype.toJSON = function () {
829 829 var data = {};
830 830 data.input = this.get_text();
831 831 data.cell_type = 'code';
832 832 if (this.input_prompt_number !== ' ') {
833 833 data.prompt_number = this.input_prompt_number;
834 834 };
835 835 var outputs = [];
836 836 var len = this.outputs.length;
837 837 for (var i=0; i<len; i++) {
838 838 outputs[i] = this.outputs[i];
839 839 };
840 840 data.outputs = outputs;
841 841 data.language = 'python';
842 842 data.collapsed = this.collapsed;
843 843 return data;
844 844 };
845 845
846 846
847 847 IPython.CodeCell = CodeCell;
848 848
849 849 return IPython;
850 850 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now