//---------------------------------------------------------------------------- // Copyright (C) 2008-2011 The IPython Development Team // // Distributed under the terms of the BSD License. The full license is in // the file COPYING, distributed as part of this software. //---------------------------------------------------------------------------- //============================================================================ // CodeCell //============================================================================ var IPython = (function (IPython) { var utils = IPython.utils; var CodeCell = function (notebook) { this.code_mirror = null; this.input_prompt_number = ' '; this.is_completing = false; this.completion_cursor = null; this.outputs = []; this.collapsed = false; IPython.Cell.apply(this, arguments); }; CodeCell.prototype = new IPython.Cell(); CodeCell.prototype.create_element = function () { var cell = $('
').addClass('cell border-box-sizing code_cell vbox'); cell.attr('tabindex','2'); var input = $('
').addClass('input hbox'); input.append($('
').addClass('prompt input_prompt')); var input_area = $('
').addClass('input_area box-flex1'); this.code_mirror = CodeMirror(input_area.get(0), { indentUnit : 4, mode: 'python', theme: 'ipython', readOnly: this.read_only, onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) }); input.append(input_area); var output = $('
').addClass('output vbox'); cell.append(input).append(output); this.element = cell; this.collapse(); }; //TODO, try to diminish the number of parameters. CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time,that){ if (pre_cursor === "" || pre_cursor === "(" ) { // don't do anything if line beggin with '(' or is empty } else { // Will set a timer to request tooltip in `time` that.tooltip_timeout = setTimeout(function(){ IPython.notebook.request_tool_tip(that, pre_cursor) },time); } }; CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { // This method gets called in CodeMirror's onKeyDown/onKeyPress // handlers and is used to provide custom key handling. Its return // value is used to determine if CodeMirror should ignore the event: // true = ignore, false = don't ignore. // note that we are comparing and setting the time to wait at each key press. // a better wqy might be to generate a new function on each time change and // assign it to CodeCell.prototype.request_tooltip_after_time tooltip_wait_time = this.notebook.time_before_tooltip; tooltip_on_tab = this.notebook.tooltip_on_tab; var that = this; // whatever key is pressed, first, cancel the tooltip request before // they are sent, and remove tooltip if any if(event.type === 'keydown' ){ CodeCell.prototype.remove_and_cancel_tooltip(that.tooltip_timeout); that.tooltip_timeout=null; } if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) { // Always ignore shift-enter in CodeMirror as we handle it. return true; }else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) { // triger aon keypress (!) otherwise inconsistent event.which depending on plateform // browser and keyboard layout ! // Pressing '(' , request tooltip, don't forget to reappend it var cursor = editor.getCursor(); var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'('; CodeCell.prototype.request_tooltip_after_time(pre_cursor,tooltip_wait_time,that); } else if (event.keyCode === 9 && event.type == 'keydown') { // Tab completion. var cur = editor.getCursor(); //Do not trim here because of tooltip var pre_cursor = editor.getRange({line:cur.line,ch:0},cur); if (pre_cursor.trim() === "") { // Don't autocomplete if the part of the line before the cursor // is empty. In this case, let CodeMirror handle indentation. return false; } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) { CodeCell.prototype.request_tooltip_after_time(pre_cursor,0,that); } else { pre_cursor.trim(); // Autocomplete the current line. event.stop(); var line = editor.getLine(cur.line); this.is_completing = true; this.completion_cursor = cur; IPython.notebook.complete_cell(this, line, cur.ch); return true; } } else if (event.keyCode === 8 && event.type == 'keydown') { // If backspace and the line ends with 4 spaces, remove them. var cur = editor.getCursor(); var line = editor.getLine(cur.line); var ending = line.slice(-4); if (ending === ' ') { editor.replaceRange('', {line: cur.line, ch: cur.ch-4}, {line: cur.line, ch: cur.ch} ); event.stop(); return true; } else { return false; } } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey && event.type == 'keydown') { // toggle line numbers with Ctrl-Shift-L this.toggle_line_numbers(); } else { // keypress/keyup also trigger on TAB press, and we don't want to // use those to disable tab completion. if (this.is_completing && event.keyCode !== 9) { var ed_cur = editor.getCursor(); var cc_cur = this.completion_cursor; if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) { this.is_completing = false; this.completion_cursor = null; } } return false; }; return false; }; CodeCell.prototype.remove_and_cancel_tooltip = function(timeout) { // note that we don't handle closing directly inside the calltip // as in the completer, because it is not focusable, so won't // get the event. if(timeout != null) { clearTimeout(timeout);} $('#tooltip').remove(); } CodeCell.prototype.finish_tooltip = function (reply) { defstring=reply.definition; docstring=reply.docstring; if(docstring == null){docstring=""}; name=reply.name; var that = this; var tooltip = $('
').attr('id', 'tooltip').addClass('tooltip'); // remove to have the tooltip not Limited in X and Y tooltip.addClass('smalltooltip'); var pre=$('
').html(utils.fixConsole(docstring));
        var expandlink=$('').attr('href',"#");
            expandlink.addClass("ui-corner-all"); //rounded corner
            expandlink.attr('role',"button");
            //expandlink.addClass('ui-button');
            //expandlink.addClass('ui-state-default');
        var expandspan=$('').text('Expand');
            expandspan.addClass('ui-icon');
            expandspan.addClass('ui-icon-plus');
        expandlink.append(expandspan);
        expandlink.attr('id','expanbutton');
        expandlink.click(function(){
            tooltip.removeClass('smalltooltip');
            tooltip.addClass('bigtooltip');
            $('#expanbutton').remove();
            setTimeout(function(){that.code_mirror.focus();}, 50);
        });
        var morelink=$('').attr('href',"#");
            morelink.attr('role',"button");
            morelink.addClass('ui-button');
            //morelink.addClass("ui-corner-all"); //rounded corner
            //morelink.addClass('ui-state-default');
        var morespan=$('').text('Open in Pager');
            morespan.addClass('ui-icon');
            morespan.addClass('ui-icon-arrowstop-l-n');
        morelink.append(morespan);
        morelink.click(function(){
            var msg_id = IPython.notebook.kernel.execute(name+"?");
            IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.selected_cell().cell_id;
            CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
            setTimeout(function(){that.code_mirror.focus();}, 50);
        });

        var closelink=$('').attr('href',"#");
            closelink.attr('role',"button");
            closelink.addClass('ui-button');
            //closelink.addClass("ui-corner-all"); //rounded corner
            //closelink.adClass('ui-state-default'); // grey background and blue cross
        var closespan=$('').text('Close');
            closespan.addClass('ui-icon');
            closespan.addClass('ui-icon-close');
        closelink.append(closespan);
        closelink.click(function(){
            CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
            setTimeout(function(){that.code_mirror.focus();}, 50);
            });
        //construct the tooltip
        tooltip.append(closelink);
        tooltip.append(expandlink);
        tooltip.append(morelink);
        if(defstring){
            defstring_html= $('
').html(utils.fixConsole(defstring));
            tooltip.append(defstring_html);
        }
        tooltip.append(pre);
        var pos = this.code_mirror.cursorCoords();
        tooltip.css('left',pos.x+'px');
        tooltip.css('top',pos.yBot+'px');
        $('body').append(tooltip);

        // issues with cross-closing if multiple tooltip in less than 5sec
        // keep it comented for now
        // setTimeout(CodeCell.prototype.remove_and_cancell_tooltip, 5000);
    };

    // As you type completer
    CodeCell.prototype.finish_completing = function (matched_text, matches) {
        //return if not completing or nothing to complete
        if (!this.is_completing || matches.length === 0) {return;}

        // for later readability
        var key = { tab:9,
                    esc:27,
                    backspace:8,
                    space:13,
                    shift:16,
                    enter:32,
                    // _ is 189
                    isCompSymbol : function (code)
                        {return ((code>64 && code <=122)|| code == 189)}
                    }

        // smart completion, sort kwarg ending with '='
        var newm = new Array();
        if(this.notebook.smart_completer)
        {
            kwargs = new Array();
            other = new Array();
            for(var i=0;i').html(matches[i]));
            }
            select.children().first().attr('selected','true');
        }

        // create html for completer
        var complete = $('
').addClass('completions'); complete.attr('id','complete'); complete.append($('

').attr('id', 'asyoutype').html(matched_text));//pseudo input field var select = $('