##// END OF EJS Templates
clean and comment tooltip file
Matthias BUSSONNIER -
Show More
@@ -1,301 +1,297 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Tooltip
9 // Tooltip
10 //============================================================================
10 //============================================================================
11
12 // Todo :
13 // use codemirror highlight example to
14 // highlight the introspection request and introspect on mouse hove ...
15 //
16 //
11 //
12 // you can set the autocall time by setting `IPython.notebook.time_before_tooltip` in ms
13
17 var IPython = (function (IPython) {
14 var IPython = (function (IPython) {
18
15
19 var utils = IPython.utils;
16 var utils = IPython.utils;
20
17
18 // tooltip constructor
21 var Tooltip = function (notebook) {
19 var Tooltip = function (notebook) {
22 this.tooltip = $('#tooltip');
23 var that = this;
20 var that = this;
21
22 // handle to html
23 this.tooltip = $('#tooltip');
24 var tooltip = this.tooltip;
24 this._hidden = true;
25 this._hidden = true;
25
26
26 // variable for consecutive call
27 // variable for consecutive call
27 this._old_cell = null ;
28 this._old_cell = null ;
28 this._old_request = null ;
29 this._old_request = null ;
29 this._consecutive_conter = 0;
30 this._consecutive_conter = 0;
30
31
31 // 'sticky ?'
32 // 'sticky ?'
32 this._sticky = false;
33 this._sticky = false;
33
34
34 // contain the button in the upper right corner
35 // contain the button in the upper right corner
35 this.buttons = $('<div/>')
36 this.buttons = $('<div/>')
36 .addClass('tooltipbuttons');
37 .addClass('tooltipbuttons');
37
38
38 // will contain the docstring
39 // will contain the docstring
39 this.text = $('<div/>')
40 this.text = $('<div/>')
40 .addClass('tooltiptext')
41 .addClass('tooltiptext')
41 .addClass('smalltooltip');
42 .addClass('smalltooltip');
42
43 var tooltip = this.tooltip;
44
43
45 // build the buttons menu on the upper right
44 // build the buttons menu on the upper right
46
45
47 // expand the tooltip to see more
46 // expand the tooltip to see more
48 var expandlink=$('<a/>').attr('href',"#")
47 var expandlink=$('<a/>').attr('href',"#")
49 .addClass("ui-corner-all") //rounded corner
48 .addClass("ui-corner-all") //rounded corner
50 .attr('role',"button")
49 .attr('role',"button")
51 .attr('id','expanbutton')
50 .attr('id','expanbutton')
52 .click(function(){that.expand()})
51 .click(function(){that.expand()})
53 .append(
52 .append(
54 $('<span/>').text('Expand')
53 $('<span/>').text('Expand')
55 .addClass('ui-icon')
54 .addClass('ui-icon')
56 .addClass('ui-icon-plus')
55 .addClass('ui-icon-plus')
57 );
56 );
58
57
59 // open in pager
58 // open in pager
60 var morelink=$('<a/>').attr('href',"#")
59 var morelink=$('<a/>').attr('href',"#")
61 .attr('role',"button")
60 .attr('role',"button")
62 .addClass('ui-button');
61 .addClass('ui-button');
63 var morespan=$('<span/>').text('Open in Pager')
62 var morespan=$('<span/>').text('Open in Pager')
64 .addClass('ui-icon')
63 .addClass('ui-icon')
65 .addClass('ui-icon-arrowstop-l-n');
64 .addClass('ui-icon-arrowstop-l-n');
66 morelink.append(morespan);
65 morelink.append(morespan);
67 morelink.click(function(){
66 morelink.click(function(){
68 that.showInPager();
67 that.showInPager();
69 });
68 });
70
69
71 // close the tooltip
70 // close the tooltip
72 var closelink=$('<a/>').attr('href',"#");
71 var closelink=$('<a/>').attr('href',"#");
73 closelink.attr('role',"button");
72 closelink.attr('role',"button");
74 closelink.addClass('ui-button');
73 closelink.addClass('ui-button');
75 var closespan=$('<span/>').text('Close');
74 var closespan=$('<span/>').text('Close');
76 closespan.addClass('ui-icon');
75 closespan.addClass('ui-icon');
77 closespan.addClass('ui-icon-close');
76 closespan.addClass('ui-icon-close');
78 closelink.append(closespan);
77 closelink.append(closespan);
79 closelink.click(function(){
78 closelink.click(function(){
80 that.remove_and_cancel_tooltip(true);
79 that.remove_and_cancel_tooltip(true);
81 });
80 });
82
81
83 //construct the tooltip
82 //construct the tooltip
84 // add in the reverse order you want them to appear
83 // add in the reverse order you want them to appear
85 this.buttons.append(closelink);
84 this.buttons.append(closelink);
86 this.buttons.append(expandlink);
85 this.buttons.append(expandlink);
87 this.buttons.append(morelink);
86 this.buttons.append(morelink);
88
87
89 // we need a phony element to make the small arrow
88 // we need a phony element to make the small arrow
90 // of the tooltip in css
89 // of the tooltip in css
91 // we could try to move the arrow later
90 // we will move the arrow later
92 this.arrow = $('<div/>').addClass('pretooltiparrow');
91 this.arrow = $('<div/>').addClass('pretooltiparrow');
93 this.tooltip.append(this.buttons);
92 this.tooltip.append(this.buttons);
94 this.tooltip.append(this.arrow);
93 this.tooltip.append(this.arrow);
95 this.tooltip.append(this.text);
94 this.tooltip.append(this.text);
96 };
95 };
97
96
97 // will resend the request on behalf on the cell which invoked the tooltip
98 // to show in it in pager. This is done so to be sure of having the same
99 // result as invoking `something?`
98 Tooltip.prototype.showInPager = function()
100 Tooltip.prototype.showInPager = function()
99 {
101 {
100 var msg_id = IPython.notebook.kernel.execute(that.name+"?");
102 var msg_id = IPython.notebook.kernel.execute(that.name+"?");
101 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
103 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
102 this.remove_and_cancel_tooltip();
104 this.remove_and_cancel_tooltip();
103 this._cmfocus();
105 this._cmfocus();
104 }
106 }
105
107
106
108 // grow the tooltip verticaly
107 Tooltip.prototype.expand = function(){
109 Tooltip.prototype.expand = function(){
108 this.text.removeClass('smalltooltip');
110 this.text.removeClass('smalltooltip');
109 this.text.addClass('bigtooltip');
111 this.text.addClass('bigtooltip');
110 $('#expanbutton').addClass('hidden');
112 $('#expanbutton').addClass('hidden');
111 this._cmfocus();
113 this._cmfocus();
112 }
114 }
113
115
114 // deal with all the logic of hiding the tooltip
116 // deal with all the logic of hiding the tooltip
115 // and reset it's status
117 // and reset it's status
116 Tooltip.prototype.hide = function()
118 Tooltip.prototype.hide = function()
117 {
119 {
118 this.tooltip.addClass('hide');
120 this.tooltip.addClass('hide');
119 $('#expanbutton').removeClass('hidden');
121 $('#expanbutton').removeClass('hidden');
120 this.text.removeClass('bigtooltip');
122 this.text.removeClass('bigtooltip');
121 this.text.addClass('smalltooltip');
123 this.text.addClass('smalltooltip');
122 // keep scroll top to be sure to always see the first line
124 // keep scroll top to be sure to always see the first line
123 this.text.scrollTop(0);
125 this.text.scrollTop(0);
124 this._hidden = true;
126 this._hidden = true;
125 }
127 }
126
128
127 //TODO, try to diminish the number of parameters.
128 Tooltip.prototype.request_tooltip_after_time = function (pre_cursor,time){
129 };
130
131
132 Tooltip.prototype.remove_and_cancel_tooltip = function(force) {
129 Tooltip.prototype.remove_and_cancel_tooltip = function(force) {
133 // note that we don't handle closing directly inside the calltip
130 // note that we don't handle closing directly inside the calltip
134 // as in the completer, because it is not focusable, so won't
131 // as in the completer, because it is not focusable, so won't
135 // get the event.
132 // get the event.
136 if(this._sticky == false || force == true)
133 if(this._sticky == false || force == true)
137 {
134 {
138 this.hide();
135 this.hide();
139 }
136 }
140 this.cancel_pending();
137 this.cancel_pending();
141 this._old_cell = null ;
138 this._old_cell = null ;
142 this._old_request = null ;
139 this._old_request = null ;
143 this._consecutive_conter = 0;
140 this._consecutive_conter = 0;
144 }
141 }
145
142
143 // cancel autocall done after '(' for example.
146 Tooltip.prototype.cancel_pending = function(){
144 Tooltip.prototype.cancel_pending = function(){
147 if (this.tooltip_timeout != null){
145 if (this.tooltip_timeout != null){
148 clearTimeout(this.tooltip_timeout);
146 clearTimeout(this.tooltip_timeout);
149 this.tooltip_timeout = null;
147 this.tooltip_timeout = null;
150 }
148 }
151 }
149 }
152
150
151 // will trigger tooltip after timeout
153 Tooltip.prototype.pending = function(cell,text)
152 Tooltip.prototype.pending = function(cell,text)
154 {
153 {
155 var that = this;
154 var that = this;
156 this.tooltip_timeout = setTimeout(function(){that.request(cell)} , IPython.notebook.time_before_tooltip);
155 this.tooltip_timeout = setTimeout(function(){that.request(cell)} , IPython.notebook.time_before_tooltip);
157 }
156 }
157
158 // make an imediate completion request
158 Tooltip.prototype.request = function(cell)
159 Tooltip.prototype.request = function(cell)
159 {
160 {
160 this.cancel_pending();
161 this.cancel_pending();
161 var editor = cell.code_mirror;
162 var editor = cell.code_mirror;
162 this.code_mirror = editor;
163 this.code_mirror = editor;
163 var cursor = editor.getCursor();
164 var cursor = editor.getCursor();
164 var text = editor.getRange({line:cursor.line,ch:0},cursor).trim();
165 var text = editor.getRange({line:cursor.line,ch:0},cursor).trim();
165
166
166 if( this._old_cell == cell && this._old_request == text && this._hidden == false)
167 if( this._old_cell == cell && this._old_request == text && this._hidden == false)
167 {
168 {
168 this._consecutive_conter = this._consecutive_conter +1;
169 this._consecutive_conter = this._consecutive_conter +1;
169 } else {
170 } else {
170 this._old_cell = cell ;
171 this._old_cell = cell ;
171 this._old_request = text ;
172 this._old_request = text ;
172 this._consecutive_conter =0;
173 this._consecutive_conter =0;
173 this.cancel_stick();
174 this.cancel_stick();
174 }
175 }
175
176
176 if( this._consecutive_conter == 1 )
177 if( this._consecutive_conter == 1 )
177 {
178 {
178 this.expand()
179 this.expand()
179 return;
180 return;
180 }
181 }
181 else if( this._consecutive_conter == 2)
182 else if( this._consecutive_conter == 2)
182 {
183 {
183 this.stick();
184 this.stick();
184 return;
185 return;
185 }
186 }
186 else if( this._consecutive_conter == 3)
187 else if( this._consecutive_conter == 3)
187 {
188 {
188 console.log('should open in pager');
189 console.log('should open in pager');
189 this._old_cell = null ;
190 this._old_cell = null ;
190 this._cancel_stick
191 this._cancel_stick();
191 this._old_request = null ;
192 this._old_request = null ;
192 this._consecutive_conter = 0;
193 this._consecutive_conter = 0;
193 this.showInPager();
194 this.showInPager();
194 this._cmfocus();
195 this._cmfocus();
195 return;
196 return;
196 }
197 }
197 else if( this._consecutive_conter == 4)
198 else if( this._consecutive_conter == 4)
198 {
199 {
199
200
200 }
201 }
201
202
202 if (text === "" || text === "(" ) {
203 if (text === "" || text === "(" ) {
203 return;
204 return;
204 // don't do anything if line beggin with '(' or is empty
205 // don't do anything if line beggin with '(' or is empty
205 }
206 }
206 IPython.notebook.request_tool_tip(cell, text);
207 IPython.notebook.request_tool_tip(cell, text);
207 }
208 }
209
210 // cancel the option of having the tooltip to stick
208 Tooltip.prototype.cancel_stick = function()
211 Tooltip.prototype.cancel_stick = function()
209 {
212 {
210 clearTimeout(this._stick_timeout);
213 clearTimeout(this._stick_timeout);
211 this._sticky = false;
214 this._sticky = false;
212 }
215 }
213
216
214 Tooltip.prototype.stick = function()
217 // put the tooltip in a sicky state for 10 seconds
218 // it won't be removed by remove_and_cancell() unless you called with
219 // the first parameter set to true.
220 // remove_and_cancell_tooltip(true)
221 Tooltip.prototype.stick = function()
215 {
222 {
216 console.log('tooltip will stick for at least 10 sec');
223 console.log('tooltip will stick for at least 10 sec');
217 var that = this;
224 var that = this;
218 this._sticky = true;
225 this._sticky = true;
219 this._stick_timeout = setTimeout( function(){
226 this._stick_timeout = setTimeout( function(){
220 that._sticky = false;
227 that._sticky = false;
221 console.log('tooltip will not stick anymore');
228 console.log('tooltip will not stick anymore');
222 }, 10*1000
229 }, 10*1000
223 );
230 );
224
225
226 }
231 }
227
232
233 // should be called with the kernel reply to actually show the tooltip
228 Tooltip.prototype.show = function(reply, codecell)
234 Tooltip.prototype.show = function(reply, codecell)
229 {
235 {
230 // move the bubble if it is not hidden
236 // move the bubble if it is not hidden
231 // otherwise fade it
237 // otherwise fade it
232 var editor = codecell.code_mirror;
238 var editor = codecell.code_mirror;
233 this.name = reply.name;
239 this.name = reply.name;
234 this.code_mirror = editor;
240 this.code_mirror = editor;
235
241
236 // do some math to have the tooltip arrow on more or less on left or right
242 // do some math to have the tooltip arrow on more or less on left or right
237 // width of the editor
243 // width of the editor
238 var w= $(this.code_mirror.getScrollerElement()).width();
244 var w= $(this.code_mirror.getScrollerElement()).width();
239 // ofset of the editor
245 // ofset of the editor
240 var o= $(this.code_mirror.getScrollerElement()).offset();
246 var o= $(this.code_mirror.getScrollerElement()).offset();
241 var pos = editor.cursorCoords();
247 var pos = editor.cursorCoords();
242 var xinit = pos.x;
248 var xinit = pos.x;
243 var xinter = o.left + (xinit-o.left)/w*(w-450);
249 var xinter = o.left + (xinit-o.left)/w*(w-450);
244 var posarrowleft = xinit - xinter;
250 var posarrowleft = xinit - xinter;
245
251
246
252
247 if( this._hidden == false)
253 if( this._hidden == false)
248 {
254 {
249 this.tooltip.animate({'left' : xinter-30+'px','top' :(pos.yBot+10)+'px'});
255 this.tooltip.animate({'left' : xinter-30+'px','top' :(pos.yBot+10)+'px'});
250 } else
256 } else
251 {
257 {
252 this.tooltip.css({'left' : xinter-30+'px'});
258 this.tooltip.css({'left' : xinter-30+'px'});
253 this.tooltip.css({'top' :(pos.yBot+10)+'px'});
259 this.tooltip.css({'top' :(pos.yBot+10)+'px'});
254 }
260 }
255 this.arrow.animate({'left' : posarrowleft+'px'});
261 this.arrow.animate({'left' : posarrowleft+'px'});
256 this.tooltip.removeClass('hidden')
262 this.tooltip.removeClass('hidden')
257 this.tooltip.removeClass('hide');
263 this.tooltip.removeClass('hide');
258 this._hidden = false;
264 this._hidden = false;
259
265
260 // build docstring
266 // build docstring
261 defstring = reply.call_def;
267 defstring = reply.call_def;
262 if (defstring == null) { defstring = reply.init_definition; }
268 if (defstring == null) { defstring = reply.init_definition; }
263 if (defstring == null) { defstring = reply.definition; }
269 if (defstring == null) { defstring = reply.definition; }
264
270
265 docstring = reply.call_docstring;
271 docstring = reply.call_docstring;
266 if (docstring == null) { docstring = reply.init_docstring; }
272 if (docstring == null) { docstring = reply.init_docstring; }
267 if (docstring == null) { docstring = reply.docstring; }
273 if (docstring == null) { docstring = reply.docstring; }
268 if (docstring == null) { docstring = "<empty docstring>"; }
274 if (docstring == null) { docstring = "<empty docstring>"; }
269
275
270 this.text.children().remove();
276 this.text.children().remove();
271
277
272 var pre=$('<pre/>').html(utils.fixConsole(docstring));
278 var pre=$('<pre/>').html(utils.fixConsole(docstring));
273 if(defstring){
279 if(defstring){
274 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
280 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
275 this.text.append(defstring_html);
281 this.text.append(defstring_html);
276 }
282 }
277 this.text.append(pre);
283 this.text.append(pre);
278 // keep scroll top to be sure to always see the first line
284 // keep scroll top to be sure to always see the first line
279 this.text.scrollTop(0);
285 this.text.scrollTop(0);
280
281
282 }
283
284 Tooltip.prototype.showInPager = function(text){
285 var msg_id = IPython.notebook.kernel.execute(this.name+"?");
286 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
287 this.remove_and_cancel_tooltip(true);
288 this._cmfocus();
289 }
286 }
290
287
288 // convenient funciton to have the correct codemirror back into focus
291 Tooltip.prototype._cmfocus = function()
289 Tooltip.prototype._cmfocus = function()
292 {
290 {
293 var cm = this.code_mirror;
291 var cm = this.code_mirror;
294 setTimeout(function(){cm.focus();}, 50);
292 setTimeout(function(){cm.focus();}, 50);
295 }
293 }
296
294
297
298 IPython.Tooltip = Tooltip;
295 IPython.Tooltip = Tooltip;
299
300 return IPython;
296 return IPython;
301 }(IPython));
297 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now