##// END OF EJS Templates
multiple tooltip action...
Matthias BUSSONNIER -
Show More
@@ -1,552 +1,532
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 //============================================================================
9 9 // CodeCell
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16 var key = IPython.utils.keycodes;
17 17
18 18 var CodeCell = function (notebook) {
19 19 this.code_mirror = null;
20 20 this.input_prompt_number = null;
21 21 this.outputs = [];
22 22 this.collapsed = false;
23 this.tooltip_timeout = null;
24 23 this.clear_out_timeout = null;
25 24 IPython.Cell.apply(this, arguments);
26 25 };
27 26
28 27
29 28 CodeCell.prototype = new IPython.Cell();
30 29
31 30
32 31 CodeCell.prototype.create_element = function () {
33 32 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
34 33 cell.attr('tabindex','2');
35 34 var input = $('<div></div>').addClass('input hbox');
36 35 input.append($('<div/>').addClass('prompt input_prompt'));
37 36 var input_area = $('<div/>').addClass('input_area box-flex1');
38 37 this.code_mirror = CodeMirror(input_area.get(0), {
39 38 indentUnit : 4,
40 39 mode: 'python',
41 40 theme: 'ipython',
42 41 readOnly: this.read_only,
43 42 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
44 43 });
45 44 input.append(input_area);
46 45 var output = $('<div></div>').addClass('output vbox');
47 46 cell.append(input).append(output);
48 47 this.element = cell;
49 48 this.collapse();
50 49
51 50 // construct a completer
52 51 this.completer = new IPython.Completer(this);
53 52 };
54 53
55 //TODO, try to diminish the number of parameters.
56 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
57 var that = this;
58 if (pre_cursor === "" || pre_cursor === "(" ) {
59 // don't do anything if line beggin with '(' or is empty
60 } else {
61 if(time ==0)
62 { IPython.tooltip.request(that, pre_cursor) }
63 else
64 { IPython.tooltip.pending(that, pre_cursor) }
65 }
66 };
67
68 54 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
69 55 // This method gets called in CodeMirror's onKeyDown/onKeyPress
70 56 // handlers and is used to provide custom key handling. Its return
71 57 // value is used to determine if CodeMirror should ignore the event:
72 58 // true = ignore, false = don't ignore.
73 59
74 60 if (this.read_only){
75 61 return false;
76 62 }
77 63
78 // note that we are comparing and setting the time to wait at each key press.
79 // a better way might be to generate a new function on each time change and
80 // assign it to CodeCell.prototype.request_tooltip_after_time
81 var tooltip_wait_time = this.notebook.time_before_tooltip;
82 64 var tooltip_on_tab = this.notebook.tooltip_on_tab;
83 65 var that = this;
84 66 // whatever key is pressed, first, cancel the tooltip request before
85 // they are sent, and remove tooltip if any
86 if(event.type === 'keydown' ) {
67 // they are sent, and remove tooltip if any, except for tab again
68 if(event.type === 'keydown' && event.which != key.tab ) {
87 69 IPython.tooltip.remove_and_cancel_tooltip();
88 70 };
89 71
90 72
91 73 if (event.keyCode === key.enter && (event.shiftKey || event.ctrlKey)) {
92 74 // Always ignore shift-enter in CodeMirror as we handle it.
93 75 return true;
94 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
95 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
76 } else if (event.which === 40 && event.type === 'keypress' && this.notebook.time_before_tooltip >= 0) {
77 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
96 78 // browser and keyboard layout !
97 79 // Pressing '(' , request tooltip, don't forget to reappend it
98 var cursor = editor.getCursor();
99 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
100 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
80 IPython.tooltip.pending(that);
101 81 } else if (event.which === key.upArrow) {
102 82 // If we are not at the top, let CM handle the up arrow and
103 83 // prevent the global keydown handler from handling it.
104 84 if (!that.at_top()) {
105 85 event.stop();
106 86 return false;
107 87 } else {
108 88 return true;
109 89 };
110 90 } else if (event.which === key.downArrow) {
111 91 // If we are not at the bottom, let CM handle the down arrow and
112 92 // prevent the global keydown handler from handling it.
113 93 if (!that.at_bottom()) {
114 94 event.stop();
115 95 return false;
116 96 } else {
117 97 return true;
118 98 };
119 99 } else if (event.keyCode === key.tab && event.type == 'keydown') {
120 100 // Tab completion.
121 101 var cur = editor.getCursor();
122 102 //Do not trim here because of tooltip
123 103 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
124 104 if (pre_cursor.trim() === "") {
125 105 // Don't autocomplete if the part of the line before the cursor
126 106 // is empty. In this case, let CodeMirror handle indentation.
127 107 return false;
128 108 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
129 that.request_tooltip_after_time(pre_cursor,0);
109 IPython.tooltip.request(that);
130 110 // Prevent the event from bubbling up.
131 111 event.stop();
132 112 // Prevent CodeMirror from handling the tab.
133 113 return true;
134 114 } else {
135 115 event.stop();
136 116 this.completer.startCompletion();
137 117 return true;
138 118 };
139 119 } else if (event.keyCode === key.backspace && event.type == 'keydown') {
140 120 // If backspace and the line ends with 4 spaces, remove them.
141 121 var cur = editor.getCursor();
142 122 var line = editor.getLine(cur.line);
143 123 var ending = line.slice(-4);
144 124 if (ending === ' ') {
145 125 editor.replaceRange('',
146 126 {line: cur.line, ch: cur.ch-4},
147 127 {line: cur.line, ch: cur.ch}
148 128 );
149 129 event.stop();
150 130 return true;
151 131 } else {
152 132 return false;
153 133 };
154 134 } else {
155 135 // keypress/keyup also trigger on TAB press, and we don't want to
156 136 // use those to disable tab completion.
157 137 return false;
158 138 };
159 139 return false;
160 140 };
161 141
162 142 CodeCell.prototype.finish_tooltip = function (reply) {
163 143 IPython.tooltip.show(reply, this);
164 144 };
165 145
166 146
167 147 // called when completion came back from the kernel. just forward
168 148 CodeCell.prototype.finish_completing = function (matched_text, matches) {
169 149 this.completer.finish_completing(matched_text,matches);
170 150 }
171 151
172 152
173 153 CodeCell.prototype.select = function () {
174 154 IPython.Cell.prototype.select.apply(this);
175 155 this.code_mirror.refresh();
176 156 this.code_mirror.focus();
177 157 // We used to need an additional refresh() after the focus, but
178 158 // it appears that this has been fixed in CM. This bug would show
179 159 // up on FF when a newly loaded markdown cell was edited.
180 160 };
181 161
182 162
183 163 CodeCell.prototype.select_all = function () {
184 164 var start = {line: 0, ch: 0};
185 165 var nlines = this.code_mirror.lineCount();
186 166 var last_line = this.code_mirror.getLine(nlines-1);
187 167 var end = {line: nlines-1, ch: last_line.length};
188 168 this.code_mirror.setSelection(start, end);
189 169 };
190 170
191 171
192 172 CodeCell.prototype.append_output = function (json, dynamic) {
193 173 // If dynamic is true, javascript output will be eval'd.
194 174 this.expand();
195 175 this.flush_clear_timeout();
196 176 if (json.output_type === 'pyout') {
197 177 this.append_pyout(json, dynamic);
198 178 } else if (json.output_type === 'pyerr') {
199 179 this.append_pyerr(json);
200 180 } else if (json.output_type === 'display_data') {
201 181 this.append_display_data(json, dynamic);
202 182 } else if (json.output_type === 'stream') {
203 183 this.append_stream(json);
204 184 };
205 185 this.outputs.push(json);
206 186 };
207 187
208 188
209 189 CodeCell.prototype.create_output_area = function () {
210 190 var oa = $("<div/>").addClass("hbox output_area");
211 191 oa.append($('<div/>').addClass('prompt'));
212 192 return oa;
213 193 };
214 194
215 195
216 196 CodeCell.prototype.append_pyout = function (json, dynamic) {
217 197 var n = json.prompt_number || ' ';
218 198 var toinsert = this.create_output_area();
219 199 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
220 200 this.append_mime_type(json, toinsert, dynamic);
221 201 this.element.find('div.output').append(toinsert);
222 202 // If we just output latex, typeset it.
223 203 if ((json.latex !== undefined) || (json.html !== undefined)) {
224 204 this.typeset();
225 205 };
226 206 };
227 207
228 208
229 209 CodeCell.prototype.append_pyerr = function (json) {
230 210 var tb = json.traceback;
231 211 if (tb !== undefined && tb.length > 0) {
232 212 var s = '';
233 213 var len = tb.length;
234 214 for (var i=0; i<len; i++) {
235 215 s = s + tb[i] + '\n';
236 216 }
237 217 s = s + '\n';
238 218 var toinsert = this.create_output_area();
239 219 this.append_text(s, toinsert);
240 220 this.element.find('div.output').append(toinsert);
241 221 };
242 222 };
243 223
244 224
245 225 CodeCell.prototype.append_stream = function (json) {
246 226 // temporary fix: if stream undefined (json file written prior to this patch),
247 227 // default to most likely stdout:
248 228 if (json.stream == undefined){
249 229 json.stream = 'stdout';
250 230 }
251 231 if (!utils.fixConsole(json.text)){
252 232 // fixConsole gives nothing (empty string, \r, etc.)
253 233 // so don't append any elements, which might add undesirable space
254 234 return;
255 235 }
256 236 var subclass = "output_"+json.stream;
257 237 if (this.outputs.length > 0){
258 238 // have at least one output to consider
259 239 var last = this.outputs[this.outputs.length-1];
260 240 if (last.output_type == 'stream' && json.stream == last.stream){
261 241 // latest output was in the same stream,
262 242 // so append directly into its pre tag
263 243 // escape ANSI & HTML specials:
264 244 var text = utils.fixConsole(json.text);
265 245 this.element.find('div.'+subclass).last().find('pre').append(text);
266 246 return;
267 247 }
268 248 }
269 249
270 250 // If we got here, attach a new div
271 251 var toinsert = this.create_output_area();
272 252 this.append_text(json.text, toinsert, "output_stream "+subclass);
273 253 this.element.find('div.output').append(toinsert);
274 254 };
275 255
276 256
277 257 CodeCell.prototype.append_display_data = function (json, dynamic) {
278 258 var toinsert = this.create_output_area();
279 259 this.append_mime_type(json, toinsert, dynamic);
280 260 this.element.find('div.output').append(toinsert);
281 261 // If we just output latex, typeset it.
282 262 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
283 263 this.typeset();
284 264 };
285 265 };
286 266
287 267
288 268 CodeCell.prototype.append_mime_type = function (json, element, dynamic) {
289 269 if (json.javascript !== undefined && dynamic) {
290 270 this.append_javascript(json.javascript, element, dynamic);
291 271 } else if (json.html !== undefined) {
292 272 this.append_html(json.html, element);
293 273 } else if (json.latex !== undefined) {
294 274 this.append_latex(json.latex, element);
295 275 } else if (json.svg !== undefined) {
296 276 this.append_svg(json.svg, element);
297 277 } else if (json.png !== undefined) {
298 278 this.append_png(json.png, element);
299 279 } else if (json.jpeg !== undefined) {
300 280 this.append_jpeg(json.jpeg, element);
301 281 } else if (json.text !== undefined) {
302 282 this.append_text(json.text, element);
303 283 };
304 284 };
305 285
306 286
307 287 CodeCell.prototype.append_html = function (html, element) {
308 288 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
309 289 toinsert.append(html);
310 290 element.append(toinsert);
311 291 };
312 292
313 293
314 294 CodeCell.prototype.append_javascript = function (js, container) {
315 295 // We just eval the JS code, element appears in the local scope.
316 296 var element = $("<div/>").addClass("box_flex1 output_subarea");
317 297 container.append(element);
318 298 // Div for js shouldn't be drawn, as it will add empty height to the area.
319 299 container.hide();
320 300 // If the Javascript appends content to `element` that should be drawn, then
321 301 // it must also call `container.show()`.
322 302 eval(js);
323 303 }
324 304
325 305
326 306 CodeCell.prototype.append_text = function (data, element, extra_class) {
327 307 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
328 308 // escape ANSI & HTML specials in plaintext:
329 309 data = utils.fixConsole(data);
330 310 if (extra_class){
331 311 toinsert.addClass(extra_class);
332 312 }
333 313 toinsert.append($("<pre/>").html(data));
334 314 element.append(toinsert);
335 315 };
336 316
337 317
338 318 CodeCell.prototype.append_svg = function (svg, element) {
339 319 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
340 320 toinsert.append(svg);
341 321 element.append(toinsert);
342 322 };
343 323
344 324
345 325 CodeCell.prototype.append_png = function (png, element) {
346 326 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
347 327 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
348 328 element.append(toinsert);
349 329 };
350 330
351 331
352 332 CodeCell.prototype.append_jpeg = function (jpeg, element) {
353 333 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
354 334 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
355 335 element.append(toinsert);
356 336 };
357 337
358 338
359 339 CodeCell.prototype.append_latex = function (latex, element) {
360 340 // This method cannot do the typesetting because the latex first has to
361 341 // be on the page.
362 342 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
363 343 toinsert.append(latex);
364 344 element.append(toinsert);
365 345 };
366 346
367 347
368 348 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
369 349 var that = this;
370 350 if (this.clear_out_timeout != null){
371 351 // fire previous pending clear *immediately*
372 352 clearTimeout(this.clear_out_timeout);
373 353 this.clear_out_timeout = null;
374 354 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
375 355 }
376 356 // store flags for flushing the timeout
377 357 this._clear_stdout = stdout;
378 358 this._clear_stderr = stderr;
379 359 this._clear_other = other;
380 360 this.clear_out_timeout = setTimeout(function(){
381 361 // really clear timeout only after a short delay
382 362 // this reduces flicker in 'clear_output; print' cases
383 363 that.clear_out_timeout = null;
384 364 that._clear_stdout = that._clear_stderr = that._clear_other = null;
385 365 that.clear_output_callback(stdout, stderr, other);
386 366 }, 500
387 367 );
388 368 };
389 369
390 370 CodeCell.prototype.clear_output_callback = function (stdout, stderr, other) {
391 371 var output_div = this.element.find("div.output");
392 372
393 373 if (stdout && stderr && other){
394 374 // clear all, no need for logic
395 375 output_div.html("");
396 376 this.outputs = [];
397 377 return;
398 378 }
399 379 // remove html output
400 380 // each output_subarea that has an identifying class is in an output_area
401 381 // which is the element to be removed.
402 382 if (stdout){
403 383 output_div.find("div.output_stdout").parent().remove();
404 384 }
405 385 if (stderr){
406 386 output_div.find("div.output_stderr").parent().remove();
407 387 }
408 388 if (other){
409 389 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
410 390 }
411 391
412 392 // remove cleared outputs from JSON list:
413 393 for (var i = this.outputs.length - 1; i >= 0; i--){
414 394 var out = this.outputs[i];
415 395 var output_type = out.output_type;
416 396 if (output_type == "display_data" && other){
417 397 this.outputs.splice(i,1);
418 398 }else if (output_type == "stream"){
419 399 if (stdout && out.stream == "stdout"){
420 400 this.outputs.splice(i,1);
421 401 }else if (stderr && out.stream == "stderr"){
422 402 this.outputs.splice(i,1);
423 403 }
424 404 }
425 405 }
426 406 };
427 407
428 408
429 409 CodeCell.prototype.clear_input = function () {
430 410 this.code_mirror.setValue('');
431 411 };
432 412
433 413 CodeCell.prototype.flush_clear_timeout = function() {
434 414 var output_div = this.element.find('div.output');
435 415 if (this.clear_out_timeout){
436 416 clearTimeout(this.clear_out_timeout);
437 417 this.clear_out_timeout = null;
438 418 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
439 419 };
440 420 }
441 421
442 422
443 423 CodeCell.prototype.collapse = function () {
444 424 if (!this.collapsed) {
445 425 this.element.find('div.output').hide();
446 426 this.collapsed = true;
447 427 };
448 428 };
449 429
450 430
451 431 CodeCell.prototype.expand = function () {
452 432 if (this.collapsed) {
453 433 this.element.find('div.output').show();
454 434 this.collapsed = false;
455 435 };
456 436 };
457 437
458 438
459 439 CodeCell.prototype.toggle_output = function () {
460 440 if (this.collapsed) {
461 441 this.expand();
462 442 } else {
463 443 this.collapse();
464 444 };
465 445 };
466 446
467 447 CodeCell.prototype.set_input_prompt = function (number) {
468 448 this.input_prompt_number = number;
469 449 var ns = number || "&nbsp;";
470 450 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
471 451 };
472 452
473 453
474 454 CodeCell.prototype.get_text = function () {
475 455 return this.code_mirror.getValue();
476 456 };
477 457
478 458
479 459 CodeCell.prototype.set_text = function (code) {
480 460 return this.code_mirror.setValue(code);
481 461 };
482 462
483 463
484 464 CodeCell.prototype.at_top = function () {
485 465 var cursor = this.code_mirror.getCursor();
486 466 if (cursor.line === 0) {
487 467 return true;
488 468 } else {
489 469 return false;
490 470 }
491 471 };
492 472
493 473
494 474 CodeCell.prototype.at_bottom = function () {
495 475 var cursor = this.code_mirror.getCursor();
496 476 if (cursor.line === (this.code_mirror.lineCount()-1)) {
497 477 return true;
498 478 } else {
499 479 return false;
500 480 }
501 481 };
502 482
503 483
504 484 CodeCell.prototype.fromJSON = function (data) {
505 485 if (data.cell_type === 'code') {
506 486 if (data.input !== undefined) {
507 487 this.set_text(data.input);
508 488 }
509 489 if (data.prompt_number !== undefined) {
510 490 this.set_input_prompt(data.prompt_number);
511 491 } else {
512 492 this.set_input_prompt();
513 493 };
514 494 var len = data.outputs.length;
515 495 for (var i=0; i<len; i++) {
516 496 // append with dynamic=false.
517 497 this.append_output(data.outputs[i], false);
518 498 };
519 499 if (data.collapsed !== undefined) {
520 500 if (data.collapsed) {
521 501 this.collapse();
522 502 } else {
523 503 this.expand();
524 504 };
525 505 };
526 506 };
527 507 };
528 508
529 509
530 510 CodeCell.prototype.toJSON = function () {
531 511 var data = {};
532 512 data.input = this.get_text();
533 513 data.cell_type = 'code';
534 514 if (this.input_prompt_number) {
535 515 data.prompt_number = this.input_prompt_number;
536 516 };
537 517 var outputs = [];
538 518 var len = this.outputs.length;
539 519 for (var i=0; i<len; i++) {
540 520 outputs[i] = this.outputs[i];
541 521 };
542 522 data.outputs = outputs;
543 523 data.language = 'python';
544 524 data.collapsed = this.collapsed;
545 525 return data;
546 526 };
547 527
548 528
549 529 IPython.CodeCell = CodeCell;
550 530
551 531 return IPython;
552 532 }(IPython));
@@ -1,205 +1,301
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 //============================================================================
9 9 // Tooltip
10 10 //============================================================================
11 11
12 12 // Todo :
13 13 // use codemirror highlight example to
14 14 // highlight the introspection request and introspect on mouse hove ...
15 15 //
16 16 //
17 17 var IPython = (function (IPython) {
18 18
19 19 var utils = IPython.utils;
20 20
21 21 var Tooltip = function (notebook) {
22 22 this.tooltip = $('#tooltip');
23 23 var that = this;
24 24 this._hidden = true;
25 25
26 // variable for consecutive call
27 this._old_cell = null ;
28 this._old_request = null ;
29 this._consecutive_conter = 0;
30
31 // 'sticky ?'
32 this._sticky = false;
33
26 34 // contain the button in the upper right corner
27 35 this.buttons = $('<div/>')
28 36 .addClass('tooltipbuttons');
29 37
30 38 // will contain the docstring
31 39 this.text = $('<div/>')
32 40 .addClass('tooltiptext')
33 41 .addClass('smalltooltip');
34 42
35 43 var tooltip = this.tooltip;
36 var text = this.text;
37 44
38 45 // build the buttons menu on the upper right
39 46
40 47 // expand the tooltip to see more
41 48 var expandlink=$('<a/>').attr('href',"#")
42 49 .addClass("ui-corner-all") //rounded corner
43 50 .attr('role',"button")
44 51 .attr('id','expanbutton')
45 .click(function(){
46 text.removeClass('smalltooltip');
47 text.addClass('bigtooltip');
48 $('#expanbutton').addClass('hidden');
49 that._cmfocus();
50 })
52 .click(function(){that.expand()})
51 53 .append(
52 54 $('<span/>').text('Expand')
53 55 .addClass('ui-icon')
54 56 .addClass('ui-icon-plus')
55 57 );
56 58
57 59 // open in pager
58 60 var morelink=$('<a/>').attr('href',"#")
59 61 .attr('role',"button")
60 62 .addClass('ui-button');
61 63 var morespan=$('<span/>').text('Open in Pager')
62 64 .addClass('ui-icon')
63 65 .addClass('ui-icon-arrowstop-l-n');
64 66 morelink.append(morespan);
65 67 morelink.click(function(){
66 var msg_id = IPython.notebook.kernel.execute(that.name+"?");
67 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
68 that.remove_and_cancel_tooltip();
69 that._cmfocus();
68 that.showInPager();
70 69 });
71 70
72 71 // close the tooltip
73 72 var closelink=$('<a/>').attr('href',"#");
74 73 closelink.attr('role',"button");
75 74 closelink.addClass('ui-button');
76 75 var closespan=$('<span/>').text('Close');
77 76 closespan.addClass('ui-icon');
78 77 closespan.addClass('ui-icon-close');
79 78 closelink.append(closespan);
80 79 closelink.click(function(){
81 80 that.hide();
82 81 });
83 82
84 83 //construct the tooltip
85 84 // add in the reverse order you want them to appear
86 85 this.buttons.append(closelink);
87 86 this.buttons.append(expandlink);
88 87 this.buttons.append(morelink);
89 88
90 89 // we need a phony element to make the small arrow
91 90 // of the tooltip in css
92 91 // we could try to move the arrow later
93 92 this.arrow = $('<div/>').addClass('pretooltiparrow');
94 93 this.tooltip.append(this.buttons);
95 94 this.tooltip.append(this.arrow);
96 95 this.tooltip.append(this.text);
97 96 };
98 97
98 Tooltip.prototype.showInPager = function()
99 {
100 var msg_id = IPython.notebook.kernel.execute(that.name+"?");
101 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
102 this.remove_and_cancel_tooltip();
103 this._cmfocus();
104 }
105
106
107 Tooltip.prototype.expand = function(){
108 this.text.removeClass('smalltooltip');
109 this.text.addClass('bigtooltip');
110 $('#expanbutton').addClass('hidden');
111 this._cmfocus();
112 }
113
99 114 // deal with all the logic of hiding the tooltip
100 115 // and reset it's status
101 116 Tooltip.prototype.hide = function()
102 117 {
103 118 this.tooltip.addClass('hide');
104 119 $('#expanbutton').removeClass('hidden');
105 120 this.text.removeClass('bigtooltip');
106 121 this.text.addClass('smalltooltip');
107 122 // keep scroll top to be sure to always see the first line
108 123 this.text.scrollTop(0);
109 124 this._hidden = true;
110 125 }
111 126
112 127 //TODO, try to diminish the number of parameters.
113 128 Tooltip.prototype.request_tooltip_after_time = function (pre_cursor,time){
114 129 };
115 130
116 131
117 Tooltip.prototype.remove_and_cancel_tooltip = function() {
132 Tooltip.prototype.remove_and_cancel_tooltip = function(force) {
118 133 // note that we don't handle closing directly inside the calltip
119 134 // as in the completer, because it is not focusable, so won't
120 135 // get the event.
136 if(this._sticky == false || force == true)
137 {
121 138 this.hide();
139 }
140 this.cancel_pending();
141 this._old_cell = null ;
142 this._old_request = null ;
143 this._consecutive_conter = 0;
144 }
145
146 Tooltip.prototype.cancel_pending = function(){
122 147 if (this.tooltip_timeout != null){
123 148 clearTimeout(this.tooltip_timeout);
124 149 this.tooltip_timeout = null;
125 150 }
126 151 }
127 152
128 153 Tooltip.prototype.pending = function(cell,text)
129 154 {
130 155 var that = this;
131 this.tooltip_timeout = setTimeout(function(){that.request(cell, text)} , IPython.notebook.time_before_tooltip);
156 this.tooltip_timeout = setTimeout(function(){that.request(cell)} , IPython.notebook.time_before_tooltip);
157 }
158 Tooltip.prototype.request = function(cell)
159 {
160 this.cancel_pending();
161 var editor = cell.code_mirror;
162 this.code_mirror = editor;
163 var cursor = editor.getCursor();
164 var text = editor.getRange({line:cursor.line,ch:0},cursor).trim();
165
166 if( this._old_cell == cell && this._old_request == text && this._hidden == false)
167 {
168 this._consecutive_conter = this._consecutive_conter +1;
169 } else {
170 this._old_cell = cell ;
171 this._old_request = text ;
172 this._consecutive_conter =0;
173 this.cancel_stick();
174 }
175
176 if( this._consecutive_conter == 1 )
177 {
178 this.expand()
179 return;
180 }
181 else if( this._consecutive_conter == 2)
182 {
183 this.stick();
184 return;
132 185 }
133 Tooltip.prototype.request = function(cell,text)
186 else if( this._consecutive_conter == 3)
134 187 {
188 console.log('should open in pager');
189 this._old_cell = null ;
190 this._cancel_stick
191 this._old_request = null ;
192 this._consecutive_conter = 0;
193 this.showInPager();
194 this._cmfocus();
195 return;
196 }
197 else if( this._consecutive_conter == 4)
198 {
199
200 }
201
202 if (text === "" || text === "(" ) {
203 return;
204 // don't do anything if line beggin with '(' or is empty
205 }
135 206 IPython.notebook.request_tool_tip(cell, text);
136 207 }
208 Tooltip.prototype.cancel_stick = function()
209 {
210 clearTimeout(this._stick_timeout);
211 this._sticky = false;
212 }
213
214 Tooltip.prototype.stick = function()
215 {
216 console.log('tooltip will stick for at least 10 sec');
217 var that = this;
218 this._sticky = true;
219 this._stick_timeout = setTimeout( function(){
220 that._sticky = false;
221 console.log('tooltip will not stick anymore');
222 }, 10*1000
223 );
224
225
226 }
137 227
138 228 Tooltip.prototype.show = function(reply, codecell)
139 229 {
140 230 // move the bubble if it is not hidden
141 231 // otherwise fade it
142 232 var editor = codecell.code_mirror;
143 233 this.name = reply.name;
144 234 this.code_mirror = editor;
235
236 // do some math to have the tooltip arrow on more or less on left or right
237 // width of the editor
238 var w= $(this.code_mirror.getScrollerElement()).width();
239 // ofset of the editor
240 var o= $(this.code_mirror.getScrollerElement()).offset();
145 241 var pos = editor.cursorCoords();
146 242 var xinit = pos.x;
147 var xinter = xinit/1000*600;
243 var xinter = o.left + (xinit-o.left)/w*(w-450);
148 244 var posarrowleft = xinit - xinter;
149 245
150 246
151 247 if( this._hidden == false)
152 248 {
153 249 this.tooltip.animate({'left' : xinter-30+'px','top' :(pos.yBot+10)+'px'});
154 250 } else
155 251 {
156 252 this.tooltip.css({'left' : xinter-30+'px'});
157 253 this.tooltip.css({'top' :(pos.yBot+10)+'px'});
158 254 }
159 255 this.arrow.animate({'left' : posarrowleft+'px'});
160 256 this.tooltip.removeClass('hidden')
161 257 this.tooltip.removeClass('hide');
162 258 this._hidden = false;
163 259
164 260 // build docstring
165 261 defstring = reply.call_def;
166 262 if (defstring == null) { defstring = reply.init_definition; }
167 263 if (defstring == null) { defstring = reply.definition; }
168 264
169 265 docstring = reply.call_docstring;
170 266 if (docstring == null) { docstring = reply.init_docstring; }
171 267 if (docstring == null) { docstring = reply.docstring; }
172 268 if (docstring == null) { docstring = "<empty docstring>"; }
173 269
174 270 this.text.children().remove();
175 271
176 272 var pre=$('<pre/>').html(utils.fixConsole(docstring));
177 273 if(defstring){
178 274 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
179 275 this.text.append(defstring_html);
180 276 }
181 277 this.text.append(pre);
182 278 // keep scroll top to be sure to always see the first line
183 279 this.text.scrollTop(0);
184 280
185 281
186 282 }
187 283
188 Tooltip.prototype.showInPager = function(){
189 var msg_id = IPython.notebook.kernel.execute(name+"?");
284 Tooltip.prototype.showInPager = function(text){
285 var msg_id = IPython.notebook.kernel.execute(this.name+"?");
190 286 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
191 that.remove_and_cancel_tooltip();
192 setTimeout(function(){that.code_mirror.focus();}, 50);
287 this.remove_and_cancel_tooltip(true);
288 this._cmfocus();
193 289 }
194 290
195 291 Tooltip.prototype._cmfocus = function()
196 292 {
197 293 var cm = this.code_mirror;
198 294 setTimeout(function(){cm.focus();}, 50);
199 295 }
200 296
201 297
202 298 IPython.Tooltip = Tooltip;
203 299
204 300 return IPython;
205 301 }(IPython));
@@ -1,242 +1,242
1 1 {% extends page.html %}
2 2 {% block stylesheet %}
3 3
4 4 {% if mathjax_url %}
5 5 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
6 6 {% end %}
7 7 <script type="text/javascript">
8 8 // MathJax disabled, set as null to distingish from *missing* MathJax,
9 9 // where it will be undefined, and should prompt a dialog later.
10 10 window.mathjax_url = "{{mathjax_url}}";
11 11 </script>
12 12
13 13 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
14 14 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
15 15
16 16 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
17 17
18 18 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
19 19 <link rel="stylesheet" href="{{ static_url("css/tooltip.css") }}" type="text/css" />
20 20 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
21 21
22 22 {% end %}
23 23
24 24
25 25 {% block params %}
26 26
27 27 data-project={{project}}
28 28 data-base-project-url={{base_project_url}}
29 29 data-base-kernel-url={{base_kernel_url}}
30 30 data-read-only={{read_only and not logged_in}}
31 31 data-notebook-id={{notebook_id}}
32 32
33 33 {% end %}
34 34
35 35
36 36 {% block header %}
37 37
38 38 <span id="save_widget">
39 39 <span id="notebook_name"></span>
40 40 <span id="save_status"></span>
41 41 </span>
42 42
43 43 {% end %}
44 44
45 45
46 46 {% block site %}
47 47
48 48 <div id="menubar_container">
49 49 <div id="menubar">
50 50 <ul id="menus">
51 51 <li><a href="#">File</a>
52 52 <ul>
53 53 <li id="new_notebook"><a href="#">New</a></li>
54 54 <li id="open_notebook"><a href="#">Open...</a></li>
55 55 <hr/>
56 56 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
57 57 <li id="rename_notebook"><a href="#">Rename...</a></li>
58 58 <li id="save_notebook"><a href="#">Save</a></li>
59 59 <hr/>
60 60 <li><a href="#">Download as</a>
61 61 <ul>
62 62 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
63 63 <li id="download_py"><a href="#">Python (.py)</a></li>
64 64 </ul>
65 65 </li>
66 66 <hr/>
67 67 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
68 68 <hr/>
69 69 <li id="kill_and_exit"><a href="#" >Close and halt</a></li>
70 70 </ul>
71 71 </li>
72 72 <li><a href="#">Edit</a>
73 73 <ul>
74 74 <li id="cut_cell"><a href="#">Cut Cell</a></li>
75 75 <li id="copy_cell"><a href="#">Copy Cell</a></li>
76 76 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
77 77 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
78 78 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
79 79 <li id="delete_cell"><a href="#">Delete</a></li>
80 80 <hr/>
81 81 <li id="split_cell"><a href="#">Split Cell</a></li>
82 82 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
83 83 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
84 84 <hr/>
85 85 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
86 86 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
87 87 <hr/>
88 88 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
89 89 <li id="select_next"><a href="#">Select Next Cell</a></li>
90 90 </ul>
91 91 </li>
92 92 <li><a href="#">View</a>
93 93 <ul>
94 94 <li id="toggle_header"><a href="#">Toggle Header</a></li>
95 95 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
96 96 </ul>
97 97 </li>
98 98 <li><a href="#">Insert</a>
99 99 <ul>
100 100 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
101 101 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
102 102 </ul>
103 103 </li>
104 104 <li><a href="#">Cell</a>
105 105 <ul>
106 106 <li id="run_cell"><a href="#">Run</a></li>
107 107 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
108 108 <li id="run_all_cells"><a href="#">Run All</a></li>
109 109 <hr/>
110 110 <li id="to_code"><a href="#">Code</a></li>
111 111 <li id="to_markdown"><a href="#">Markdown </a></li>
112 112 <li id="to_raw"><a href="#">Raw Text</a></li>
113 113 <li id="to_heading1"><a href="#">Heading 1</a></li>
114 114 <li id="to_heading2"><a href="#">Heading 2</a></li>
115 115 <li id="to_heading3"><a href="#">Heading 3</a></li>
116 116 <li id="to_heading4"><a href="#">Heading 4</a></li>
117 117 <li id="to_heading5"><a href="#">Heading 5</a></li>
118 118 <li id="to_heading6"><a href="#">Heading 6</a></li>
119 119 <hr/>
120 120 <li id="toggle_output"><a href="#">Toggle Output</a></li>
121 121 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
122 122 </ul>
123 123 </li>
124 124 <li><a href="#">Kernel</a>
125 125 <ul>
126 126 <li id="int_kernel"><a href="#">Interrupt</a></li>
127 127 <li id="restart_kernel"><a href="#">Restart</a></li>
128 128 </ul>
129 129 </li>
130 130 <li><a href="#">Help</a>
131 131 <ul>
132 132 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
133 133 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
134 134 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
135 135 <hr/>
136 136 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
137 137 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
138 138 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
139 139 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
140 140 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
141 141 </ul>
142 142 </li>
143 143 </ul>
144 144
145 145 </div>
146 146 <div id="notification"></div>
147 147 </div>
148 148
149 149
150 150 <div id="toolbar">
151 151
152 152 <span>
153 153 <button id="save_b">Save</button>
154 154 </span>
155 155 <span id="cut_copy_paste">
156 156 <button id="cut_b" title="Cut Cell">Cut Cell</button>
157 157 <button id="copy_b" title="Copy Cell">Copy Cell</button>
158 158 <button id="paste_b" title="Paste Cell">Paste Cell</button>
159 159 </span>
160 160 <span id="move_up_down">
161 161 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
162 162 <button id="move_down_b" title="Move Cell Down">Move Down</button>
163 163 </span>
164 164 <span id="insert_above_below">
165 165 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
166 166 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
167 167 </span>
168 168 <span id="run_int">
169 169 <button id="run_b" title="Run Cell">Run Cell</button>
170 170 <button id="interrupt_b" title="Interrupt">Interrupt</button>
171 171 </span>
172 172 <span>
173 173 <select id="cell_type">
174 174 <option value="code">Code</option>
175 175 <option value="markdown">Markdown</option>
176 176 <option value="raw">Raw Text</option>
177 177 <option value="heading1">Heading 1</option>
178 178 <option value="heading2">Heading 2</option>
179 179 <option value="heading3">Heading 3</option>
180 180 <option value="heading4">Heading 4</option>
181 181 <option value="heading5">Heading 5</option>
182 182 <option value="heading6">Heading 6</option>
183 183 </select>
184 184 </span>
185 185
186 186 </div>
187 187
188 188 <div id="main_app">
189 189
190 190 <div id="notebook_panel">
191 191 <div id="notebook"></div>
192 192 <div id="pager_splitter"></div>
193 193 <div id="pager"></div>
194 194 </div>
195 195
196 196 </div>
197 <div id='tooltip' class='tooltip ui-corner-all hidden'></div>
197 <div id='tooltip' class='tooltip ui-corner-all hidden hide'></div>
198 198
199 199
200 200 {% end %}
201 201
202 202
203 203 {% block script %}
204 204
205 205 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
206 206 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
207 207 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
208 208 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
209 209 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
210 210 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
211 211 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
212 212 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
213 213
214 214 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
215 215
216 216 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
217 217 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
218 218
219 219 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
220 220 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
221 221 <script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
222 222 <script src="{{ static_url("js/initmathjax.js") }}" type="text/javascript" charset="utf-8"></script>
223 223 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
224 224 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
225 225 <script src="{{ static_url("js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
226 226 <script src="{{ static_url("js/context-hint.js") }} charset="utf-8"></script>
227 227 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
228 228 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
229 229 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
230 230 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
231 231 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
232 232 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
233 233 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
234 234 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
235 235 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
236 236 <script src="{{ static_url("js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
237 237 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
238 238
239 239 <script src="{{ static_url("js/context-hint.js") }} charset="utf-8"></script>
240 240 <script src="{{ static_url("codemirror/lib/util/simple-hint.js") }} charset="utf-8"></script>
241 241
242 242 {% end %}
General Comments 0
You need to be logged in to leave comments. Login now