~ubuntu-branches/ubuntu/trusty/qiime/trusty

« back to all changes in this revision

Viewing changes to web/home_static/nih-cloud-apr2012/Timing_files/codecell.js

  • Committer: Package Import Robot
  • Author(s): Andreas Tille
  • Date: 2013-06-17 18:28:26 UTC
  • mfrom: (9.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20130617182826-376az5ad080a0sfe
Tags: 1.7.0+dfsg-1
Upload preparations done for BioLinux to Debian

Show diffs side-by-side

added added

removed removed

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