##// END OF EJS Templates
tidy up code
Matthias BUSSONNIER -
Show More
@@ -1,778 +1,784 b''
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
13
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15
15
16 var CodeCell = function (notebook) {
16 var CodeCell = function (notebook) {
17 this.code_mirror = null;
17 this.code_mirror = null;
18 this.input_prompt_number = ' ';
18 this.input_prompt_number = ' ';
19 this.is_completing = false;
19 this.is_completing = false;
20 this.completion_cursor = null;
20 this.completion_cursor = null;
21 this.outputs = [];
21 this.outputs = [];
22 this.collapsed = false;
22 this.collapsed = false;
23 IPython.Cell.apply(this, arguments);
23 IPython.Cell.apply(this, arguments);
24 };
24 };
25
25
26
26
27 CodeCell.prototype = new IPython.Cell();
27 CodeCell.prototype = new IPython.Cell();
28
28
29
29
30 CodeCell.prototype.create_element = function () {
30 CodeCell.prototype.create_element = function () {
31 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
31 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
32 cell.attr('tabindex','2');
32 cell.attr('tabindex','2');
33 var input = $('<div></div>').addClass('input hbox');
33 var input = $('<div></div>').addClass('input hbox');
34 input.append($('<div/>').addClass('prompt input_prompt'));
34 input.append($('<div/>').addClass('prompt input_prompt'));
35 var input_area = $('<div/>').addClass('input_area box-flex1');
35 var input_area = $('<div/>').addClass('input_area box-flex1');
36 this.code_mirror = CodeMirror(input_area.get(0), {
36 this.code_mirror = CodeMirror(input_area.get(0), {
37 indentUnit : 4,
37 indentUnit : 4,
38 mode: 'python',
38 mode: 'python',
39 theme: 'ipython',
39 theme: 'ipython',
40 readOnly: this.read_only,
40 readOnly: this.read_only,
41 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
41 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
42 });
42 });
43 input.append(input_area);
43 input.append(input_area);
44 var output = $('<div></div>').addClass('output vbox');
44 var output = $('<div></div>').addClass('output vbox');
45 cell.append(input).append(output);
45 cell.append(input).append(output);
46 this.element = cell;
46 this.element = cell;
47 this.collapse();
47 this.collapse();
48 };
48 };
49
49
50 //TODO, try to diminish the number of parameters.
50 //TODO, try to diminish the number of parameters.
51 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time,that){
51 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time,that){
52 if (pre_cursor === "" || pre_cursor === "(" ) {
52 if (pre_cursor === "" || pre_cursor === "(" ) {
53 // don't do anything if line beggin with '(' or is empty
53 // don't do anything if line beggin with '(' or is empty
54 } else {
54 } else {
55 // Will set a timer to request tooltip in `time`
55 // Will set a timer to request tooltip in `time`
56 that.tooltip_timeout = setTimeout(function(){
56 that.tooltip_timeout = setTimeout(function(){
57 IPython.notebook.request_tool_tip(that, pre_cursor)
57 IPython.notebook.request_tool_tip(that, pre_cursor)
58 },time);
58 },time);
59 }
59 }
60 };
60 };
61
61
62 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
62 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
63 // This method gets called in CodeMirror's onKeyDown/onKeyPress
63 // This method gets called in CodeMirror's onKeyDown/onKeyPress
64 // handlers and is used to provide custom key handling. Its return
64 // handlers and is used to provide custom key handling. Its return
65 // value is used to determine if CodeMirror should ignore the event:
65 // value is used to determine if CodeMirror should ignore the event:
66 // true = ignore, false = don't ignore.
66 // true = ignore, false = don't ignore.
67
67
68 // note that we are comparing and setting the time to wait at each key press.
68 // note that we are comparing and setting the time to wait at each key press.
69 // a better wqy might be to generate a new function on each time change and
69 // a better wqy might be to generate a new function on each time change and
70 // assign it to CodeCell.prototype.request_tooltip_after_time
70 // assign it to CodeCell.prototype.request_tooltip_after_time
71 tooltip_wait_time = this.notebook.time_before_tooltip;
71 tooltip_wait_time = this.notebook.time_before_tooltip;
72 tooltip_on_tab = this.notebook.tooltip_on_tab;
72 tooltip_on_tab = this.notebook.tooltip_on_tab;
73 var that = this;
73 var that = this;
74 // whatever key is pressed, first, cancel the tooltip request before
74 // whatever key is pressed, first, cancel the tooltip request before
75 // they are sent, and remove tooltip if any
75 // they are sent, and remove tooltip if any
76 if(event.type === 'keydown' && this.tooltip_timeout != null){
76 if(event.type === 'keydown' && this.tooltip_timeout != null){
77 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
77 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
78 that.tooltip_timeout=null;
78 that.tooltip_timeout=null;
79 }
79 }
80
80
81 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
81 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
82 // Always ignore shift-enter in CodeMirror as we handle it.
82 // Always ignore shift-enter in CodeMirror as we handle it.
83 return true;
83 return true;
84 }else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
84 }else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
85 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
85 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
86 // browser and keyboard layout !
86 // browser and keyboard layout !
87 // Pressing '(' , request tooltip, don't forget to reappend it
87 // Pressing '(' , request tooltip, don't forget to reappend it
88 var cursor = editor.getCursor();
88 var cursor = editor.getCursor();
89 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
89 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
90 CodeCell.prototype.request_tooltip_after_time(pre_cursor,tooltip_wait_time,that);
90 CodeCell.prototype.request_tooltip_after_time(pre_cursor,tooltip_wait_time,that);
91 } else if (event.keyCode === 9 && event.type == 'keydown') {
91 } else if (event.keyCode === 9 && event.type == 'keydown') {
92 // Tab completion.
92 // Tab completion.
93 var cur = editor.getCursor();
93 var cur = editor.getCursor();
94 //Do not trim here because of tooltip
94 //Do not trim here because of tooltip
95 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
95 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
96 if (pre_cursor.trim() === "") {
96 if (pre_cursor.trim() === "") {
97 // Don't autocomplete if the part of the line before the cursor
97 // Don't autocomplete if the part of the line before the cursor
98 // is empty. In this case, let CodeMirror handle indentation.
98 // is empty. In this case, let CodeMirror handle indentation.
99 return false;
99 return false;
100 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
100 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
101 CodeCell.prototype.request_tooltip_after_time(pre_cursor,0,that);
101 CodeCell.prototype.request_tooltip_after_time(pre_cursor,0,that);
102 } else {
102 } else {
103 pre_cursor.trim();
103 pre_cursor.trim();
104 // Autocomplete the current line.
104 // Autocomplete the current line.
105 event.stop();
105 event.stop();
106 var line = editor.getLine(cur.line);
106 var line = editor.getLine(cur.line);
107 this.is_completing = true;
107 this.is_completing = true;
108 this.completion_cursor = cur;
108 this.completion_cursor = cur;
109 IPython.notebook.complete_cell(this, line, cur.ch);
109 IPython.notebook.complete_cell(this, line, cur.ch);
110 return true;
110 return true;
111 }
111 }
112 } else if (event.keyCode === 8 && event.type == 'keydown') {
112 } else if (event.keyCode === 8 && event.type == 'keydown') {
113 // If backspace and the line ends with 4 spaces, remove them.
113 // If backspace and the line ends with 4 spaces, remove them.
114 var cur = editor.getCursor();
114 var cur = editor.getCursor();
115 var line = editor.getLine(cur.line);
115 var line = editor.getLine(cur.line);
116 var ending = line.slice(-4);
116 var ending = line.slice(-4);
117 if (ending === ' ') {
117 if (ending === ' ') {
118 editor.replaceRange('',
118 editor.replaceRange('',
119 {line: cur.line, ch: cur.ch-4},
119 {line: cur.line, ch: cur.ch-4},
120 {line: cur.line, ch: cur.ch}
120 {line: cur.line, ch: cur.ch}
121 );
121 );
122 event.stop();
122 event.stop();
123 return true;
123 return true;
124 } else {
124 } else {
125 return false;
125 return false;
126 }
126 }
127 } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey
127 } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey
128 && event.type == 'keydown') {
128 && event.type == 'keydown') {
129 // toggle line numbers with Ctrl-Shift-L
129 // toggle line numbers with Ctrl-Shift-L
130 this.toggle_line_numbers();
130 this.toggle_line_numbers();
131 }
131 }
132 else {
132 else {
133 // keypress/keyup also trigger on TAB press, and we don't want to
133 // keypress/keyup also trigger on TAB press, and we don't want to
134 // use those to disable tab completion.
134 // use those to disable tab completion.
135 if (this.is_completing && event.keyCode !== 9) {
135 if (this.is_completing && event.keyCode !== 9) {
136 var ed_cur = editor.getCursor();
136 var ed_cur = editor.getCursor();
137 var cc_cur = this.completion_cursor;
137 var cc_cur = this.completion_cursor;
138 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
138 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
139 this.is_completing = false;
139 this.is_completing = false;
140 this.completion_cursor = null;
140 this.completion_cursor = null;
141 }
141 }
142 }
142 }
143 return false;
143 return false;
144 };
144 };
145 return false;
145 return false;
146 };
146 };
147
147
148 CodeCell.prototype.remove_and_cancell_tooltip = function(timeout)
148 CodeCell.prototype.remove_and_cancell_tooltip = function(timeout)
149 {
149 {
150 // note that we don't handle closing directly inside the calltip
150 // note that we don't handle closing directly inside the calltip
151 // as in the completer, because it is not focusable, so won't
151 // as in the completer, because it is not focusable, so won't
152 // get the event.
152 // get the event.
153 clearTimeout(timeout);
153 clearTimeout(timeout);
154 $('#tooltip').remove();
154 $('#tooltip').remove();
155 }
155 }
156
156
157 CodeCell.prototype.finish_tooltip = function (reply) {
157 CodeCell.prototype.finish_tooltip = function (reply) {
158 defstring=reply.definition;
158 defstring=reply.definition;
159 docstring=reply.docstring;
159 docstring=reply.docstring;
160 if(docstring == null){docstring="<empty docstring>"};
160 if(docstring == null){docstring="<empty docstring>"};
161 name=reply.name;
161 name=reply.name;
162
162
163 var that = this;
163 var that = this;
164 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
164 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
165 // remove to have the tooltip not Limited in X and Y
165 // remove to have the tooltip not Limited in X and Y
166 tooltip.addClass('smalltooltip');
166 tooltip.addClass('smalltooltip');
167 var pre=$('<pre/>').html(utils.fixConsole(docstring));
167 var pre=$('<pre/>').html(utils.fixConsole(docstring));
168 var expandlink=$('<a/>').attr('href',"#");
168 var expandlink=$('<a/>').attr('href',"#");
169 expandlink.addClass("ui-corner-all"); //rounded corner
169 expandlink.addClass("ui-corner-all"); //rounded corner
170 expandlink.attr('role',"button");
170 expandlink.attr('role',"button");
171 //expandlink.addClass('ui-button');
171 //expandlink.addClass('ui-button');
172 //expandlink.addClass('ui-state-default');
172 //expandlink.addClass('ui-state-default');
173 var expandspan=$('<span/>').text('Expand');
173 var expandspan=$('<span/>').text('Expand');
174 expandspan.addClass('ui-icon');
174 expandspan.addClass('ui-icon');
175 expandspan.addClass('ui-icon-plus');
175 expandspan.addClass('ui-icon-plus');
176 expandlink.append(expandspan);
176 expandlink.append(expandspan);
177 expandlink.attr('id','expanbutton');
177 expandlink.attr('id','expanbutton');
178 expandlink.click(function(){
178 expandlink.click(function(){
179 tooltip.removeClass('smalltooltip');
179 tooltip.removeClass('smalltooltip');
180 tooltip.addClass('bigtooltip');
180 tooltip.addClass('bigtooltip');
181 $('#expanbutton').remove();
181 $('#expanbutton').remove();
182 setTimeout(function(){that.code_mirror.focus();}, 50);
182 setTimeout(function(){that.code_mirror.focus();}, 50);
183 });
183 });
184 var morelink=$('<a/>').attr('href',"#");
184 var morelink=$('<a/>').attr('href',"#");
185 morelink.attr('role',"button");
185 morelink.attr('role',"button");
186 morelink.addClass('ui-button');
186 morelink.addClass('ui-button');
187 //morelink.addClass("ui-corner-all"); //rounded corner
187 //morelink.addClass("ui-corner-all"); //rounded corner
188 //morelink.addClass('ui-state-default');
188 //morelink.addClass('ui-state-default');
189 var morespan=$('<span/>').text('Open in Pager');
189 var morespan=$('<span/>').text('Open in Pager');
190 morespan.addClass('ui-icon');
190 morespan.addClass('ui-icon');
191 morespan.addClass('ui-icon-arrowstop-l-n');
191 morespan.addClass('ui-icon-arrowstop-l-n');
192 morelink.append(morespan);
192 morelink.append(morespan);
193 morelink.click(function(){
193 morelink.click(function(){
194 var msg_id = IPython.notebook.kernel.execute(name+"?");
194 var msg_id = IPython.notebook.kernel.execute(name+"?");
195 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.selected_cell().cell_id;
195 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.selected_cell().cell_id;
196 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
196 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
197 setTimeout(function(){that.code_mirror.focus();}, 50);
197 setTimeout(function(){that.code_mirror.focus();}, 50);
198 });
198 });
199
199
200 var closelink=$('<a/>').attr('href',"#");
200 var closelink=$('<a/>').attr('href',"#");
201 closelink.attr('role',"button");
201 closelink.attr('role',"button");
202 closelink.addClass('ui-button');
202 closelink.addClass('ui-button');
203 //closelink.addClass("ui-corner-all"); //rounded corner
203 //closelink.addClass("ui-corner-all"); //rounded corner
204 //closelink.adClass('ui-state-default'); // grey background and blue cross
204 //closelink.adClass('ui-state-default'); // grey background and blue cross
205 var closespan=$('<span/>').text('Close');
205 var closespan=$('<span/>').text('Close');
206 closespan.addClass('ui-icon');
206 closespan.addClass('ui-icon');
207 closespan.addClass('ui-icon-close');
207 closespan.addClass('ui-icon-close');
208 closelink.append(closespan);
208 closelink.append(closespan);
209 closelink.click(function(){
209 closelink.click(function(){
210 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
210 CodeCell.prototype.remove_and_cancell_tooltip(that.tooltip_timeout);
211 setTimeout(function(){that.code_mirror.focus();}, 50);
211 setTimeout(function(){that.code_mirror.focus();}, 50);
212 });
212 });
213 //construct the tooltip
213 //construct the tooltip
214 tooltip.append(closelink);
214 tooltip.append(closelink);
215 tooltip.append(expandlink);
215 tooltip.append(expandlink);
216 tooltip.append(morelink);
216 tooltip.append(morelink);
217 if(defstring){
217 if(defstring){
218 defstring_html= $('<pre/>').html(utils.fixConsole(defstring));
218 defstring_html= $('<pre/>').html(utils.fixConsole(defstring));
219 tooltip.append(defstring_html);
219 tooltip.append(defstring_html);
220 }
220 }
221 tooltip.append(pre);
221 tooltip.append(pre);
222 var pos = this.code_mirror.cursorCoords();
222 var pos = this.code_mirror.cursorCoords();
223 tooltip.css('left',pos.x+'px');
223 tooltip.css('left',pos.x+'px');
224 tooltip.css('top',pos.yBot+'px');
224 tooltip.css('top',pos.yBot+'px');
225 $('body').append(tooltip);
225 $('body').append(tooltip);
226
226
227 // issues with cross-closing if multiple tooltip in less than 5sec
227 // issues with cross-closing if multiple tooltip in less than 5sec
228 // keep it comented for now
228 // keep it comented for now
229 // setTimeout(CodeCell.prototype.remove_and_cancell_tooltip, 5000);
229 // setTimeout(CodeCell.prototype.remove_and_cancell_tooltip, 5000);
230 };
230 };
231
231
232 // As you type completer
232 // As you type completer
233 CodeCell.prototype.finish_completing = function (matched_text, matches) {
233 CodeCell.prototype.finish_completing = function (matched_text, matches) {
234 //return if not completing or nothing to complete
235 if (!this.is_completing || matches.length === 0) {return;}
234
236
235 // smart completion, sort kwarg ending with '='
237 // for later readability
236 var key = { tab:9,
238 var key = { tab:9,
237 esc:8,
239 esc:27,
240 backspace:8,
238 space:13,
241 space:13,
239 shift:16,
242 shift:16,
240 enter:32,
243 enter:32,
241 // _ is 189
244 // _ is 189
242 isCompSymbol : function (code) {return ((code>64 && code <=122)|| code == 189)}
245 isCompSymbol : function (code)
246 {return ((code>64 && code <=122)|| code == 189)}
243 }
247 }
248
249 // smart completion, sort kwarg ending with '='
244 var newm = new Array();
250 var newm = new Array();
245 if(this.notebook.smart_completer)
251 if(this.notebook.smart_completer)
246 {
252 {
247 kwargs = new Array();
253 kwargs = new Array();
248 other = new Array();
254 other = new Array();
249 for(var i=0;i<matches.length; ++i){
255 for(var i=0;i<matches.length; ++i){
250 if(matches[i].substr(-1) === '='){
256 if(matches[i].substr(-1) === '='){
251 kwargs.push(matches[i]);
257 kwargs.push(matches[i]);
252 }else{other.push(matches[i]);}
258 }else{other.push(matches[i]);}
253 }
259 }
254 newm = kwargs.concat(other);
260 newm = kwargs.concat(other);
255 matches=newm;
261 matches=newm;
256 }
262 }
257 // end sort kwargs
263 // end sort kwargs
258
264
265 // give common prefix of a array of string
259 function sharedStart(A){
266 function sharedStart(A){
260 if(A.length > 1 ){
267 if(A.length > 1 ){
261 var tem1, tem2, s, A= A.slice(0).sort();
268 var tem1, tem2, s, A= A.slice(0).sort();
262 tem1= A[0];
269 tem1= A[0];
263 s= tem1.length;
270 s= tem1.length;
264 tem2= A.pop();
271 tem2= A.pop();
265 while(s && tem2.indexOf(tem1)== -1){
272 while(s && tem2.indexOf(tem1)== -1){
266 tem1= tem1.substring(0, --s);
273 tem1= tem1.substring(0, --s);
267 }
274 }
268 return tem1;
275 return tem1;
269 }
276 }
270 return "";
277 return "";
271 }
278 }
272
279
273 if (!this.is_completing || matches.length === 0) {return;}
274
280
275 //try to check if the user is typing tab at least twice after a word
281 //try to check if the user is typing tab at least twice after a word
276 // and completion is "done"
282 // and completion is "done"
277 fallback_on_tooltip_after=2
283 fallback_on_tooltip_after=2
278 if(matches.length==1 && matched_text === matches[0])
284 if(matches.length==1 && matched_text === matches[0])
279 {
285 {
280 if(this.npressed >fallback_on_tooltip_after && this.prevmatch==matched_text)
286 if(this.npressed >fallback_on_tooltip_after && this.prevmatch==matched_text)
281 {
287 {
282 console.log('Ok, you really want to complete after pressing tab '+this.npressed+' times !');
288 console.log('Ok, you really want to complete after pressing tab '+this.npressed+' times !');
283 console.log('You should understand that there is no (more) completion for that !');
289 console.log('You should understand that there is no (more) completion for that !');
284 console.log("I'll show you the tooltip, will you stop bothering me ?");
290 console.log("I'll show you the tooltip, will you stop bothering me ?");
285 this.request_tooltip_after_time(matched_text+'(',0,this);
291 this.request_tooltip_after_time(matched_text+'(',0,this);
286 return;
292 return;
287 }
293 }
288 this.prevmatch=matched_text
294 this.prevmatch=matched_text
289 this.npressed=this.npressed+1;
295 this.npressed=this.npressed+1;
290 }
296 }
291 else
297 else
292 {
298 {
293 this.prevmatch="";
299 this.prevmatch="";
294 this.npressed=0;
300 this.npressed=0;
295 }
301 }
296 // end fallback on tooltip
302 // end fallback on tooltip
297
303 //==================================
298 // Real completion logic start here
304 // Real completion logic start here
299 var that = this;
305 var that = this;
300 var cur = this.completion_cursor;
306 var cur = this.completion_cursor;
301 var done = false;
307 var done = false;
302
308
303 // call to dismmiss the completer
309 // call to dismmiss the completer
304 var close = function () {
310 var close = function () {
305 if (done) return;
311 if (done) return;
306 done = true;
312 done = true;
307 if (complete!=undefined)
313 if (complete!=undefined)
308 {complete.remove();}
314 {complete.remove();}
309 that.is_completing = false;
315 that.is_completing = false;
310 that.completion_cursor = null;
316 that.completion_cursor = null;
311 };
317 };
312
318
313 // insert the given text and exit the completer
319 // insert the given text and exit the completer
314 var insert = function (selected_text) {
320 var insert = function (selected_text) {
315 that.code_mirror.replaceRange(
321 that.code_mirror.replaceRange(
316 selected_text,
322 selected_text,
317 {line: cur.line, ch: (cur.ch-matched_text.length)},
323 {line: cur.line, ch: (cur.ch-matched_text.length)},
318 {line: cur.line, ch: cur.ch}
324 {line: cur.line, ch: cur.ch}
319 );
325 );
320 event.stopPropagation();
326 event.stopPropagation();
321 event.preventDefault();
327 event.preventDefault();
322 close();
328 close();
323 setTimeout(function(){that.code_mirror.focus();}, 50);
329 setTimeout(function(){that.code_mirror.focus();}, 50);
324 };
330 };
325
331
326 // insert the curent highlited selection and exit
332 // insert the curent highlited selection and exit
327 var pick = function () {
333 var pick = function () {
328 insert(select.val()[0]);
334 insert(select.val()[0]);
329 };
335 };
330
336
331
337
332 // Define function to clear the completer, refill it with the new
338 // Define function to clear the completer, refill it with the new
333 // matches, update the pseuso typing field. Note that this is case
339 // matches, update the pseuso typing field. autopick insert match if
334 // insensitive for now
340 // only one left, in no matches (anymore) dismiss itself by pasting
341 // what the user have typed until then
335 var complete_with = function(matches,typed_text,autopick)
342 var complete_with = function(matches,typed_text,autopick)
336 {
343 {
337 // If autopick an only one match, past.
344 // If autopick an only one match, past.
338 // Used to 'pick' when pressing tab
345 // Used to 'pick' when pressing tab
339 if (matches.length < 1) {
346 if (matches.length < 1) {
340 insert(typed_text);
347 insert(typed_text);
341 } else if (autopick && matches.length==1) {
348 } else if (autopick && matches.length==1) {
342 insert(matches[0]);
349 insert(matches[0]);
343 }
350 }
344 //clear the previous completion if any
351 //clear the previous completion if any
345 complete.children().children().remove();
352 complete.children().children().remove();
346 $('#asyoutype').text(typed_text);
353 $('#asyoutype').text(typed_text);
347 select=$('#asyoutypeselect');
354 select=$('#asyoutypeselect');
348 for (var i=0; i<matches.length; ++i) {
355 for (var i=0; i<matches.length; ++i) {
349 select.append($('<option/>').html(matches[i]));
356 select.append($('<option/>').html(matches[i]));
350 }
357 }
351 select.children().first().attr('selected','true');
358 select.children().first().attr('selected','true');
352 }
359 }
353
360
354 // create html for completer
361 // create html for completer
355 var complete = $('<div/>').addClass('completions');
362 var complete = $('<div/>').addClass('completions');
356 complete.attr('id','complete');
363 complete.attr('id','complete');
357 complete.append($('<p/>').attr('id', 'asyoutype').html(matched_text));//pseudo input field
364 complete.append($('<p/>').attr('id', 'asyoutype').html(matched_text));//pseudo input field
358
365
359 var select = $('<select/>').attr('multiple','true');
366 var select = $('<select/>').attr('multiple','true');
360 select.attr('id', 'asyoutypeselect')
367 select.attr('id', 'asyoutypeselect')
361 select.attr('size',Math.min(10,matches.length));
368 select.attr('size',Math.min(10,matches.length));
362 var pos = this.code_mirror.cursorCoords();
369 var pos = this.code_mirror.cursorCoords();
363
370
364 // TODO: I propose to remove enough horizontal pixel
371 // TODO: I propose to remove enough horizontal pixel
365 // to align the text later
372 // to align the text later
366 complete.css('left',pos.x+'px');
373 complete.css('left',pos.x+'px');
367 complete.css('top',pos.yBot+'px');
374 complete.css('top',pos.yBot+'px');
368 complete.append(select);
375 complete.append(select);
369
376
370 $('body').append(complete);
377 $('body').append(complete);
371
378
372 //do a first actual completion
379 // So a first actual completion. see if all the completion start wit
380 // the same letter and complete if necessary
373 fastForward = sharedStart(matches)
381 fastForward = sharedStart(matches)
374 typed_characters= fastForward.substr(matched_text.length);
382 typed_characters= fastForward.substr(matched_text.length);
375 complete_with(matches,matched_text+typed_characters,true);
383 complete_with(matches,matched_text+typed_characters,true);
376 filterd=matches;
384 filterd=matches;
377 // Give focus to select, and make it filter the match as the user type
385 // Give focus to select, and make it filter the match as the user type
378 // by filtering the previous matches
386 // by filtering the previous matches. Called by .keypress and .keydown
379 var downandpress = function (event,press_or_down) {
387 var downandpress = function (event,press_or_down) {
380 var code = event.which;
388 var code = event.which;
381 var autopick = false; // auto 'pick' if only one match
389 var autopick = false; // auto 'pick' if only one match
382 if (press_or_down === 0){
390 if (press_or_down === 0){
383 press=true; down=false; //Are we called from keypress or keydown
391 press=true; down=false; //Are we called from keypress or keydown
384 } else if (press_or_down == 1){
392 } else if (press_or_down == 1){
385 press=false; down=true;
393 press=false; down=true;
386 }
394 }
387 if (code === key.shift) {
395 if (code === key.shift) {
388 // nothing on Shift
396 // nothing on Shift
389 return;
397 return;
390 }
398 }
391 if (code === key.space || code === key.enter) {
399 if (code === key.space || code === key.enter) {
392 // Pressing SPACE or ENTER will cause a pick
400 // Pressing SPACE or ENTER will cause a pick
393 event.stopPropagation();
401 event.stopPropagation();
394 event.preventDefault();
402 event.preventDefault();
395 pick();
403 pick();
396 } else if (code === 38 || code === 40) {
404 } else if (code === 38 || code === 40) {
397 // We don't want the document keydown handler to handle UP/DOWN,
405 // We don't want the document keydown handler to handle UP/DOWN,
398 // but we want the default action.
406 // but we want the default action.
399 event.stopPropagation();
407 event.stopPropagation();
400 //} else if ( key.isCompSymbol(code)|| (code==key.backspace)||(code==key.tab && down)){
408 //} else if ( key.isCompSymbol(code)|| (code==key.backspace)||(code==key.tab && down)){
401 } else if ( (code==key.backspace)||(code==key.tab) || press || key.isCompSymbol(code)){
409 } else if ( (code==key.backspace)||(code==key.tab) || press || key.isCompSymbol(code)){
402 // issues with _-.. on chrome at least
403 if((code != key.backspace) && (code != key.tab) && press)
410 if((code != key.backspace) && (code != key.tab) && press)
404 {
411 {
405 var newchar = String.fromCharCode(code);
412 var newchar = String.fromCharCode(code);
406 typed_characters=typed_characters+newchar;
413 typed_characters=typed_characters+newchar;
407 } else if (code == key.tab) {
414 } else if (code == key.tab) {
408 fastForward = sharedStart(filterd)
415 fastForward = sharedStart(filterd)
409 ffsub = fastForward.substr(matched_text.length+typed_characters.length);
416 ffsub = fastForward.substr(matched_text.length+typed_characters.length);
410 typed_characters=typed_characters+ffsub;
417 typed_characters=typed_characters+ffsub;
411 autopick=true;
418 autopick=true;
412 event.stopPropagation();
419 event.stopPropagation();
413 event.preventDefault();
420 event.preventDefault();
414 } else if (code == key.backspace) {
421 } else if (code == key.backspace) {
415 // 8 is backspace remove 1 char cancel if
422 // cancel if user have erase everything, otherwise decrease
416 // user have erase everything, otherwise
423 // what we filter with
417 // decrease what we filter with
418 if (typed_characters.length <= 0)
424 if (typed_characters.length <= 0)
419 {
425 {
420 insert(matched_text)
426 insert(matched_text)
421 }
427 }
422 typed_characters=typed_characters.substr(0,typed_characters.length-1);
428 typed_characters=typed_characters.substr(0,typed_characters.length-1);
423 }
429 }
424 re = new RegExp("^"+"\%?"+matched_text+typed_characters,"");
430 re = new RegExp("^"+"\%?"+matched_text+typed_characters,"");
425 filterd= matches.filter(function(x){return re.test(x)});
431 filterd = matches.filter(function(x){return re.test(x)});
426 complete_with(filterd,matched_text+typed_characters,autopick);
432 complete_with(filterd,matched_text+typed_characters,autopick);
427 } else if(down){ // abort only on press
433 } else if(down){ // abort only on .keydown
428 // abort with what the user have pressed until now
434 // abort with what the user have pressed until now
429 console.log('aborting with keycode : '+code+press);
435 console.log('aborting with keycode : '+code+' is down :'+down);
430 insert(matched_text+typed_characters);
436 insert(matched_text+typed_characters);
431 }
437 }
432 }
438 }
433 select.keydown(function (event) {
439 select.keydown(function (event) {
434 downandpress(event,1)
440 downandpress(event,1)
435 });
441 });
436 select.keypress(function (event) {
442 select.keypress(function (event) {
437 downandpress(event,0)
443 downandpress(event,0)
438 });
444 });
439 // Double click also causes a pick.
445 // Double click also causes a pick.
440 // and bind the last actions.
446 // and bind the last actions.
441 select.dblclick(pick);
447 select.dblclick(pick);
442 select.blur(close);
448 select.blur(close);
443 select.focus();
449 select.focus();
444 };
450 };
445
451
446 CodeCell.prototype.toggle_line_numbers = function () {
452 CodeCell.prototype.toggle_line_numbers = function () {
447 if (this.code_mirror.getOption('lineNumbers') == false) {
453 if (this.code_mirror.getOption('lineNumbers') == false) {
448 this.code_mirror.setOption('lineNumbers', true);
454 this.code_mirror.setOption('lineNumbers', true);
449 } else {
455 } else {
450 this.code_mirror.setOption('lineNumbers', false);
456 this.code_mirror.setOption('lineNumbers', false);
451 }
457 }
452 this.code_mirror.refresh();
458 this.code_mirror.refresh();
453 };
459 };
454
460
455 CodeCell.prototype.select = function () {
461 CodeCell.prototype.select = function () {
456 IPython.Cell.prototype.select.apply(this);
462 IPython.Cell.prototype.select.apply(this);
457 // Todo: this dance is needed because as of CodeMirror 2.12, focus is
463 // Todo: this dance is needed because as of CodeMirror 2.12, focus is
458 // not causing the cursor to blink if the editor is empty initially.
464 // not causing the cursor to blink if the editor is empty initially.
459 // While this seems to fix the issue, this should be fixed
465 // While this seems to fix the issue, this should be fixed
460 // in CodeMirror proper.
466 // in CodeMirror proper.
461 var s = this.code_mirror.getValue();
467 var s = this.code_mirror.getValue();
462 this.code_mirror.focus();
468 this.code_mirror.focus();
463 if (s === '') this.code_mirror.setValue('');
469 if (s === '') this.code_mirror.setValue('');
464 };
470 };
465
471
466
472
467 CodeCell.prototype.select_all = function () {
473 CodeCell.prototype.select_all = function () {
468 var start = {line: 0, ch: 0};
474 var start = {line: 0, ch: 0};
469 var nlines = this.code_mirror.lineCount();
475 var nlines = this.code_mirror.lineCount();
470 var last_line = this.code_mirror.getLine(nlines-1);
476 var last_line = this.code_mirror.getLine(nlines-1);
471 var end = {line: nlines-1, ch: last_line.length};
477 var end = {line: nlines-1, ch: last_line.length};
472 this.code_mirror.setSelection(start, end);
478 this.code_mirror.setSelection(start, end);
473 };
479 };
474
480
475
481
476 CodeCell.prototype.append_output = function (json) {
482 CodeCell.prototype.append_output = function (json) {
477 this.expand();
483 this.expand();
478 if (json.output_type === 'pyout') {
484 if (json.output_type === 'pyout') {
479 this.append_pyout(json);
485 this.append_pyout(json);
480 } else if (json.output_type === 'pyerr') {
486 } else if (json.output_type === 'pyerr') {
481 this.append_pyerr(json);
487 this.append_pyerr(json);
482 } else if (json.output_type === 'display_data') {
488 } else if (json.output_type === 'display_data') {
483 this.append_display_data(json);
489 this.append_display_data(json);
484 } else if (json.output_type === 'stream') {
490 } else if (json.output_type === 'stream') {
485 this.append_stream(json);
491 this.append_stream(json);
486 };
492 };
487 this.outputs.push(json);
493 this.outputs.push(json);
488 };
494 };
489
495
490
496
491 CodeCell.prototype.create_output_area = function () {
497 CodeCell.prototype.create_output_area = function () {
492 var oa = $("<div/>").addClass("hbox output_area");
498 var oa = $("<div/>").addClass("hbox output_area");
493 oa.append($('<div/>').addClass('prompt'));
499 oa.append($('<div/>').addClass('prompt'));
494 return oa;
500 return oa;
495 };
501 };
496
502
497
503
498 CodeCell.prototype.append_pyout = function (json) {
504 CodeCell.prototype.append_pyout = function (json) {
499 n = json.prompt_number || ' ';
505 n = json.prompt_number || ' ';
500 var toinsert = this.create_output_area();
506 var toinsert = this.create_output_area();
501 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
507 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
502 this.append_mime_type(json, toinsert);
508 this.append_mime_type(json, toinsert);
503 this.element.find('div.output').append(toinsert);
509 this.element.find('div.output').append(toinsert);
504 // If we just output latex, typeset it.
510 // If we just output latex, typeset it.
505 if ((json.latex !== undefined) || (json.html !== undefined)) {
511 if ((json.latex !== undefined) || (json.html !== undefined)) {
506 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
512 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
507 };
513 };
508 };
514 };
509
515
510
516
511 CodeCell.prototype.append_pyerr = function (json) {
517 CodeCell.prototype.append_pyerr = function (json) {
512 var tb = json.traceback;
518 var tb = json.traceback;
513 if (tb !== undefined && tb.length > 0) {
519 if (tb !== undefined && tb.length > 0) {
514 var s = '';
520 var s = '';
515 var len = tb.length;
521 var len = tb.length;
516 for (var i=0; i<len; i++) {
522 for (var i=0; i<len; i++) {
517 s = s + tb[i] + '\n';
523 s = s + tb[i] + '\n';
518 }
524 }
519 s = s + '\n';
525 s = s + '\n';
520 var toinsert = this.create_output_area();
526 var toinsert = this.create_output_area();
521 this.append_text(s, toinsert);
527 this.append_text(s, toinsert);
522 this.element.find('div.output').append(toinsert);
528 this.element.find('div.output').append(toinsert);
523 };
529 };
524 };
530 };
525
531
526
532
527 CodeCell.prototype.append_stream = function (json) {
533 CodeCell.prototype.append_stream = function (json) {
528 // temporary fix: if stream undefined (json file written prior to this patch),
534 // temporary fix: if stream undefined (json file written prior to this patch),
529 // default to most likely stdout:
535 // default to most likely stdout:
530 if (json.stream == undefined){
536 if (json.stream == undefined){
531 json.stream = 'stdout';
537 json.stream = 'stdout';
532 }
538 }
533 var subclass = "output_"+json.stream;
539 var subclass = "output_"+json.stream;
534 if (this.outputs.length > 0){
540 if (this.outputs.length > 0){
535 // have at least one output to consider
541 // have at least one output to consider
536 var last = this.outputs[this.outputs.length-1];
542 var last = this.outputs[this.outputs.length-1];
537 if (last.output_type == 'stream' && json.stream == last.stream){
543 if (last.output_type == 'stream' && json.stream == last.stream){
538 // latest output was in the same stream,
544 // latest output was in the same stream,
539 // so append directly into its pre tag
545 // so append directly into its pre tag
540 this.element.find('div.'+subclass).last().find('pre').append(json.text);
546 this.element.find('div.'+subclass).last().find('pre').append(json.text);
541 return;
547 return;
542 }
548 }
543 }
549 }
544
550
545 // If we got here, attach a new div
551 // If we got here, attach a new div
546 var toinsert = this.create_output_area();
552 var toinsert = this.create_output_area();
547 this.append_text(json.text, toinsert, "output_stream "+subclass);
553 this.append_text(json.text, toinsert, "output_stream "+subclass);
548 this.element.find('div.output').append(toinsert);
554 this.element.find('div.output').append(toinsert);
549 };
555 };
550
556
551
557
552 CodeCell.prototype.append_display_data = function (json) {
558 CodeCell.prototype.append_display_data = function (json) {
553 var toinsert = this.create_output_area();
559 var toinsert = this.create_output_area();
554 this.append_mime_type(json, toinsert);
560 this.append_mime_type(json, toinsert);
555 this.element.find('div.output').append(toinsert);
561 this.element.find('div.output').append(toinsert);
556 // If we just output latex, typeset it.
562 // If we just output latex, typeset it.
557 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
563 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
558 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
564 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
559 };
565 };
560 };
566 };
561
567
562
568
563 CodeCell.prototype.append_mime_type = function (json, element) {
569 CodeCell.prototype.append_mime_type = function (json, element) {
564 if (json.html !== undefined) {
570 if (json.html !== undefined) {
565 this.append_html(json.html, element);
571 this.append_html(json.html, element);
566 } else if (json.latex !== undefined) {
572 } else if (json.latex !== undefined) {
567 this.append_latex(json.latex, element);
573 this.append_latex(json.latex, element);
568 } else if (json.svg !== undefined) {
574 } else if (json.svg !== undefined) {
569 this.append_svg(json.svg, element);
575 this.append_svg(json.svg, element);
570 } else if (json.png !== undefined) {
576 } else if (json.png !== undefined) {
571 this.append_png(json.png, element);
577 this.append_png(json.png, element);
572 } else if (json.jpeg !== undefined) {
578 } else if (json.jpeg !== undefined) {
573 this.append_jpeg(json.jpeg, element);
579 this.append_jpeg(json.jpeg, element);
574 } else if (json.text !== undefined) {
580 } else if (json.text !== undefined) {
575 this.append_text(json.text, element);
581 this.append_text(json.text, element);
576 };
582 };
577 };
583 };
578
584
579
585
580 CodeCell.prototype.append_html = function (html, element) {
586 CodeCell.prototype.append_html = function (html, element) {
581 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
587 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
582 toinsert.append(html);
588 toinsert.append(html);
583 element.append(toinsert);
589 element.append(toinsert);
584 };
590 };
585
591
586
592
587 CodeCell.prototype.append_text = function (data, element, extra_class) {
593 CodeCell.prototype.append_text = function (data, element, extra_class) {
588 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
594 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
589 if (extra_class){
595 if (extra_class){
590 toinsert.addClass(extra_class);
596 toinsert.addClass(extra_class);
591 }
597 }
592 toinsert.append($("<pre/>").html(data));
598 toinsert.append($("<pre/>").html(data));
593 element.append(toinsert);
599 element.append(toinsert);
594 };
600 };
595
601
596
602
597 CodeCell.prototype.append_svg = function (svg, element) {
603 CodeCell.prototype.append_svg = function (svg, element) {
598 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
604 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
599 toinsert.append(svg);
605 toinsert.append(svg);
600 element.append(toinsert);
606 element.append(toinsert);
601 };
607 };
602
608
603
609
604 CodeCell.prototype.append_png = function (png, element) {
610 CodeCell.prototype.append_png = function (png, element) {
605 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
611 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
606 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
612 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
607 element.append(toinsert);
613 element.append(toinsert);
608 };
614 };
609
615
610
616
611 CodeCell.prototype.append_jpeg = function (jpeg, element) {
617 CodeCell.prototype.append_jpeg = function (jpeg, element) {
612 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
618 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
613 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
619 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
614 element.append(toinsert);
620 element.append(toinsert);
615 };
621 };
616
622
617
623
618 CodeCell.prototype.append_latex = function (latex, element) {
624 CodeCell.prototype.append_latex = function (latex, element) {
619 // This method cannot do the typesetting because the latex first has to
625 // This method cannot do the typesetting because the latex first has to
620 // be on the page.
626 // be on the page.
621 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
627 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
622 toinsert.append(latex);
628 toinsert.append(latex);
623 element.append(toinsert);
629 element.append(toinsert);
624 };
630 };
625
631
626
632
627 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
633 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
628 var output_div = this.element.find("div.output");
634 var output_div = this.element.find("div.output");
629 if (stdout && stderr && other){
635 if (stdout && stderr && other){
630 // clear all, no need for logic
636 // clear all, no need for logic
631 output_div.html("");
637 output_div.html("");
632 this.outputs = [];
638 this.outputs = [];
633 return;
639 return;
634 }
640 }
635 // remove html output
641 // remove html output
636 // each output_subarea that has an identifying class is in an output_area
642 // each output_subarea that has an identifying class is in an output_area
637 // which is the element to be removed.
643 // which is the element to be removed.
638 if (stdout){
644 if (stdout){
639 output_div.find("div.output_stdout").parent().remove();
645 output_div.find("div.output_stdout").parent().remove();
640 }
646 }
641 if (stderr){
647 if (stderr){
642 output_div.find("div.output_stderr").parent().remove();
648 output_div.find("div.output_stderr").parent().remove();
643 }
649 }
644 if (other){
650 if (other){
645 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
651 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
646 }
652 }
647
653
648 // remove cleared outputs from JSON list:
654 // remove cleared outputs from JSON list:
649 for (var i = this.outputs.length - 1; i >= 0; i--){
655 for (var i = this.outputs.length - 1; i >= 0; i--){
650 var out = this.outputs[i];
656 var out = this.outputs[i];
651 var output_type = out.output_type;
657 var output_type = out.output_type;
652 if (output_type == "display_data" && other){
658 if (output_type == "display_data" && other){
653 this.outputs.splice(i,1);
659 this.outputs.splice(i,1);
654 }else if (output_type == "stream"){
660 }else if (output_type == "stream"){
655 if (stdout && out.stream == "stdout"){
661 if (stdout && out.stream == "stdout"){
656 this.outputs.splice(i,1);
662 this.outputs.splice(i,1);
657 }else if (stderr && out.stream == "stderr"){
663 }else if (stderr && out.stream == "stderr"){
658 this.outputs.splice(i,1);
664 this.outputs.splice(i,1);
659 }
665 }
660 }
666 }
661 }
667 }
662 };
668 };
663
669
664
670
665 CodeCell.prototype.clear_input = function () {
671 CodeCell.prototype.clear_input = function () {
666 this.code_mirror.setValue('');
672 this.code_mirror.setValue('');
667 };
673 };
668
674
669
675
670 CodeCell.prototype.collapse = function () {
676 CodeCell.prototype.collapse = function () {
671 if (!this.collapsed) {
677 if (!this.collapsed) {
672 this.element.find('div.output').hide();
678 this.element.find('div.output').hide();
673 this.collapsed = true;
679 this.collapsed = true;
674 };
680 };
675 };
681 };
676
682
677
683
678 CodeCell.prototype.expand = function () {
684 CodeCell.prototype.expand = function () {
679 if (this.collapsed) {
685 if (this.collapsed) {
680 this.element.find('div.output').show();
686 this.element.find('div.output').show();
681 this.collapsed = false;
687 this.collapsed = false;
682 };
688 };
683 };
689 };
684
690
685
691
686 CodeCell.prototype.toggle_output = function () {
692 CodeCell.prototype.toggle_output = function () {
687 if (this.collapsed) {
693 if (this.collapsed) {
688 this.expand();
694 this.expand();
689 } else {
695 } else {
690 this.collapse();
696 this.collapse();
691 };
697 };
692 };
698 };
693
699
694 CodeCell.prototype.set_input_prompt = function (number) {
700 CodeCell.prototype.set_input_prompt = function (number) {
695 var n = number || '&nbsp;';
701 var n = number || '&nbsp;';
696 this.input_prompt_number = n;
702 this.input_prompt_number = n;
697 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
703 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
698 };
704 };
699
705
700
706
701 CodeCell.prototype.get_code = function () {
707 CodeCell.prototype.get_code = function () {
702 return this.code_mirror.getValue();
708 return this.code_mirror.getValue();
703 };
709 };
704
710
705
711
706 CodeCell.prototype.set_code = function (code) {
712 CodeCell.prototype.set_code = function (code) {
707 return this.code_mirror.setValue(code);
713 return this.code_mirror.setValue(code);
708 };
714 };
709
715
710
716
711 CodeCell.prototype.at_top = function () {
717 CodeCell.prototype.at_top = function () {
712 var cursor = this.code_mirror.getCursor();
718 var cursor = this.code_mirror.getCursor();
713 if (cursor.line === 0) {
719 if (cursor.line === 0) {
714 return true;
720 return true;
715 } else {
721 } else {
716 return false;
722 return false;
717 }
723 }
718 };
724 };
719
725
720
726
721 CodeCell.prototype.at_bottom = function () {
727 CodeCell.prototype.at_bottom = function () {
722 var cursor = this.code_mirror.getCursor();
728 var cursor = this.code_mirror.getCursor();
723 if (cursor.line === (this.code_mirror.lineCount()-1)) {
729 if (cursor.line === (this.code_mirror.lineCount()-1)) {
724 return true;
730 return true;
725 } else {
731 } else {
726 return false;
732 return false;
727 }
733 }
728 };
734 };
729
735
730
736
731 CodeCell.prototype.fromJSON = function (data) {
737 CodeCell.prototype.fromJSON = function (data) {
732 console.log('Import from JSON:', data);
738 console.log('Import from JSON:', data);
733 if (data.cell_type === 'code') {
739 if (data.cell_type === 'code') {
734 if (data.input !== undefined) {
740 if (data.input !== undefined) {
735 this.set_code(data.input);
741 this.set_code(data.input);
736 }
742 }
737 if (data.prompt_number !== undefined) {
743 if (data.prompt_number !== undefined) {
738 this.set_input_prompt(data.prompt_number);
744 this.set_input_prompt(data.prompt_number);
739 } else {
745 } else {
740 this.set_input_prompt();
746 this.set_input_prompt();
741 };
747 };
742 var len = data.outputs.length;
748 var len = data.outputs.length;
743 for (var i=0; i<len; i++) {
749 for (var i=0; i<len; i++) {
744 this.append_output(data.outputs[i]);
750 this.append_output(data.outputs[i]);
745 };
751 };
746 if (data.collapsed !== undefined) {
752 if (data.collapsed !== undefined) {
747 if (data.collapsed) {
753 if (data.collapsed) {
748 this.collapse();
754 this.collapse();
749 };
755 };
750 };
756 };
751 };
757 };
752 };
758 };
753
759
754
760
755 CodeCell.prototype.toJSON = function () {
761 CodeCell.prototype.toJSON = function () {
756 var data = {};
762 var data = {};
757 data.input = this.get_code();
763 data.input = this.get_code();
758 data.cell_type = 'code';
764 data.cell_type = 'code';
759 if (this.input_prompt_number !== ' ') {
765 if (this.input_prompt_number !== ' ') {
760 data.prompt_number = this.input_prompt_number;
766 data.prompt_number = this.input_prompt_number;
761 };
767 };
762 var outputs = [];
768 var outputs = [];
763 var len = this.outputs.length;
769 var len = this.outputs.length;
764 for (var i=0; i<len; i++) {
770 for (var i=0; i<len; i++) {
765 outputs[i] = this.outputs[i];
771 outputs[i] = this.outputs[i];
766 };
772 };
767 data.outputs = outputs;
773 data.outputs = outputs;
768 data.language = 'python';
774 data.language = 'python';
769 data.collapsed = this.collapsed;
775 data.collapsed = this.collapsed;
770 // console.log('Export to JSON:',data);
776 // console.log('Export to JSON:',data);
771 return data;
777 return data;
772 };
778 };
773
779
774
780
775 IPython.CodeCell = CodeCell;
781 IPython.CodeCell = CodeCell;
776
782
777 return IPython;
783 return IPython;
778 }(IPython));
784 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now