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