diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css index 22458a7..924a6c1 100644 --- a/IPython/frontend/html/notebook/static/css/notebook.css +++ b/IPython/frontend/html/notebook/static/css/notebook.css @@ -115,6 +115,18 @@ span.section_row_buttons a { float: right; } +#timebeforetooltip_span { + float: right; +} + +#tooltipontab_span { + float: right; +} + +#smartcompleter_span { + float: right; +} + .checkbox_label { font-size: 85%; float: right; @@ -321,7 +333,7 @@ div.text_cell_render { .ansigrey {color: grey;} .ansibold {font-weight: bold;} -.completions { +.completions , .tooltip{ position: absolute; z-index: 10; overflow: auto; @@ -337,6 +349,63 @@ div.text_cell_render { font-family: monospace; } +@-moz-keyframes fadeIn { + from {opacity:0;} + to {opacity:1;} +} + +@-webkit-keyframes fadeIn { + from {opacity:0;} + to {opacity:1;} +} + +@keyframes fadeIn { + from {opacity:0;} + to {opacity:1;} +} + +/*"close" "expand" and "Open in pager button" of +/* the tooltip*/ +.tooltip a{ + float:right; +} + +/*properties of tooltip after "expand"*/ +.bigtooltip{ + height:60%; +} + +/*properties of tooltip before "expand"*/ +.smalltooltip{ + text-overflow: ellipsis; + overflow: hidden; + height:15%; +} + +.tooltip{ + /*transition when "expand"ing tooltip */ + -webkit-transition-property: height; + -webkit-transition-duration: 1s; + -moz-transition-property: height; + -moz-transition-duration: 1s; + transition-property: height; + transition-duration: 1s; + max-width:700px; + border-radius: 0px 10px 10px 10px; + box-shadow: 3px 3px 5px #999; + /*fade-in animation when inserted*/ + -webkit-animation: fadeIn 200ms; + -moz-animation: fadeIn 200ms; + animation: fadeIn 200ms; + vertical-align: middle; + background: #FDFDD8; + outline: none; + padding: 3px; + margin: 0px; + font-family: monospace; + min-height:50px; +} + @media print { body { overflow: visible !important; } .ui-widget-content { border: 0px; } diff --git a/IPython/frontend/html/notebook/static/js/cell.js b/IPython/frontend/html/notebook/static/js/cell.js index 2d86c62..b186bd8 100644 --- a/IPython/frontend/html/notebook/static/js/cell.js +++ b/IPython/frontend/html/notebook/static/js/cell.js @@ -85,7 +85,6 @@ var IPython = (function (IPython) { } }; - // Subclasses must implement create_element. Cell.prototype.create_element = function () {}; diff --git a/IPython/frontend/html/notebook/static/js/codecell.js b/IPython/frontend/html/notebook/static/js/codecell.js index 62534e5..dcd81a3 100644 --- a/IPython/frontend/html/notebook/static/js/codecell.js +++ b/IPython/frontend/html/notebook/static/js/codecell.js @@ -47,24 +47,60 @@ var IPython = (function (IPython) { 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' && this.tooltip_timeout != null){ + CodeCell.prototype.remove_and_cancell_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(); - var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim(); - if (pre_cursor === "") { + //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); @@ -108,11 +144,130 @@ var IPython = (function (IPython) { }; }; + CodeCell.prototype.remove_and_cancell_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. + 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);
+    };
+
 
     CodeCell.prototype.finish_completing = function (matched_text, matches) {
         // console.log("Got matches", matched_text, matches);
+        var newm = new Array();
+        if(this.notebook.smart_completer)
+        {
+            kwargs = new Array();
+            other = new Array();
+            for(var i=0;i after "(" or a white space');
+        this.content.find('#tooltipontab_label').attr('title', 'Show Tooltip when pressing Tab');
+
+        this.content.find('#timebeforetooltip').attr('title', 'Time before a tooltip auto-appear when "(" is pressed (negative value supress tooltip)');
+        this.content.find('#timebeforetooltip_label').attr('title', 'Time before a tooltip auto-appear when "(" is pressed (negative value supress tooltip)');
+
+        this.content.find('#smartcompleter').attr('title', 'When inside function call, completer try to propose kwargs first');
+        this.content.find('#smartcompleter_label').attr('title', 'When inside function call, completer try to propose kwargs first');
+    };
+
+
+    ConfigSection.prototype.bind_events = function () {
+        PanelSection.prototype.bind_events.apply(this);
+        this.content.find('#tooltipontab').change(function () {
+            var state = $('#tooltipontab').prop('checked');
+            IPython.notebook.set_tooltipontab(state);
+        });
+        this.content.find('#timebeforetooltip').change(function () {
+            var state = $('#timebeforetooltip').prop('value');
+            IPython.notebook.set_timebeforetooltip(state);
+        });
+        this.content.find('#smartcompleter').change(function () {
+            var state = $('#smartcompleter').prop('checked');
+            IPython.notebook.set_smartcompleter(state);
+        });
+    };
+
     // CellSection
 
     var CellSection = function () {
         PanelSection.apply(this, arguments);
     };
 
-
     CellSection.prototype = new PanelSection();
 
 
@@ -201,6 +240,10 @@ var IPython = (function (IPython) {
             var state = $('#autoindent').prop('checked');
             IPython.notebook.set_autoindent(state);
         });
+        this.content.find('#tooltipontab').change(function () {
+            var state = $('#tooltipontab').prop('checked');
+            IPython.notebook.set_tooltipontab(state);
+        });
     };
 
 
@@ -280,6 +323,7 @@ var IPython = (function (IPython) {
     IPython.PanelSection = PanelSection;
     IPython.NotebookSection = NotebookSection;
     IPython.CellSection = CellSection;
+    IPython.ConfigSection = ConfigSection;
     IPython.KernelSection = KernelSection;
     IPython.HelpSection = HelpSection;
 
diff --git a/IPython/frontend/html/notebook/templates/notebook.html b/IPython/frontend/html/notebook/templates/notebook.html
index e2fdc3b..0655e5b 100644
--- a/IPython/frontend/html/notebook/templates/notebook.html
+++ b/IPython/frontend/html/notebook/templates/notebook.html
@@ -251,6 +251,32 @@
             
+
+
+

Config

+
+
+
+ + + + Tooltip on tab: +
+
+ + + + Smart completer: +
+
+ + + + Time before tooltip : +
+
+
+