##// END OF EJS Templates
Fixes to terminal mode execution (ctrl-enter).
Brian E. Granger -
Show More
@@ -1,313 +1,312
1
1
2 //============================================================================
2 //============================================================================
3 // CodeCell
3 // CodeCell
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var utils = IPython.utils;
8 var utils = IPython.utils;
9
9
10 var CodeCell = function (notebook) {
10 var CodeCell = function (notebook) {
11 this.code_mirror = null;
11 this.code_mirror = null;
12 this.input_prompt_number = ' ';
12 this.input_prompt_number = ' ';
13 this.is_completing = false;
13 this.is_completing = false;
14 this.completion_cursor = null;
14 this.completion_cursor = null;
15 IPython.Cell.apply(this, arguments);
15 IPython.Cell.apply(this, arguments);
16 };
16 };
17
17
18
18
19 CodeCell.prototype = new IPython.Cell();
19 CodeCell.prototype = new IPython.Cell();
20
20
21
21
22 CodeCell.prototype.create_element = function () {
22 CodeCell.prototype.create_element = function () {
23 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
23 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
24 var input = $('<div></div>').addClass('input hbox');
24 var input = $('<div></div>').addClass('input hbox');
25 input.append($('<div/>').addClass('prompt input_prompt'));
25 input.append($('<div/>').addClass('prompt input_prompt'));
26 var input_area = $('<div/>').addClass('input_area box-flex1');
26 var input_area = $('<div/>').addClass('input_area box-flex1');
27 this.code_mirror = CodeMirror(input_area.get(0), {
27 this.code_mirror = CodeMirror(input_area.get(0), {
28 indentUnit : 4,
28 indentUnit : 4,
29 enterMode : 'flat',
29 enterMode : 'flat',
30 tabMode: 'shift',
30 tabMode: 'shift',
31 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
31 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
32 });
32 });
33 input.append(input_area);
33 input.append(input_area);
34 var output = $('<div></div>').addClass('output vbox');
34 var output = $('<div></div>').addClass('output vbox');
35 cell.append(input).append(output);
35 cell.append(input).append(output);
36 this.element = cell;
36 this.element = cell;
37 this.collapse()
37 this.collapse()
38 };
38 };
39
39
40
40
41 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
41 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
42 // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and
42 // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and
43 // is used to provide custom key handling. Its return value is used to determine
43 // is used to provide custom key handling. Its return value is used to determine
44 // if CodeMirror should ignore the event: true = ignore, false = don't ignore.
44 // if CodeMirror should ignore the event: true = ignore, false = don't ignore.
45 if (event.keyCode === 13 && event.shiftKey) {
45 if (event.keyCode === 13 && event.shiftKey) {
46 // Always ignore shift-enter in CodeMirror as we handle it.
46 // Always ignore shift-enter in CodeMirror as we handle it.
47 return true;
47 return true;
48 // } else if (event.keyCode == 32 && (event.ctrlKey || event.metaKey) && !event.altKey) {
48 // } else if (event.keyCode == 32 && (event.ctrlKey || event.metaKey) && !event.altKey) {
49 } else if (event.keyCode == 9) {
49 } else if (event.keyCode == 9) {
50 var cur = editor.getCursor();
50 var cur = editor.getCursor();
51 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim();
51 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim();
52 if (pre_cursor === "") {
52 if (pre_cursor === "") {
53 // Don't autocomplete if the part of the line before the cursor is empty.
53 // Don't autocomplete if the part of the line before the cursor is empty.
54 // In this case, let CodeMirror handle indentation.
54 // In this case, let CodeMirror handle indentation.
55 return false;
55 return false;
56 } else {
56 } else {
57 // Autocomplete the current line.
57 // Autocomplete the current line.
58 event.stop();
58 event.stop();
59 var line = editor.getLine(cur.line);
59 var line = editor.getLine(cur.line);
60 this.is_completing = true;
60 this.is_completing = true;
61 this.completion_cursor = cur;
61 this.completion_cursor = cur;
62 IPython.notebook.complete_cell(this, line, cur.ch);
62 IPython.notebook.complete_cell(this, line, cur.ch);
63 return true;
63 return true;
64 }
64 }
65 } else {
65 } else {
66 if (this.is_completing && this.completion_cursor !== editor.getCursor()) {
66 if (this.is_completing && this.completion_cursor !== editor.getCursor()) {
67 this.is_completing = false;
67 this.is_completing = false;
68 this.completion_cursor = null;
68 this.completion_cursor = null;
69 console.log("Stopped completing early");
70 }
69 }
71 return false;
70 return false;
72 };
71 };
73 };
72 };
74
73
75
74
76 CodeCell.prototype.finish_completing = function (matched_text, matches) {
75 CodeCell.prototype.finish_completing = function (matched_text, matches) {
77 if (!this.is_completing || matches.length === 0) {return;}
76 if (!this.is_completing || matches.length === 0) {return;}
78 // console.log("Got matches", matched_text, matches);
77 // console.log("Got matches", matched_text, matches);
79
78
80 var that = this;
79 var that = this;
81 var cur = this.completion_cursor;
80 var cur = this.completion_cursor;
82 var complete = $('<div/>').addClass('completions');
81 var complete = $('<div/>').addClass('completions');
83 var select = $('<select/>').attr('multiple','true');
82 var select = $('<select/>').attr('multiple','true');
84 for (var i=0; i<matches.length; ++i) {
83 for (var i=0; i<matches.length; ++i) {
85 select.append($('<option/>').text(matches[i]));
84 select.append($('<option/>').text(matches[i]));
86 }
85 }
87 select.children().first().attr('selected','true');
86 select.children().first().attr('selected','true');
88 select.attr('size',Math.min(10,matches.length));
87 select.attr('size',Math.min(10,matches.length));
89 var pos = this.code_mirror.cursorCoords();
88 var pos = this.code_mirror.cursorCoords();
90 complete.css('left',pos.x+'px');
89 complete.css('left',pos.x+'px');
91 complete.css('top',pos.yBot+'px');
90 complete.css('top',pos.yBot+'px');
92 complete.append(select);
91 complete.append(select);
93
92
94 $('body').append(complete);
93 $('body').append(complete);
95 var done = false;
94 var done = false;
96
95
97 var insert = function (selected_text) {
96 var insert = function (selected_text) {
98 that.code_mirror.replaceRange(
97 that.code_mirror.replaceRange(
99 selected_text,
98 selected_text,
100 {line: cur.line, ch: (cur.ch-matched_text.length)},
99 {line: cur.line, ch: (cur.ch-matched_text.length)},
101 {line: cur.line, ch: cur.ch}
100 {line: cur.line, ch: cur.ch}
102 );
101 );
103 };
102 };
104
103
105 var close = function () {
104 var close = function () {
106 if (done) return;
105 if (done) return;
107 done = true;
106 done = true;
108 complete.remove();
107 complete.remove();
109 that.is_completing = false;
108 that.is_completing = false;
110 that.completion_cursor = null;
109 that.completion_cursor = null;
111 };
110 };
112
111
113 var pick = function () {
112 var pick = function () {
114 insert(select.val()[0]);
113 insert(select.val()[0]);
115 close();
114 close();
116 setTimeout(function(){that.code_mirror.focus();}, 50);
115 setTimeout(function(){that.code_mirror.focus();}, 50);
117 };
116 };
118
117
119 select.blur(close);
118 select.blur(close);
120 select.keydown(function (event) {
119 select.keydown(function (event) {
121 var code = event.which;
120 var code = event.which;
122 if (code === 13 || code === 32) {
121 if (code === 13 || code === 32) {
123 // Pressing SPACE or ENTER will cause a pick
122 // Pressing SPACE or ENTER will cause a pick
124 event.stopPropagation();
123 event.stopPropagation();
125 event.preventDefault();
124 event.preventDefault();
126 pick();
125 pick();
127 } else if (code === 38 || code === 40) {
126 } else if (code === 38 || code === 40) {
128 // We don't want the document keydown handler to handle UP/DOWN,
127 // We don't want the document keydown handler to handle UP/DOWN,
129 // but we want the default action.
128 // but we want the default action.
130 event.stopPropagation();
129 event.stopPropagation();
131 } else {
130 } else {
132 // All other key presses simple exit completion.
131 // All other key presses simple exit completion.
133 event.stopPropagation();
132 event.stopPropagation();
134 event.preventDefault();
133 event.preventDefault();
135 close();
134 close();
136 that.code_mirror.focus();
135 that.code_mirror.focus();
137 }
136 }
138 });
137 });
139 // Double click also causes a pick.
138 // Double click also causes a pick.
140 select.dblclick(pick);
139 select.dblclick(pick);
141 select.focus();
140 select.focus();
142 };
141 };
143
142
144
143
145 CodeCell.prototype.select = function () {
144 CodeCell.prototype.select = function () {
146 IPython.Cell.prototype.select.apply(this);
145 IPython.Cell.prototype.select.apply(this);
147 this.code_mirror.focus();
146 this.code_mirror.focus();
148 };
147 };
149
148
150
149
151 CodeCell.prototype.append_pyout = function (data, n) {
150 CodeCell.prototype.append_pyout = function (data, n) {
152 var toinsert = $("<div/>").addClass("output_area output_pyout hbox");
151 var toinsert = $("<div/>").addClass("output_area output_pyout hbox");
153 toinsert.append($('<div/>').
152 toinsert.append($('<div/>').
154 addClass('prompt output_prompt').
153 addClass('prompt output_prompt').
155 html('Out[' + n + ']:')
154 html('Out[' + n + ']:')
156 );
155 );
157 this.append_display_data(data, toinsert);
156 this.append_display_data(data, toinsert);
158 toinsert.children().last().addClass("box_flex1");
157 toinsert.children().last().addClass("box_flex1");
159 this.element.find("div.output").append(toinsert);
158 this.element.find("div.output").append(toinsert);
160 // If we just output latex, typeset it.
159 // If we just output latex, typeset it.
161 if (data["text/latex"] !== undefined) {
160 if (data["text/latex"] !== undefined) {
162 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
161 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
163 };
162 };
164 };
163 };
165
164
166
165
167 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
166 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
168 var s = '';
167 var s = '';
169 var len = tb.length;
168 var len = tb.length;
170 for (var i=0; i<len; i++) {
169 for (var i=0; i<len; i++) {
171 s = s + tb[i] + '\n';
170 s = s + tb[i] + '\n';
172 }
171 }
173 s = s + '\n';
172 s = s + '\n';
174 this.append_stream(s);
173 this.append_stream(s);
175 };
174 };
176
175
177
176
178 CodeCell.prototype.append_display_data = function (data, element) {
177 CodeCell.prototype.append_display_data = function (data, element) {
179 if (data["text/latex"] !== undefined) {
178 if (data["text/latex"] !== undefined) {
180 this.append_latex(data["text/latex"], element);
179 this.append_latex(data["text/latex"], element);
181 // If it is undefined, then we just appended to div.output, which
180 // If it is undefined, then we just appended to div.output, which
182 // makes the latex visible and we can typeset it. The typesetting
181 // makes the latex visible and we can typeset it. The typesetting
183 // has to be done after the latex is on the page.
182 // has to be done after the latex is on the page.
184 if (element === undefined) {
183 if (element === undefined) {
185 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
184 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
186 };
185 };
187 } else if (data["image/svg+xml"] !== undefined) {
186 } else if (data["image/svg+xml"] !== undefined) {
188 this.append_svg(data["image/svg+xml"], element);
187 this.append_svg(data["image/svg+xml"], element);
189 } else if (data["image/png"] !== undefined) {
188 } else if (data["image/png"] !== undefined) {
190 this.append_png(data["image/png"], element);
189 this.append_png(data["image/png"], element);
191 } else if (data["text/plain"] !== undefined) {
190 } else if (data["text/plain"] !== undefined) {
192 this.append_stream(data["text/plain"], element);
191 this.append_stream(data["text/plain"], element);
193 };
192 };
194 return element;
193 return element;
195 };
194 };
196
195
197
196
198 CodeCell.prototype.append_stream = function (data, element) {
197 CodeCell.prototype.append_stream = function (data, element) {
199 element = element || this.element.find("div.output");
198 element = element || this.element.find("div.output");
200 var toinsert = $("<div/>").addClass("output_area output_stream");
199 var toinsert = $("<div/>").addClass("output_area output_stream");
201 toinsert.append($("<pre/>").html(utils.fixConsole(data)));
200 toinsert.append($("<pre/>").html(utils.fixConsole(data)));
202 element.append(toinsert);
201 element.append(toinsert);
203 return element;
202 return element;
204 };
203 };
205
204
206
205
207 CodeCell.prototype.append_svg = function (svg, element) {
206 CodeCell.prototype.append_svg = function (svg, element) {
208 element = element || this.element.find("div.output");
207 element = element || this.element.find("div.output");
209 var toinsert = $("<div/>").addClass("output_area output_svg");
208 var toinsert = $("<div/>").addClass("output_area output_svg");
210 toinsert.append(svg);
209 toinsert.append(svg);
211 element.append(toinsert);
210 element.append(toinsert);
212 return element;
211 return element;
213 };
212 };
214
213
215
214
216 CodeCell.prototype.append_png = function (png, element) {
215 CodeCell.prototype.append_png = function (png, element) {
217 element = element || this.element.find("div.output");
216 element = element || this.element.find("div.output");
218 var toinsert = $("<div/>").addClass("output_area output_png");
217 var toinsert = $("<div/>").addClass("output_area output_png");
219 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
218 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
220 element.append(toinsert);
219 element.append(toinsert);
221 return element;
220 return element;
222 };
221 };
223
222
224
223
225 CodeCell.prototype.append_latex = function (latex, element) {
224 CodeCell.prototype.append_latex = function (latex, element) {
226 // This method cannot do the typesetting because the latex first has to
225 // This method cannot do the typesetting because the latex first has to
227 // be on the page.
226 // be on the page.
228 element = element || this.element.find("div.output");
227 element = element || this.element.find("div.output");
229 var toinsert = $("<div/>").addClass("output_area output_latex");
228 var toinsert = $("<div/>").addClass("output_area output_latex");
230 toinsert.append(latex);
229 toinsert.append(latex);
231 element.append(toinsert);
230 element.append(toinsert);
232 return element;
231 return element;
233 }
232 }
234
233
235
234
236 CodeCell.prototype.clear_output = function () {
235 CodeCell.prototype.clear_output = function () {
237 this.element.find("div.output").html("");
236 this.element.find("div.output").html("");
238 };
237 };
239
238
240
239
241 CodeCell.prototype.clear_input = function () {
240 CodeCell.prototype.clear_input = function () {
242 this.code_mirror.setValue('');
241 this.code_mirror.setValue('');
243 };
242 };
244
243
245
244
246 CodeCell.prototype.collapse = function () {
245 CodeCell.prototype.collapse = function () {
247 this.element.find('div.output').hide();
246 this.element.find('div.output').hide();
248 };
247 };
249
248
250
249
251 CodeCell.prototype.expand = function () {
250 CodeCell.prototype.expand = function () {
252 this.element.find('div.output').show();
251 this.element.find('div.output').show();
253 };
252 };
254
253
255
254
256 CodeCell.prototype.set_input_prompt = function (number) {
255 CodeCell.prototype.set_input_prompt = function (number) {
257 var n = number || ' ';
256 var n = number || ' ';
258 this.input_prompt_number = n
257 this.input_prompt_number = n
259 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
258 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
260 };
259 };
261
260
262
261
263 CodeCell.prototype.get_code = function () {
262 CodeCell.prototype.get_code = function () {
264 return this.code_mirror.getValue();
263 return this.code_mirror.getValue();
265 };
264 };
266
265
267
266
268 CodeCell.prototype.set_code = function (code) {
267 CodeCell.prototype.set_code = function (code) {
269 return this.code_mirror.setValue(code);
268 return this.code_mirror.setValue(code);
270 };
269 };
271
270
272
271
273 CodeCell.prototype.at_top = function () {
272 CodeCell.prototype.at_top = function () {
274 var cursor = this.code_mirror.getCursor();
273 var cursor = this.code_mirror.getCursor();
275 if (cursor.line === 0) {
274 if (cursor.line === 0) {
276 return true;
275 return true;
277 } else {
276 } else {
278 return false;
277 return false;
279 }
278 }
280 };
279 };
281
280
282
281
283 CodeCell.prototype.at_bottom = function () {
282 CodeCell.prototype.at_bottom = function () {
284 var cursor = this.code_mirror.getCursor();
283 var cursor = this.code_mirror.getCursor();
285 if (cursor.line === (this.code_mirror.lineCount()-1)) {
284 if (cursor.line === (this.code_mirror.lineCount()-1)) {
286 return true;
285 return true;
287 } else {
286 } else {
288 return false;
287 return false;
289 }
288 }
290 };
289 };
291
290
292
291
293 CodeCell.prototype.fromJSON = function (data) {
292 CodeCell.prototype.fromJSON = function (data) {
294 if (data.cell_type === 'code') {
293 if (data.cell_type === 'code') {
295 this.set_code(data.code);
294 this.set_code(data.code);
296 this.set_input_prompt(data.prompt_number);
295 this.set_input_prompt(data.prompt_number);
297 };
296 };
298 };
297 };
299
298
300
299
301 CodeCell.prototype.toJSON = function () {
300 CodeCell.prototype.toJSON = function () {
302 return {
301 return {
303 code : this.get_code(),
302 code : this.get_code(),
304 cell_type : 'code',
303 cell_type : 'code',
305 prompt_number : this.input_prompt_number
304 prompt_number : this.input_prompt_number
306 };
305 };
307 };
306 };
308
307
309 IPython.CodeCell = CodeCell;
308 IPython.CodeCell = CodeCell;
310
309
311 return IPython;
310 return IPython;
312 }(IPython));
311 }(IPython));
313
312
@@ -1,618 +1,624
1
1
2 //============================================================================
2 //============================================================================
3 // Notebook
3 // Notebook
4 //============================================================================
4 //============================================================================
5
5
6 var IPython = (function (IPython) {
6 var IPython = (function (IPython) {
7
7
8 var utils = IPython.utils;
8 var utils = IPython.utils;
9
9
10 var Notebook = function (selector) {
10 var Notebook = function (selector) {
11 this.element = $(selector);
11 this.element = $(selector);
12 this.element.scroll();
12 this.element.scroll();
13 this.element.data("notebook", this);
13 this.element.data("notebook", this);
14 this.next_prompt_number = 1;
14 this.next_prompt_number = 1;
15 this.kernel = null;
15 this.kernel = null;
16 this.msg_cell_map = {};
16 this.msg_cell_map = {};
17 this.filename = null;
17 this.filename = null;
18 this.notebook_load_re = /%notebook load/
18 this.notebook_load_re = /%notebook load/
19 this.notebook_save_re = /%notebook save/
19 this.notebook_save_re = /%notebook save/
20 this.notebook_filename_re = /(\w)+.ipynb/
20 this.notebook_filename_re = /(\w)+.ipynb/
21 this.style();
21 this.style();
22 this.create_elements();
22 this.create_elements();
23 this.bind_events();
23 this.bind_events();
24 this.start_kernel();
24 this.start_kernel();
25 };
25 };
26
26
27
27
28 Notebook.prototype.style = function () {
28 Notebook.prototype.style = function () {
29 $('div#notebook').addClass('border-box-sizing');
29 $('div#notebook').addClass('border-box-sizing');
30 };
30 };
31
31
32
32
33 Notebook.prototype.create_elements = function () {
33 Notebook.prototype.create_elements = function () {
34 // We add this end_space div to the end of the notebook div to:
34 // We add this end_space div to the end of the notebook div to:
35 // i) provide a margin between the last cell and the end of the notebook
35 // i) provide a margin between the last cell and the end of the notebook
36 // ii) to prevent the div from scrolling up when the last cell is being
36 // ii) to prevent the div from scrolling up when the last cell is being
37 // edited, but is too low on the page, which browsers will do automatically.
37 // edited, but is too low on the page, which browsers will do automatically.
38 this.element.append($('<div class="end_space"></div>').height(50));
38 this.element.append($('<div class="end_space"></div>').height(50));
39 $('div#notebook').addClass('border-box-sizing');
39 $('div#notebook').addClass('border-box-sizing');
40 };
40 };
41
41
42
42
43 Notebook.prototype.bind_events = function () {
43 Notebook.prototype.bind_events = function () {
44 var that = this;
44 var that = this;
45 $(document).keydown(function (event) {
45 $(document).keydown(function (event) {
46 // console.log(event);
46 // console.log(event);
47 if (event.which === 38) {
47 if (event.which === 38) {
48 var cell = that.selected_cell();
48 var cell = that.selected_cell();
49 if (cell.at_top()) {
49 if (cell.at_top()) {
50 event.preventDefault();
50 event.preventDefault();
51 that.select_prev();
51 that.select_prev();
52 };
52 };
53 } else if (event.which === 40) {
53 } else if (event.which === 40) {
54 var cell = that.selected_cell();
54 var cell = that.selected_cell();
55 if (cell.at_bottom()) {
55 if (cell.at_bottom()) {
56 event.preventDefault();
56 event.preventDefault();
57 that.select_next();
57 that.select_next();
58 };
58 };
59 } else if (event.which === 13 && event.shiftKey) {
59 } else if (event.which === 13 && event.shiftKey) {
60 that.execute_selected_cell(true);
60 that.execute_selected_cell();
61 return false;
61 return false;
62 } else if (event.which === 13 && event.ctrlKey) {
62 } else if (event.which === 13 && event.ctrlKey) {
63 that.execute_selected_cell(false);
63 that.execute_selected_cell({terminal:true});
64 that.selected_cell().clear_input();
65 return false;
64 return false;
66 };
65 };
67 });
66 });
68
67
69 this.element.bind('collapse_pager', function () {
68 this.element.bind('collapse_pager', function () {
70 var app_height = $('div#notebook_app').height(); // content height
69 var app_height = $('div#notebook_app').height(); // content height
71 var splitter_height = $('div#pager_splitter').outerHeight(true);
70 var splitter_height = $('div#pager_splitter').outerHeight(true);
72 var new_height = app_height - splitter_height;
71 var new_height = app_height - splitter_height;
73 that.element.animate({height : new_height + 'px'}, 'fast');
72 that.element.animate({height : new_height + 'px'}, 'fast');
74 });
73 });
75
74
76 this.element.bind('expand_pager', function () {
75 this.element.bind('expand_pager', function () {
77 var app_height = $('div#notebook_app').height(); // content height
76 var app_height = $('div#notebook_app').height(); // content height
78 var splitter_height = $('div#pager_splitter').outerHeight(true);
77 var splitter_height = $('div#pager_splitter').outerHeight(true);
79 var pager_height = $('div#pager').outerHeight(true);
78 var pager_height = $('div#pager').outerHeight(true);
80 var new_height = app_height - pager_height - splitter_height;
79 var new_height = app_height - pager_height - splitter_height;
81 that.element.animate({height : new_height + 'px'}, 'fast');
80 that.element.animate({height : new_height + 'px'}, 'fast');
82 });
81 });
83
82
84 this.element.bind('collapse_left_panel', function () {
83 this.element.bind('collapse_left_panel', function () {
85 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
84 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
86 var new_margin = splitter_width;
85 var new_margin = splitter_width;
87 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
86 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
88 });
87 });
89
88
90 this.element.bind('expand_left_panel', function () {
89 this.element.bind('expand_left_panel', function () {
91 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
90 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
92 var left_panel_width = IPython.left_panel.width;
91 var left_panel_width = IPython.left_panel.width;
93 var new_margin = splitter_width + left_panel_width;
92 var new_margin = splitter_width + left_panel_width;
94 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
93 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
95 });
94 });
96 };
95 };
97
96
98
97
99 Notebook.prototype.scroll_to_bottom = function () {
98 Notebook.prototype.scroll_to_bottom = function () {
100 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
99 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
101 };
100 };
102
101
103 // Cell indexing, retrieval, etc.
102 // Cell indexing, retrieval, etc.
104
103
105
104
106 Notebook.prototype.cell_elements = function () {
105 Notebook.prototype.cell_elements = function () {
107 return this.element.children("div.cell");
106 return this.element.children("div.cell");
108 }
107 }
109
108
110
109
111 Notebook.prototype.ncells = function (cell) {
110 Notebook.prototype.ncells = function (cell) {
112 return this.cell_elements().length;
111 return this.cell_elements().length;
113 }
112 }
114
113
115
114
116 // TODO: we are often calling cells as cells()[i], which we should optimize
115 // TODO: we are often calling cells as cells()[i], which we should optimize
117 // to cells(i) or a new method.
116 // to cells(i) or a new method.
118 Notebook.prototype.cells = function () {
117 Notebook.prototype.cells = function () {
119 return this.cell_elements().toArray().map(function (e) {
118 return this.cell_elements().toArray().map(function (e) {
120 return $(e).data("cell");
119 return $(e).data("cell");
121 });
120 });
122 }
121 }
123
122
124
123
125 Notebook.prototype.find_cell_index = function (cell) {
124 Notebook.prototype.find_cell_index = function (cell) {
126 var result = null;
125 var result = null;
127 this.cell_elements().filter(function (index) {
126 this.cell_elements().filter(function (index) {
128 if ($(this).data("cell") === cell) {
127 if ($(this).data("cell") === cell) {
129 result = index;
128 result = index;
130 };
129 };
131 });
130 });
132 return result;
131 return result;
133 };
132 };
134
133
135
134
136 Notebook.prototype.index_or_selected = function (index) {
135 Notebook.prototype.index_or_selected = function (index) {
137 return index || this.selected_index() || 0;
136 return index || this.selected_index() || 0;
138 }
137 }
139
138
140
139
141 Notebook.prototype.select = function (index) {
140 Notebook.prototype.select = function (index) {
142 if (index !== undefined && index >= 0 && index < this.ncells()) {
141 if (index !== undefined && index >= 0 && index < this.ncells()) {
143 if (this.selected_index() !== null) {
142 if (this.selected_index() !== null) {
144 this.selected_cell().unselect();
143 this.selected_cell().unselect();
145 };
144 };
146 this.cells()[index].select();
145 this.cells()[index].select();
147 if (index === (this.ncells()-1)) {
146 if (index === (this.ncells()-1)) {
148 this.scroll_to_bottom();
147 this.scroll_to_bottom();
149 };
148 };
150 };
149 };
151 return this;
150 return this;
152 };
151 };
153
152
154
153
155 Notebook.prototype.select_next = function () {
154 Notebook.prototype.select_next = function () {
156 var index = this.selected_index();
155 var index = this.selected_index();
157 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
156 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
158 this.select(index+1);
157 this.select(index+1);
159 };
158 };
160 return this;
159 return this;
161 };
160 };
162
161
163
162
164 Notebook.prototype.select_prev = function () {
163 Notebook.prototype.select_prev = function () {
165 var index = this.selected_index();
164 var index = this.selected_index();
166 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
165 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
167 this.select(index-1);
166 this.select(index-1);
168 };
167 };
169 return this;
168 return this;
170 };
169 };
171
170
172
171
173 Notebook.prototype.selected_index = function () {
172 Notebook.prototype.selected_index = function () {
174 var result = null;
173 var result = null;
175 this.cell_elements().filter(function (index) {
174 this.cell_elements().filter(function (index) {
176 if ($(this).data("cell").selected === true) {
175 if ($(this).data("cell").selected === true) {
177 result = index;
176 result = index;
178 };
177 };
179 });
178 });
180 return result;
179 return result;
181 };
180 };
182
181
183
182
184 Notebook.prototype.cell_for_msg = function (msg_id) {
183 Notebook.prototype.cell_for_msg = function (msg_id) {
185 var cell_id = this.msg_cell_map[msg_id];
184 var cell_id = this.msg_cell_map[msg_id];
186 var result = null;
185 var result = null;
187 this.cell_elements().filter(function (index) {
186 this.cell_elements().filter(function (index) {
188 cell = $(this).data("cell");
187 cell = $(this).data("cell");
189 if (cell.cell_id === cell_id) {
188 if (cell.cell_id === cell_id) {
190 result = cell;
189 result = cell;
191 };
190 };
192 });
191 });
193 return result;
192 return result;
194 };
193 };
195
194
196
195
197 Notebook.prototype.selected_cell = function () {
196 Notebook.prototype.selected_cell = function () {
198 return this.cell_elements().eq(this.selected_index()).data("cell");
197 return this.cell_elements().eq(this.selected_index()).data("cell");
199 }
198 }
200
199
201
200
202 // Cell insertion, deletion and moving.
201 // Cell insertion, deletion and moving.
203
202
204
203
205 Notebook.prototype.delete_cell = function (index) {
204 Notebook.prototype.delete_cell = function (index) {
206 var i = index || this.selected_index();
205 var i = index || this.selected_index();
207 if (i !== null && i >= 0 && i < this.ncells()) {
206 if (i !== null && i >= 0 && i < this.ncells()) {
208 this.cell_elements().eq(i).remove();
207 this.cell_elements().eq(i).remove();
209 if (i === (this.ncells())) {
208 if (i === (this.ncells())) {
210 this.select(i-1);
209 this.select(i-1);
211 } else {
210 } else {
212 this.select(i);
211 this.select(i);
213 };
212 };
214 };
213 };
215 return this;
214 return this;
216 };
215 };
217
216
218
217
219 Notebook.prototype.append_cell = function (cell) {
218 Notebook.prototype.append_cell = function (cell) {
220 this.element.find('div.end_space').before(cell.element);
219 this.element.find('div.end_space').before(cell.element);
221 return this;
220 return this;
222 };
221 };
223
222
224
223
225 Notebook.prototype.insert_cell_after = function (cell, index) {
224 Notebook.prototype.insert_cell_after = function (cell, index) {
226 var ncells = this.ncells();
225 var ncells = this.ncells();
227 if (ncells === 0) {
226 if (ncells === 0) {
228 this.append_cell(cell);
227 this.append_cell(cell);
229 return this;
228 return this;
230 };
229 };
231 if (index >= 0 && index < ncells) {
230 if (index >= 0 && index < ncells) {
232 this.cell_elements().eq(index).after(cell.element);
231 this.cell_elements().eq(index).after(cell.element);
233 };
232 };
234 return this
233 return this
235 };
234 };
236
235
237
236
238 Notebook.prototype.insert_cell_before = function (cell, index) {
237 Notebook.prototype.insert_cell_before = function (cell, index) {
239 var ncells = this.ncells();
238 var ncells = this.ncells();
240 if (ncells === 0) {
239 if (ncells === 0) {
241 this.append_cell(cell);
240 this.append_cell(cell);
242 return this;
241 return this;
243 };
242 };
244 if (index >= 0 && index < ncells) {
243 if (index >= 0 && index < ncells) {
245 this.cell_elements().eq(index).before(cell.element);
244 this.cell_elements().eq(index).before(cell.element);
246 };
245 };
247 return this;
246 return this;
248 };
247 };
249
248
250
249
251 Notebook.prototype.move_cell_up = function (index) {
250 Notebook.prototype.move_cell_up = function (index) {
252 var i = index || this.selected_index();
251 var i = index || this.selected_index();
253 if (i !== null && i < this.ncells() && i > 0) {
252 if (i !== null && i < this.ncells() && i > 0) {
254 var pivot = this.cell_elements().eq(i-1);
253 var pivot = this.cell_elements().eq(i-1);
255 var tomove = this.cell_elements().eq(i);
254 var tomove = this.cell_elements().eq(i);
256 if (pivot !== null && tomove !== null) {
255 if (pivot !== null && tomove !== null) {
257 tomove.detach();
256 tomove.detach();
258 pivot.before(tomove);
257 pivot.before(tomove);
259 this.select(i-1);
258 this.select(i-1);
260 };
259 };
261 };
260 };
262 return this;
261 return this;
263 }
262 }
264
263
265
264
266 Notebook.prototype.move_cell_down = function (index) {
265 Notebook.prototype.move_cell_down = function (index) {
267 var i = index || this.selected_index();
266 var i = index || this.selected_index();
268 if (i !== null && i < (this.ncells()-1) && i >= 0) {
267 if (i !== null && i < (this.ncells()-1) && i >= 0) {
269 var pivot = this.cell_elements().eq(i+1)
268 var pivot = this.cell_elements().eq(i+1)
270 var tomove = this.cell_elements().eq(i)
269 var tomove = this.cell_elements().eq(i)
271 if (pivot !== null && tomove !== null) {
270 if (pivot !== null && tomove !== null) {
272 tomove.detach();
271 tomove.detach();
273 pivot.after(tomove);
272 pivot.after(tomove);
274 this.select(i+1);
273 this.select(i+1);
275 };
274 };
276 };
275 };
277 return this;
276 return this;
278 }
277 }
279
278
280
279
281 Notebook.prototype.sort_cells = function () {
280 Notebook.prototype.sort_cells = function () {
282 var ncells = this.ncells();
281 var ncells = this.ncells();
283 var sindex = this.selected_index();
282 var sindex = this.selected_index();
284 var swapped;
283 var swapped;
285 do {
284 do {
286 swapped = false
285 swapped = false
287 for (var i=1; i<ncells; i++) {
286 for (var i=1; i<ncells; i++) {
288 current = this.cell_elements().eq(i).data("cell");
287 current = this.cell_elements().eq(i).data("cell");
289 previous = this.cell_elements().eq(i-1).data("cell");
288 previous = this.cell_elements().eq(i-1).data("cell");
290 if (previous.input_prompt_number > current.input_prompt_number) {
289 if (previous.input_prompt_number > current.input_prompt_number) {
291 this.move_cell_up(i);
290 this.move_cell_up(i);
292 swapped = true;
291 swapped = true;
293 };
292 };
294 };
293 };
295 } while (swapped);
294 } while (swapped);
296 this.select(sindex);
295 this.select(sindex);
297 return this;
296 return this;
298 };
297 };
299
298
300
299
301 Notebook.prototype.insert_code_cell_before = function (index) {
300 Notebook.prototype.insert_code_cell_before = function (index) {
302 // TODO: Bounds check for i
301 // TODO: Bounds check for i
303 var i = this.index_or_selected(index);
302 var i = this.index_or_selected(index);
304 var cell = new IPython.CodeCell(this);
303 var cell = new IPython.CodeCell(this);
305 // cell.set_input_prompt(this.next_prompt_number);
304 // cell.set_input_prompt(this.next_prompt_number);
306 cell.set_input_prompt();
305 cell.set_input_prompt();
307 this.next_prompt_number = this.next_prompt_number + 1;
306 this.next_prompt_number = this.next_prompt_number + 1;
308 this.insert_cell_before(cell, i);
307 this.insert_cell_before(cell, i);
309 this.select(this.find_cell_index(cell));
308 this.select(this.find_cell_index(cell));
310 return this;
309 return this;
311 }
310 }
312
311
313
312
314 Notebook.prototype.insert_code_cell_after = function (index) {
313 Notebook.prototype.insert_code_cell_after = function (index) {
315 // TODO: Bounds check for i
314 // TODO: Bounds check for i
316 var i = this.index_or_selected(index);
315 var i = this.index_or_selected(index);
317 var cell = new IPython.CodeCell(this);
316 var cell = new IPython.CodeCell(this);
318 // cell.set_input_prompt(this.next_prompt_number);
317 // cell.set_input_prompt(this.next_prompt_number);
319 cell.set_input_prompt();
318 cell.set_input_prompt();
320 this.next_prompt_number = this.next_prompt_number + 1;
319 this.next_prompt_number = this.next_prompt_number + 1;
321 this.insert_cell_after(cell, i);
320 this.insert_cell_after(cell, i);
322 this.select(this.find_cell_index(cell));
321 this.select(this.find_cell_index(cell));
323 return this;
322 return this;
324 }
323 }
325
324
326
325
327 Notebook.prototype.insert_text_cell_before = function (index) {
326 Notebook.prototype.insert_text_cell_before = function (index) {
328 // TODO: Bounds check for i
327 // TODO: Bounds check for i
329 var i = this.index_or_selected(index);
328 var i = this.index_or_selected(index);
330 var cell = new IPython.TextCell(this);
329 var cell = new IPython.TextCell(this);
331 cell.config_mathjax();
330 cell.config_mathjax();
332 this.insert_cell_before(cell, i);
331 this.insert_cell_before(cell, i);
333 this.select(this.find_cell_index(cell));
332 this.select(this.find_cell_index(cell));
334 return this;
333 return this;
335 }
334 }
336
335
337
336
338 Notebook.prototype.insert_text_cell_after = function (index) {
337 Notebook.prototype.insert_text_cell_after = function (index) {
339 // TODO: Bounds check for i
338 // TODO: Bounds check for i
340 var i = this.index_or_selected(index);
339 var i = this.index_or_selected(index);
341 var cell = new IPython.TextCell(this);
340 var cell = new IPython.TextCell(this);
342 cell.config_mathjax();
341 cell.config_mathjax();
343 this.insert_cell_after(cell, i);
342 this.insert_cell_after(cell, i);
344 this.select(this.find_cell_index(cell));
343 this.select(this.find_cell_index(cell));
345 return this;
344 return this;
346 }
345 }
347
346
348
347
349 Notebook.prototype.text_to_code = function (index) {
348 Notebook.prototype.text_to_code = function (index) {
350 // TODO: Bounds check for i
349 // TODO: Bounds check for i
351 var i = this.index_or_selected(index);
350 var i = this.index_or_selected(index);
352 var source_element = this.cell_elements().eq(i);
351 var source_element = this.cell_elements().eq(i);
353 var source_cell = source_element.data("cell");
352 var source_cell = source_element.data("cell");
354 if (source_cell instanceof IPython.TextCell) {
353 if (source_cell instanceof IPython.TextCell) {
355 this.insert_code_cell_after(i);
354 this.insert_code_cell_after(i);
356 var target_cell = this.cells()[i+1];
355 var target_cell = this.cells()[i+1];
357 target_cell.set_code(source_cell.get_text());
356 target_cell.set_code(source_cell.get_text());
358 source_element.remove();
357 source_element.remove();
359 };
358 };
360 };
359 };
361
360
362
361
363 Notebook.prototype.code_to_text = function (index) {
362 Notebook.prototype.code_to_text = function (index) {
364 // TODO: Bounds check for i
363 // TODO: Bounds check for i
365 var i = this.index_or_selected(index);
364 var i = this.index_or_selected(index);
366 var source_element = this.cell_elements().eq(i);
365 var source_element = this.cell_elements().eq(i);
367 var source_cell = source_element.data("cell");
366 var source_cell = source_element.data("cell");
368 if (source_cell instanceof IPython.CodeCell) {
367 if (source_cell instanceof IPython.CodeCell) {
369 this.insert_text_cell_after(i);
368 this.insert_text_cell_after(i);
370 var target_cell = this.cells()[i+1];
369 var target_cell = this.cells()[i+1];
371 var text = source_cell.get_code();
370 var text = source_cell.get_code();
372 if (text === "") {text = target_cell.placeholder;};
371 if (text === "") {text = target_cell.placeholder;};
373 target_cell.set_text(text);
372 target_cell.set_text(text);
374 source_element.remove();
373 source_element.remove();
375 target_cell.edit();
374 target_cell.edit();
376 };
375 };
377 };
376 };
378
377
379
378
380 // Cell collapsing
379 // Cell collapsing
381
380
382 Notebook.prototype.collapse = function (index) {
381 Notebook.prototype.collapse = function (index) {
383 var i = this.index_or_selected(index);
382 var i = this.index_or_selected(index);
384 this.cells()[i].collapse();
383 this.cells()[i].collapse();
385 };
384 };
386
385
387
386
388 Notebook.prototype.expand = function (index) {
387 Notebook.prototype.expand = function (index) {
389 var i = this.index_or_selected(index);
388 var i = this.index_or_selected(index);
390 this.cells()[i].expand();
389 this.cells()[i].expand();
391 };
390 };
392
391
393
392
394 // Kernel related things
393 // Kernel related things
395
394
396 Notebook.prototype.start_kernel = function () {
395 Notebook.prototype.start_kernel = function () {
397 this.kernel = new IPython.Kernel();
396 this.kernel = new IPython.Kernel();
398 this.kernel.start_kernel($.proxy(this.kernel_started, this));
397 this.kernel.start_kernel($.proxy(this.kernel_started, this));
399 };
398 };
400
399
401
400
402 Notebook.prototype.handle_shell_reply = function (e) {
401 Notebook.prototype.handle_shell_reply = function (e) {
403 reply = $.parseJSON(e.data);
402 reply = $.parseJSON(e.data);
404 var header = reply.header;
403 var header = reply.header;
405 var content = reply.content;
404 var content = reply.content;
406 var msg_type = header.msg_type;
405 var msg_type = header.msg_type;
407 // console.log(reply);
406 // console.log(reply);
408 var cell = this.cell_for_msg(reply.parent_header.msg_id);
407 var cell = this.cell_for_msg(reply.parent_header.msg_id);
409 if (msg_type === "execute_reply") {
408 if (msg_type === "execute_reply") {
410 cell.set_input_prompt(content.execution_count);
409 cell.set_input_prompt(content.execution_count);
411 } else if (msg_type === "complete_reply") {
410 } else if (msg_type === "complete_reply") {
412 cell.finish_completing(content.matched_text, content.matches);
411 cell.finish_completing(content.matched_text, content.matches);
413 };
412 };
414 var payload = content.payload || [];
413 var payload = content.payload || [];
415 this.handle_payload(payload);
414 this.handle_payload(payload);
416 };
415 };
417
416
418
417
419 Notebook.prototype.handle_payload = function (payload) {
418 Notebook.prototype.handle_payload = function (payload) {
420 var l = payload.length;
419 var l = payload.length;
421 if (l > 0) {
420 if (l > 0) {
422 IPython.pager.clear();
421 IPython.pager.clear();
423 IPython.pager.expand();
422 IPython.pager.expand();
424 };
423 };
425 for (var i=0; i<l; i++) {
424 for (var i=0; i<l; i++) {
426 IPython.pager.append_text(payload[i].text);
425 IPython.pager.append_text(payload[i].text);
427 };
426 };
428 };
427 };
429
428
430
429
431 Notebook.prototype.handle_iopub_reply = function (e) {
430 Notebook.prototype.handle_iopub_reply = function (e) {
432 reply = $.parseJSON(e.data);
431 reply = $.parseJSON(e.data);
433 var content = reply.content;
432 var content = reply.content;
434 // console.log(reply);
433 // console.log(reply);
435 var msg_type = reply.header.msg_type;
434 var msg_type = reply.header.msg_type;
436 var cell = this.cell_for_msg(reply.parent_header.msg_id);
435 var cell = this.cell_for_msg(reply.parent_header.msg_id);
437 if (msg_type === "stream") {
436 if (msg_type === "stream") {
438 cell.expand();
437 cell.expand();
439 cell.append_stream(content.data + "\n");
438 cell.append_stream(content.data + "\n");
440 } else if (msg_type === "display_data") {
439 } else if (msg_type === "display_data") {
441 cell.expand();
440 cell.expand();
442 cell.append_display_data(content.data);
441 cell.append_display_data(content.data);
443 } else if (msg_type === "pyout") {
442 } else if (msg_type === "pyout") {
444 cell.expand();
443 cell.expand();
445 cell.append_pyout(content.data, content.execution_count)
444 cell.append_pyout(content.data, content.execution_count)
446 } else if (msg_type === "pyerr") {
445 } else if (msg_type === "pyerr") {
447 cell.expand();
446 cell.expand();
448 cell.append_pyerr(content.ename, content.evalue, content.traceback);
447 cell.append_pyerr(content.ename, content.evalue, content.traceback);
449 } else if (msg_type === "status") {
448 } else if (msg_type === "status") {
450 if (content.execution_state === "busy") {
449 if (content.execution_state === "busy") {
451 IPython.kernel_status_widget.status_busy();
450 IPython.kernel_status_widget.status_busy();
452 } else if (content.execution_state === "idle") {
451 } else if (content.execution_state === "idle") {
453 IPython.kernel_status_widget.status_idle();
452 IPython.kernel_status_widget.status_idle();
454 };
453 };
455 }
454 }
456 };
455 };
457
456
458
457
459 Notebook.prototype.kernel_started = function () {
458 Notebook.prototype.kernel_started = function () {
460 console.log("Kernel started: ", this.kernel.kernel_id);
459 console.log("Kernel started: ", this.kernel.kernel_id);
461 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
460 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
462 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
461 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
463 };
462 };
464
463
465
464
466 Notebook.prototype.execute_selected_cell = function (add_new) {
465 Notebook.prototype.execute_selected_cell = function (options) {
467 if (add_new === undefined) {add_new = true;};
466 // add_new: should a new cell be added if we are at the end of the nb
467 // terminal: execute in terminal mode, which stays in the current cell
468 default_options = {terminal: false, add_new: true}
469 $.extend(default_options, options)
468 var that = this;
470 var that = this;
469 var cell = that.selected_cell();
471 var cell = that.selected_cell();
470 var cell_index = that.find_cell_index(cell);
472 var cell_index = that.find_cell_index(cell);
471 // TODO: the logic here needs to be moved into appropriate
473 // TODO: the logic here needs to be moved into appropriate
472 // methods of Notebook.
474 // methods of Notebook.
473 if (cell instanceof IPython.CodeCell) {
475 if (cell instanceof IPython.CodeCell) {
474 cell.clear_output();
476 cell.clear_output();
475 var code = cell.get_code();
477 var code = cell.get_code();
476 if (that.notebook_load_re.test(code)) {
478 if (that.notebook_load_re.test(code)) {
477 var code_parts = code.split(' ');
479 var code_parts = code.split(' ');
478 if (code_parts.length === 3) {
480 if (code_parts.length === 3) {
479 that.load_notebook(code_parts[2]);
481 that.load_notebook(code_parts[2]);
480 };
482 };
481 } else if (that.notebook_save_re.test(code)) {
483 } else if (that.notebook_save_re.test(code)) {
482 var code_parts = code.split(' ');
484 var code_parts = code.split(' ');
483 if (code_parts.length === 3) {
485 if (code_parts.length === 3) {
484 that.save_notebook(code_parts[2]);
486 that.save_notebook(code_parts[2]);
485 } else {
487 } else {
486 that.save_notebook()
488 that.save_notebook()
487 };
489 };
488 } else {
490 } else {
489 var msg_id = that.kernel.execute(cell.get_code());
491 var msg_id = that.kernel.execute(cell.get_code());
490 that.msg_cell_map[msg_id] = cell.cell_id;
492 that.msg_cell_map[msg_id] = cell.cell_id;
491 };
493 };
492 } else if (cell instanceof IPython.TextCell) {
494 } else if (cell instanceof IPython.TextCell) {
493 cell.render();
495 cell.render();
494 }
496 }
495 if ((cell_index === (that.ncells()-1)) && add_new) {
497 if (default_options.terminal) {
496 that.insert_code_cell_after();
498 cell.clear_input();
497 // If we are adding a new cell at the end, scroll down to show it.
498 that.scroll_to_bottom();
499 } else {
499 } else {
500 that.select(cell_index+1);
500 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
501 that.insert_code_cell_after();
502 // If we are adding a new cell at the end, scroll down to show it.
503 that.scroll_to_bottom();
504 } else {
505 that.select(cell_index+1);
506 };
501 };
507 };
502 };
508 };
503
509
504
510
505 Notebook.prototype.execute_all_cells = function () {
511 Notebook.prototype.execute_all_cells = function () {
506 var ncells = this.ncells();
512 var ncells = this.ncells();
507 for (var i=0; i<ncells; i++) {
513 for (var i=0; i<ncells; i++) {
508 this.select(i);
514 this.select(i);
509 this.execute_selected_cell(false);
515 this.execute_selected_cell({add_new:false});
510 };
516 };
511 this.scroll_to_bottom();
517 this.scroll_to_bottom();
512 };
518 };
513
519
514
520
515 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
521 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
516 var msg_id = this.kernel.complete(line, cursor_pos);
522 var msg_id = this.kernel.complete(line, cursor_pos);
517 this.msg_cell_map[msg_id] = cell.cell_id;
523 this.msg_cell_map[msg_id] = cell.cell_id;
518 };
524 };
519
525
520 // Persistance and loading
526 // Persistance and loading
521
527
522
528
523 Notebook.prototype.fromJSON = function (data) {
529 Notebook.prototype.fromJSON = function (data) {
524 var ncells = this.ncells();
530 var ncells = this.ncells();
525 for (var i=0; i<ncells; i++) {
531 for (var i=0; i<ncells; i++) {
526 // Always delete cell 0 as they get renumbered as they are deleted.
532 // Always delete cell 0 as they get renumbered as they are deleted.
527 this.delete_cell(0);
533 this.delete_cell(0);
528 };
534 };
529 var new_cells = data.cells;
535 var new_cells = data.cells;
530 ncells = new_cells.length;
536 ncells = new_cells.length;
531 var cell_data = null;
537 var cell_data = null;
532 for (var i=0; i<ncells; i++) {
538 for (var i=0; i<ncells; i++) {
533 cell_data = new_cells[i];
539 cell_data = new_cells[i];
534 if (cell_data.cell_type == 'code') {
540 if (cell_data.cell_type == 'code') {
535 this.insert_code_cell_after();
541 this.insert_code_cell_after();
536 this.selected_cell().fromJSON(cell_data);
542 this.selected_cell().fromJSON(cell_data);
537 } else if (cell_data.cell_type === 'text') {
543 } else if (cell_data.cell_type === 'text') {
538 this.insert_text_cell_after();
544 this.insert_text_cell_after();
539 this.selected_cell().fromJSON(cell_data);
545 this.selected_cell().fromJSON(cell_data);
540 };
546 };
541 };
547 };
542 };
548 };
543
549
544
550
545 Notebook.prototype.toJSON = function () {
551 Notebook.prototype.toJSON = function () {
546 var cells = this.cells();
552 var cells = this.cells();
547 var ncells = cells.length;
553 var ncells = cells.length;
548 cell_array = new Array(ncells);
554 cell_array = new Array(ncells);
549 for (var i=0; i<ncells; i++) {
555 for (var i=0; i<ncells; i++) {
550 cell_array[i] = cells[i].toJSON();
556 cell_array[i] = cells[i].toJSON();
551 };
557 };
552 json = {
558 json = {
553 cells : cell_array
559 cells : cell_array
554 };
560 };
555 return json
561 return json
556 };
562 };
557
563
558
564
559 Notebook.prototype.test_filename = function (filename) {
565 Notebook.prototype.test_filename = function (filename) {
560 if (this.notebook_filename_re.test(filename)) {
566 if (this.notebook_filename_re.test(filename)) {
561 return true;
567 return true;
562 } else {
568 } else {
563 var bad_filename = $('<div/>');
569 var bad_filename = $('<div/>');
564 bad_filename.html(
570 bad_filename.html(
565 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
571 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
566 );
572 );
567 bad_filename.dialog({title: 'Invalid filename', modal: true});
573 bad_filename.dialog({title: 'Invalid filename', modal: true});
568 return false;
574 return false;
569 };
575 };
570 };
576 };
571
577
572 Notebook.prototype.save_notebook = function (filename) {
578 Notebook.prototype.save_notebook = function (filename) {
573 this.filename = filename || this.filename || '';
579 this.filename = filename || this.filename || '';
574 if (this.filename === '') {
580 if (this.filename === '') {
575 var no_filename = $('<div/>');
581 var no_filename = $('<div/>');
576 no_filename.html(
582 no_filename.html(
577 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
583 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
578 );
584 );
579 no_filename.dialog({title: 'Missing filename', modal: true});
585 no_filename.dialog({title: 'Missing filename', modal: true});
580 return;
586 return;
581 }
587 }
582 if (!this.test_filename(this.filename)) {return;}
588 if (!this.test_filename(this.filename)) {return;}
583 var thedata = this.toJSON();
589 var thedata = this.toJSON();
584 var settings = {
590 var settings = {
585 processData : false,
591 processData : false,
586 cache : false,
592 cache : false,
587 type : "PUT",
593 type : "PUT",
588 data : JSON.stringify(thedata),
594 data : JSON.stringify(thedata),
589 success : function (data, status, xhr) {console.log(data);}
595 success : function (data, status, xhr) {console.log(data);}
590 };
596 };
591 $.ajax("/notebooks/" + this.filename, settings);
597 $.ajax("/notebooks/" + this.filename, settings);
592 };
598 };
593
599
594
600
595 Notebook.prototype.load_notebook = function (filename) {
601 Notebook.prototype.load_notebook = function (filename) {
596 if (!this.test_filename(filename)) {return;}
602 if (!this.test_filename(filename)) {return;}
597 var that = this;
603 var that = this;
598 // We do the call with settings so we can set cache to false.
604 // We do the call with settings so we can set cache to false.
599 var settings = {
605 var settings = {
600 processData : false,
606 processData : false,
601 cache : false,
607 cache : false,
602 type : "GET",
608 type : "GET",
603 dataType : "json",
609 dataType : "json",
604 success : function (data, status, xhr) {
610 success : function (data, status, xhr) {
605 that.fromJSON(data);
611 that.fromJSON(data);
606 that.filename = filename;
612 that.filename = filename;
607 that.kernel.restart();
613 that.kernel.restart();
608 }
614 }
609 };
615 };
610 $.ajax("/notebooks/" + filename, settings);
616 $.ajax("/notebooks/" + filename, settings);
611 }
617 }
612
618
613 IPython.Notebook = Notebook;
619 IPython.Notebook = Notebook;
614
620
615 return IPython;
621 return IPython;
616
622
617 }(IPython));
623 }(IPython));
618
624
General Comments 0
You need to be logged in to leave comments. Login now