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