##// END OF EJS Templates
Clean code, retab and minor fix...
Matthias BUSSONNIER -
Show More
@@ -1,232 +1,231 b''
1 // function completer.
1 // function completer.
2 //
2 //
3 // completer should be a class that take an cell instance
3 // completer should be a class that take an cell instance
4
4
5 var IPython = (function(IPython ) {
5 var IPython = (function(IPython ) {
6 // that will prevent us from misspelling
6 // that will prevent us from misspelling
7 "use strict";
7 "use strict";
8
8
9 // easyier key mapping
9 // easyier key mapping
10 var key = IPython.utils.keycodes;
10 var key = IPython.utils.keycodes;
11
11
12 // what is the common start of all completions
12 // what is the common start of all completions
13 function sharedStart(B){
13 function sharedStart(B){
14 if(B.length == 1){return B[0]}
14 if(B.length == 1){return B[0];}
15 var A = new Array()
15 var A = new Array();
16 for(var i=0; i< B.length; i++)
16 for(var i=0; i< B.length; i++)
17 {
17 {
18 A.push(B[i].str);
18 A.push(B[i].str);
19 }
19 }
20 if(A.length > 1 ){
20 if(A.length > 1 ){
21 var tem1, tem2, s, A = A.slice(0).sort();
21 var tem1, tem2, s;
22 A = A.slice(0).sort();
22 tem1 = A[0];
23 tem1 = A[0];
23 s = tem1.length;
24 s = tem1.length;
24 tem2 = A.pop();
25 tem2 = A.pop();
25 while(s && tem2.indexOf(tem1) == -1){
26 while(s && tem2.indexOf(tem1) == -1){
26 tem1 = tem1.substring(0, --s);
27 tem1 = tem1.substring(0, --s);
27 }
28 }
28 if (tem1 == "" || tem2.indexOf(tem1) != 0){return null;}
29 if (tem1 == "" || tem2.indexOf(tem1) != 0){return null;}
29 return { str : tem1,
30 return { str : tem1,
30 type : "computed",
31 type : "computed",
31 from : B[0].from,
32 from : B[0].from,
32 to : B[0].to
33 to : B[0].to
33 };
34 };
34 }
35 }
35 return null;
36 return null;
36 }
37 }
37
38
38
39
39 var Completer = function(cell) {
40 var Completer = function(cell) {
40 this.editor = cell.code_mirror;
41 this.editor = cell.code_mirror;
41 // if last caractere before cursor is not in this, we stop completing
42 // if last caractere before cursor is not in this, we stop completing
42 this.reg = /[0-9a-z.]/i; // casse insensitive
43 this.reg = /[0-9a-z.]/i; // casse insensitive
43 }
44 };
44
45
45 Completer.prototype.kernelCompletionRequest = function(){
46 Completer.prototype.kernelCompletionRequest = function(){
46 var cur = this.editor.getCursor();
47 var cur = this.editor.getCursor();
47 var line = this.editor.getLine(cur.line);
48 var line = this.editor.getLine(cur.line);
48 // one could fork here and directly call finish completing if kernel is busy
49 // one could fork here and directly call finish completing if kernel is busy
49 var callbacks = {'complete_reply': $.proxy(this.finish_completing,this)};
50 var callbacks = {'complete_reply': $.proxy(this.finish_completing,this)};
50 IPython.notebook.kernel.complete(line, cur.ch, callbacks);
51 IPython.notebook.kernel.complete(line, cur.ch, callbacks);
51 }
52 };
52
53
53
54
54 Completer.prototype.startCompletion = function()
55 Completer.prototype.startCompletion = function()
55 {
56 {
56 // call for a 'first' completion, that will set the editor and do some
57 // call for a 'first' completion, that will set the editor and do some
57 // special behaviour like autopicking if only one completion availlable
58 // special behaviour like autopicking if only one completion availlable
58 //
59 //
59 if (this.editor.somethingSelected()) return;
60 if (this.editor.somethingSelected()) return;
60 this.done = false;
61 this.done = false;
61 // use to get focus back on opera
62 // use to get focus back on opera
62 this.carryOnCompletion(true);
63 this.carryOnCompletion(true);
63 }
64 };
64
65
65 Completer.prototype.carryOnCompletion = function(ff) {
66 Completer.prototype.carryOnCompletion = function(ff) {
66 // Pass true as parameter if you want the commpleter to autopick when
67 // Pass true as parameter if you want the commpleter to autopick when
67 // only one completion. This function is automatically reinvoked at
68 // only one completion. This function is automatically reinvoked at
68 // each keystroke with ff = false
69 // each keystroke with ff = false
69
70
70 var cur = this.editor.getCursor();
71 var cur = this.editor.getCursor();
71 var pre_cursor = this.editor.getRange({line:cur.line,ch:cur.ch-1},cur);
72 var pre_cursor = this.editor.getRange({line:cur.line,ch:cur.ch-1},cur);
72
73
73 // we need to check that we are still on a word boundary
74 // we need to check that we are still on a word boundary
74 // because while typing the completer is still reinvoking itself
75 // because while typing the completer is still reinvoking itself
75 if(!this.reg.test(pre_cursor)){ this.close(); return;}
76 if(!this.reg.test(pre_cursor)){ this.close(); return;}
76
77
77 this.autopick = false;
78 this.autopick = false;
78 if( ff != 'undefined' && ff==true)
79 if( ff != 'undefined' && ff==true)
79 { this.autopick=true; }
80 { this.autopick=true; }
80
81
81 // We want a single cursor position.
82 // We want a single cursor position.
82 if (this.editor.somethingSelected()) return;
83 if (this.editor.somethingSelected()) return;
83
84
84 //one kernel completion came back, finish_completing will be called with the results
85 //one kernel completion came back, finish_completing will be called with the results
85 this.kernelCompletionRequest();
86 this.kernelCompletionRequest();
86 }
87 };
87
88
88 Completer.prototype.finish_completing =function (content) {
89 Completer.prototype.finish_completing =function (content) {
89 // let's build a function that wrap all that stuff into what is needed
90 // let's build a function that wrap all that stuff into what is needed
90 // for the new completer:
91 // for the new completer:
91 var matched_text = content.matched_text;
92 var matched_text = content.matched_text;
92 var matches = content.matches;
93 var matches = content.matches;
93
94
94 var cur = this.editor.getCursor();
95 var cur = this.editor.getCursor();
95 var results = CodeMirror.contextHint(this.editor);
96 var results = CodeMirror.contextHint(this.editor);
96
97
97 // append the introspection result, in order, at at the beginning of
98 // append the introspection result, in order, at at the beginning of
98 // the table and compute the replacement range from current cursor
99 // the table and compute the replacement range from current cursor
99 // positon and matched_text length.
100 // positon and matched_text length.
100 for(var i= matches.length-1; i>=0 ;--i)
101 for(var i= matches.length-1; i>=0 ;--i)
101 {
102 {
102 results.unshift(
103 results.unshift(
103 { str : matches[i],
104 { str : matches[i],
104 type : "introspection",
105 type : "introspection",
105 from : {line: cur.line, ch: cur.ch-matched_text.length},
106 from : {line: cur.line, ch: cur.ch-matched_text.length},
106 to : {line: cur.line, ch: cur.ch}
107 to : {line: cur.line, ch: cur.ch}
107 })
108 });
108 }
109 }
109
110
110 // one the 2 sources results have been merge, deal with it
111 // one the 2 sources results have been merge, deal with it
111 this.raw_result = results;
112 this.raw_result = results;
112
113
113 // if empty result return
114 // if empty result return
114 if (!this.raw_result || !this.raw_result.length) return;
115 if (!this.raw_result || !this.raw_result.length) return;
115
116
116 // When there is only one completion, use it directly.
117 // When there is only one completion, use it directly.
117 if (this.autopick == true && this.raw_result.length == 1)
118 if (this.autopick == true && this.raw_result.length == 1)
118 {
119 {
119 this.insert(this.raw_result[0]);
120 this.insert(this.raw_result[0]);
120 return true;
121 return;
121 }
122 }
122
123
123 if (this.raw_result.length == 1)
124 if (this.raw_result.length == 1)
124 {
125 {
125 // test if first and only completion totally matches
126 // test if first and only completion totally matches
126 // what is typed, in this case dismiss
127 // what is typed, in this case dismiss
127 var str = this.raw_result[0].str
128 var str = this.raw_result[0].str;
128 var cur = this.editor.getCursor();
129 var pre_cursor = this.editor.getRange({line:cur.line,ch:cur.ch-str.length},cur);
129 var pre_cursor = this.editor.getRange({line:cur.line,ch:cur.ch-str.length},cur);
130 if(pre_cursor == str)
130 if(pre_cursor == str)
131 { this.close(); return ; }
131 { this.close(); return ; }
132 }
132 }
133
133
134 this.complete = $('<div/>').addClass('completions');
134 this.complete = $('<div/>').addClass('completions');
135 this.complete.attr('id','complete');
135 this.complete.attr('id','complete');
136
136
137 this.sel = $('<select/>')
137 this.sel = $('<select/>')
138 .attr('multiple','true')
138 .attr('multiple','true')
139 .attr('size',Math.min(10,this.raw_result.length));
139 .attr('size',Math.min(10,this.raw_result.length));
140 var pos = this.editor.cursorCoords();
140 var pos = this.editor.cursorCoords();
141
141
142 // TODO: I propose to remove enough horizontal pixel
142 // TODO: I propose to remove enough horizontal pixel
143 // to align the text later
143 // to align the text later
144 this.complete.css('left',pos.x+'px');
144 this.complete.css('left',pos.x+'px');
145 this.complete.css('top',pos.yBot+'px');
145 this.complete.css('top',pos.yBot+'px');
146 this.complete.append(this.sel);
146 this.complete.append(this.sel);
147
147
148 $('body').append(this.complete);
148 $('body').append(this.complete);
149 //build the container
149 //build the container
150 var that = this;
150 var that = this;
151 this.sel.dblclick(function(){that.pick()});
151 this.sel.dblclick(function(){that.pick();});
152 this.sel.blur(this.close);
152 this.sel.blur(this.close);
153 this.sel.keydown(function(event){that.keydown(event)});
153 this.sel.keydown(function(event){that.keydown(event);});
154
154
155 this.build_gui_list(this.raw_result);
155 this.build_gui_list(this.raw_result);
156
156
157 this.sel.focus();
157 this.sel.focus();
158 // Opera sometimes ignores focusing a freshly created node
158 // Opera sometimes ignores focusing a freshly created node
159 if (window.opera) setTimeout(function(){if (!this.done) this.sel.focus();}, 100);
159 if (window.opera) setTimeout(function(){if (!this.done) this.sel.focus();}, 100);
160 return true;
160 return true;
161 }
161 }
162
162
163 Completer.prototype.insert = function(completion) {
163 Completer.prototype.insert = function(completion) {
164 this.editor.replaceRange(completion.str, completion.from, completion.to);
164 this.editor.replaceRange(completion.str, completion.from, completion.to);
165 }
165 }
166
166
167 Completer.prototype.build_gui_list = function(completions){
167 Completer.prototype.build_gui_list = function(completions){
168 // Need to clear the all list
168 // Need to clear the all list
169 for (var i = 0; i < completions.length; ++i) {
169 for (var i = 0; i < completions.length; ++i) {
170 var opt = $('<option/>')
170 var opt = $('<option/>')
171 .text(completions[i].str)
171 .text(completions[i].str)
172 .addClass(completions[i].type);
172 .addClass(completions[i].type);
173 this.sel.append(opt);
173 this.sel.append(opt);
174 }
174 }
175 this.sel.children().first().attr('selected','true');
175 this.sel.children().first().attr('selected','true');
176 }
176 }
177
177
178 Completer.prototype.close = function() {
178 Completer.prototype.close = function() {
179 if (this.done) return;
179 if (this.done) return;
180 this.done = true;
180 this.done = true;
181 $('.completions').remove();
181 $('.completions').remove();
182 }
182 }
183
183
184 Completer.prototype.pick = function(){
184 Completer.prototype.pick = function(){
185 this.insert(this.raw_result[this.sel[0].selectedIndex]);
185 this.insert(this.raw_result[this.sel[0].selectedIndex]);
186 this.close();
186 this.close();
187 var that = this;
187 var that = this;
188 setTimeout(function(){that.editor.focus();}, 50);
188 setTimeout(function(){that.editor.focus();}, 50);
189 }
189 }
190
190
191
191
192 Completer.prototype.keydown = function(event) {
192 Completer.prototype.keydown = function(event) {
193 var code = event.keyCode;
193 var code = event.keyCode;
194 var that = this;
194 // Enter
195 // Enter
195 if (code == key.enter) {CodeMirror.e_stop(event); this.pick();}
196 if (code == key.enter) {CodeMirror.e_stop(event); this.pick();}
196 // Escape or backspace
197 // Escape or backspace
197 else if (code == key.esc ) {CodeMirror.e_stop(event); this.close(); this.editor.focus();}
198 else if (code == key.esc ) {CodeMirror.e_stop(event); this.close(); this.editor.focus();}
198 else if (code == key.space || code == key.backspace) {this.close(); this.editor.focus();}
199 else if (code == key.space || code == key.backspace) {this.close(); this.editor.focus();}
199 else if (code == key.tab){
200 else if (code == key.tab){
200 //all the fastforwarding operation,
201 //all the fastforwarding operation,
201 //Check that shared start is not null which can append with prefixed completion
202 //Check that shared start is not null which can append with prefixed completion
202 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
203 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
203 // to erase py
204 // to erase py
204 var sh = sharedStart(this.raw_result);
205 var sh = sharedStart(this.raw_result);
205 if(sh){
206 if(sh){
206 this.insert(sh);
207 this.insert(sh);
207 }
208 }
208 this.close();
209 this.close();
209 CodeMirror.e_stop(event);
210 CodeMirror.e_stop(event);
210 this.editor.focus();
211 this.editor.focus();
211 //reinvoke self
212 //reinvoke self
212 var that = this;
213 setTimeout(function(){that.carryOnCompletion();}, 50);
213 setTimeout(function(){that.carryOnCompletion();}, 50);
214 }
214 }
215 else if (code == key.upArrow || code == key.downArrow) {
215 else if (code == key.upArrow || code == key.downArrow) {
216 // need to do that to be able to move the arrow
216 // need to do that to be able to move the arrow
217 // when on the first or last line ofo a code cell
217 // when on the first or last line ofo a code cell
218 event.stopPropagation();
218 event.stopPropagation();
219 }
219 }
220 else if (code != key.upArrow && code != key.downArrow) {
220 else if (code != key.upArrow && code != key.downArrow) {
221 this.close(); this.editor.focus();
221 this.close(); this.editor.focus();
222 //we give focus to the editor immediately and call sell in 50 ms
222 //we give focus to the editor immediately and call sell in 50 ms
223 var that = this;
224 setTimeout(function(){that.carryOnCompletion();}, 50);
223 setTimeout(function(){that.carryOnCompletion();}, 50);
225 }
224 }
226 }
225 }
227
226
228
227
229 IPython.Completer = Completer;
228 IPython.Completer = Completer;
230
229
231 return IPython;
230 return IPython;
232 }(IPython));
231 }(IPython));
@@ -1,1149 +1,1149 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 // Notebook
9 // Notebook
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 var key = IPython.utils.keycodes;
15 var key = IPython.utils.keycodes;
16
16
17 var Notebook = function (selector) {
17 var Notebook = function (selector) {
18 this.read_only = IPython.read_only;
18 this.read_only = IPython.read_only;
19 this.element = $(selector);
19 this.element = $(selector);
20 this.element.scroll();
20 this.element.scroll();
21 this.element.data("notebook", this);
21 this.element.data("notebook", this);
22 this.next_prompt_number = 1;
22 this.next_prompt_number = 1;
23 this.kernel = null;
23 this.kernel = null;
24 this.clipboard = null;
24 this.clipboard = null;
25 this.paste_enabled = false;
25 this.paste_enabled = false;
26 this.dirty = false;
26 this.dirty = false;
27 this.metadata = {};
27 this.metadata = {};
28 this.control_key_active = false;
28 this.control_key_active = false;
29 this.notebook_id = null;
29 this.notebook_id = null;
30 this.notebook_name = null;
30 this.notebook_name = null;
31 this.notebook_name_blacklist_re = /[\/\\]/;
31 this.notebook_name_blacklist_re = /[\/\\]/;
32 this.nbformat = 3 // Increment this when changing the nbformat
32 this.nbformat = 3 // Increment this when changing the nbformat
33 this.style();
33 this.style();
34 this.create_elements();
34 this.create_elements();
35 this.bind_events();
35 this.bind_events();
36 };
36 };
37
37
38
38
39 Notebook.prototype.style = function () {
39 Notebook.prototype.style = function () {
40 $('div#notebook').addClass('border-box-sizing');
40 $('div#notebook').addClass('border-box-sizing');
41 };
41 };
42
42
43
43
44 Notebook.prototype.create_elements = function () {
44 Notebook.prototype.create_elements = function () {
45 // We add this end_space div to the end of the notebook div to:
45 // We add this end_space div to the end of the notebook div to:
46 // i) provide a margin between the last cell and the end of the notebook
46 // i) provide a margin between the last cell and the end of the notebook
47 // ii) to prevent the div from scrolling up when the last cell is being
47 // ii) to prevent the div from scrolling up when the last cell is being
48 // edited, but is too low on the page, which browsers will do automatically.
48 // edited, but is too low on the page, which browsers will do automatically.
49 var that = this;
49 var that = this;
50 var end_space = $('<div/>').addClass('end_space').height("30%");
50 var end_space = $('<div/>').addClass('end_space').height("30%");
51 end_space.dblclick(function (e) {
51 end_space.dblclick(function (e) {
52 if (that.read_only) return;
52 if (that.read_only) return;
53 var ncells = that.ncells();
53 var ncells = that.ncells();
54 that.insert_cell_below('code',ncells-1);
54 that.insert_cell_below('code',ncells-1);
55 });
55 });
56 this.element.append(end_space);
56 this.element.append(end_space);
57 $('div#notebook').addClass('border-box-sizing');
57 $('div#notebook').addClass('border-box-sizing');
58 };
58 };
59
59
60
60
61 Notebook.prototype.bind_events = function () {
61 Notebook.prototype.bind_events = function () {
62 var that = this;
62 var that = this;
63
63
64 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
64 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
65 var index = that.find_cell_index(data.cell);
65 var index = that.find_cell_index(data.cell);
66 var new_cell = that.insert_cell_below('code',index);
66 var new_cell = that.insert_cell_below('code',index);
67 new_cell.set_text(data.text);
67 new_cell.set_text(data.text);
68 that.dirty = true;
68 that.dirty = true;
69 });
69 });
70
70
71 $([IPython.events]).on('select.Cell', function (event, data) {
71 $([IPython.events]).on('select.Cell', function (event, data) {
72 var index = that.find_cell_index(data.cell);
72 var index = that.find_cell_index(data.cell);
73 that.select(index);
73 that.select(index);
74 });
74 });
75
75
76
76
77 $(document).keydown(function (event) {
77 $(document).keydown(function (event) {
78 // console.log(event);
78 // console.log(event);
79 if (that.read_only) return true;
79 if (that.read_only) return true;
80
80
81 // Save (CTRL+S) or (AppleKey+S)
81 // Save (CTRL+S) or (AppleKey+S)
82 //metaKey = applekey on mac
82 //metaKey = applekey on mac
83 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
83 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
84 that.save_notebook();
84 that.save_notebook();
85 event.preventDefault();
85 event.preventDefault();
86 return false;
86 return false;
87 } else if (event.which === key.esc) {
87 } else if (event.which === key.esc) {
88 // Intercept escape at highest level to avoid closing
88 // Intercept escape at highest level to avoid closing
89 // websocket connection with firefox
89 // websocket connection with firefox
90 event.preventDefault();
90 event.preventDefault();
91 }
91 }
92 if (event.which === key.upArrow && !event.shiftKey) {
92 if (event.which === key.upArrow && !event.shiftKey) {
93 var cell = that.get_selected_cell();
93 var cell = that.get_selected_cell();
94 if (cell.at_top()) {
94 if (cell.at_top()) {
95 event.preventDefault();
95 event.preventDefault();
96 that.select_prev();
96 that.select_prev();
97 };
97 };
98 } else if (event.which === key.downArrow && !event.shiftKey) {
98 } else if (event.which === key.downArrow && !event.shiftKey) {
99 var cell = that.get_selected_cell();
99 var cell = that.get_selected_cell();
100 if (cell.at_bottom()) {
100 if (cell.at_bottom()) {
101 event.preventDefault();
101 event.preventDefault();
102 that.select_next();
102 that.select_next();
103 };
103 };
104 } else if (event.which === key.enter && event.shiftKey) {
104 } else if (event.which === key.enter && event.shiftKey) {
105 that.execute_selected_cell();
105 that.execute_selected_cell();
106 return false;
106 return false;
107 } else if (event.which === key.enter && event.ctrlKey) {
107 } else if (event.which === key.enter && event.ctrlKey) {
108 that.execute_selected_cell({terminal:true});
108 that.execute_selected_cell({terminal:true});
109 return false;
109 return false;
110 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
110 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
111 that.control_key_active = true;
111 that.control_key_active = true;
112 return false;
112 return false;
113 } else if (event.which === 88 && that.control_key_active) {
113 } else if (event.which === 88 && that.control_key_active) {
114 // Cut selected cell = x
114 // Cut selected cell = x
115 that.cut_cell();
115 that.cut_cell();
116 that.control_key_active = false;
116 that.control_key_active = false;
117 return false;
117 return false;
118 } else if (event.which === 67 && that.control_key_active) {
118 } else if (event.which === 67 && that.control_key_active) {
119 // Copy selected cell = c
119 // Copy selected cell = c
120 that.copy_cell();
120 that.copy_cell();
121 that.control_key_active = false;
121 that.control_key_active = false;
122 return false;
122 return false;
123 } else if (event.which === 86 && that.control_key_active) {
123 } else if (event.which === 86 && that.control_key_active) {
124 // Paste selected cell = v
124 // Paste selected cell = v
125 that.paste_cell();
125 that.paste_cell();
126 that.control_key_active = false;
126 that.control_key_active = false;
127 return false;
127 return false;
128 } else if (event.which === 68 && that.control_key_active) {
128 } else if (event.which === 68 && that.control_key_active) {
129 // Delete selected cell = d
129 // Delete selected cell = d
130 that.delete_cell();
130 that.delete_cell();
131 that.control_key_active = false;
131 that.control_key_active = false;
132 return false;
132 return false;
133 } else if (event.which === 65 && that.control_key_active) {
133 } else if (event.which === 65 && that.control_key_active) {
134 // Insert code cell above selected = a
134 // Insert code cell above selected = a
135 that.insert_cell_above('code');
135 that.insert_cell_above('code');
136 that.control_key_active = false;
136 that.control_key_active = false;
137 return false;
137 return false;
138 } else if (event.which === 66 && that.control_key_active) {
138 } else if (event.which === 66 && that.control_key_active) {
139 // Insert code cell below selected = b
139 // Insert code cell below selected = b
140 that.insert_cell_below('code');
140 that.insert_cell_below('code');
141 that.control_key_active = false;
141 that.control_key_active = false;
142 return false;
142 return false;
143 } else if (event.which === 89 && that.control_key_active) {
143 } else if (event.which === 89 && that.control_key_active) {
144 // To code = y
144 // To code = y
145 that.to_code();
145 that.to_code();
146 that.control_key_active = false;
146 that.control_key_active = false;
147 return false;
147 return false;
148 } else if (event.which === 77 && that.control_key_active) {
148 } else if (event.which === 77 && that.control_key_active) {
149 // To markdown = m
149 // To markdown = m
150 that.to_markdown();
150 that.to_markdown();
151 that.control_key_active = false;
151 that.control_key_active = false;
152 return false;
152 return false;
153 } else if (event.which === 84 && that.control_key_active) {
153 } else if (event.which === 84 && that.control_key_active) {
154 // To Raw = t
154 // To Raw = t
155 that.to_raw();
155 that.to_raw();
156 that.control_key_active = false;
156 that.control_key_active = false;
157 return false;
157 return false;
158 } else if (event.which === 49 && that.control_key_active) {
158 } else if (event.which === 49 && that.control_key_active) {
159 // To Heading 1 = 1
159 // To Heading 1 = 1
160 that.to_heading(undefined, 1);
160 that.to_heading(undefined, 1);
161 that.control_key_active = false;
161 that.control_key_active = false;
162 return false;
162 return false;
163 } else if (event.which === 50 && that.control_key_active) {
163 } else if (event.which === 50 && that.control_key_active) {
164 // To Heading 2 = 2
164 // To Heading 2 = 2
165 that.to_heading(undefined, 2);
165 that.to_heading(undefined, 2);
166 that.control_key_active = false;
166 that.control_key_active = false;
167 return false;
167 return false;
168 } else if (event.which === 51 && that.control_key_active) {
168 } else if (event.which === 51 && that.control_key_active) {
169 // To Heading 3 = 3
169 // To Heading 3 = 3
170 that.to_heading(undefined, 3);
170 that.to_heading(undefined, 3);
171 that.control_key_active = false;
171 that.control_key_active = false;
172 return false;
172 return false;
173 } else if (event.which === 52 && that.control_key_active) {
173 } else if (event.which === 52 && that.control_key_active) {
174 // To Heading 4 = 4
174 // To Heading 4 = 4
175 that.to_heading(undefined, 4);
175 that.to_heading(undefined, 4);
176 that.control_key_active = false;
176 that.control_key_active = false;
177 return false;
177 return false;
178 } else if (event.which === 53 && that.control_key_active) {
178 } else if (event.which === 53 && that.control_key_active) {
179 // To Heading 5 = 5
179 // To Heading 5 = 5
180 that.to_heading(undefined, 5);
180 that.to_heading(undefined, 5);
181 that.control_key_active = false;
181 that.control_key_active = false;
182 return false;
182 return false;
183 } else if (event.which === 54 && that.control_key_active) {
183 } else if (event.which === 54 && that.control_key_active) {
184 // To Heading 6 = 6
184 // To Heading 6 = 6
185 that.to_heading(undefined, 6);
185 that.to_heading(undefined, 6);
186 that.control_key_active = false;
186 that.control_key_active = false;
187 return false;
187 return false;
188 } else if (event.which === 79 && that.control_key_active) {
188 } else if (event.which === 79 && that.control_key_active) {
189 // Toggle output = o
189 // Toggle output = o
190 that.toggle_output();
190 that.toggle_output();
191 that.control_key_active = false;
191 that.control_key_active = false;
192 return false;
192 return false;
193 } else if (event.which === 83 && that.control_key_active) {
193 } else if (event.which === 83 && that.control_key_active) {
194 // Save notebook = s
194 // Save notebook = s
195 that.save_notebook();
195 that.save_notebook();
196 that.control_key_active = false;
196 that.control_key_active = false;
197 return false;
197 return false;
198 } else if (event.which === 74 && that.control_key_active) {
198 } else if (event.which === 74 && that.control_key_active) {
199 // Move cell down = j
199 // Move cell down = j
200 that.move_cell_down();
200 that.move_cell_down();
201 that.control_key_active = false;
201 that.control_key_active = false;
202 return false;
202 return false;
203 } else if (event.which === 75 && that.control_key_active) {
203 } else if (event.which === 75 && that.control_key_active) {
204 // Move cell up = k
204 // Move cell up = k
205 that.move_cell_up();
205 that.move_cell_up();
206 that.control_key_active = false;
206 that.control_key_active = false;
207 return false;
207 return false;
208 } else if (event.which === 80 && that.control_key_active) {
208 } else if (event.which === 80 && that.control_key_active) {
209 // Select previous = p
209 // Select previous = p
210 that.select_prev();
210 that.select_prev();
211 that.control_key_active = false;
211 that.control_key_active = false;
212 return false;
212 return false;
213 } else if (event.which === 78 && that.control_key_active) {
213 } else if (event.which === 78 && that.control_key_active) {
214 // Select next = n
214 // Select next = n
215 that.select_next();
215 that.select_next();
216 that.control_key_active = false;
216 that.control_key_active = false;
217 return false;
217 return false;
218 } else if (event.which === 76 && that.control_key_active) {
218 } else if (event.which === 76 && that.control_key_active) {
219 // Toggle line numbers = l
219 // Toggle line numbers = l
220 that.cell_toggle_line_numbers();
220 that.cell_toggle_line_numbers();
221 that.control_key_active = false;
221 that.control_key_active = false;
222 return false;
222 return false;
223 } else if (event.which === 73 && that.control_key_active) {
223 } else if (event.which === 73 && that.control_key_active) {
224 // Interrupt kernel = i
224 // Interrupt kernel = i
225 that.kernel.interrupt();
225 that.kernel.interrupt();
226 that.control_key_active = false;
226 that.control_key_active = false;
227 return false;
227 return false;
228 } else if (event.which === 190 && that.control_key_active) {
228 } else if (event.which === 190 && that.control_key_active) {
229 // Restart kernel = . # matches qt console
229 // Restart kernel = . # matches qt console
230 that.restart_kernel();
230 that.restart_kernel();
231 that.control_key_active = false;
231 that.control_key_active = false;
232 return false;
232 return false;
233 } else if (event.which === 72 && that.control_key_active) {
233 } else if (event.which === 72 && that.control_key_active) {
234 // Show keyboard shortcuts = h
234 // Show keyboard shortcuts = h
235 IPython.quick_help.show_keyboard_shortcuts();
235 IPython.quick_help.show_keyboard_shortcuts();
236 that.control_key_active = false;
236 that.control_key_active = false;
237 return false;
237 return false;
238 } else if (that.control_key_active) {
238 } else if (that.control_key_active) {
239 that.control_key_active = false;
239 that.control_key_active = false;
240 return true;
240 return true;
241 };
241 };
242 return true;
242 return true;
243 });
243 });
244
244
245 var collapse_time = function(time){
245 var collapse_time = function(time){
246 var app_height = $('div#main_app').height(); // content height
246 var app_height = $('div#main_app').height(); // content height
247 var splitter_height = $('div#pager_splitter').outerHeight(true);
247 var splitter_height = $('div#pager_splitter').outerHeight(true);
248 var new_height = app_height - splitter_height;
248 var new_height = app_height - splitter_height;
249 that.element.animate({height : new_height + 'px'}, time);
249 that.element.animate({height : new_height + 'px'}, time);
250 }
250 }
251
251
252 this.element.bind('collapse_pager', function (event,extrap) {
252 this.element.bind('collapse_pager', function (event,extrap) {
253 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
253 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
254 collapse_time(time);
254 collapse_time(time);
255 });
255 });
256
256
257 var expand_time = function(time) {
257 var expand_time = function(time) {
258 var app_height = $('div#main_app').height(); // content height
258 var app_height = $('div#main_app').height(); // content height
259 var splitter_height = $('div#pager_splitter').outerHeight(true);
259 var splitter_height = $('div#pager_splitter').outerHeight(true);
260 var pager_height = $('div#pager').outerHeight(true);
260 var pager_height = $('div#pager').outerHeight(true);
261 var new_height = app_height - pager_height - splitter_height;
261 var new_height = app_height - pager_height - splitter_height;
262 that.element.animate({height : new_height + 'px'}, time);
262 that.element.animate({height : new_height + 'px'}, time);
263 }
263 }
264
264
265 this.element.bind('expand_pager', function (event, extrap) {
265 this.element.bind('expand_pager', function (event, extrap) {
266 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
266 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
267 expand_time(time);
267 expand_time(time);
268 });
268 });
269
269
270 $(window).bind('beforeunload', function () {
270 $(window).bind('beforeunload', function () {
271 // TODO: Make killing the kernel configurable.
271 // TODO: Make killing the kernel configurable.
272 var kill_kernel = false;
272 var kill_kernel = false;
273 if (kill_kernel) {
273 if (kill_kernel) {
274 that.kernel.kill();
274 that.kernel.kill();
275 }
275 }
276 if (that.dirty && ! that.read_only) {
276 if (that.dirty && ! that.read_only) {
277 return "You have unsaved changes that will be lost if you leave this page.";
277 return "You have unsaved changes that will be lost if you leave this page.";
278 };
278 };
279 // Null is the *only* return value that will make the browser not
279 // Null is the *only* return value that will make the browser not
280 // pop up the "don't leave" dialog.
280 // pop up the "don't leave" dialog.
281 return null;
281 return null;
282 });
282 });
283 };
283 };
284
284
285
285
286 Notebook.prototype.scroll_to_bottom = function () {
286 Notebook.prototype.scroll_to_bottom = function () {
287 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
287 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
288 };
288 };
289
289
290
290
291 Notebook.prototype.scroll_to_top = function () {
291 Notebook.prototype.scroll_to_top = function () {
292 this.element.animate({scrollTop:0}, 0);
292 this.element.animate({scrollTop:0}, 0);
293 };
293 };
294
294
295
295
296 // Cell indexing, retrieval, etc.
296 // Cell indexing, retrieval, etc.
297
297
298 Notebook.prototype.get_cell_elements = function () {
298 Notebook.prototype.get_cell_elements = function () {
299 return this.element.children("div.cell");
299 return this.element.children("div.cell");
300 };
300 };
301
301
302
302
303 Notebook.prototype.get_cell_element = function (index) {
303 Notebook.prototype.get_cell_element = function (index) {
304 var result = null;
304 var result = null;
305 var e = this.get_cell_elements().eq(index);
305 var e = this.get_cell_elements().eq(index);
306 if (e.length !== 0) {
306 if (e.length !== 0) {
307 result = e;
307 result = e;
308 }
308 }
309 return result;
309 return result;
310 };
310 };
311
311
312
312
313 Notebook.prototype.ncells = function (cell) {
313 Notebook.prototype.ncells = function (cell) {
314 return this.get_cell_elements().length;
314 return this.get_cell_elements().length;
315 };
315 };
316
316
317
317
318 // TODO: we are often calling cells as cells()[i], which we should optimize
318 // TODO: we are often calling cells as cells()[i], which we should optimize
319 // to cells(i) or a new method.
319 // to cells(i) or a new method.
320 Notebook.prototype.get_cells = function () {
320 Notebook.prototype.get_cells = function () {
321 return this.get_cell_elements().toArray().map(function (e) {
321 return this.get_cell_elements().toArray().map(function (e) {
322 return $(e).data("cell");
322 return $(e).data("cell");
323 });
323 });
324 };
324 };
325
325
326
326
327 Notebook.prototype.get_cell = function (index) {
327 Notebook.prototype.get_cell = function (index) {
328 var result = null;
328 var result = null;
329 var ce = this.get_cell_element(index);
329 var ce = this.get_cell_element(index);
330 if (ce !== null) {
330 if (ce !== null) {
331 result = ce.data('cell');
331 result = ce.data('cell');
332 }
332 }
333 return result;
333 return result;
334 }
334 }
335
335
336
336
337 Notebook.prototype.get_next_cell = function (cell) {
337 Notebook.prototype.get_next_cell = function (cell) {
338 var result = null;
338 var result = null;
339 var index = this.find_cell_index(cell);
339 var index = this.find_cell_index(cell);
340 if (index !== null && index < this.ncells()) {
340 if (index !== null && index < this.ncells()) {
341 result = this.get_cell(index+1);
341 result = this.get_cell(index+1);
342 }
342 }
343 return result;
343 return result;
344 }
344 }
345
345
346
346
347 Notebook.prototype.get_prev_cell = function (cell) {
347 Notebook.prototype.get_prev_cell = function (cell) {
348 var result = null;
348 var result = null;
349 var index = this.find_cell_index(cell);
349 var index = this.find_cell_index(cell);
350 if (index !== null && index > 1) {
350 if (index !== null && index > 1) {
351 result = this.get_cell(index-1);
351 result = this.get_cell(index-1);
352 }
352 }
353 return result;
353 return result;
354 }
354 }
355
355
356 Notebook.prototype.find_cell_index = function (cell) {
356 Notebook.prototype.find_cell_index = function (cell) {
357 var result = null;
357 var result = null;
358 this.get_cell_elements().filter(function (index) {
358 this.get_cell_elements().filter(function (index) {
359 if ($(this).data("cell") === cell) {
359 if ($(this).data("cell") === cell) {
360 result = index;
360 result = index;
361 };
361 };
362 });
362 });
363 return result;
363 return result;
364 };
364 };
365
365
366
366
367 Notebook.prototype.index_or_selected = function (index) {
367 Notebook.prototype.index_or_selected = function (index) {
368 var i;
368 var i;
369 if (index === undefined || index === null) {
369 if (index === undefined || index === null) {
370 i = this.get_selected_index();
370 i = this.get_selected_index();
371 if (i === null) {
371 if (i === null) {
372 i = 0;
372 i = 0;
373 }
373 }
374 } else {
374 } else {
375 i = index;
375 i = index;
376 }
376 }
377 return i;
377 return i;
378 };
378 };
379
379
380
380
381 Notebook.prototype.get_selected_cell = function () {
381 Notebook.prototype.get_selected_cell = function () {
382 var index = this.get_selected_index();
382 var index = this.get_selected_index();
383 return this.get_cell(index);
383 return this.get_cell(index);
384 };
384 };
385
385
386
386
387 Notebook.prototype.is_valid_cell_index = function (index) {
387 Notebook.prototype.is_valid_cell_index = function (index) {
388 if (index !== null && index >= 0 && index < this.ncells()) {
388 if (index !== null && index >= 0 && index < this.ncells()) {
389 return true;
389 return true;
390 } else {
390 } else {
391 return false;
391 return false;
392 };
392 };
393 }
393 }
394
394
395 Notebook.prototype.get_selected_index = function () {
395 Notebook.prototype.get_selected_index = function () {
396 var result = null;
396 var result = null;
397 this.get_cell_elements().filter(function (index) {
397 this.get_cell_elements().filter(function (index) {
398 if ($(this).data("cell").selected === true) {
398 if ($(this).data("cell").selected === true) {
399 result = index;
399 result = index;
400 };
400 };
401 });
401 });
402 return result;
402 return result;
403 };
403 };
404
404
405
405
406 // Cell selection.
406 // Cell selection.
407
407
408 Notebook.prototype.select = function (index) {
408 Notebook.prototype.select = function (index) {
409 if (index !== undefined && index >= 0 && index < this.ncells()) {
409 if (index !== undefined && index >= 0 && index < this.ncells()) {
410 sindex = this.get_selected_index()
410 sindex = this.get_selected_index()
411 if (sindex !== null && index !== sindex) {
411 if (sindex !== null && index !== sindex) {
412 this.get_cell(sindex).unselect();
412 this.get_cell(sindex).unselect();
413 };
413 };
414 var cell = this.get_cell(index)
414 var cell = this.get_cell(index)
415 cell.select();
415 cell.select();
416 if (cell.cell_type === 'heading') {
416 if (cell.cell_type === 'heading') {
417 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
417 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
418 {'cell_type':cell.cell_type,level:cell.level}
418 {'cell_type':cell.cell_type,level:cell.level}
419 );
419 );
420 } else {
420 } else {
421 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
421 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
422 {'cell_type':cell.cell_type}
422 {'cell_type':cell.cell_type}
423 );
423 );
424 };
424 };
425 };
425 };
426 return this;
426 return this;
427 };
427 };
428
428
429
429
430 Notebook.prototype.select_next = function () {
430 Notebook.prototype.select_next = function () {
431 var index = this.get_selected_index();
431 var index = this.get_selected_index();
432 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
432 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
433 this.select(index+1);
433 this.select(index+1);
434 };
434 };
435 return this;
435 return this;
436 };
436 };
437
437
438
438
439 Notebook.prototype.select_prev = function () {
439 Notebook.prototype.select_prev = function () {
440 var index = this.get_selected_index();
440 var index = this.get_selected_index();
441 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
441 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
442 this.select(index-1);
442 this.select(index-1);
443 };
443 };
444 return this;
444 return this;
445 };
445 };
446
446
447
447
448 // Cell movement
448 // Cell movement
449
449
450 Notebook.prototype.move_cell_up = function (index) {
450 Notebook.prototype.move_cell_up = function (index) {
451 var i = this.index_or_selected();
451 var i = this.index_or_selected();
452 if (i !== null && i < this.ncells() && i > 0) {
452 if (i !== null && i < this.ncells() && i > 0) {
453 var pivot = this.get_cell_element(i-1);
453 var pivot = this.get_cell_element(i-1);
454 var tomove = this.get_cell_element(i);
454 var tomove = this.get_cell_element(i);
455 if (pivot !== null && tomove !== null) {
455 if (pivot !== null && tomove !== null) {
456 tomove.detach();
456 tomove.detach();
457 pivot.before(tomove);
457 pivot.before(tomove);
458 this.select(i-1);
458 this.select(i-1);
459 };
459 };
460 };
460 };
461 this.dirty = true;
461 this.dirty = true;
462 return this;
462 return this;
463 };
463 };
464
464
465
465
466 Notebook.prototype.move_cell_down = function (index) {
466 Notebook.prototype.move_cell_down = function (index) {
467 var i = this.index_or_selected();
467 var i = this.index_or_selected();
468 if (i !== null && i < (this.ncells()-1) && i >= 0) {
468 if (i !== null && i < (this.ncells()-1) && i >= 0) {
469 var pivot = this.get_cell_element(i+1);
469 var pivot = this.get_cell_element(i+1);
470 var tomove = this.get_cell_element(i);
470 var tomove = this.get_cell_element(i);
471 if (pivot !== null && tomove !== null) {
471 if (pivot !== null && tomove !== null) {
472 tomove.detach();
472 tomove.detach();
473 pivot.after(tomove);
473 pivot.after(tomove);
474 this.select(i+1);
474 this.select(i+1);
475 };
475 };
476 };
476 };
477 this.dirty = true;
477 this.dirty = true;
478 return this;
478 return this;
479 };
479 };
480
480
481
481
482 Notebook.prototype.sort_cells = function () {
482 Notebook.prototype.sort_cells = function () {
483 // This is not working right now. Calling this will actually crash
483 // This is not working right now. Calling this will actually crash
484 // the browser. I think there is an infinite loop in here...
484 // the browser. I think there is an infinite loop in here...
485 var ncells = this.ncells();
485 var ncells = this.ncells();
486 var sindex = this.get_selected_index();
486 var sindex = this.get_selected_index();
487 var swapped;
487 var swapped;
488 do {
488 do {
489 swapped = false;
489 swapped = false;
490 for (var i=1; i<ncells; i++) {
490 for (var i=1; i<ncells; i++) {
491 current = this.get_cell(i);
491 current = this.get_cell(i);
492 previous = this.get_cell(i-1);
492 previous = this.get_cell(i-1);
493 if (previous.input_prompt_number > current.input_prompt_number) {
493 if (previous.input_prompt_number > current.input_prompt_number) {
494 this.move_cell_up(i);
494 this.move_cell_up(i);
495 swapped = true;
495 swapped = true;
496 };
496 };
497 };
497 };
498 } while (swapped);
498 } while (swapped);
499 this.select(sindex);
499 this.select(sindex);
500 return this;
500 return this;
501 };
501 };
502
502
503 // Insertion, deletion.
503 // Insertion, deletion.
504
504
505 Notebook.prototype.delete_cell = function (index) {
505 Notebook.prototype.delete_cell = function (index) {
506 var i = this.index_or_selected(index);
506 var i = this.index_or_selected(index);
507 if (this.is_valid_cell_index(i)) {
507 if (this.is_valid_cell_index(i)) {
508 var ce = this.get_cell_element(i);
508 var ce = this.get_cell_element(i);
509 ce.remove();
509 ce.remove();
510 if (i === (this.ncells())) {
510 if (i === (this.ncells())) {
511 this.select(i-1);
511 this.select(i-1);
512 } else {
512 } else {
513 this.select(i);
513 this.select(i);
514 };
514 };
515 this.dirty = true;
515 this.dirty = true;
516 };
516 };
517 return this;
517 return this;
518 };
518 };
519
519
520
520
521 Notebook.prototype.insert_cell_below = function (type, index) {
521 Notebook.prototype.insert_cell_below = function (type, index) {
522 // type = ('code','html','markdown')
522 // type = ('code','html','markdown')
523 // index = cell index or undefined to insert below selected
523 // index = cell index or undefined to insert below selected
524 index = this.index_or_selected(index);
524 index = this.index_or_selected(index);
525 var cell = null;
525 var cell = null;
526 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
526 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
527 if (type === 'code') {
527 if (type === 'code') {
528 cell = new IPython.CodeCell(this.kernel);
528 cell = new IPython.CodeCell(this.kernel);
529 cell.set_input_prompt();
529 cell.set_input_prompt();
530 } else if (type === 'markdown') {
530 } else if (type === 'markdown') {
531 cell = new IPython.MarkdownCell();
531 cell = new IPython.MarkdownCell();
532 } else if (type === 'html') {
532 } else if (type === 'html') {
533 cell = new IPython.HTMLCell();
533 cell = new IPython.HTMLCell();
534 } else if (type === 'raw') {
534 } else if (type === 'raw') {
535 cell = new IPython.RawCell();
535 cell = new IPython.RawCell();
536 } else if (type === 'heading') {
536 } else if (type === 'heading') {
537 cell = new IPython.HeadingCell();
537 cell = new IPython.HeadingCell();
538 };
538 };
539 if (cell !== null) {
539 if (cell !== null) {
540 if (this.ncells() === 0) {
540 if (this.ncells() === 0) {
541 this.element.find('div.end_space').before(cell.element);
541 this.element.find('div.end_space').before(cell.element);
542 } else if (this.is_valid_cell_index(index)) {
542 } else if (this.is_valid_cell_index(index)) {
543 this.get_cell_element(index).after(cell.element);
543 this.get_cell_element(index).after(cell.element);
544 };
544 };
545 cell.render();
545 cell.render();
546 this.select(this.find_cell_index(cell));
546 this.select(this.find_cell_index(cell));
547 this.dirty = true;
547 this.dirty = true;
548 return cell;
548 return cell;
549 };
549 };
550 };
550 };
551 return cell;
551 return cell;
552 };
552 };
553
553
554
554
555 Notebook.prototype.insert_cell_above = function (type, index) {
555 Notebook.prototype.insert_cell_above = function (type, index) {
556 // type = ('code','html','markdown')
556 // type = ('code','html','markdown')
557 // index = cell index or undefined to insert above selected
557 // index = cell index or undefined to insert above selected
558 index = this.index_or_selected(index);
558 index = this.index_or_selected(index);
559 var cell = null;
559 var cell = null;
560 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
560 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
561 if (type === 'code') {
561 if (type === 'code') {
562 cell = new IPython.CodeCell(this.kernel);
562 cell = new IPython.CodeCell(this.kernel);
563 cell.set_input_prompt();
563 cell.set_input_prompt();
564 } else if (type === 'markdown') {
564 } else if (type === 'markdown') {
565 cell = new IPython.MarkdownCell();
565 cell = new IPython.MarkdownCell();
566 } else if (type === 'html') {
566 } else if (type === 'html') {
567 cell = new IPython.HTMLCell();
567 cell = new IPython.HTMLCell();
568 } else if (type === 'raw') {
568 } else if (type === 'raw') {
569 cell = new IPython.RawCell();
569 cell = new IPython.RawCell();
570 } else if (type === 'heading') {
570 } else if (type === 'heading') {
571 cell = new IPython.HeadingCell();
571 cell = new IPython.HeadingCell();
572 };
572 };
573 if (cell !== null) {
573 if (cell !== null) {
574 if (this.ncells() === 0) {
574 if (this.ncells() === 0) {
575 this.element.find('div.end_space').before(cell.element);
575 this.element.find('div.end_space').before(cell.element);
576 } else if (this.is_valid_cell_index(index)) {
576 } else if (this.is_valid_cell_index(index)) {
577 this.get_cell_element(index).before(cell.element);
577 this.get_cell_element(index).before(cell.element);
578 };
578 };
579 cell.render();
579 cell.render();
580 this.select(this.find_cell_index(cell));
580 this.select(this.find_cell_index(cell));
581 this.dirty = true;
581 this.dirty = true;
582 return cell;
582 return cell;
583 };
583 };
584 };
584 };
585 return cell;
585 return cell;
586 };
586 };
587
587
588
588
589 Notebook.prototype.to_code = function (index) {
589 Notebook.prototype.to_code = function (index) {
590 var i = this.index_or_selected(index);
590 var i = this.index_or_selected(index);
591 if (this.is_valid_cell_index(i)) {
591 if (this.is_valid_cell_index(i)) {
592 var source_element = this.get_cell_element(i);
592 var source_element = this.get_cell_element(i);
593 var source_cell = source_element.data("cell");
593 var source_cell = source_element.data("cell");
594 if (!(source_cell instanceof IPython.CodeCell)) {
594 if (!(source_cell instanceof IPython.CodeCell)) {
595 target_cell = this.insert_cell_below('code',i);
595 target_cell = this.insert_cell_below('code',i);
596 var text = source_cell.get_text();
596 var text = source_cell.get_text();
597 if (text === source_cell.placeholder) {
597 if (text === source_cell.placeholder) {
598 text = '';
598 text = '';
599 }
599 }
600 target_cell.set_text(text);
600 target_cell.set_text(text);
601 source_element.remove();
601 source_element.remove();
602 this.dirty = true;
602 this.dirty = true;
603 };
603 };
604 };
604 };
605 };
605 };
606
606
607
607
608 Notebook.prototype.to_markdown = function (index) {
608 Notebook.prototype.to_markdown = function (index) {
609 var i = this.index_or_selected(index);
609 var i = this.index_or_selected(index);
610 if (this.is_valid_cell_index(i)) {
610 if (this.is_valid_cell_index(i)) {
611 var source_element = this.get_cell_element(i);
611 var source_element = this.get_cell_element(i);
612 var source_cell = source_element.data("cell");
612 var source_cell = source_element.data("cell");
613 if (!(source_cell instanceof IPython.MarkdownCell)) {
613 if (!(source_cell instanceof IPython.MarkdownCell)) {
614 target_cell = this.insert_cell_below('markdown',i);
614 target_cell = this.insert_cell_below('markdown',i);
615 var text = source_cell.get_text();
615 var text = source_cell.get_text();
616 if (text === source_cell.placeholder) {
616 if (text === source_cell.placeholder) {
617 text = '';
617 text = '';
618 };
618 };
619 // The edit must come before the set_text.
619 // The edit must come before the set_text.
620 target_cell.edit();
620 target_cell.edit();
621 target_cell.set_text(text);
621 target_cell.set_text(text);
622 source_element.remove();
622 source_element.remove();
623 this.dirty = true;
623 this.dirty = true;
624 };
624 };
625 };
625 };
626 };
626 };
627
627
628
628
629 Notebook.prototype.to_html = function (index) {
629 Notebook.prototype.to_html = function (index) {
630 var i = this.index_or_selected(index);
630 var i = this.index_or_selected(index);
631 if (this.is_valid_cell_index(i)) {
631 if (this.is_valid_cell_index(i)) {
632 var source_element = this.get_cell_element(i);
632 var source_element = this.get_cell_element(i);
633 var source_cell = source_element.data("cell");
633 var source_cell = source_element.data("cell");
634 var target_cell = null;
634 var target_cell = null;
635 if (!(source_cell instanceof IPython.HTMLCell)) {
635 if (!(source_cell instanceof IPython.HTMLCell)) {
636 target_cell = this.insert_cell_below('html',i);
636 target_cell = this.insert_cell_below('html',i);
637 var text = source_cell.get_text();
637 var text = source_cell.get_text();
638 if (text === source_cell.placeholder) {
638 if (text === source_cell.placeholder) {
639 text = '';
639 text = '';
640 };
640 };
641 // The edit must come before the set_text.
641 // The edit must come before the set_text.
642 target_cell.edit();
642 target_cell.edit();
643 target_cell.set_text(text);
643 target_cell.set_text(text);
644 source_element.remove();
644 source_element.remove();
645 this.dirty = true;
645 this.dirty = true;
646 };
646 };
647 };
647 };
648 };
648 };
649
649
650
650
651 Notebook.prototype.to_raw = function (index) {
651 Notebook.prototype.to_raw = function (index) {
652 var i = this.index_or_selected(index);
652 var i = this.index_or_selected(index);
653 if (this.is_valid_cell_index(i)) {
653 if (this.is_valid_cell_index(i)) {
654 var source_element = this.get_cell_element(i);
654 var source_element = this.get_cell_element(i);
655 var source_cell = source_element.data("cell");
655 var source_cell = source_element.data("cell");
656 var target_cell = null;
656 var target_cell = null;
657 if (!(source_cell instanceof IPython.RawCell)) {
657 if (!(source_cell instanceof IPython.RawCell)) {
658 target_cell = this.insert_cell_below('raw',i);
658 target_cell = this.insert_cell_below('raw',i);
659 var text = source_cell.get_text();
659 var text = source_cell.get_text();
660 if (text === source_cell.placeholder) {
660 if (text === source_cell.placeholder) {
661 text = '';
661 text = '';
662 };
662 };
663 // The edit must come before the set_text.
663 // The edit must come before the set_text.
664 target_cell.edit();
664 target_cell.edit();
665 target_cell.set_text(text);
665 target_cell.set_text(text);
666 source_element.remove();
666 source_element.remove();
667 this.dirty = true;
667 this.dirty = true;
668 };
668 };
669 };
669 };
670 };
670 };
671
671
672
672
673 Notebook.prototype.to_heading = function (index, level) {
673 Notebook.prototype.to_heading = function (index, level) {
674 level = level || 1;
674 level = level || 1;
675 var i = this.index_or_selected(index);
675 var i = this.index_or_selected(index);
676 if (this.is_valid_cell_index(i)) {
676 if (this.is_valid_cell_index(i)) {
677 var source_element = this.get_cell_element(i);
677 var source_element = this.get_cell_element(i);
678 var source_cell = source_element.data("cell");
678 var source_cell = source_element.data("cell");
679 var target_cell = null;
679 var target_cell = null;
680 if (source_cell instanceof IPython.HeadingCell) {
680 if (source_cell instanceof IPython.HeadingCell) {
681 source_cell.set_level(level);
681 source_cell.set_level(level);
682 } else {
682 } else {
683 target_cell = this.insert_cell_below('heading',i);
683 target_cell = this.insert_cell_below('heading',i);
684 var text = source_cell.get_text();
684 var text = source_cell.get_text();
685 if (text === source_cell.placeholder) {
685 if (text === source_cell.placeholder) {
686 text = '';
686 text = '';
687 };
687 };
688 // The edit must come before the set_text.
688 // The edit must come before the set_text.
689 target_cell.set_level(level);
689 target_cell.set_level(level);
690 target_cell.edit();
690 target_cell.edit();
691 target_cell.set_text(text);
691 target_cell.set_text(text);
692 source_element.remove();
692 source_element.remove();
693 this.dirty = true;
693 this.dirty = true;
694 };
694 };
695 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
695 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
696 {'cell_type':'heading',level:level}
696 {'cell_type':'heading',level:level}
697 );
697 );
698 };
698 };
699 };
699 };
700
700
701
701
702 // Cut/Copy/Paste
702 // Cut/Copy/Paste
703
703
704 Notebook.prototype.enable_paste = function () {
704 Notebook.prototype.enable_paste = function () {
705 var that = this;
705 var that = this;
706 if (!this.paste_enabled) {
706 if (!this.paste_enabled) {
707 $('#paste_cell').removeClass('ui-state-disabled')
707 $('#paste_cell').removeClass('ui-state-disabled')
708 .on('click', function () {that.paste_cell();});
708 .on('click', function () {that.paste_cell();});
709 $('#paste_cell_above').removeClass('ui-state-disabled')
709 $('#paste_cell_above').removeClass('ui-state-disabled')
710 .on('click', function () {that.paste_cell_above();});
710 .on('click', function () {that.paste_cell_above();});
711 $('#paste_cell_below').removeClass('ui-state-disabled')
711 $('#paste_cell_below').removeClass('ui-state-disabled')
712 .on('click', function () {that.paste_cell_below();});
712 .on('click', function () {that.paste_cell_below();});
713 this.paste_enabled = true;
713 this.paste_enabled = true;
714 };
714 };
715 };
715 };
716
716
717
717
718 Notebook.prototype.disable_paste = function () {
718 Notebook.prototype.disable_paste = function () {
719 if (this.paste_enabled) {
719 if (this.paste_enabled) {
720 $('#paste_cell').addClass('ui-state-disabled').off('click');
720 $('#paste_cell').addClass('ui-state-disabled').off('click');
721 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
721 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
722 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
722 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
723 this.paste_enabled = false;
723 this.paste_enabled = false;
724 };
724 };
725 };
725 };
726
726
727
727
728 Notebook.prototype.cut_cell = function () {
728 Notebook.prototype.cut_cell = function () {
729 this.copy_cell();
729 this.copy_cell();
730 this.delete_cell();
730 this.delete_cell();
731 }
731 }
732
732
733 Notebook.prototype.copy_cell = function () {
733 Notebook.prototype.copy_cell = function () {
734 var cell = this.get_selected_cell();
734 var cell = this.get_selected_cell();
735 this.clipboard = cell.toJSON();
735 this.clipboard = cell.toJSON();
736 this.enable_paste();
736 this.enable_paste();
737 };
737 };
738
738
739
739
740 Notebook.prototype.paste_cell = function () {
740 Notebook.prototype.paste_cell = function () {
741 if (this.clipboard !== null && this.paste_enabled) {
741 if (this.clipboard !== null && this.paste_enabled) {
742 var cell_data = this.clipboard;
742 var cell_data = this.clipboard;
743 var new_cell = this.insert_cell_above(cell_data.cell_type);
743 var new_cell = this.insert_cell_above(cell_data.cell_type);
744 new_cell.fromJSON(cell_data);
744 new_cell.fromJSON(cell_data);
745 old_cell = this.get_next_cell(new_cell);
745 old_cell = this.get_next_cell(new_cell);
746 this.delete_cell(this.find_cell_index(old_cell));
746 this.delete_cell(this.find_cell_index(old_cell));
747 this.select(this.find_cell_index(new_cell));
747 this.select(this.find_cell_index(new_cell));
748 };
748 };
749 };
749 };
750
750
751
751
752 Notebook.prototype.paste_cell_above = function () {
752 Notebook.prototype.paste_cell_above = function () {
753 if (this.clipboard !== null && this.paste_enabled) {
753 if (this.clipboard !== null && this.paste_enabled) {
754 var cell_data = this.clipboard;
754 var cell_data = this.clipboard;
755 var new_cell = this.insert_cell_above(cell_data.cell_type);
755 var new_cell = this.insert_cell_above(cell_data.cell_type);
756 new_cell.fromJSON(cell_data);
756 new_cell.fromJSON(cell_data);
757 };
757 };
758 };
758 };
759
759
760
760
761 Notebook.prototype.paste_cell_below = function () {
761 Notebook.prototype.paste_cell_below = function () {
762 if (this.clipboard !== null && this.paste_enabled) {
762 if (this.clipboard !== null && this.paste_enabled) {
763 var cell_data = this.clipboard;
763 var cell_data = this.clipboard;
764 var new_cell = this.insert_cell_below(cell_data.cell_type);
764 var new_cell = this.insert_cell_below(cell_data.cell_type);
765 new_cell.fromJSON(cell_data);
765 new_cell.fromJSON(cell_data);
766 };
766 };
767 };
767 };
768
768
769
769
770 // Split/merge
770 // Split/merge
771
771
772 Notebook.prototype.split_cell = function () {
772 Notebook.prototype.split_cell = function () {
773 // Todo: implement spliting for other cell types.
773 // Todo: implement spliting for other cell types.
774 var cell = this.get_selected_cell();
774 var cell = this.get_selected_cell();
775 if (cell.is_splittable()) {
775 if (cell.is_splittable()) {
776 texta = cell.get_pre_cursor();
776 texta = cell.get_pre_cursor();
777 textb = cell.get_post_cursor();
777 textb = cell.get_post_cursor();
778 if (cell instanceof IPython.CodeCell) {
778 if (cell instanceof IPython.CodeCell) {
779 cell.set_text(texta);
779 cell.set_text(texta);
780 var new_cell = this.insert_cell_below('code');
780 var new_cell = this.insert_cell_below('code');
781 new_cell.set_text(textb);
781 new_cell.set_text(textb);
782 } else if (cell instanceof IPython.MarkdownCell) {
782 } else if (cell instanceof IPython.MarkdownCell) {
783 cell.set_text(texta);
783 cell.set_text(texta);
784 cell.render();
784 cell.render();
785 var new_cell = this.insert_cell_below('markdown');
785 var new_cell = this.insert_cell_below('markdown');
786 new_cell.edit(); // editor must be visible to call set_text
786 new_cell.edit(); // editor must be visible to call set_text
787 new_cell.set_text(textb);
787 new_cell.set_text(textb);
788 new_cell.render();
788 new_cell.render();
789 } else if (cell instanceof IPython.HTMLCell) {
789 } else if (cell instanceof IPython.HTMLCell) {
790 cell.set_text(texta);
790 cell.set_text(texta);
791 cell.render();
791 cell.render();
792 var new_cell = this.insert_cell_below('html');
792 var new_cell = this.insert_cell_below('html');
793 new_cell.edit(); // editor must be visible to call set_text
793 new_cell.edit(); // editor must be visible to call set_text
794 new_cell.set_text(textb);
794 new_cell.set_text(textb);
795 new_cell.render();
795 new_cell.render();
796 };
796 };
797 };
797 };
798 };
798 };
799
799
800
800
801 Notebook.prototype.merge_cell_above = function () {
801 Notebook.prototype.merge_cell_above = function () {
802 var index = this.get_selected_index();
802 var index = this.get_selected_index();
803 var cell = this.get_cell(index);
803 var cell = this.get_cell(index);
804 if (index > 0) {
804 if (index > 0) {
805 upper_cell = this.get_cell(index-1);
805 upper_cell = this.get_cell(index-1);
806 upper_text = upper_cell.get_text();
806 upper_text = upper_cell.get_text();
807 text = cell.get_text();
807 text = cell.get_text();
808 if (cell instanceof IPython.CodeCell) {
808 if (cell instanceof IPython.CodeCell) {
809 cell.set_text(upper_text+'\n'+text);
809 cell.set_text(upper_text+'\n'+text);
810 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
810 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
811 cell.edit();
811 cell.edit();
812 cell.set_text(upper_text+'\n'+text);
812 cell.set_text(upper_text+'\n'+text);
813 cell.render();
813 cell.render();
814 };
814 };
815 this.delete_cell(index-1);
815 this.delete_cell(index-1);
816 this.select(this.find_cell_index(cell));
816 this.select(this.find_cell_index(cell));
817 };
817 };
818 };
818 };
819
819
820
820
821 Notebook.prototype.merge_cell_below = function () {
821 Notebook.prototype.merge_cell_below = function () {
822 var index = this.get_selected_index();
822 var index = this.get_selected_index();
823 var cell = this.get_cell(index);
823 var cell = this.get_cell(index);
824 if (index < this.ncells()-1) {
824 if (index < this.ncells()-1) {
825 lower_cell = this.get_cell(index+1);
825 lower_cell = this.get_cell(index+1);
826 lower_text = lower_cell.get_text();
826 lower_text = lower_cell.get_text();
827 text = cell.get_text();
827 text = cell.get_text();
828 if (cell instanceof IPython.CodeCell) {
828 if (cell instanceof IPython.CodeCell) {
829 cell.set_text(text+'\n'+lower_text);
829 cell.set_text(text+'\n'+lower_text);
830 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
830 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
831 cell.edit();
831 cell.edit();
832 cell.set_text(text+'\n'+lower_text);
832 cell.set_text(text+'\n'+lower_text);
833 cell.render();
833 cell.render();
834 };
834 };
835 this.delete_cell(index+1);
835 this.delete_cell(index+1);
836 this.select(this.find_cell_index(cell));
836 this.select(this.find_cell_index(cell));
837 };
837 };
838 };
838 };
839
839
840
840
841 // Cell collapsing and output clearing
841 // Cell collapsing and output clearing
842
842
843 Notebook.prototype.collapse = function (index) {
843 Notebook.prototype.collapse = function (index) {
844 var i = this.index_or_selected(index);
844 var i = this.index_or_selected(index);
845 this.get_cell(i).collapse();
845 this.get_cell(i).collapse();
846 this.dirty = true;
846 this.dirty = true;
847 };
847 };
848
848
849
849
850 Notebook.prototype.expand = function (index) {
850 Notebook.prototype.expand = function (index) {
851 var i = this.index_or_selected(index);
851 var i = this.index_or_selected(index);
852 this.get_cell(i).expand();
852 this.get_cell(i).expand();
853 this.dirty = true;
853 this.dirty = true;
854 };
854 };
855
855
856
856
857 Notebook.prototype.toggle_output = function (index) {
857 Notebook.prototype.toggle_output = function (index) {
858 var i = this.index_or_selected(index);
858 var i = this.index_or_selected(index);
859 this.get_cell(i).toggle_output();
859 this.get_cell(i).toggle_output();
860 this.dirty = true;
860 this.dirty = true;
861 };
861 };
862
862
863
863
864 Notebook.prototype.clear_all_output = function () {
864 Notebook.prototype.clear_all_output = function () {
865 var ncells = this.ncells();
865 var ncells = this.ncells();
866 var cells = this.get_cells();
866 var cells = this.get_cells();
867 for (var i=0; i<ncells; i++) {
867 for (var i=0; i<ncells; i++) {
868 if (cells[i] instanceof IPython.CodeCell) {
868 if (cells[i] instanceof IPython.CodeCell) {
869 cells[i].clear_output(true,true,true);
869 cells[i].clear_output(true,true,true);
870 // Make all In[] prompts blank, as well
870 // Make all In[] prompts blank, as well
871 // TODO: make this configurable (via checkbox?)
871 // TODO: make this configurable (via checkbox?)
872 cells[i].set_input_prompt();
872 cells[i].set_input_prompt();
873 }
873 }
874 };
874 };
875 this.dirty = true;
875 this.dirty = true;
876 };
876 };
877
877
878
878
879 // Other cell functions: line numbers, ...
879 // Other cell functions: line numbers, ...
880
880
881 Notebook.prototype.cell_toggle_line_numbers = function() {
881 Notebook.prototype.cell_toggle_line_numbers = function() {
882 this.get_selected_cell().toggle_line_numbers();
882 this.get_selected_cell().toggle_line_numbers();
883 };
883 };
884
884
885 // Kernel related things
885 // Kernel related things
886
886
887 Notebook.prototype.start_kernel = function () {
887 Notebook.prototype.start_kernel = function () {
888 var base_url = $('body').data('baseKernelUrl') + "kernels";
888 var base_url = $('body').data('baseKernelUrl') + "kernels";
889 this.kernel = new IPython.Kernel(base_url);
889 this.kernel = new IPython.Kernel(base_url);
890 this.kernel.start(this.notebook_id);
890 this.kernel.start(this.notebook_id);
891 };
891 };
892
892
893
893
894 Notebook.prototype.restart_kernel = function () {
894 Notebook.prototype.restart_kernel = function () {
895 var that = this;
895 var that = this;
896 var dialog = $('<div/>');
896 var dialog = $('<div/>');
897 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
897 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
898 $(document).append(dialog);
898 $(document).append(dialog);
899 dialog.dialog({
899 dialog.dialog({
900 resizable: false,
900 resizable: false,
901 modal: true,
901 modal: true,
902 title: "Restart kernel or continue running?",
902 title: "Restart kernel or continue running?",
903 closeText: '',
903 closeText: '',
904 buttons : {
904 buttons : {
905 "Restart": function () {
905 "Restart": function () {
906 that.kernel.restart();
906 that.kernel.restart();
907 $(this).dialog('close');
907 $(this).dialog('close');
908 },
908 },
909 "Continue running": function () {
909 "Continue running": function () {
910 $(this).dialog('close');
910 $(this).dialog('close');
911 }
911 }
912 }
912 }
913 });
913 });
914 };
914 };
915
915
916
916
917 Notebook.prototype.execute_selected_cell = function (options) {
917 Notebook.prototype.execute_selected_cell = function (options) {
918 // add_new: should a new cell be added if we are at the end of the nb
918 // add_new: should a new cell be added if we are at the end of the nb
919 // terminal: execute in terminal mode, which stays in the current cell
919 // terminal: execute in terminal mode, which stays in the current cell
920 default_options = {terminal: false, add_new: true};
920 default_options = {terminal: false, add_new: true};
921 $.extend(default_options, options);
921 $.extend(default_options, options);
922 var that = this;
922 var that = this;
923 var cell = that.get_selected_cell();
923 var cell = that.get_selected_cell();
924 var cell_index = that.find_cell_index(cell);
924 var cell_index = that.find_cell_index(cell);
925 if (cell instanceof IPython.CodeCell) {
925 if (cell instanceof IPython.CodeCell) {
926 cell.execute();
926 cell.execute();
927 } else if (cell instanceof IPython.HTMLCell) {
927 } else if (cell instanceof IPython.HTMLCell) {
928 cell.render();
928 cell.render();
929 }
929 }
930 if (default_options.terminal) {
930 if (default_options.terminal) {
931 cell.select_all();
931 cell.select_all();
932 } else {
932 } else {
933 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
933 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
934 that.insert_cell_below('code');
934 that.insert_cell_below('code');
935 // If we are adding a new cell at the end, scroll down to show it.
935 // If we are adding a new cell at the end, scroll down to show it.
936 that.scroll_to_bottom();
936 that.scroll_to_bottom();
937 } else {
937 } else {
938 that.select(cell_index+1);
938 that.select(cell_index+1);
939 };
939 };
940 };
940 };
941 this.dirty = true;
941 this.dirty = true;
942 };
942 };
943
943
944
944
945 Notebook.prototype.execute_all_cells = function () {
945 Notebook.prototype.execute_all_cells = function () {
946 var ncells = this.ncells();
946 var ncells = this.ncells();
947 for (var i=0; i<ncells; i++) {
947 for (var i=0; i<ncells; i++) {
948 this.select(i);
948 this.select(i);
949 this.execute_selected_cell({add_new:false});
949 this.execute_selected_cell({add_new:false});
950 };
950 };
951 this.scroll_to_bottom();
951 this.scroll_to_bottom();
952 };
952 };
953
953
954 // Persistance and loading
954 // Persistance and loading
955
955
956 Notebook.prototype.get_notebook_id = function () {
956 Notebook.prototype.get_notebook_id = function () {
957 return this.notebook_id;
957 return this.notebook_id;
958 };
958 };
959
959
960
960
961 Notebook.prototype.get_notebook_name = function () {
961 Notebook.prototype.get_notebook_name = function () {
962 return this.notebook_name;
962 return this.notebook_name;
963 };
963 };
964
964
965
965
966 Notebook.prototype.set_notebook_name = function (name) {
966 Notebook.prototype.set_notebook_name = function (name) {
967 this.notebook_name = name;
967 this.notebook_name = name;
968 };
968 };
969
969
970
970
971 Notebook.prototype.test_notebook_name = function (nbname) {
971 Notebook.prototype.test_notebook_name = function (nbname) {
972 nbname = nbname || '';
972 nbname = nbname || '';
973 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
973 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
974 return true;
974 return true;
975 } else {
975 } else {
976 return false;
976 return false;
977 };
977 };
978 };
978 };
979
979
980
980
981 Notebook.prototype.fromJSON = function (data) {
981 Notebook.prototype.fromJSON = function (data) {
982 var ncells = this.ncells();
982 var ncells = this.ncells();
983 var i;
983 var i;
984 for (i=0; i<ncells; i++) {
984 for (i=0; i<ncells; i++) {
985 // Always delete cell 0 as they get renumbered as they are deleted.
985 // Always delete cell 0 as they get renumbered as they are deleted.
986 this.delete_cell(0);
986 this.delete_cell(0);
987 };
987 };
988 // Save the metadata and name.
988 // Save the metadata and name.
989 this.metadata = data.metadata;
989 this.metadata = data.metadata;
990 this.notebook_name = data.metadata.name;
990 this.notebook_name = data.metadata.name;
991 // Only handle 1 worksheet for now.
991 // Only handle 1 worksheet for now.
992 var worksheet = data.worksheets[0];
992 var worksheet = data.worksheets[0];
993 if (worksheet !== undefined) {
993 if (worksheet !== undefined) {
994 var new_cells = worksheet.cells;
994 var new_cells = worksheet.cells;
995 ncells = new_cells.length;
995 ncells = new_cells.length;
996 var cell_data = null;
996 var cell_data = null;
997 var new_cell = null;
997 var new_cell = null;
998 for (i=0; i<ncells; i++) {
998 for (i=0; i<ncells; i++) {
999 cell_data = new_cells[i];
999 cell_data = new_cells[i];
1000 // VERSIONHACK: plaintext -> raw
1000 // VERSIONHACK: plaintext -> raw
1001 // handle never-released plaintext name for raw cells
1001 // handle never-released plaintext name for raw cells
1002 if (cell_data.cell_type === 'plaintext'){
1002 if (cell_data.cell_type === 'plaintext'){
1003 cell_data.cell_type = 'raw';
1003 cell_data.cell_type = 'raw';
1004 }
1004 }
1005
1005
1006 new_cell = this.insert_cell_below(cell_data.cell_type);
1006 new_cell = this.insert_cell_below(cell_data.cell_type);
1007 new_cell.fromJSON(cell_data);
1007 new_cell.fromJSON(cell_data);
1008 };
1008 };
1009 };
1009 };
1010 };
1010 };
1011
1011
1012
1012
1013 Notebook.prototype.toJSON = function () {
1013 Notebook.prototype.toJSON = function () {
1014 var cells = this.get_cells();
1014 var cells = this.get_cells();
1015 var ncells = cells.length;
1015 var ncells = cells.length;
1016 cell_array = new Array(ncells);
1016 cell_array = new Array(ncells);
1017 for (var i=0; i<ncells; i++) {
1017 for (var i=0; i<ncells; i++) {
1018 cell_array[i] = cells[i].toJSON();
1018 cell_array[i] = cells[i].toJSON();
1019 };
1019 };
1020 data = {
1020 data = {
1021 // Only handle 1 worksheet for now.
1021 // Only handle 1 worksheet for now.
1022 worksheets : [{cells:cell_array}],
1022 worksheets : [{cells:cell_array}],
1023 metadata : this.metadata
1023 metadata : this.metadata
1024 };
1024 };
1025 return data;
1025 return data;
1026 };
1026 };
1027
1027
1028 Notebook.prototype.save_notebook = function () {
1028 Notebook.prototype.save_notebook = function () {
1029 // We may want to move the name/id/nbformat logic inside toJSON?
1029 // We may want to move the name/id/nbformat logic inside toJSON?
1030 var data = this.toJSON();
1030 var data = this.toJSON();
1031 data.metadata.name = this.notebook_name;
1031 data.metadata.name = this.notebook_name;
1032 data.nbformat = this.nbformat;
1032 data.nbformat = this.nbformat;
1033 // We do the call with settings so we can set cache to false.
1033 // We do the call with settings so we can set cache to false.
1034 var settings = {
1034 var settings = {
1035 processData : false,
1035 processData : false,
1036 cache : false,
1036 cache : false,
1037 type : "PUT",
1037 type : "PUT",
1038 data : JSON.stringify(data),
1038 data : JSON.stringify(data),
1039 headers : {'Content-Type': 'application/json'},
1039 headers : {'Content-Type': 'application/json'},
1040 success : $.proxy(this.save_notebook_success,this),
1040 success : $.proxy(this.save_notebook_success,this),
1041 error : $.proxy(this.save_notebook_error,this)
1041 error : $.proxy(this.save_notebook_error,this)
1042 };
1042 };
1043 $([IPython.events]).trigger('notebook_saving.Notebook');
1043 $([IPython.events]).trigger('notebook_saving.Notebook');
1044 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1044 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1045 $.ajax(url, settings);
1045 $.ajax(url, settings);
1046 };
1046 };
1047
1047
1048
1048
1049 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1049 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1050 this.dirty = false;
1050 this.dirty = false;
1051 $([IPython.events]).trigger('notebook_saved.Notebook');
1051 $([IPython.events]).trigger('notebook_saved.Notebook');
1052 };
1052 };
1053
1053
1054
1054
1055 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1055 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1056 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1056 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1057 };
1057 };
1058
1058
1059
1059
1060 Notebook.prototype.load_notebook = function (notebook_id) {
1060 Notebook.prototype.load_notebook = function (notebook_id) {
1061 var that = this;
1061 var that = this;
1062 this.notebook_id = notebook_id;
1062 this.notebook_id = notebook_id;
1063 // We do the call with settings so we can set cache to false.
1063 // We do the call with settings so we can set cache to false.
1064 var settings = {
1064 var settings = {
1065 processData : false,
1065 processData : false,
1066 cache : false,
1066 cache : false,
1067 type : "GET",
1067 type : "GET",
1068 dataType : "json",
1068 dataType : "json",
1069 success : $.proxy(this.load_notebook_success,this),
1069 success : $.proxy(this.load_notebook_success,this),
1070 error : $.proxy(this.load_notebook_error,this),
1070 error : $.proxy(this.load_notebook_error,this),
1071 };
1071 };
1072 $([IPython.events]).trigger('notebook_loading.Notebook');
1072 $([IPython.events]).trigger('notebook_loading.Notebook');
1073 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1073 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1074 $.ajax(url, settings);
1074 $.ajax(url, settings);
1075 };
1075 };
1076
1076
1077
1077
1078 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1078 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1079 // Create the kernel before creating cells as they need to be passed it.
1079 // Create the kernel before creating cells as they need to be passed it.
1080 if (! this.read_only) {
1080 if (! this.read_only) {
1081 this.start_kernel();
1081 this.start_kernel();
1082 }
1082 }
1083 this.fromJSON(data);
1083 this.fromJSON(data);
1084 if (this.ncells() === 0) {
1084 if (this.ncells() === 0) {
1085 this.insert_cell_below('code');
1085 this.insert_cell_below('code');
1086 };
1086 };
1087 this.dirty = false;
1087 this.dirty = false;
1088 this.select(0);
1088 this.select(0);
1089 this.scroll_to_top();
1089 this.scroll_to_top();
1090 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1090 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1091 msg = "This notebook has been converted from an older " +
1091 msg = "This notebook has been converted from an older " +
1092 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1092 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1093 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1093 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1094 "newer notebook format will be used and older verions of IPython " +
1094 "newer notebook format will be used and older verions of IPython " +
1095 "may not be able to read it. To keep the older version, close the " +
1095 "may not be able to read it. To keep the older version, close the " +
1096 "notebook without saving it.";
1096 "notebook without saving it.";
1097 var dialog = $('<div/>');
1097 var dialog = $('<div/>');
1098 dialog.html(msg);
1098 dialog.html(msg);
1099 this.element.append(dialog);
1099 this.element.append(dialog);
1100 dialog.dialog({
1100 dialog.dialog({
1101 resizable: false,
1101 resizable: false,
1102 modal: true,
1102 modal: true,
1103 title: "Notebook converted",
1103 title: "Notebook converted",
1104 closeText: "",
1104 closeText: "",
1105 close: function(event, ui) {$(this).dialog('destroy').remove();},
1105 close: function(event, ui) {$(this).dialog('destroy').remove();},
1106 buttons : {
1106 buttons : {
1107 "OK": function () {
1107 "OK": function () {
1108 $(this).dialog('close');
1108 $(this).dialog('close');
1109 }
1109 }
1110 },
1110 },
1111 width: 400
1111 width: 400
1112 });
1112 });
1113 }
1113 }
1114 $([IPython.events]).trigger('notebook_loaded.Notebook');
1114 $([IPython.events]).trigger('notebook_loaded.Notebook');
1115 };
1115 };
1116
1116
1117
1117
1118 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1118 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1119 if (xhr.status === 500) {
1119 if (xhr.status === 500) {
1120 msg = "An error occurred while loading this notebook. Most likely " +
1120 msg = "An error occurred while loading this notebook. Most likely " +
1121 "this notebook is in a newer format than is supported by this " +
1121 "this notebook is in a newer format than is supported by this " +
1122 "version of IPython. This version can load notebook formats " +
1122 "version of IPython. This version can load notebook formats " +
1123 "v"+this.nbformat+" or earlier.";
1123 "v"+this.nbformat+" or earlier.";
1124 var dialog = $('<div/>');
1124 var dialog = $('<div/>');
1125 dialog.html(msg);
1125 dialog.html(msg);
1126 this.element.append(dialog);
1126 this.element.append(dialog);
1127 dialog.dialog({
1127 dialog.dialog({
1128 resizable: false,
1128 resizable: false,
1129 modal: true,
1129 modal: true,
1130 title: "Error loading notebook",
1130 title: "Error loading notebook",
1131 closeText: "",
1131 closeText: "",
1132 close: function(event, ui) {$(this).dialog('destroy').remove();},
1132 close: function(event, ui) {$(this).dialog('destroy').remove();},
1133 buttons : {
1133 buttons : {
1134 "OK": function () {
1134 "OK": function () {
1135 $(this).dialog('close');
1135 $(this).dialog('close');
1136 }
1136 }
1137 },
1137 },
1138 width: 400
1138 width: 400
1139 });
1139 });
1140 }
1140 }
1141 }
1141 }
1142
1142
1143 IPython.Notebook = Notebook;
1143 IPython.Notebook = Notebook;
1144
1144
1145
1145
1146 return IPython;
1146 return IPython;
1147
1147
1148 }(IPython));
1148 }(IPython));
1149
1149
@@ -1,297 +1,294 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 // Tooltip
9 // Tooltip
10 //============================================================================
10 //============================================================================
11 //
11 //
12 // you can set the autocall time by setting `IPython.notebook.time_before_tooltip` in ms
12 // you can set the autocall time by setting `IPython.tooltip.time_before_tooltip` in ms
13
13
14 var IPython = (function (IPython) {
14 var IPython = (function (IPython) {
15
15
16 var utils = IPython.utils;
16 var utils = IPython.utils;
17
17
18 // tooltip constructor
18 // tooltip constructor
19 var Tooltip = function () {
19 var Tooltip = function () {
20 var that = this;
20 var that = this;
21 this.time_before_tooltip = 1200;
21 this.time_before_tooltip = 1200;
22
22
23 // handle to html
23 // handle to html
24 this.tooltip = $('#tooltip');
24 this.tooltip = $('#tooltip');
25 var tooltip = this.tooltip;
25 var tooltip = this.tooltip;
26 this._hidden = true;
26 this._hidden = true;
27
27
28 // variable for consecutive call
28 // variable for consecutive call
29 this._old_cell = null ;
29 this._old_cell = null ;
30 this._old_request = null ;
30 this._old_request = null ;
31 this._consecutive_conter = 0;
31 this._consecutive_conter = 0;
32
32
33 // 'sticky ?'
33 // 'sticky ?'
34 this._sticky = false;
34 this._sticky = false;
35
35
36 // contain the button in the upper right corner
36 // contain the button in the upper right corner
37 this.buttons = $('<div/>')
37 this.buttons = $('<div/>')
38 .addClass('tooltipbuttons');
38 .addClass('tooltipbuttons');
39
39
40 // will contain the docstring
40 // will contain the docstring
41 this.text = $('<div/>')
41 this.text = $('<div/>')
42 .addClass('tooltiptext')
42 .addClass('tooltiptext')
43 .addClass('smalltooltip');
43 .addClass('smalltooltip');
44
44
45 // build the buttons menu on the upper right
45 // build the buttons menu on the upper right
46
46
47 // expand the tooltip to see more
47 // expand the tooltip to see more
48 var expandlink=$('<a/>').attr('href',"#")
48 var expandlink=$('<a/>').attr('href',"#")
49 .addClass("ui-corner-all") //rounded corner
49 .addClass("ui-corner-all") //rounded corner
50 .attr('role',"button")
50 .attr('role',"button")
51 .attr('id','expanbutton')
51 .attr('id','expanbutton')
52 .click(function(){that.expand()})
52 .click(function(){that.expand()})
53 .append(
53 .append(
54 $('<span/>').text('Expand')
54 $('<span/>').text('Expand')
55 .addClass('ui-icon')
55 .addClass('ui-icon')
56 .addClass('ui-icon-plus')
56 .addClass('ui-icon-plus')
57 );
57 );
58
58
59 // open in pager
59 // open in pager
60 var morelink=$('<a/>').attr('href',"#")
60 var morelink=$('<a/>').attr('href',"#")
61 .attr('role',"button")
61 .attr('role',"button")
62 .addClass('ui-button');
62 .addClass('ui-button');
63 var morespan=$('<span/>').text('Open in Pager')
63 var morespan=$('<span/>').text('Open in Pager')
64 .addClass('ui-icon')
64 .addClass('ui-icon')
65 .addClass('ui-icon-arrowstop-l-n');
65 .addClass('ui-icon-arrowstop-l-n');
66 morelink.append(morespan);
66 morelink.append(morespan);
67 morelink.click(function(){
67 morelink.click(function(){
68 that.showInPager();
68 that.showInPager();
69 });
69 });
70
70
71 // close the tooltip
71 // close the tooltip
72 var closelink=$('<a/>').attr('href',"#");
72 var closelink=$('<a/>').attr('href',"#");
73 closelink.attr('role',"button");
73 closelink.attr('role',"button");
74 closelink.addClass('ui-button');
74 closelink.addClass('ui-button');
75 var closespan=$('<span/>').text('Close');
75 var closespan=$('<span/>').text('Close');
76 closespan.addClass('ui-icon');
76 closespan.addClass('ui-icon');
77 closespan.addClass('ui-icon-close');
77 closespan.addClass('ui-icon-close');
78 closelink.append(closespan);
78 closelink.append(closespan);
79 closelink.click(function(){
79 closelink.click(function(){
80 that.remove_and_cancel_tooltip(true);
80 that.remove_and_cancel_tooltip(true);
81 });
81 });
82
82
83 //construct the tooltip
83 //construct the tooltip
84 // add in the reverse order you want them to appear
84 // add in the reverse order you want them to appear
85 this.buttons.append(closelink);
85 this.buttons.append(closelink);
86 this.buttons.append(expandlink);
86 this.buttons.append(expandlink);
87 this.buttons.append(morelink);
87 this.buttons.append(morelink);
88
88
89 // we need a phony element to make the small arrow
89 // we need a phony element to make the small arrow
90 // of the tooltip in css
90 // of the tooltip in css
91 // we will move the arrow later
91 // we will move the arrow later
92 this.arrow = $('<div/>').addClass('pretooltiparrow');
92 this.arrow = $('<div/>').addClass('pretooltiparrow');
93 this.tooltip.append(this.buttons);
93 this.tooltip.append(this.buttons);
94 this.tooltip.append(this.arrow);
94 this.tooltip.append(this.arrow);
95 this.tooltip.append(this.text);
95 this.tooltip.append(this.text);
96 };
96 };
97
97
98 // will resend the request on behalf on the cell which invoked the tooltip
99 // to show in it in pager. This is done so to be sure of having the same
100 // result as invoking `something?`
101 Tooltip.prototype.showInPager = function()
98 Tooltip.prototype.showInPager = function()
102 {
99 {
103 var that = this;
100 var that = this;
104 var callbacks = {'execute_reply': $.proxy(that._handle_execute_reply,that)}
101 var callbacks = {'execute_reply': $.proxy(that._handle_execute_reply,that)}
105 var msg_id = IPython.notebook.kernel.execute(this.name+"?", callbacks);
102 var msg_id = IPython.notebook.kernel.execute(this.name+"?", callbacks);
106
103
107 this.remove_and_cancel_tooltip();
104 this.remove_and_cancel_tooltip();
108 this._cmfocus();
105 this._cmfocus();
109 }
106 }
110
107
111 // grow the tooltip verticaly
108 // grow the tooltip verticaly
112 Tooltip.prototype.expand = function(){
109 Tooltip.prototype.expand = function(){
113 this.text.removeClass('smalltooltip');
110 this.text.removeClass('smalltooltip');
114 this.text.addClass('bigtooltip');
111 this.text.addClass('bigtooltip');
115 $('#expanbutton').addClass('hidden');
112 $('#expanbutton').addClass('hidden');
116 this._cmfocus();
113 this._cmfocus();
117 }
114 }
118
115
119 // deal with all the logic of hiding the tooltip
116 // deal with all the logic of hiding the tooltip
120 // and reset it's status
117 // and reset it's status
121 Tooltip.prototype.hide = function()
118 Tooltip.prototype.hide = function()
122 {
119 {
123 this.tooltip.addClass('hide');
120 this.tooltip.addClass('hide');
124 $('#expanbutton').removeClass('hidden');
121 $('#expanbutton').removeClass('hidden');
125 this.text.removeClass('bigtooltip');
122 this.text.removeClass('bigtooltip');
126 this.text.addClass('smalltooltip');
123 this.text.addClass('smalltooltip');
127 // keep scroll top to be sure to always see the first line
124 // keep scroll top to be sure to always see the first line
128 this.text.scrollTop(0);
125 this.text.scrollTop(0);
129 this._hidden = true;
126 this._hidden = true;
130 }
127 }
131
128
132 Tooltip.prototype.remove_and_cancel_tooltip = function(force) {
129 Tooltip.prototype.remove_and_cancel_tooltip = function(force) {
133 // note that we don't handle closing directly inside the calltip
130 // note that we don't handle closing directly inside the calltip
134 // as in the completer, because it is not focusable, so won't
131 // as in the completer, because it is not focusable, so won't
135 // get the event.
132 // get the event.
136 if(this._sticky == false || force == true)
133 if(this._sticky == false || force == true)
137 {
134 {
138 this.hide();
135 this.hide();
139 }
136 }
140 this.cancel_pending();
137 this.cancel_pending();
141 this._old_cell = null ;
138 this._old_cell = null ;
142 this._old_request = null ;
139 this._old_request = null ;
143 this._consecutive_conter = 0;
140 this._consecutive_conter = 0;
144 }
141 }
145
142
146 // cancel autocall done after '(' for example.
143 // cancel autocall done after '(' for example.
147 Tooltip.prototype.cancel_pending = function(){
144 Tooltip.prototype.cancel_pending = function(){
148 if (this.tooltip_timeout != null){
145 if (this.tooltip_timeout != null){
149 clearTimeout(this.tooltip_timeout);
146 clearTimeout(this.tooltip_timeout);
150 this.tooltip_timeout = null;
147 this.tooltip_timeout = null;
151 }
148 }
152 }
149 }
153
150
154 // will trigger tooltip after timeout
151 // will trigger tooltip after timeout
155 Tooltip.prototype.pending = function(cell,text)
152 Tooltip.prototype.pending = function(cell,text)
156 {
153 {
157 var that = this;
154 var that = this;
158 this.tooltip_timeout = setTimeout(function(){that.request(cell)} , that.time_before_tooltip);
155 this.tooltip_timeout = setTimeout(function(){that.request(cell)} , that.time_before_tooltip);
159 }
156 }
160
157
161 // make an imediate completion request
158 // make an imediate completion request
162 Tooltip.prototype.request = function(cell)
159 Tooltip.prototype.request = function(cell)
163 {
160 {
164 this.cancel_pending();
161 this.cancel_pending();
165 var editor = cell.code_mirror;
162 var editor = cell.code_mirror;
166 this.code_mirror = editor;
163 this.code_mirror = editor;
167 var cursor = editor.getCursor();
164 var cursor = editor.getCursor();
168 var text = editor.getRange({line:cursor.line,ch:0},cursor).trim();
165 var text = editor.getRange({line:cursor.line,ch:0},cursor).trim();
169
166
170 if( this._old_cell == cell && this._old_request == text && this._hidden == false)
167 if( this._old_cell == cell && this._old_request == text && this._hidden == false)
171 {
168 {
172 this._consecutive_conter = this._consecutive_conter +1;
169 this._consecutive_conter = this._consecutive_conter +1;
173 } else {
170 } else {
174 this._old_cell = cell ;
171 this._old_cell = cell ;
175 this._old_request = text ;
172 this._old_request = text ;
176 this._consecutive_conter =0;
173 this._consecutive_conter =0;
177 this.cancel_stick();
174 this.cancel_stick();
178 }
175 }
179
176
180 if( this._consecutive_conter == 1 )
177 if( this._consecutive_conter == 1 )
181 {
178 {
182 this.expand()
179 this.expand()
183 return;
180 return;
184 }
181 }
185 else if( this._consecutive_conter == 2)
182 else if( this._consecutive_conter == 2)
186 {
183 {
187 this.stick();
184 this.stick();
188 return;
185 return;
189 }
186 }
190 else if( this._consecutive_conter == 3)
187 else if( this._consecutive_conter == 3)
191 {
188 {
192 this._old_cell = null ;
189 this._old_cell = null ;
193 this.cancel_stick();
190 this.cancel_stick();
194 this._old_request = null ;
191 this._old_request = null ;
195 this._consecutive_conter = 0;
192 this._consecutive_conter = 0;
196 this.showInPager();
193 this.showInPager();
197 this._cmfocus();
194 this._cmfocus();
198 return;
195 return;
199 }
196 }
200 else if( this._consecutive_conter == 4)
197 else if( this._consecutive_conter == 4)
201 {
198 {
202
199
203 }
200 }
204
201
205 if (text === "" || text === "(" ) {
202 if (text === "" || text === "(" ) {
206 return;
203 return;
207 // don't do anything if line beggin with '(' or is empty
204 // don't do anything if line beggin with '(' or is empty
208 }
205 }
209 cell.request_tooltip(text);
206 cell.request_tooltip(text);
210 }
207 }
211
208
212 // cancel the option of having the tooltip to stick
209 // cancel the option of having the tooltip to stick
213 Tooltip.prototype.cancel_stick = function()
210 Tooltip.prototype.cancel_stick = function()
214 {
211 {
215 clearTimeout(this._stick_timeout);
212 clearTimeout(this._stick_timeout);
216 this._sticky = false;
213 this._sticky = false;
217 }
214 }
218
215
219 // put the tooltip in a sicky state for 10 seconds
216 // put the tooltip in a sicky state for 10 seconds
220 // it won't be removed by remove_and_cancell() unless you called with
217 // it won't be removed by remove_and_cancell() unless you called with
221 // the first parameter set to true.
218 // the first parameter set to true.
222 // remove_and_cancell_tooltip(true)
219 // remove_and_cancell_tooltip(true)
223 Tooltip.prototype.stick = function()
220 Tooltip.prototype.stick = function()
224 {
221 {
225 var that = this;
222 var that = this;
226 this._sticky = true;
223 this._sticky = true;
227 this._stick_timeout = setTimeout( function(){
224 this._stick_timeout = setTimeout( function(){
228 that._sticky = false;
225 that._sticky = false;
229 }, 10*1000
226 }, 10*1000
230 );
227 );
231 }
228 }
232
229
233 // should be called with the kernel reply to actually show the tooltip
230 // should be called with the kernel reply to actually show the tooltip
234 Tooltip.prototype.show = function(reply, codecell)
231 Tooltip.prototype.show = function(reply, codecell)
235 {
232 {
236 // move the bubble if it is not hidden
233 // move the bubble if it is not hidden
237 // otherwise fade it
234 // otherwise fade it
238 var editor = codecell.code_mirror;
235 var editor = codecell.code_mirror;
239 this.name = reply.name;
236 this.name = reply.name;
240 this.code_mirror = editor;
237 this.code_mirror = editor;
241
238
242 // do some math to have the tooltip arrow on more or less on left or right
239 // do some math to have the tooltip arrow on more or less on left or right
243 // width of the editor
240 // width of the editor
244 var w= $(this.code_mirror.getScrollerElement()).width();
241 var w= $(this.code_mirror.getScrollerElement()).width();
245 // ofset of the editor
242 // ofset of the editor
246 var o= $(this.code_mirror.getScrollerElement()).offset();
243 var o= $(this.code_mirror.getScrollerElement()).offset();
247 var pos = editor.cursorCoords();
244 var pos = editor.cursorCoords();
248 var xinit = pos.x;
245 var xinit = pos.x;
249 var xinter = o.left + (xinit-o.left)/w*(w-450);
246 var xinter = o.left + (xinit-o.left)/w*(w-450);
250 var posarrowleft = xinit - xinter;
247 var posarrowleft = xinit - xinter;
251
248
252
249
253 if( this._hidden == false)
250 if( this._hidden == false)
254 {
251 {
255 this.tooltip.animate({'left' : xinter-30+'px','top' :(pos.yBot+10)+'px'});
252 this.tooltip.animate({'left' : xinter-30+'px','top' :(pos.yBot+10)+'px'});
256 } else
253 } else
257 {
254 {
258 this.tooltip.css({'left' : xinter-30+'px'});
255 this.tooltip.css({'left' : xinter-30+'px'});
259 this.tooltip.css({'top' :(pos.yBot+10)+'px'});
256 this.tooltip.css({'top' :(pos.yBot+10)+'px'});
260 }
257 }
261 this.arrow.animate({'left' : posarrowleft+'px'});
258 this.arrow.animate({'left' : posarrowleft+'px'});
262 this.tooltip.removeClass('hidden')
259 this.tooltip.removeClass('hidden')
263 this.tooltip.removeClass('hide');
260 this.tooltip.removeClass('hide');
264 this._hidden = false;
261 this._hidden = false;
265
262
266 // build docstring
263 // build docstring
267 defstring = reply.call_def;
264 defstring = reply.call_def;
268 if (defstring == null) { defstring = reply.init_definition; }
265 if (defstring == null) { defstring = reply.init_definition; }
269 if (defstring == null) { defstring = reply.definition; }
266 if (defstring == null) { defstring = reply.definition; }
270
267
271 docstring = reply.call_docstring;
268 docstring = reply.call_docstring;
272 if (docstring == null) { docstring = reply.init_docstring; }
269 if (docstring == null) { docstring = reply.init_docstring; }
273 if (docstring == null) { docstring = reply.docstring; }
270 if (docstring == null) { docstring = reply.docstring; }
274 if (docstring == null) { docstring = "<empty docstring>"; }
271 if (docstring == null) { docstring = "<empty docstring>"; }
275
272
276 this.text.children().remove();
273 this.text.children().remove();
277
274
278 var pre=$('<pre/>').html(utils.fixConsole(docstring));
275 var pre=$('<pre/>').html(utils.fixConsole(docstring));
279 if(defstring){
276 if(defstring){
280 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
277 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
281 this.text.append(defstring_html);
278 this.text.append(defstring_html);
282 }
279 }
283 this.text.append(pre);
280 this.text.append(pre);
284 // keep scroll top to be sure to always see the first line
281 // keep scroll top to be sure to always see the first line
285 this.text.scrollTop(0);
282 this.text.scrollTop(0);
286 }
283 }
287
284
288 // convenient funciton to have the correct codemirror back into focus
285 // convenient funciton to have the correct codemirror back into focus
289 Tooltip.prototype._cmfocus = function()
286 Tooltip.prototype._cmfocus = function()
290 {
287 {
291 var cm = this.code_mirror;
288 var cm = this.code_mirror;
292 setTimeout(function(){cm.focus();}, 50);
289 setTimeout(function(){cm.focus();}, 50);
293 }
290 }
294
291
295 IPython.Tooltip = Tooltip;
292 IPython.Tooltip = Tooltip;
296 return IPython;
293 return IPython;
297 }(IPython));
294 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now