##// END OF EJS Templates
update description of sticky tooltip...
Min RK -
Show More
@@ -1,326 +1,326
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 event.preventDefault();
44 44 }).append(
45 45 $('<span/>').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
46 46
47 47 // open in pager
48 48 var morelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button').attr('title', 'show the current docstring in pager (press shift-tab 4 times)');
49 49 var morespan = $('<span/>').text('Open in Pager').addClass('ui-icon').addClass('ui-icon-arrowstop-l-n');
50 50 morelink.append(morespan);
51 51 morelink.click(function () {
52 52 that.showInPager(that._old_cell);
53 53 event.preventDefault();
54 54 });
55 55
56 56 // close the tooltip
57 57 var closelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button');
58 58 var closespan = $('<span/>').text('Close').addClass('ui-icon').addClass('ui-icon-close');
59 59 closelink.append(closespan);
60 60 closelink.click(function () {
61 61 that.remove_and_cancel_tooltip(true);
62 62 event.preventDefault();
63 63 });
64 64
65 65 this._clocklink = $('<a/>').attr('href', "#");
66 66 this._clocklink.attr('role', "button");
67 67 this._clocklink.addClass('ui-button');
68 this._clocklink.attr('title', 'Tooltip is not dismissed while typing for 10 seconds');
68 this._clocklink.attr('title', 'Tooltip will linger for 10 seconds while you type');
69 69 var clockspan = $('<span/>').text('Close');
70 70 clockspan.addClass('ui-icon');
71 71 clockspan.addClass('ui-icon-clock');
72 72 this._clocklink.append(clockspan);
73 73 this._clocklink.click(function () {
74 74 that.cancel_stick();
75 75 event.preventDefault();
76 76 });
77 77
78 78
79 79
80 80
81 81 //construct the tooltip
82 82 // add in the reverse order you want them to appear
83 83 this.buttons.append(closelink);
84 84 this.buttons.append(expandlink);
85 85 this.buttons.append(morelink);
86 86 this.buttons.append(this._clocklink);
87 87 this._clocklink.hide();
88 88
89 89
90 90 // we need a phony element to make the small arrow
91 91 // of the tooltip in css
92 92 // we will move the arrow later
93 93 this.arrow = $('<div/>').addClass('pretooltiparrow');
94 94 this.tooltip.append(this.buttons);
95 95 this.tooltip.append(this.arrow);
96 96 this.tooltip.append(this.text);
97 97
98 98 // function that will be called if you press tab 1, 2, 3... times in a row
99 99 this.tabs_functions = [function (cell, text, cursor) {
100 100 that._request_tooltip(cell, text, cursor);
101 101 }, function () {
102 102 that.expand();
103 103 }, function () {
104 104 that.stick();
105 105 }, function (cell) {
106 106 that.cancel_stick();
107 107 that.showInPager(cell);
108 108 }];
109 109 // call after all the tabs function above have bee call to clean their effects
110 110 // if necessary
111 111 this.reset_tabs_function = function (cell, text) {
112 112 this._old_cell = (cell) ? cell : null;
113 113 this._old_request = (text) ? text : null;
114 114 this._consecutive_counter = 0;
115 115 };
116 116 };
117 117
118 118 Tooltip.prototype.is_visible = function () {
119 119 return !this._hidden;
120 120 };
121 121
122 122 Tooltip.prototype.showInPager = function (cell) {
123 123 /**
124 124 * reexecute last call in pager by appending ? to show back in pager
125 125 */
126 126 this.events.trigger('open_with_text.Pager', this._reply.content);
127 127 this.remove_and_cancel_tooltip();
128 128 };
129 129
130 130 // grow the tooltip verticaly
131 131 Tooltip.prototype.expand = function () {
132 132 this.text.removeClass('smalltooltip');
133 133 this.text.addClass('bigtooltip');
134 134 $('#expanbutton').hide('slow');
135 135 };
136 136
137 137 // deal with all the logic of hiding the tooltip
138 138 // and reset it's status
139 139 Tooltip.prototype._hide = function () {
140 140 this._hidden = true;
141 141 this.tooltip.fadeOut('fast');
142 142 $('#expanbutton').show('slow');
143 143 this.text.removeClass('bigtooltip');
144 144 this.text.addClass('smalltooltip');
145 145 // keep scroll top to be sure to always see the first line
146 146 this.text.scrollTop(0);
147 147 this.code_mirror = null;
148 148 };
149 149
150 150 // return true on successfully removing a visible tooltip; otherwise return
151 151 // false.
152 152 Tooltip.prototype.remove_and_cancel_tooltip = function (force) {
153 153 /**
154 154 * note that we don't handle closing directly inside the calltip
155 155 * as in the completer, because it is not focusable, so won't
156 156 * get the event.
157 157 */
158 158 this.cancel_pending();
159 159 if (!this._hidden) {
160 160 if (force || !this._sticky) {
161 161 this.cancel_stick();
162 162 this._hide();
163 163 }
164 164 this.reset_tabs_function();
165 165 return true;
166 166 } else {
167 167 return false;
168 168 }
169 169 };
170 170
171 171 // cancel autocall done after '(' for example.
172 172 Tooltip.prototype.cancel_pending = function () {
173 173 if (this._tooltip_timeout !== null) {
174 174 clearTimeout(this._tooltip_timeout);
175 175 this._tooltip_timeout = null;
176 176 }
177 177 };
178 178
179 179 // will trigger tooltip after timeout
180 180 Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
181 181 var that = this;
182 182 this._tooltip_timeout = setTimeout(function () {
183 183 that.request(cell, hide_if_no_docstring);
184 184 }, that.time_before_tooltip);
185 185 };
186 186
187 187 // easy access for julia monkey patching.
188 188 Tooltip.last_token_re = /[a-z_][0-9a-z._]*$/gi;
189 189
190 190 Tooltip.prototype._request_tooltip = function (cell, text, cursor_pos) {
191 191 var callbacks = $.proxy(this._show, this);
192 192 var msg_id = cell.kernel.inspect(text, cursor_pos, callbacks);
193 193 };
194 194
195 195 // make an immediate completion request
196 196 Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
197 197 /**
198 198 * request(codecell)
199 199 * Deal with extracting the text from the cell and counting
200 200 * call in a row
201 201 */
202 202 this.cancel_pending();
203 203 var editor = cell.code_mirror;
204 204 var cursor = editor.getCursor();
205 205 var cursor_pos = utils.to_absolute_cursor_pos(editor, cursor);
206 206 var text = cell.get_text();
207 207
208 208 this._hide_if_no_docstring = hide_if_no_docstring;
209 209
210 210 if(editor.somethingSelected()){
211 211 // get only the most recent selection.
212 212 text = editor.getSelection();
213 213 }
214 214
215 215 // need a permanent handle to code_mirror for future auto recall
216 216 this.code_mirror = editor;
217 217
218 218 // now we treat the different number of keypress
219 219 // first if same cell, same text, increment counter by 1
220 220 if (this._old_cell == cell && this._old_request == text && this._hidden === false) {
221 221 this._consecutive_counter++;
222 222 } else {
223 223 // else reset
224 224 this.cancel_stick();
225 225 this.reset_tabs_function (cell, text);
226 226 }
227 227
228 228 this.tabs_functions[this._consecutive_counter](cell, text, cursor_pos);
229 229
230 230 // then if we are at the end of list function, reset
231 231 if (this._consecutive_counter == this.tabs_functions.length) {
232 232 this.reset_tabs_function (cell, text, cursor);
233 233 }
234 234
235 235 return;
236 236 };
237 237
238 238 // cancel the option of having the tooltip to stick
239 239 Tooltip.prototype.cancel_stick = function () {
240 240 clearTimeout(this._stick_timeout);
241 241 this._stick_timeout = null;
242 242 this._clocklink.hide('slow');
243 243 this._sticky = false;
244 244 };
245 245
246 246 // put the tooltip in a sicky state for 10 seconds
247 247 // it won't be removed by remove_and_cancell() unless you called with
248 248 // the first parameter set to true.
249 249 // remove_and_cancell_tooltip(true)
250 250 Tooltip.prototype.stick = function (time) {
251 251 time = (time !== undefined) ? time : 10;
252 252 var that = this;
253 253 this._sticky = true;
254 254 this._clocklink.show('slow');
255 255 this._stick_timeout = setTimeout(function () {
256 256 that._sticky = false;
257 257 that._clocklink.hide('slow');
258 258 }, time * 1000);
259 259 };
260 260
261 261 // should be called with the kernel reply to actually show the tooltip
262 262 Tooltip.prototype._show = function (reply) {
263 263 /**
264 264 * move the bubble if it is not hidden
265 265 * otherwise fade it
266 266 */
267 267 this._reply = reply;
268 268 var content = reply.content;
269 269 if (!content.found) {
270 270 // object not found, nothing to show
271 271 return;
272 272 }
273 273 this.name = content.name;
274 274
275 275 // do some math to have the tooltip arrow on more or less on left or right
276 276 // position of the editor
277 277 var cm_pos = $(this.code_mirror.getWrapperElement()).position();
278 278
279 279 // anchor and head positions are local within CodeMirror element
280 280 var anchor = this.code_mirror.cursorCoords(false, 'local');
281 281 var head = this.code_mirror.cursorCoords(true, 'local');
282 282 // locate the target at the center of anchor, head
283 283 var center_left = (head.left + anchor.left) / 2;
284 284 // locate the left edge of the tooltip, at most 450 px left of the arrow
285 285 var edge_left = Math.max(center_left - 450, 0);
286 286 // locate the arrow at the cursor. A 24 px offset seems necessary.
287 287 var arrow_left = center_left - edge_left - 24;
288 288
289 289 // locate left, top within container element
290 290 var left = (cm_pos.left + edge_left) + 'px';
291 291 var top = (cm_pos.top + head.bottom + 10) + 'px';
292 292
293 293 if (this._hidden === false) {
294 294 this.tooltip.animate({
295 295 left: left,
296 296 top: top
297 297 });
298 298 } else {
299 299 this.tooltip.css({
300 300 left: left
301 301 });
302 302 this.tooltip.css({
303 303 top: top
304 304 });
305 305 }
306 306 this.arrow.animate({
307 307 'left': arrow_left + 'px'
308 308 });
309 309
310 310 this._hidden = false;
311 311 this.tooltip.fadeIn('fast');
312 312 this.text.children().remove();
313 313
314 314 // This should support rich data types, but only text/plain for now
315 315 // Any HTML within the docstring is escaped by the fixConsole() method.
316 316 var pre = $('<pre/>').html(utils.fixConsole(content.data['text/plain']));
317 317 this.text.append(pre);
318 318 // keep scroll top to be sure to always see the first line
319 319 this.text.scrollTop(0);
320 320 };
321 321
322 322 // Backwards compatibility.
323 323 IPython.Tooltip = Tooltip;
324 324
325 325 return {'Tooltip': Tooltip};
326 326 });
General Comments 0
You need to be logged in to leave comments. Login now