##// END OF EJS Templates
Merge pull request #4442 from Carreau/fix-oir...
Min RK -
r13331:7453734f merge
parent child Browse files
Show More
@@ -0,0 +1,2 b''
1 * ``object_info_request`` as been replaced by ``object_info`` for consistency in the javascript API.
2 ``object_info`` as a simpler interface to register callback that is incompatible with ``object_info_request``.
@@ -1,381 +1,379 b''
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 // Tooltip
9 9 //============================================================================
10 10 //
11 11 // you can set the autocall time by setting `IPython.tooltip.time_before_tooltip` in ms
12 12 //
13 13 // you can configure the differents action of pressing tab several times in a row by
14 14 // setting/appending different fonction in the array
15 15 // IPython.tooltip.tabs_functions
16 16 //
17 17 // eg :
18 18 // IPython.tooltip.tabs_functions[4] = function (){console.log('this is the action of the 4th tab pressing')}
19 19 //
20 20 var IPython = (function (IPython) {
21 21 "use strict";
22 22
23 23 var utils = IPython.utils;
24 24
25 25 // tooltip constructor
26 26 var Tooltip = function () {
27 27 var that = this;
28 28 this.time_before_tooltip = 1200;
29 29
30 30 // handle to html
31 31 this.tooltip = $('#tooltip');
32 32 this._hidden = true;
33 33
34 34 // variable for consecutive call
35 35 this._old_cell = null;
36 36 this._old_request = null;
37 37 this._consecutive_counter = 0;
38 38
39 39 // 'sticky ?'
40 40 this._sticky = false;
41 41
42 42 // display tooltip if the docstring is empty?
43 43 this._hide_if_no_docstring = false;
44 44
45 45 // contain the button in the upper right corner
46 46 this.buttons = $('<div/>').addClass('tooltipbuttons');
47 47
48 48 // will contain the docstring
49 49 this.text = $('<div/>').addClass('tooltiptext').addClass('smalltooltip');
50 50
51 51 // build the buttons menu on the upper right
52 52 // expand the tooltip to see more
53 53 var expandlink = $('<a/>').attr('href', "#").addClass("ui-corner-all") //rounded corner
54 54 .attr('role', "button").attr('id', 'expanbutton').attr('title', 'Grow the tooltip vertically (press tab 2 times)').click(function () {
55 55 that.expand()
56 56 }).append(
57 57 $('<span/>').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
58 58
59 59 // open in pager
60 60 var morelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button').attr('title', 'show the current docstring in pager (press tab 4 times)');
61 61 var morespan = $('<span/>').text('Open in Pager').addClass('ui-icon').addClass('ui-icon-arrowstop-l-n');
62 62 morelink.append(morespan);
63 63 morelink.click(function () {
64 64 that.showInPager(that._old_cell);
65 65 });
66 66
67 67 // close the tooltip
68 68 var closelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button');
69 69 var closespan = $('<span/>').text('Close').addClass('ui-icon').addClass('ui-icon-close');
70 70 closelink.append(closespan);
71 71 closelink.click(function () {
72 72 that.remove_and_cancel_tooltip(true);
73 73 });
74 74
75 75 this._clocklink = $('<a/>').attr('href', "#");
76 76 this._clocklink.attr('role', "button");
77 77 this._clocklink.addClass('ui-button');
78 78 this._clocklink.attr('title', 'Tootip is not dismissed while typing for 10 seconds');
79 79 var clockspan = $('<span/>').text('Close');
80 80 clockspan.addClass('ui-icon');
81 81 clockspan.addClass('ui-icon-clock');
82 82 this._clocklink.append(clockspan);
83 83 this._clocklink.click(function () {
84 84 that.cancel_stick();
85 85 });
86 86
87 87
88 88
89 89
90 90 //construct the tooltip
91 91 // add in the reverse order you want them to appear
92 92 this.buttons.append(closelink);
93 93 this.buttons.append(expandlink);
94 94 this.buttons.append(morelink);
95 95 this.buttons.append(this._clocklink);
96 96 this._clocklink.hide();
97 97
98 98
99 99 // we need a phony element to make the small arrow
100 100 // of the tooltip in css
101 101 // we will move the arrow later
102 102 this.arrow = $('<div/>').addClass('pretooltiparrow');
103 103 this.tooltip.append(this.buttons);
104 104 this.tooltip.append(this.arrow);
105 105 this.tooltip.append(this.text);
106 106
107 107 // function that will be called if you press tab 1, 2, 3... times in a row
108 108 this.tabs_functions = [function (cell, text) {
109 109 that._request_tooltip(cell, text);
110 110 }, function () {
111 111 that.expand();
112 112 }, function () {
113 113 that.stick();
114 114 }, function (cell) {
115 115 that.cancel_stick();
116 116 that.showInPager(cell);
117 117 }];
118 118 // call after all the tabs function above have bee call to clean their effects
119 119 // if necessary
120 120 this.reset_tabs_function = function (cell, text) {
121 121 this._old_cell = (cell) ? cell : null;
122 122 this._old_request = (text) ? text : null;
123 123 this._consecutive_counter = 0;
124 124 }
125 125 };
126 126
127 127 Tooltip.prototype.showInPager = function (cell) {
128 128 // reexecute last call in pager by appending ? to show back in pager
129 129 var that = this;
130 130 var empty = function () {};
131 131 cell.kernel.execute(
132 132 that.name + '?', {
133 133 'execute_reply': empty,
134 134 'output': empty,
135 135 'clear_output': empty,
136 136 'cell': cell
137 137 }, {
138 138 'silent': false,
139 139 'store_history': true
140 140 });
141 141 this.remove_and_cancel_tooltip();
142 142 }
143 143
144 144 // grow the tooltip verticaly
145 145 Tooltip.prototype.expand = function () {
146 146 this.text.removeClass('smalltooltip');
147 147 this.text.addClass('bigtooltip');
148 148 $('#expanbutton').hide('slow');
149 149 }
150 150
151 151 // deal with all the logic of hiding the tooltip
152 152 // and reset it's status
153 153 Tooltip.prototype._hide = function () {
154 154 this.tooltip.fadeOut('fast');
155 155 $('#expanbutton').show('slow');
156 156 this.text.removeClass('bigtooltip');
157 157 this.text.addClass('smalltooltip');
158 158 // keep scroll top to be sure to always see the first line
159 159 this.text.scrollTop(0);
160 160 this._hidden = true;
161 161 this.code_mirror = null;
162 162 }
163 163
164 164 // return true on successfully removing a visible tooltip; otherwise return
165 165 // false.
166 166 Tooltip.prototype.remove_and_cancel_tooltip = function (force) {
167 167 // note that we don't handle closing directly inside the calltip
168 168 // as in the completer, because it is not focusable, so won't
169 169 // get the event.
170 170 this.cancel_pending();
171 171 if (!this._hidden) {
172 172 if (force || !this._sticky) {
173 173 this.cancel_stick();
174 174 this._hide();
175 175 }
176 176 this.reset_tabs_function();
177 177 return true;
178 178 } else {
179 179 return false;
180 180 }
181 181 }
182 182
183 183 // cancel autocall done after '(' for example.
184 184 Tooltip.prototype.cancel_pending = function () {
185 185 if (this._tooltip_timeout != null) {
186 186 clearTimeout(this._tooltip_timeout);
187 187 this._tooltip_timeout = null;
188 188 }
189 189 }
190 190
191 191 // will trigger tooltip after timeout
192 192 Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
193 193 var that = this;
194 194 this._tooltip_timeout = setTimeout(function () {
195 195 that.request(cell, hide_if_no_docstring)
196 196 }, that.time_before_tooltip);
197 197 }
198 198
199 199 // easy access for julia monkey patching.
200 200 Tooltip.last_token_re = /[a-z_][0-9a-z._]+$/gi;
201 201
202 202 Tooltip.prototype.extract_oir_token = function(line){
203 203 // use internally just to make the request to the kernel
204 204 // Feel free to shorten this logic if you are better
205 205 // than me in regEx
206 206 // basicaly you shoul be able to get xxx.xxx.xxx from
207 207 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
208 208 // remove everything between matchin bracket (need to iterate)
209 209 var matchBracket = /\([^\(\)]+\)/g;
210 210 var endBracket = /\([^\(]*$/g;
211 211 var oldline = line;
212 212
213 213 line = line.replace(matchBracket, "");
214 214 while (oldline != line) {
215 215 oldline = line;
216 216 line = line.replace(matchBracket, "");
217 217 }
218 218 // remove everything after last open bracket
219 219 line = line.replace(endBracket, "");
220 220 return Tooltip.last_token_re.exec(line)
221 221 };
222 222
223 223 Tooltip.prototype._request_tooltip = function (cell, line) {
224 var callbacks = { shell : {
225 reply : $.proxy(this._show, this)
226 }};
224 var callbacks = $.proxy(this._show, this);
227 225 var oir_token = this.extract_oir_token(line);
228 var msg_id = cell.kernel.object_info_request(oir_token, callbacks);
226 var msg_id = cell.kernel.object_info(oir_token, callbacks);
229 227 };
230 228
231 229 // make an imediate completion request
232 230 Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
233 231 // request(codecell)
234 232 // Deal with extracting the text from the cell and counting
235 233 // call in a row
236 234 this.cancel_pending();
237 235 var editor = cell.code_mirror;
238 236 var cursor = editor.getCursor();
239 237 var text = editor.getRange({
240 238 line: cursor.line,
241 239 ch: 0
242 240 }, cursor).trim();
243 241
244 242 this._hide_if_no_docstring = hide_if_no_docstring;
245 243
246 244 if(editor.somethingSelected()){
247 245 text = editor.getSelection();
248 246 }
249 247
250 248 // need a permanent handel to code_mirror for future auto recall
251 249 this.code_mirror = editor;
252 250
253 251 // now we treat the different number of keypress
254 252 // first if same cell, same text, increment counter by 1
255 253 if (this._old_cell == cell && this._old_request == text && this._hidden == false) {
256 254 this._consecutive_counter++;
257 255 } else {
258 256 // else reset
259 257 this.cancel_stick();
260 258 this.reset_tabs_function (cell, text);
261 259 }
262 260
263 261 // don't do anything if line beggin with '(' or is empty
264 262 if (text === "" || text === "(") {
265 263 return;
266 264 }
267 265
268 266 this.tabs_functions[this._consecutive_counter](cell, text);
269 267
270 268 // then if we are at the end of list function, reset
271 269 if (this._consecutive_counter == this.tabs_functions.length) this.reset_tabs_function (cell, text);
272 270
273 271 return;
274 272 }
275 273
276 274 // cancel the option of having the tooltip to stick
277 275 Tooltip.prototype.cancel_stick = function () {
278 276 clearTimeout(this._stick_timeout);
279 277 this._stick_timeout = null;
280 278 this._clocklink.hide('slow');
281 279 this._sticky = false;
282 280 }
283 281
284 282 // put the tooltip in a sicky state for 10 seconds
285 283 // it won't be removed by remove_and_cancell() unless you called with
286 284 // the first parameter set to true.
287 285 // remove_and_cancell_tooltip(true)
288 286 Tooltip.prototype.stick = function (time) {
289 287 time = (time != undefined) ? time : 10;
290 288 var that = this;
291 289 this._sticky = true;
292 290 this._clocklink.show('slow');
293 291 this._stick_timeout = setTimeout(function () {
294 292 that._sticky = false;
295 293 that._clocklink.hide('slow');
296 294 }, time * 1000);
297 295 }
298 296
299 297 // should be called with the kernel reply to actually show the tooltip
300 298 Tooltip.prototype._show = function (reply) {
301 299 // move the bubble if it is not hidden
302 300 // otherwise fade it
303 301 var content = reply.content;
304 302 this.name = content.name;
305 303
306 304 // do some math to have the tooltip arrow on more or less on left or right
307 305 // width of the editor
308 306 var w = $(this.code_mirror.getScrollerElement()).width();
309 307 // ofset of the editor
310 308 var o = $(this.code_mirror.getScrollerElement()).offset();
311 309
312 310 // whatever anchor/head order but arrow at mid x selection
313 311 var anchor = this.code_mirror.cursorCoords(false);
314 312 var head = this.code_mirror.cursorCoords(true);
315 313 var xinit = (head.left+anchor.left)/2;
316 314 var xinter = o.left + (xinit - o.left) / w * (w - 450);
317 315 var posarrowleft = xinit - xinter;
318 316
319 317 if (this._hidden == false) {
320 318 this.tooltip.animate({
321 319 'left': xinter - 30 + 'px',
322 320 'top': (head.bottom + 10) + 'px'
323 321 });
324 322 } else {
325 323 this.tooltip.css({
326 324 'left': xinter - 30 + 'px'
327 325 });
328 326 this.tooltip.css({
329 327 'top': (head.bottom + 10) + 'px'
330 328 });
331 329 }
332 330 this.arrow.animate({
333 331 'left': posarrowleft + 'px'
334 332 });
335 333
336 334 // build docstring
337 335 var defstring = content.call_def;
338 336 if (defstring == null) {
339 337 defstring = content.init_definition;
340 338 }
341 339 if (defstring == null) {
342 340 defstring = content.definition;
343 341 }
344 342
345 343 var docstring = content.call_docstring;
346 344 if (docstring == null) {
347 345 docstring = content.init_docstring;
348 346 }
349 347 if (docstring == null) {
350 348 docstring = content.docstring;
351 349 }
352 350
353 351 if (docstring == null) {
354 352 // For reals this time, no docstring
355 353 if (this._hide_if_no_docstring) {
356 354 return;
357 355 } else {
358 356 docstring = "<empty docstring>";
359 357 }
360 358 }
361 359
362 360 this.tooltip.fadeIn('fast');
363 361 this._hidden = false;
364 362 this.text.children().remove();
365 363
366 364 var pre = $('<pre/>').html(utils.fixConsole(docstring));
367 365 if (defstring) {
368 366 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
369 367 this.text.append(defstring_html);
370 368 }
371 369 this.text.append(pre);
372 370 // keep scroll top to be sure to always see the first line
373 371 this.text.scrollTop(0);
374 372 }
375 373
376 374
377 375 IPython.Tooltip = Tooltip;
378 376
379 377 return IPython;
380 378
381 379 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now