##// END OF EJS Templates
fix scrolltop
Matthias Bussonnier -
Show More
@@ -1,643 +1,633
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 // CodeCell
9 // CodeCell
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16 var key = IPython.utils.keycodes;
16 var key = IPython.utils.keycodes;
17
17
18 var CodeCell = function (notebook) {
18 var CodeCell = function (notebook) {
19 this.code_mirror = null;
19 this.code_mirror = null;
20 this.input_prompt_number = null;
20 this.input_prompt_number = null;
21 this.outputs = [];
21 this.outputs = [];
22 this.collapsed = false;
22 this.collapsed = false;
23 this.tooltip_timeout = null;
23 this.tooltip_timeout = null;
24 this.clear_out_timeout = null;
24 this.clear_out_timeout = null;
25 IPython.Cell.apply(this, arguments);
25 IPython.Cell.apply(this, arguments);
26 };
26 };
27
27
28
28
29 CodeCell.prototype = new IPython.Cell();
29 CodeCell.prototype = new IPython.Cell();
30
30
31
31
32 CodeCell.prototype.create_element = function () {
32 CodeCell.prototype.create_element = function () {
33 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
33 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
34 cell.attr('tabindex','2');
34 cell.attr('tabindex','2');
35 var input = $('<div></div>').addClass('input hbox');
35 var input = $('<div></div>').addClass('input hbox');
36 input.append($('<div/>').addClass('prompt input_prompt'));
36 input.append($('<div/>').addClass('prompt input_prompt'));
37 var input_area = $('<div/>').addClass('input_area box-flex1');
37 var input_area = $('<div/>').addClass('input_area box-flex1');
38 this.code_mirror = CodeMirror(input_area.get(0), {
38 this.code_mirror = CodeMirror(input_area.get(0), {
39 indentUnit : 4,
39 indentUnit : 4,
40 mode: 'python',
40 mode: 'python',
41 theme: 'ipython',
41 theme: 'ipython',
42 readOnly: this.read_only,
42 readOnly: this.read_only,
43 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
43 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
44 });
44 });
45 input.append(input_area);
45 input.append(input_area);
46 var output = $('<div></div>').addClass('output vbox');
46 var output = $('<div></div>').addClass('output vbox');
47 cell.append(input).append(output);
47 cell.append(input).append(output);
48 this.element = cell;
48 this.element = cell;
49 this.collapse();
49 this.collapse();
50
50
51 // construct a completer
51 // construct a completer
52 this.completer = new IPython.Completer(this);
52 this.completer = new IPython.Completer(this);
53 };
53 };
54
54
55 //TODO, try to diminish the number of parameters.
55 //TODO, try to diminish the number of parameters.
56 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
56 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
57 var that = this;
57 var that = this;
58 if (pre_cursor === "" || pre_cursor === "(" ) {
58 if (pre_cursor === "" || pre_cursor === "(" ) {
59 // don't do anything if line beggin with '(' or is empty
59 // don't do anything if line beggin with '(' or is empty
60 } else {
60 } else {
61 // Will set a timer to request tooltip in `time`
61 // Will set a timer to request tooltip in `time`
62 that.tooltip_timeout = setTimeout(function(){
62 that.tooltip_timeout = setTimeout(function(){
63 IPython.notebook.request_tool_tip(that, pre_cursor)
63 IPython.notebook.request_tool_tip(that, pre_cursor)
64 },time);
64 },time);
65 }
65 }
66 };
66 };
67
67
68 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
68 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
69 // This method gets called in CodeMirror's onKeyDown/onKeyPress
69 // This method gets called in CodeMirror's onKeyDown/onKeyPress
70 // handlers and is used to provide custom key handling. Its return
70 // handlers and is used to provide custom key handling. Its return
71 // value is used to determine if CodeMirror should ignore the event:
71 // value is used to determine if CodeMirror should ignore the event:
72 // true = ignore, false = don't ignore.
72 // true = ignore, false = don't ignore.
73
73
74 if (this.read_only){
74 if (this.read_only){
75 return false;
75 return false;
76 }
76 }
77
77
78 // note that we are comparing and setting the time to wait at each key press.
78 // note that we are comparing and setting the time to wait at each key press.
79 // a better wqy might be to generate a new function on each time change and
79 // a better wqy might be to generate a new function on each time change and
80 // assign it to CodeCell.prototype.request_tooltip_after_time
80 // assign it to CodeCell.prototype.request_tooltip_after_time
81 var tooltip_wait_time = this.notebook.time_before_tooltip;
81 var tooltip_wait_time = this.notebook.time_before_tooltip;
82 var tooltip_on_tab = this.notebook.tooltip_on_tab;
82 var tooltip_on_tab = this.notebook.tooltip_on_tab;
83 var that = this;
83 var that = this;
84 // whatever key is pressed, first, cancel the tooltip request before
84 // whatever key is pressed, first, cancel the tooltip request before
85 // they are sent, and remove tooltip if any
85 // they are sent, and remove tooltip if any
86 if(event.type === 'keydown' ) {
86 if(event.type === 'keydown' ) {
87 that.remove_and_cancel_tooltip();
87 IPython.tooltip.remove_and_cancel_tooltip();
88 };
88 };
89
89
90
90
91 if (event.keyCode === key.enter && (event.shiftKey || event.ctrlKey)) {
91 if (event.keyCode === key.enter && (event.shiftKey || event.ctrlKey)) {
92 // Always ignore shift-enter in CodeMirror as we handle it.
92 // Always ignore shift-enter in CodeMirror as we handle it.
93 return true;
93 return true;
94 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
94 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
95 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
95 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
96 // browser and keyboard layout !
96 // browser and keyboard layout !
97 // Pressing '(' , request tooltip, don't forget to reappend it
97 // Pressing '(' , request tooltip, don't forget to reappend it
98 var cursor = editor.getCursor();
98 var cursor = editor.getCursor();
99 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
99 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
100 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
100 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
101 } else if (event.which === key.upArrow) {
101 } else if (event.which === key.upArrow) {
102 // If we are not at the top, let CM handle the up arrow and
102 // If we are not at the top, let CM handle the up arrow and
103 // prevent the global keydown handler from handling it.
103 // prevent the global keydown handler from handling it.
104 if (!that.at_top()) {
104 if (!that.at_top()) {
105 event.stop();
105 event.stop();
106 return false;
106 return false;
107 } else {
107 } else {
108 return true;
108 return true;
109 };
109 };
110 } else if (event.which === key.downArrow) {
110 } else if (event.which === key.downArrow) {
111 // If we are not at the bottom, let CM handle the down arrow and
111 // If we are not at the bottom, let CM handle the down arrow and
112 // prevent the global keydown handler from handling it.
112 // prevent the global keydown handler from handling it.
113 if (!that.at_bottom()) {
113 if (!that.at_bottom()) {
114 event.stop();
114 event.stop();
115 return false;
115 return false;
116 } else {
116 } else {
117 return true;
117 return true;
118 };
118 };
119 } else if (event.keyCode === key.tab && event.type == 'keydown') {
119 } else if (event.keyCode === key.tab && event.type == 'keydown') {
120 // Tab completion.
120 // Tab completion.
121 var cur = editor.getCursor();
121 var cur = editor.getCursor();
122 //Do not trim here because of tooltip
122 //Do not trim here because of tooltip
123 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
123 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
124 if (pre_cursor.trim() === "") {
124 if (pre_cursor.trim() === "") {
125 // Don't autocomplete if the part of the line before the cursor
125 // Don't autocomplete if the part of the line before the cursor
126 // is empty. In this case, let CodeMirror handle indentation.
126 // is empty. In this case, let CodeMirror handle indentation.
127 return false;
127 return false;
128 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
128 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
129 that.request_tooltip_after_time(pre_cursor,0);
129 that.request_tooltip_after_time(pre_cursor,0);
130 // Prevent the event from bubbling up.
130 // Prevent the event from bubbling up.
131 event.stop();
131 event.stop();
132 // Prevent CodeMirror from handling the tab.
132 // Prevent CodeMirror from handling the tab.
133 return true;
133 return true;
134 } else {
134 } else {
135 event.stop();
135 event.stop();
136 this.completer.startCompletion();
136 this.completer.startCompletion();
137 return true;
137 return true;
138 };
138 };
139 } else if (event.keyCode === key.backspace && event.type == 'keydown') {
139 } else if (event.keyCode === key.backspace && event.type == 'keydown') {
140 // If backspace and the line ends with 4 spaces, remove them.
140 // If backspace and the line ends with 4 spaces, remove them.
141 var cur = editor.getCursor();
141 var cur = editor.getCursor();
142 var line = editor.getLine(cur.line);
142 var line = editor.getLine(cur.line);
143 var ending = line.slice(-4);
143 var ending = line.slice(-4);
144 if (ending === ' ') {
144 if (ending === ' ') {
145 editor.replaceRange('',
145 editor.replaceRange('',
146 {line: cur.line, ch: cur.ch-4},
146 {line: cur.line, ch: cur.ch-4},
147 {line: cur.line, ch: cur.ch}
147 {line: cur.line, ch: cur.ch}
148 );
148 );
149 event.stop();
149 event.stop();
150 return true;
150 return true;
151 } else {
151 } else {
152 return false;
152 return false;
153 };
153 };
154 } else {
154 } else {
155 // keypress/keyup also trigger on TAB press, and we don't want to
155 // keypress/keyup also trigger on TAB press, and we don't want to
156 // use those to disable tab completion.
156 // use those to disable tab completion.
157 return false;
157 return false;
158 };
158 };
159 return false;
159 return false;
160 };
160 };
161
161
162 CodeCell.prototype.remove_and_cancel_tooltip = function() {
163 // note that we don't handle closing directly inside the calltip
164 // as in the completer, because it is not focusable, so won't
165 // get the event.
166 if (this.tooltip_timeout != null){
167 clearTimeout(this.tooltip_timeout);
168 $('#tooltip').addClass('hidden');
169 this.tooltip_timeout = null;
170 }
171 }
172
162
173 CodeCell.prototype.finish_tooltip = function (reply) {
163 CodeCell.prototype.finish_tooltip = function (reply) {
174 IPython.tooltip.show(reply,this.code_mirror.cursorCoords());
164 IPython.tooltip.show(reply,this.code_mirror.cursorCoords());
175 return;
165 return;
176 // Extract call tip data; the priority is call, init, main.
166 // Extract call tip data; the priority is call, init, main.
177 defstring = reply.call_def;
167 defstring = reply.call_def;
178 if (defstring == null) { defstring = reply.init_definition; }
168 if (defstring == null) { defstring = reply.init_definition; }
179 if (defstring == null) { defstring = reply.definition; }
169 if (defstring == null) { defstring = reply.definition; }
180
170
181 docstring = reply.call_docstring;
171 docstring = reply.call_docstring;
182 if (docstring == null) { docstring = reply.init_docstring; }
172 if (docstring == null) { docstring = reply.init_docstring; }
183 if (docstring == null) { docstring = reply.docstring; }
173 if (docstring == null) { docstring = reply.docstring; }
184 if (docstring == null) { docstring = "<empty docstring>"; }
174 if (docstring == null) { docstring = "<empty docstring>"; }
185
175
186 name=reply.name;
176 name=reply.name;
187
177
188 var that = this;
178 var that = this;
189 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
179 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
190 // remove to have the tooltip not Limited in X and Y
180 // remove to have the tooltip not Limited in X and Y
191 tooltip.addClass('smalltooltip');
181 tooltip.addClass('smalltooltip');
192 var pre=$('<pre/>').html(utils.fixConsole(docstring));
182 var pre=$('<pre/>').html(utils.fixConsole(docstring));
193 var expandlink=$('<a/>').attr('href',"#");
183 var expandlink=$('<a/>').attr('href',"#");
194 expandlink.addClass("ui-corner-all"); //rounded corner
184 expandlink.addClass("ui-corner-all"); //rounded corner
195 expandlink.attr('role',"button");
185 expandlink.attr('role',"button");
196 //expandlink.addClass('ui-button');
186 //expandlink.addClass('ui-button');
197 //expandlink.addClass('ui-state-default');
187 //expandlink.addClass('ui-state-default');
198 var expandspan=$('<span/>').text('Expand');
188 var expandspan=$('<span/>').text('Expand');
199 expandspan.addClass('ui-icon');
189 expandspan.addClass('ui-icon');
200 expandspan.addClass('ui-icon-plus');
190 expandspan.addClass('ui-icon-plus');
201 expandlink.append(expandspan);
191 expandlink.append(expandspan);
202 expandlink.attr('id','expanbutton');
192 expandlink.attr('id','expanbutton');
203 expandlink.click(function(){
193 expandlink.click(function(){
204 tooltip.removeClass('smalltooltip');
194 tooltip.removeClass('smalltooltip');
205 tooltip.addClass('bigtooltip');
195 tooltip.addClass('bigtooltip');
206 $('#expanbutton').remove();
196 $('#expanbutton').remove();
207 setTimeout(function(){that.code_mirror.focus();}, 50);
197 setTimeout(function(){that.code_mirror.focus();}, 50);
208 });
198 });
209 var morelink=$('<a/>').attr('href',"#");
199 var morelink=$('<a/>').attr('href',"#");
210 morelink.attr('role',"button");
200 morelink.attr('role',"button");
211 morelink.addClass('ui-button');
201 morelink.addClass('ui-button');
212 //morelink.addClass("ui-corner-all"); //rounded corner
202 //morelink.addClass("ui-corner-all"); //rounded corner
213 //morelink.addClass('ui-state-default');
203 //morelink.addClass('ui-state-default');
214 var morespan=$('<span/>').text('Open in Pager');
204 var morespan=$('<span/>').text('Open in Pager');
215 morespan.addClass('ui-icon');
205 morespan.addClass('ui-icon');
216 morespan.addClass('ui-icon-arrowstop-l-n');
206 morespan.addClass('ui-icon-arrowstop-l-n');
217 morelink.append(morespan);
207 morelink.append(morespan);
218 morelink.click(function(){
208 morelink.click(function(){
219 var msg_id = IPython.notebook.kernel.execute(name+"?");
209 var msg_id = IPython.notebook.kernel.execute(name+"?");
220 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
210 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
221 that.remove_and_cancel_tooltip();
211 IPython.tooltip.remove_and_cancel_tooltip();
222 setTimeout(function(){that.code_mirror.focus();}, 50);
212 setTimeout(function(){that.code_mirror.focus();}, 50);
223 });
213 });
224
214
225 var closelink=$('<a/>').attr('href',"#");
215 var closelink=$('<a/>').attr('href',"#");
226 closelink.attr('role',"button");
216 closelink.attr('role',"button");
227 closelink.addClass('ui-button');
217 closelink.addClass('ui-button');
228 //closelink.addClass("ui-corner-all"); //rounded corner
218 //closelink.addClass("ui-corner-all"); //rounded corner
229 //closelink.adClass('ui-state-default'); // grey background and blue cross
219 //closelink.adClass('ui-state-default'); // grey background and blue cross
230 var closespan=$('<span/>').text('Close');
220 var closespan=$('<span/>').text('Close');
231 closespan.addClass('ui-icon');
221 closespan.addClass('ui-icon');
232 closespan.addClass('ui-icon-close');
222 closespan.addClass('ui-icon-close');
233 closelink.append(closespan);
223 closelink.append(closespan);
234 closelink.click(function(){
224 closelink.click(function(){
235 that.remove_and_cancel_tooltip();
225 IPython.tooltip.remove_and_cancel_tooltip();
236 setTimeout(function(){that.code_mirror.focus();}, 50);
226 setTimeout(function(){that.code_mirror.focus();}, 50);
237 });
227 });
238 //construct the tooltip
228 //construct the tooltip
239 tooltip.append(closelink);
229 tooltip.append(closelink);
240 tooltip.append(expandlink);
230 tooltip.append(expandlink);
241 tooltip.append(morelink);
231 tooltip.append(morelink);
242 if(defstring){
232 if(defstring){
243 defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
233 defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
244 tooltip.append(defstring_html);
234 tooltip.append(defstring_html);
245 }
235 }
246 tooltip.append(pre);
236 tooltip.append(pre);
247 var pos = this.code_mirror.cursorCoords();
237 var pos = this.code_mirror.cursorCoords();
248 tooltip.css('left',pos.x+'px');
238 tooltip.css('left',pos.x+'px');
249 tooltip.css('top',pos.yBot+'px');
239 tooltip.css('top',pos.yBot+'px');
250 $('body').append(tooltip);
240 $('body').append(tooltip);
251
241
252 // issues with cross-closing if multiple tooltip in less than 5sec
242 // issues with cross-closing if multiple tooltip in less than 5sec
253 // keep it comented for now
243 // keep it comented for now
254 // setTimeout(that.remove_and_cancel_tooltip, 5000);
244 // setTimeout(that.remove_and_cancel_tooltip, 5000);
255 };
245 };
256
246
257
247
258 // called when completion came back from the kernel. just forward
248 // called when completion came back from the kernel. just forward
259 CodeCell.prototype.finish_completing = function (matched_text, matches) {
249 CodeCell.prototype.finish_completing = function (matched_text, matches) {
260 this.completer.finish_completing(matched_text,matches);
250 this.completer.finish_completing(matched_text,matches);
261 }
251 }
262
252
263
253
264 CodeCell.prototype.select = function () {
254 CodeCell.prototype.select = function () {
265 IPython.Cell.prototype.select.apply(this);
255 IPython.Cell.prototype.select.apply(this);
266 this.code_mirror.refresh();
256 this.code_mirror.refresh();
267 this.code_mirror.focus();
257 this.code_mirror.focus();
268 // We used to need an additional refresh() after the focus, but
258 // We used to need an additional refresh() after the focus, but
269 // it appears that this has been fixed in CM. This bug would show
259 // it appears that this has been fixed in CM. This bug would show
270 // up on FF when a newly loaded markdown cell was edited.
260 // up on FF when a newly loaded markdown cell was edited.
271 };
261 };
272
262
273
263
274 CodeCell.prototype.select_all = function () {
264 CodeCell.prototype.select_all = function () {
275 var start = {line: 0, ch: 0};
265 var start = {line: 0, ch: 0};
276 var nlines = this.code_mirror.lineCount();
266 var nlines = this.code_mirror.lineCount();
277 var last_line = this.code_mirror.getLine(nlines-1);
267 var last_line = this.code_mirror.getLine(nlines-1);
278 var end = {line: nlines-1, ch: last_line.length};
268 var end = {line: nlines-1, ch: last_line.length};
279 this.code_mirror.setSelection(start, end);
269 this.code_mirror.setSelection(start, end);
280 };
270 };
281
271
282
272
283 CodeCell.prototype.append_output = function (json, dynamic) {
273 CodeCell.prototype.append_output = function (json, dynamic) {
284 // If dynamic is true, javascript output will be eval'd.
274 // If dynamic is true, javascript output will be eval'd.
285 this.expand();
275 this.expand();
286 this.flush_clear_timeout();
276 this.flush_clear_timeout();
287 if (json.output_type === 'pyout') {
277 if (json.output_type === 'pyout') {
288 this.append_pyout(json, dynamic);
278 this.append_pyout(json, dynamic);
289 } else if (json.output_type === 'pyerr') {
279 } else if (json.output_type === 'pyerr') {
290 this.append_pyerr(json);
280 this.append_pyerr(json);
291 } else if (json.output_type === 'display_data') {
281 } else if (json.output_type === 'display_data') {
292 this.append_display_data(json, dynamic);
282 this.append_display_data(json, dynamic);
293 } else if (json.output_type === 'stream') {
283 } else if (json.output_type === 'stream') {
294 this.append_stream(json);
284 this.append_stream(json);
295 };
285 };
296 this.outputs.push(json);
286 this.outputs.push(json);
297 };
287 };
298
288
299
289
300 CodeCell.prototype.create_output_area = function () {
290 CodeCell.prototype.create_output_area = function () {
301 var oa = $("<div/>").addClass("hbox output_area");
291 var oa = $("<div/>").addClass("hbox output_area");
302 oa.append($('<div/>').addClass('prompt'));
292 oa.append($('<div/>').addClass('prompt'));
303 return oa;
293 return oa;
304 };
294 };
305
295
306
296
307 CodeCell.prototype.append_pyout = function (json, dynamic) {
297 CodeCell.prototype.append_pyout = function (json, dynamic) {
308 var n = json.prompt_number || ' ';
298 var n = json.prompt_number || ' ';
309 var toinsert = this.create_output_area();
299 var toinsert = this.create_output_area();
310 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
300 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
311 this.append_mime_type(json, toinsert, dynamic);
301 this.append_mime_type(json, toinsert, dynamic);
312 this.element.find('div.output').append(toinsert);
302 this.element.find('div.output').append(toinsert);
313 // If we just output latex, typeset it.
303 // If we just output latex, typeset it.
314 if ((json.latex !== undefined) || (json.html !== undefined)) {
304 if ((json.latex !== undefined) || (json.html !== undefined)) {
315 this.typeset();
305 this.typeset();
316 };
306 };
317 };
307 };
318
308
319
309
320 CodeCell.prototype.append_pyerr = function (json) {
310 CodeCell.prototype.append_pyerr = function (json) {
321 var tb = json.traceback;
311 var tb = json.traceback;
322 if (tb !== undefined && tb.length > 0) {
312 if (tb !== undefined && tb.length > 0) {
323 var s = '';
313 var s = '';
324 var len = tb.length;
314 var len = tb.length;
325 for (var i=0; i<len; i++) {
315 for (var i=0; i<len; i++) {
326 s = s + tb[i] + '\n';
316 s = s + tb[i] + '\n';
327 }
317 }
328 s = s + '\n';
318 s = s + '\n';
329 var toinsert = this.create_output_area();
319 var toinsert = this.create_output_area();
330 this.append_text(s, toinsert);
320 this.append_text(s, toinsert);
331 this.element.find('div.output').append(toinsert);
321 this.element.find('div.output').append(toinsert);
332 };
322 };
333 };
323 };
334
324
335
325
336 CodeCell.prototype.append_stream = function (json) {
326 CodeCell.prototype.append_stream = function (json) {
337 // temporary fix: if stream undefined (json file written prior to this patch),
327 // temporary fix: if stream undefined (json file written prior to this patch),
338 // default to most likely stdout:
328 // default to most likely stdout:
339 if (json.stream == undefined){
329 if (json.stream == undefined){
340 json.stream = 'stdout';
330 json.stream = 'stdout';
341 }
331 }
342 if (!utils.fixConsole(json.text)){
332 if (!utils.fixConsole(json.text)){
343 // fixConsole gives nothing (empty string, \r, etc.)
333 // fixConsole gives nothing (empty string, \r, etc.)
344 // so don't append any elements, which might add undesirable space
334 // so don't append any elements, which might add undesirable space
345 return;
335 return;
346 }
336 }
347 var subclass = "output_"+json.stream;
337 var subclass = "output_"+json.stream;
348 if (this.outputs.length > 0){
338 if (this.outputs.length > 0){
349 // have at least one output to consider
339 // have at least one output to consider
350 var last = this.outputs[this.outputs.length-1];
340 var last = this.outputs[this.outputs.length-1];
351 if (last.output_type == 'stream' && json.stream == last.stream){
341 if (last.output_type == 'stream' && json.stream == last.stream){
352 // latest output was in the same stream,
342 // latest output was in the same stream,
353 // so append directly into its pre tag
343 // so append directly into its pre tag
354 // escape ANSI & HTML specials:
344 // escape ANSI & HTML specials:
355 var text = utils.fixConsole(json.text);
345 var text = utils.fixConsole(json.text);
356 this.element.find('div.'+subclass).last().find('pre').append(text);
346 this.element.find('div.'+subclass).last().find('pre').append(text);
357 return;
347 return;
358 }
348 }
359 }
349 }
360
350
361 // If we got here, attach a new div
351 // If we got here, attach a new div
362 var toinsert = this.create_output_area();
352 var toinsert = this.create_output_area();
363 this.append_text(json.text, toinsert, "output_stream "+subclass);
353 this.append_text(json.text, toinsert, "output_stream "+subclass);
364 this.element.find('div.output').append(toinsert);
354 this.element.find('div.output').append(toinsert);
365 };
355 };
366
356
367
357
368 CodeCell.prototype.append_display_data = function (json, dynamic) {
358 CodeCell.prototype.append_display_data = function (json, dynamic) {
369 var toinsert = this.create_output_area();
359 var toinsert = this.create_output_area();
370 this.append_mime_type(json, toinsert, dynamic);
360 this.append_mime_type(json, toinsert, dynamic);
371 this.element.find('div.output').append(toinsert);
361 this.element.find('div.output').append(toinsert);
372 // If we just output latex, typeset it.
362 // If we just output latex, typeset it.
373 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
363 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
374 this.typeset();
364 this.typeset();
375 };
365 };
376 };
366 };
377
367
378
368
379 CodeCell.prototype.append_mime_type = function (json, element, dynamic) {
369 CodeCell.prototype.append_mime_type = function (json, element, dynamic) {
380 if (json.javascript !== undefined && dynamic) {
370 if (json.javascript !== undefined && dynamic) {
381 this.append_javascript(json.javascript, element, dynamic);
371 this.append_javascript(json.javascript, element, dynamic);
382 } else if (json.html !== undefined) {
372 } else if (json.html !== undefined) {
383 this.append_html(json.html, element);
373 this.append_html(json.html, element);
384 } else if (json.latex !== undefined) {
374 } else if (json.latex !== undefined) {
385 this.append_latex(json.latex, element);
375 this.append_latex(json.latex, element);
386 } else if (json.svg !== undefined) {
376 } else if (json.svg !== undefined) {
387 this.append_svg(json.svg, element);
377 this.append_svg(json.svg, element);
388 } else if (json.png !== undefined) {
378 } else if (json.png !== undefined) {
389 this.append_png(json.png, element);
379 this.append_png(json.png, element);
390 } else if (json.jpeg !== undefined) {
380 } else if (json.jpeg !== undefined) {
391 this.append_jpeg(json.jpeg, element);
381 this.append_jpeg(json.jpeg, element);
392 } else if (json.text !== undefined) {
382 } else if (json.text !== undefined) {
393 this.append_text(json.text, element);
383 this.append_text(json.text, element);
394 };
384 };
395 };
385 };
396
386
397
387
398 CodeCell.prototype.append_html = function (html, element) {
388 CodeCell.prototype.append_html = function (html, element) {
399 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
389 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
400 toinsert.append(html);
390 toinsert.append(html);
401 element.append(toinsert);
391 element.append(toinsert);
402 };
392 };
403
393
404
394
405 CodeCell.prototype.append_javascript = function (js, container) {
395 CodeCell.prototype.append_javascript = function (js, container) {
406 // We just eval the JS code, element appears in the local scope.
396 // We just eval the JS code, element appears in the local scope.
407 var element = $("<div/>").addClass("box_flex1 output_subarea");
397 var element = $("<div/>").addClass("box_flex1 output_subarea");
408 container.append(element);
398 container.append(element);
409 // Div for js shouldn't be drawn, as it will add empty height to the area.
399 // Div for js shouldn't be drawn, as it will add empty height to the area.
410 container.hide();
400 container.hide();
411 // If the Javascript appends content to `element` that should be drawn, then
401 // If the Javascript appends content to `element` that should be drawn, then
412 // it must also call `container.show()`.
402 // it must also call `container.show()`.
413 eval(js);
403 eval(js);
414 }
404 }
415
405
416
406
417 CodeCell.prototype.append_text = function (data, element, extra_class) {
407 CodeCell.prototype.append_text = function (data, element, extra_class) {
418 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
408 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
419 // escape ANSI & HTML specials in plaintext:
409 // escape ANSI & HTML specials in plaintext:
420 data = utils.fixConsole(data);
410 data = utils.fixConsole(data);
421 if (extra_class){
411 if (extra_class){
422 toinsert.addClass(extra_class);
412 toinsert.addClass(extra_class);
423 }
413 }
424 toinsert.append($("<pre/>").html(data));
414 toinsert.append($("<pre/>").html(data));
425 element.append(toinsert);
415 element.append(toinsert);
426 };
416 };
427
417
428
418
429 CodeCell.prototype.append_svg = function (svg, element) {
419 CodeCell.prototype.append_svg = function (svg, element) {
430 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
420 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
431 toinsert.append(svg);
421 toinsert.append(svg);
432 element.append(toinsert);
422 element.append(toinsert);
433 };
423 };
434
424
435
425
436 CodeCell.prototype.append_png = function (png, element) {
426 CodeCell.prototype.append_png = function (png, element) {
437 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
427 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
438 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
428 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
439 element.append(toinsert);
429 element.append(toinsert);
440 };
430 };
441
431
442
432
443 CodeCell.prototype.append_jpeg = function (jpeg, element) {
433 CodeCell.prototype.append_jpeg = function (jpeg, element) {
444 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
434 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
445 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
435 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
446 element.append(toinsert);
436 element.append(toinsert);
447 };
437 };
448
438
449
439
450 CodeCell.prototype.append_latex = function (latex, element) {
440 CodeCell.prototype.append_latex = function (latex, element) {
451 // This method cannot do the typesetting because the latex first has to
441 // This method cannot do the typesetting because the latex first has to
452 // be on the page.
442 // be on the page.
453 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
443 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
454 toinsert.append(latex);
444 toinsert.append(latex);
455 element.append(toinsert);
445 element.append(toinsert);
456 };
446 };
457
447
458
448
459 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
449 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
460 var that = this;
450 var that = this;
461 if (this.clear_out_timeout != null){
451 if (this.clear_out_timeout != null){
462 // fire previous pending clear *immediately*
452 // fire previous pending clear *immediately*
463 clearTimeout(this.clear_out_timeout);
453 clearTimeout(this.clear_out_timeout);
464 this.clear_out_timeout = null;
454 this.clear_out_timeout = null;
465 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
455 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
466 }
456 }
467 // store flags for flushing the timeout
457 // store flags for flushing the timeout
468 this._clear_stdout = stdout;
458 this._clear_stdout = stdout;
469 this._clear_stderr = stderr;
459 this._clear_stderr = stderr;
470 this._clear_other = other;
460 this._clear_other = other;
471 this.clear_out_timeout = setTimeout(function(){
461 this.clear_out_timeout = setTimeout(function(){
472 // really clear timeout only after a short delay
462 // really clear timeout only after a short delay
473 // this reduces flicker in 'clear_output; print' cases
463 // this reduces flicker in 'clear_output; print' cases
474 that.clear_out_timeout = null;
464 that.clear_out_timeout = null;
475 that._clear_stdout = that._clear_stderr = that._clear_other = null;
465 that._clear_stdout = that._clear_stderr = that._clear_other = null;
476 that.clear_output_callback(stdout, stderr, other);
466 that.clear_output_callback(stdout, stderr, other);
477 }, 500
467 }, 500
478 );
468 );
479 };
469 };
480
470
481 CodeCell.prototype.clear_output_callback = function (stdout, stderr, other) {
471 CodeCell.prototype.clear_output_callback = function (stdout, stderr, other) {
482 var output_div = this.element.find("div.output");
472 var output_div = this.element.find("div.output");
483
473
484 if (stdout && stderr && other){
474 if (stdout && stderr && other){
485 // clear all, no need for logic
475 // clear all, no need for logic
486 output_div.html("");
476 output_div.html("");
487 this.outputs = [];
477 this.outputs = [];
488 return;
478 return;
489 }
479 }
490 // remove html output
480 // remove html output
491 // each output_subarea that has an identifying class is in an output_area
481 // each output_subarea that has an identifying class is in an output_area
492 // which is the element to be removed.
482 // which is the element to be removed.
493 if (stdout){
483 if (stdout){
494 output_div.find("div.output_stdout").parent().remove();
484 output_div.find("div.output_stdout").parent().remove();
495 }
485 }
496 if (stderr){
486 if (stderr){
497 output_div.find("div.output_stderr").parent().remove();
487 output_div.find("div.output_stderr").parent().remove();
498 }
488 }
499 if (other){
489 if (other){
500 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
490 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
501 }
491 }
502
492
503 // remove cleared outputs from JSON list:
493 // remove cleared outputs from JSON list:
504 for (var i = this.outputs.length - 1; i >= 0; i--){
494 for (var i = this.outputs.length - 1; i >= 0; i--){
505 var out = this.outputs[i];
495 var out = this.outputs[i];
506 var output_type = out.output_type;
496 var output_type = out.output_type;
507 if (output_type == "display_data" && other){
497 if (output_type == "display_data" && other){
508 this.outputs.splice(i,1);
498 this.outputs.splice(i,1);
509 }else if (output_type == "stream"){
499 }else if (output_type == "stream"){
510 if (stdout && out.stream == "stdout"){
500 if (stdout && out.stream == "stdout"){
511 this.outputs.splice(i,1);
501 this.outputs.splice(i,1);
512 }else if (stderr && out.stream == "stderr"){
502 }else if (stderr && out.stream == "stderr"){
513 this.outputs.splice(i,1);
503 this.outputs.splice(i,1);
514 }
504 }
515 }
505 }
516 }
506 }
517 };
507 };
518
508
519
509
520 CodeCell.prototype.clear_input = function () {
510 CodeCell.prototype.clear_input = function () {
521 this.code_mirror.setValue('');
511 this.code_mirror.setValue('');
522 };
512 };
523
513
524 CodeCell.prototype.flush_clear_timeout = function() {
514 CodeCell.prototype.flush_clear_timeout = function() {
525 var output_div = this.element.find('div.output');
515 var output_div = this.element.find('div.output');
526 if (this.clear_out_timeout){
516 if (this.clear_out_timeout){
527 clearTimeout(this.clear_out_timeout);
517 clearTimeout(this.clear_out_timeout);
528 this.clear_out_timeout = null;
518 this.clear_out_timeout = null;
529 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
519 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
530 };
520 };
531 }
521 }
532
522
533
523
534 CodeCell.prototype.collapse = function () {
524 CodeCell.prototype.collapse = function () {
535 if (!this.collapsed) {
525 if (!this.collapsed) {
536 this.element.find('div.output').hide();
526 this.element.find('div.output').hide();
537 this.collapsed = true;
527 this.collapsed = true;
538 };
528 };
539 };
529 };
540
530
541
531
542 CodeCell.prototype.expand = function () {
532 CodeCell.prototype.expand = function () {
543 if (this.collapsed) {
533 if (this.collapsed) {
544 this.element.find('div.output').show();
534 this.element.find('div.output').show();
545 this.collapsed = false;
535 this.collapsed = false;
546 };
536 };
547 };
537 };
548
538
549
539
550 CodeCell.prototype.toggle_output = function () {
540 CodeCell.prototype.toggle_output = function () {
551 if (this.collapsed) {
541 if (this.collapsed) {
552 this.expand();
542 this.expand();
553 } else {
543 } else {
554 this.collapse();
544 this.collapse();
555 };
545 };
556 };
546 };
557
547
558 CodeCell.prototype.set_input_prompt = function (number) {
548 CodeCell.prototype.set_input_prompt = function (number) {
559 this.input_prompt_number = number;
549 this.input_prompt_number = number;
560 var ns = number || "&nbsp;";
550 var ns = number || "&nbsp;";
561 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
551 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
562 };
552 };
563
553
564
554
565 CodeCell.prototype.get_text = function () {
555 CodeCell.prototype.get_text = function () {
566 return this.code_mirror.getValue();
556 return this.code_mirror.getValue();
567 };
557 };
568
558
569
559
570 CodeCell.prototype.set_text = function (code) {
560 CodeCell.prototype.set_text = function (code) {
571 return this.code_mirror.setValue(code);
561 return this.code_mirror.setValue(code);
572 };
562 };
573
563
574
564
575 CodeCell.prototype.at_top = function () {
565 CodeCell.prototype.at_top = function () {
576 var cursor = this.code_mirror.getCursor();
566 var cursor = this.code_mirror.getCursor();
577 if (cursor.line === 0) {
567 if (cursor.line === 0) {
578 return true;
568 return true;
579 } else {
569 } else {
580 return false;
570 return false;
581 }
571 }
582 };
572 };
583
573
584
574
585 CodeCell.prototype.at_bottom = function () {
575 CodeCell.prototype.at_bottom = function () {
586 var cursor = this.code_mirror.getCursor();
576 var cursor = this.code_mirror.getCursor();
587 if (cursor.line === (this.code_mirror.lineCount()-1)) {
577 if (cursor.line === (this.code_mirror.lineCount()-1)) {
588 return true;
578 return true;
589 } else {
579 } else {
590 return false;
580 return false;
591 }
581 }
592 };
582 };
593
583
594
584
595 CodeCell.prototype.fromJSON = function (data) {
585 CodeCell.prototype.fromJSON = function (data) {
596 if (data.cell_type === 'code') {
586 if (data.cell_type === 'code') {
597 if (data.input !== undefined) {
587 if (data.input !== undefined) {
598 this.set_text(data.input);
588 this.set_text(data.input);
599 }
589 }
600 if (data.prompt_number !== undefined) {
590 if (data.prompt_number !== undefined) {
601 this.set_input_prompt(data.prompt_number);
591 this.set_input_prompt(data.prompt_number);
602 } else {
592 } else {
603 this.set_input_prompt();
593 this.set_input_prompt();
604 };
594 };
605 var len = data.outputs.length;
595 var len = data.outputs.length;
606 for (var i=0; i<len; i++) {
596 for (var i=0; i<len; i++) {
607 // append with dynamic=false.
597 // append with dynamic=false.
608 this.append_output(data.outputs[i], false);
598 this.append_output(data.outputs[i], false);
609 };
599 };
610 if (data.collapsed !== undefined) {
600 if (data.collapsed !== undefined) {
611 if (data.collapsed) {
601 if (data.collapsed) {
612 this.collapse();
602 this.collapse();
613 } else {
603 } else {
614 this.expand();
604 this.expand();
615 };
605 };
616 };
606 };
617 };
607 };
618 };
608 };
619
609
620
610
621 CodeCell.prototype.toJSON = function () {
611 CodeCell.prototype.toJSON = function () {
622 var data = {};
612 var data = {};
623 data.input = this.get_text();
613 data.input = this.get_text();
624 data.cell_type = 'code';
614 data.cell_type = 'code';
625 if (this.input_prompt_number) {
615 if (this.input_prompt_number) {
626 data.prompt_number = this.input_prompt_number;
616 data.prompt_number = this.input_prompt_number;
627 };
617 };
628 var outputs = [];
618 var outputs = [];
629 var len = this.outputs.length;
619 var len = this.outputs.length;
630 for (var i=0; i<len; i++) {
620 for (var i=0; i<len; i++) {
631 outputs[i] = this.outputs[i];
621 outputs[i] = this.outputs[i];
632 };
622 };
633 data.outputs = outputs;
623 data.outputs = outputs;
634 data.language = 'python';
624 data.language = 'python';
635 data.collapsed = this.collapsed;
625 data.collapsed = this.collapsed;
636 return data;
626 return data;
637 };
627 };
638
628
639
629
640 IPython.CodeCell = CodeCell;
630 IPython.CodeCell = CodeCell;
641
631
642 return IPython;
632 return IPython;
643 }(IPython));
633 }(IPython));
@@ -1,206 +1,168
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
11
12 // Todo :
12 // Todo :
13 // use codemirror highlight example to
13 // use codemirror highlight example to
14 // highlight the introspection request and introspect on mouse hove ...
14 // highlight the introspection request and introspect on mouse hove ...
15 //
16 //
15 var IPython = (function (IPython) {
17 var IPython = (function (IPython) {
16
18
17 var utils = IPython.utils;
19 var utils = IPython.utils;
18
20
19 var Tooltip = function (notebook) {
21 var Tooltip = function (notebook) {
20 this.tooltip = $('#tooltip');
22 this.tooltip = $('#tooltip');
23 var that = this;
21
24
22 // contain the button in the upper right corner
25 // contain the button in the upper right corner
23 this.buttons = $('<div/>')
26 this.buttons = $('<div/>')
24 .addClass('tooltipbuttons');
27 .addClass('tooltipbuttons');
25
28
26 // will contain the docstring
29 // will contain the docstring
27 this.text = $('<div/>')
30 this.text = $('<div/>')
28 .addClass('tooltiptext')
31 .addClass('tooltiptext')
29 .addClass('smalltooltip');
32 .addClass('smalltooltip');
30
33
31 var tooltip = this.tooltip;
34 var tooltip = this.tooltip;
32 var text = this.text;
35 var text = this.text;
33
36
34 // build the buttons menu on the upper right
37 // build the buttons menu on the upper right
35
38
36 // expand the tooltip to see more
39 // expand the tooltip to see more
37 var expandlink=$('<a/>').attr('href',"#")
40 var expandlink=$('<a/>').attr('href',"#")
38 .addClass("ui-corner-all") //rounded corner
41 .addClass("ui-corner-all") //rounded corner
39 .attr('role',"button")
42 .attr('role',"button")
40 .attr('id','expanbutton')
43 .attr('id','expanbutton')
41 .click(function(){
44 .click(function(){
42 text.removeClass('smalltooltip');
45 text.removeClass('smalltooltip');
43 text.addClass('bigtooltip');
46 text.addClass('bigtooltip');
44 $('#expanbutton').remove();
47 $('#expanbutton').addClass('hidden');
45 //setTimeout(function(){that.code_mirror.focus();}, 50);
48 //setTimeout(function(){that.code_mirror.focus();}, 50);
46 })
49 })
47 .append(
50 .append(
48 $('<span/>').text('Expand')
51 $('<span/>').text('Expand')
49 .addClass('ui-icon')
52 .addClass('ui-icon')
50 .addClass('ui-icon-plus')
53 .addClass('ui-icon-plus')
51 );
54 );
52
55
53 // open in pager
56 // open in pager
54 var morelink=$('<a/>').attr('href',"#")
57 var morelink=$('<a/>').attr('href',"#")
55 .attr('role',"button")
58 .attr('role',"button")
56 .addClass('ui-button');
59 .addClass('ui-button');
57 var morespan=$('<span/>').text('Open in Pager')
60 var morespan=$('<span/>').text('Open in Pager')
58 .addClass('ui-icon')
61 .addClass('ui-icon')
59 .addClass('ui-icon-arrowstop-l-n');
62 .addClass('ui-icon-arrowstop-l-n');
60 morelink.append(morespan);
63 morelink.append(morespan);
61 morelink.click(function(){
64 morelink.click(function(){
62 var msg_id = IPython.notebook.kernel.execute(name+"?");
65 var msg_id = IPython.notebook.kernel.execute(name+"?");
63 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
66 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
64 that.remove_and_cancel_tooltip();
67 that.remove_and_cancel_tooltip();
65 setTimeout(function(){that.code_mirror.focus();}, 50);
68 setTimeout(function(){that.code_mirror.focus();}, 50);
66 });
69 });
67
70
68 // close the tooltip
71 // close the tooltip
69 var closelink=$('<a/>').attr('href',"#");
72 var closelink=$('<a/>').attr('href',"#");
70 closelink.attr('role',"button");
73 closelink.attr('role',"button");
71 closelink.addClass('ui-button');
74 closelink.addClass('ui-button');
72 var closespan=$('<span/>').text('Close');
75 var closespan=$('<span/>').text('Close');
73 closespan.addClass('ui-icon');
76 closespan.addClass('ui-icon');
74 closespan.addClass('ui-icon-close');
77 closespan.addClass('ui-icon-close');
75 closelink.append(closespan);
78 closelink.append(closespan);
76 closelink.click(function(){
79 closelink.click(function(){
77 tooltip.addClass('hide');
80 that.hide();
78 });
81 });
79
82
80 //construct the tooltip
83 //construct the tooltip
81 // add in the reverse order you want them to appear
84 // add in the reverse order you want them to appear
82 this.buttons.append(closelink);
85 this.buttons.append(closelink);
83 this.buttons.append(expandlink);
86 this.buttons.append(expandlink);
84 this.buttons.append(morelink);
87 this.buttons.append(morelink);
85
88
86 // we need a phony element to make the small arrow
89 // we need a phony element to make the small arrow
87 // of the tooltip in css
90 // of the tooltip in css
88 // we could try to move the arrow later
91 // we could try to move the arrow later
89 arrow = $('<div/>').addClass('pretooltiparrow');
92 arrow = $('<div/>').addClass('pretooltiparrow');
90 this.tooltip.append(arrow);
93 this.tooltip.append(arrow);
91 this.tooltip.append(this.buttons);
94 this.tooltip.append(this.buttons);
92 this.tooltip.append(this.text);
95 this.tooltip.append(this.text);
93 };
96 };
94
97
95
98 // deal with all the logic of hiding the tooltip
99 // and reset it's status
100 Tooltip.prototype.hide = function()
101 {
102 this.tooltip.addClass('hide');
103 $('#expanbutton').removeClass('hidden');
104 this.text.removeClass('bigtooltip');
105 this.text.addClass('smalltooltip');
106 // keep scroll top to be sure to always see the first line
107 this.text.scrollTop(0);
108 }
96
109
97 //TODO, try to diminish the number of parameters.
110 //TODO, try to diminish the number of parameters.
98 Tooltip.prototype.request_tooltip_after_time = function (pre_cursor,time){
111 Tooltip.prototype.request_tooltip_after_time = function (pre_cursor,time){
99 };
112 };
100
113
101
114
102 Tooltip.prototype.remove_and_cancel_tooltip = function() {
115 Tooltip.prototype.remove_and_cancel_tooltip = function() {
103 // note that we don't handle closing directly inside the calltip
116 // note that we don't handle closing directly inside the calltip
104 // as in the completer, because it is not focusable, so won't
117 // as in the completer, because it is not focusable, so won't
105 // get the event.
118 // get the event.
119 this.hide();
106 if (this.tooltip_timeout != null){
120 if (this.tooltip_timeout != null){
107 clearTimeout(this.tooltip_timeout);
121 clearTimeout(this.tooltip_timeout);
108 $('#tooltip').remove();
109 this.tooltip_timeout = null;
122 this.tooltip_timeout = null;
110 }
123 }
111 }
124 }
125
112 Tooltip.prototype.show = function(reply,pos)
126 Tooltip.prototype.show = function(reply,pos)
113 {
127 {
114 this.tooltip.css('left',pos.x-30+'px');
128 this.tooltip.css('left',pos.x-30+'px');
115 this.tooltip.css('top',(pos.yBot+10)+'px');
129 this.tooltip.css('top',(pos.yBot+10)+'px');
116 this.tooltip.removeClass('hidden')
130 this.tooltip.removeClass('hidden')
117 this.tooltip.removeClass('hide');
131 this.tooltip.removeClass('hide');
118
132
119 // build docstring
133 // build docstring
120 defstring = reply.call_def;
134 defstring = reply.call_def;
121 if (defstring == null) { defstring = reply.init_definition; }
135 if (defstring == null) { defstring = reply.init_definition; }
122 if (defstring == null) { defstring = reply.definition; }
136 if (defstring == null) { defstring = reply.definition; }
123
137
124 docstring = reply.call_docstring;
138 docstring = reply.call_docstring;
125 if (docstring == null) { docstring = reply.init_docstring; }
139 if (docstring == null) { docstring = reply.init_docstring; }
126 if (docstring == null) { docstring = reply.docstring; }
140 if (docstring == null) { docstring = reply.docstring; }
127 if (docstring == null) { docstring = "<empty docstring>"; }
141 if (docstring == null) { docstring = "<empty docstring>"; }
128
142
129 this.text.children().remove();
143 this.text.children().remove();
130
144
131 var pre=$('<pre/>').html(utils.fixConsole(docstring));
145 var pre=$('<pre/>').html(utils.fixConsole(docstring));
132 if(defstring){
146 if(defstring){
133 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
147 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
134 this.text.append(defstring_html);
148 this.text.append(defstring_html);
135 }
149 }
136 this.text.append(pre)
150 this.text.append(pre);
151 // keep scroll top to be sure to always see the first line
152 this.text.scrollTop(0);
137
153
138
154
139 }
155 }
140
156
141 Tooltip.prototype.showInPager = function(){
157 Tooltip.prototype.showInPager = function(){
142 var msg_id = IPython.notebook.kernel.execute(name+"?");
158 var msg_id = IPython.notebook.kernel.execute(name+"?");
143 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
159 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
144 that.remove_and_cancel_tooltip();
160 that.remove_and_cancel_tooltip();
145 setTimeout(function(){that.code_mirror.focus();}, 50);
161 setTimeout(function(){that.code_mirror.focus();}, 50);
146 }
162 }
147
163
148 Tooltip.prototype.finish_tooltip = function (reply) {
149
150 var expandlink=$('<a/>').attr('href',"#");
151 expandlink.addClass("ui-corner-all"); //rounded corner
152 expandlink.attr('role',"button");
153
154 var expandspan=$('<span/>').text('Expand');
155 expandspan.addClass('ui-icon');
156 expandspan.addClass('ui-icon-plus');
157
158 expandlink.append(expandspan);
159 expandlink.attr('id','expanbutton');
160 expandlink.click(function(){
161 tooltip.removeClass('smalltooltip');
162 tooltip.addClass('bigtooltip');
163 $('#expanbutton').remove();
164 setTimeout(function(){that.code_mirror.focus();}, 50);
165 });
166
167 var morelink=$('<a/>').attr('href',"#");
168 morelink.attr('role',"button");
169 morelink.addClass('ui-button');
170 var morespan=$('<span/>').text('Open in Pager');
171 morespan.addClass('ui-icon');
172 morespan.addClass('ui-icon-arrowstop-l-n');
173 morelink.append(morespan);
174 morelink.click(function(){
175 this.showInPager();
176 });
177
178
179 var closelink=$('<a/>').attr('href',"#");
180 closelink.attr('role',"button");
181 closelink.addClass('ui-button');
182
183 var closespan=$('<span/>').text('Close');
184 closespan.addClass('ui-icon');
185 closespan.addClass('ui-icon-close');
186 closelink.append(closespan);
187 closelink.click(function(){
188 that.remove_and_cancel_tooltip();
189 setTimeout(function(){that.code_mirror.focus();}, 50);
190 });
191 //construct the tooltip
192 tooltip.append(closelink);
193 tooltip.append(expandlink);
194 tooltip.append(morelink);
195
196 var pos = this.code_mirror.cursorCoords();
197 tooltip.css('left',pos.x+'px');
198 tooltip.css('top',pos.yBot+'px');
199
200 };
201
202
164
203 IPython.Tooltip = Tooltip;
165 IPython.Tooltip = Tooltip;
204
166
205 return IPython;
167 return IPython;
206 }(IPython));
168 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now