##// END OF EJS Templates
Intercept <esc> avoid closing websocket on Firefox...
Matthias BUSSONNIER -
Show More
@@ -1,1009 +1,1014 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
15
16 var Notebook = function (selector) {
16 var Notebook = function (selector) {
17 this.read_only = IPython.read_only;
17 this.read_only = IPython.read_only;
18 this.element = $(selector);
18 this.element = $(selector);
19 this.element.scroll();
19 this.element.scroll();
20 this.element.data("notebook", this);
20 this.element.data("notebook", this);
21 this.next_prompt_number = 1;
21 this.next_prompt_number = 1;
22 this.kernel = null;
22 this.kernel = null;
23 this.dirty = false;
23 this.dirty = false;
24 this.msg_cell_map = {};
24 this.msg_cell_map = {};
25 this.metadata = {};
25 this.metadata = {};
26 this.control_key_active = false;
26 this.control_key_active = false;
27 this.style();
27 this.style();
28 this.create_elements();
28 this.create_elements();
29 this.bind_events();
29 this.bind_events();
30 };
30 };
31
31
32
32
33 Notebook.prototype.style = function () {
33 Notebook.prototype.style = function () {
34 $('div#notebook').addClass('border-box-sizing');
34 $('div#notebook').addClass('border-box-sizing');
35 };
35 };
36
36
37
37
38 Notebook.prototype.create_elements = function () {
38 Notebook.prototype.create_elements = function () {
39 // We add this end_space div to the end of the notebook div to:
39 // We add this end_space div to the end of the notebook div to:
40 // i) provide a margin between the last cell and the end of the notebook
40 // i) provide a margin between the last cell and the end of the notebook
41 // ii) to prevent the div from scrolling up when the last cell is being
41 // ii) to prevent the div from scrolling up when the last cell is being
42 // edited, but is too low on the page, which browsers will do automatically.
42 // edited, but is too low on the page, which browsers will do automatically.
43 var that = this;
43 var that = this;
44 var end_space = $('<div class="end_space"></div>').height(150);
44 var end_space = $('<div class="end_space"></div>').height(150);
45 end_space.dblclick(function (e) {
45 end_space.dblclick(function (e) {
46 if (that.read_only) return;
46 if (that.read_only) return;
47 var ncells = that.ncells();
47 var ncells = that.ncells();
48 that.insert_code_cell_below(ncells-1);
48 that.insert_code_cell_below(ncells-1);
49 });
49 });
50 this.element.append(end_space);
50 this.element.append(end_space);
51 $('div#notebook').addClass('border-box-sizing');
51 $('div#notebook').addClass('border-box-sizing');
52 };
52 };
53
53
54
54
55 Notebook.prototype.bind_events = function () {
55 Notebook.prototype.bind_events = function () {
56 var that = this;
56 var that = this;
57 $(document).keydown(function (event) {
57 $(document).keydown(function (event) {
58 // console.log(event);
58 // console.log(event);
59 if (that.read_only) return;
59 if (that.read_only) return;
60 if (event.which === 27) {
61 // Intercept escape at highest level to avoid closing
62 // websocket connection with firefox
63 event.preventDefault();
64 }
60 if (event.which === 38) {
65 if (event.which === 38) {
61 var cell = that.selected_cell();
66 var cell = that.selected_cell();
62 if (cell.at_top()) {
67 if (cell.at_top()) {
63 event.preventDefault();
68 event.preventDefault();
64 that.select_prev();
69 that.select_prev();
65 };
70 };
66 } else if (event.which === 40) {
71 } else if (event.which === 40) {
67 var cell = that.selected_cell();
72 var cell = that.selected_cell();
68 if (cell.at_bottom()) {
73 if (cell.at_bottom()) {
69 event.preventDefault();
74 event.preventDefault();
70 that.select_next();
75 that.select_next();
71 };
76 };
72 } else if (event.which === 13 && event.shiftKey) {
77 } else if (event.which === 13 && event.shiftKey) {
73 that.execute_selected_cell();
78 that.execute_selected_cell();
74 return false;
79 return false;
75 } else if (event.which === 13 && event.ctrlKey) {
80 } else if (event.which === 13 && event.ctrlKey) {
76 that.execute_selected_cell({terminal:true});
81 that.execute_selected_cell({terminal:true});
77 return false;
82 return false;
78 } else if (event.which === 77 && event.ctrlKey) {
83 } else if (event.which === 77 && event.ctrlKey) {
79 that.control_key_active = true;
84 that.control_key_active = true;
80 return false;
85 return false;
81 } else if (event.which === 68 && that.control_key_active) {
86 } else if (event.which === 68 && that.control_key_active) {
82 // Delete selected cell = d
87 // Delete selected cell = d
83 that.delete_cell();
88 that.delete_cell();
84 that.control_key_active = false;
89 that.control_key_active = false;
85 return false;
90 return false;
86 } else if (event.which === 65 && that.control_key_active) {
91 } else if (event.which === 65 && that.control_key_active) {
87 // Insert code cell above selected = a
92 // Insert code cell above selected = a
88 that.insert_code_cell_above();
93 that.insert_code_cell_above();
89 that.control_key_active = false;
94 that.control_key_active = false;
90 return false;
95 return false;
91 } else if (event.which === 66 && that.control_key_active) {
96 } else if (event.which === 66 && that.control_key_active) {
92 // Insert code cell below selected = b
97 // Insert code cell below selected = b
93 that.insert_code_cell_below();
98 that.insert_code_cell_below();
94 that.control_key_active = false;
99 that.control_key_active = false;
95 return false;
100 return false;
96 } else if (event.which === 67 && that.control_key_active) {
101 } else if (event.which === 67 && that.control_key_active) {
97 // To code = c
102 // To code = c
98 that.to_code();
103 that.to_code();
99 that.control_key_active = false;
104 that.control_key_active = false;
100 return false;
105 return false;
101 } else if (event.which === 77 && that.control_key_active) {
106 } else if (event.which === 77 && that.control_key_active) {
102 // To markdown = m
107 // To markdown = m
103 that.to_markdown();
108 that.to_markdown();
104 that.control_key_active = false;
109 that.control_key_active = false;
105 return false;
110 return false;
106 } else if (event.which === 84 && that.control_key_active) {
111 } else if (event.which === 84 && that.control_key_active) {
107 // Toggle output = t
112 // Toggle output = t
108 that.toggle_output();
113 that.toggle_output();
109 that.control_key_active = false;
114 that.control_key_active = false;
110 return false;
115 return false;
111 } else if (event.which === 83 && that.control_key_active) {
116 } else if (event.which === 83 && that.control_key_active) {
112 // Save notebook = s
117 // Save notebook = s
113 IPython.save_widget.save_notebook();
118 IPython.save_widget.save_notebook();
114 that.control_key_active = false;
119 that.control_key_active = false;
115 return false;
120 return false;
116 } else if (event.which === 74 && that.control_key_active) {
121 } else if (event.which === 74 && that.control_key_active) {
117 // Move cell down = j
122 // Move cell down = j
118 that.move_cell_down();
123 that.move_cell_down();
119 that.control_key_active = false;
124 that.control_key_active = false;
120 return false;
125 return false;
121 } else if (event.which === 75 && that.control_key_active) {
126 } else if (event.which === 75 && that.control_key_active) {
122 // Move cell up = k
127 // Move cell up = k
123 that.move_cell_up();
128 that.move_cell_up();
124 that.control_key_active = false;
129 that.control_key_active = false;
125 return false;
130 return false;
126 } else if (event.which === 80 && that.control_key_active) {
131 } else if (event.which === 80 && that.control_key_active) {
127 // Select previous = p
132 // Select previous = p
128 that.select_prev();
133 that.select_prev();
129 that.control_key_active = false;
134 that.control_key_active = false;
130 return false;
135 return false;
131 } else if (event.which === 78 && that.control_key_active) {
136 } else if (event.which === 78 && that.control_key_active) {
132 // Select next = n
137 // Select next = n
133 that.select_next();
138 that.select_next();
134 that.control_key_active = false;
139 that.control_key_active = false;
135 return false;
140 return false;
136 } else if (event.which === 76 && that.control_key_active) {
141 } else if (event.which === 76 && that.control_key_active) {
137 // Toggle line numbers = l
142 // Toggle line numbers = l
138 that.cell_toggle_line_numbers();
143 that.cell_toggle_line_numbers();
139 that.control_key_active = false;
144 that.control_key_active = false;
140 return false;
145 return false;
141 } else if (event.which === 73 && that.control_key_active) {
146 } else if (event.which === 73 && that.control_key_active) {
142 // Interrupt kernel = i
147 // Interrupt kernel = i
143 IPython.notebook.kernel.interrupt();
148 IPython.notebook.kernel.interrupt();
144 that.control_key_active = false;
149 that.control_key_active = false;
145 return false;
150 return false;
146 } else if (event.which === 190 && that.control_key_active) {
151 } else if (event.which === 190 && that.control_key_active) {
147 // Restart kernel = . # matches qt console
152 // Restart kernel = . # matches qt console
148 IPython.notebook.restart_kernel();
153 IPython.notebook.restart_kernel();
149 that.control_key_active = false;
154 that.control_key_active = false;
150 return false;
155 return false;
151 } else if (event.which === 72 && that.control_key_active) {
156 } else if (event.which === 72 && that.control_key_active) {
152 // Show keyboard shortcuts = h
157 // Show keyboard shortcuts = h
153 that.toggle_keyboard_shortcuts();
158 that.toggle_keyboard_shortcuts();
154 that.control_key_active = false;
159 that.control_key_active = false;
155 return false;
160 return false;
156 } else if (that.control_key_active) {
161 } else if (that.control_key_active) {
157 that.control_key_active = false;
162 that.control_key_active = false;
158 return true;
163 return true;
159 };
164 };
160 });
165 });
161
166
162 this.element.bind('collapse_pager', function () {
167 this.element.bind('collapse_pager', function () {
163 var app_height = $('div#main_app').height(); // content height
168 var app_height = $('div#main_app').height(); // content height
164 var splitter_height = $('div#pager_splitter').outerHeight(true);
169 var splitter_height = $('div#pager_splitter').outerHeight(true);
165 var new_height = app_height - splitter_height;
170 var new_height = app_height - splitter_height;
166 that.element.animate({height : new_height + 'px'}, 'fast');
171 that.element.animate({height : new_height + 'px'}, 'fast');
167 });
172 });
168
173
169 this.element.bind('expand_pager', function () {
174 this.element.bind('expand_pager', function () {
170 var app_height = $('div#main_app').height(); // content height
175 var app_height = $('div#main_app').height(); // content height
171 var splitter_height = $('div#pager_splitter').outerHeight(true);
176 var splitter_height = $('div#pager_splitter').outerHeight(true);
172 var pager_height = $('div#pager').outerHeight(true);
177 var pager_height = $('div#pager').outerHeight(true);
173 var new_height = app_height - pager_height - splitter_height;
178 var new_height = app_height - pager_height - splitter_height;
174 that.element.animate({height : new_height + 'px'}, 'fast');
179 that.element.animate({height : new_height + 'px'}, 'fast');
175 });
180 });
176
181
177 this.element.bind('collapse_left_panel', function () {
182 this.element.bind('collapse_left_panel', function () {
178 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
183 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
179 var new_margin = splitter_width;
184 var new_margin = splitter_width;
180 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
185 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
181 });
186 });
182
187
183 this.element.bind('expand_left_panel', function () {
188 this.element.bind('expand_left_panel', function () {
184 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
189 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
185 var left_panel_width = IPython.left_panel.width;
190 var left_panel_width = IPython.left_panel.width;
186 var new_margin = splitter_width + left_panel_width;
191 var new_margin = splitter_width + left_panel_width;
187 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
192 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
188 });
193 });
189
194
190 $(window).bind('beforeunload', function () {
195 $(window).bind('beforeunload', function () {
191 var kill_kernel = $('#kill_kernel').prop('checked');
196 var kill_kernel = $('#kill_kernel').prop('checked');
192 if (kill_kernel) {
197 if (kill_kernel) {
193 that.kernel.kill();
198 that.kernel.kill();
194 }
199 }
195 if (that.dirty && ! that.read_only) {
200 if (that.dirty && ! that.read_only) {
196 return "You have unsaved changes that will be lost if you leave this page.";
201 return "You have unsaved changes that will be lost if you leave this page.";
197 };
202 };
198 });
203 });
199 };
204 };
200
205
201
206
202 Notebook.prototype.toggle_keyboard_shortcuts = function () {
207 Notebook.prototype.toggle_keyboard_shortcuts = function () {
203 // toggles display of keyboard shortcut dialog
208 // toggles display of keyboard shortcut dialog
204 var that = this;
209 var that = this;
205 if ( this.shortcut_dialog ){
210 if ( this.shortcut_dialog ){
206 // if dialog is already shown, close it
211 // if dialog is already shown, close it
207 this.shortcut_dialog.dialog("close");
212 this.shortcut_dialog.dialog("close");
208 this.shortcut_dialog = null;
213 this.shortcut_dialog = null;
209 return;
214 return;
210 }
215 }
211 var dialog = $('<div/>');
216 var dialog = $('<div/>');
212 this.shortcut_dialog = dialog;
217 this.shortcut_dialog = dialog;
213 var shortcuts = [
218 var shortcuts = [
214 {key: 'Shift-Enter', help: 'run cell'},
219 {key: 'Shift-Enter', help: 'run cell'},
215 {key: 'Ctrl-Enter', help: 'run cell in-place'},
220 {key: 'Ctrl-Enter', help: 'run cell in-place'},
216 {key: 'Ctrl-m d', help: 'delete cell'},
221 {key: 'Ctrl-m d', help: 'delete cell'},
217 {key: 'Ctrl-m a', help: 'insert cell above'},
222 {key: 'Ctrl-m a', help: 'insert cell above'},
218 {key: 'Ctrl-m b', help: 'insert cell below'},
223 {key: 'Ctrl-m b', help: 'insert cell below'},
219 {key: 'Ctrl-m t', help: 'toggle output'},
224 {key: 'Ctrl-m t', help: 'toggle output'},
220 {key: 'Ctrl-m l', help: 'toggle line numbers'},
225 {key: 'Ctrl-m l', help: 'toggle line numbers'},
221 {key: 'Ctrl-m s', help: 'save notebook'},
226 {key: 'Ctrl-m s', help: 'save notebook'},
222 {key: 'Ctrl-m j', help: 'move cell down'},
227 {key: 'Ctrl-m j', help: 'move cell down'},
223 {key: 'Ctrl-m k', help: 'move cell up'},
228 {key: 'Ctrl-m k', help: 'move cell up'},
224 {key: 'Ctrl-m c', help: 'code cell'},
229 {key: 'Ctrl-m c', help: 'code cell'},
225 {key: 'Ctrl-m m', help: 'markdown cell'},
230 {key: 'Ctrl-m m', help: 'markdown cell'},
226 {key: 'Ctrl-m p', help: 'select previous'},
231 {key: 'Ctrl-m p', help: 'select previous'},
227 {key: 'Ctrl-m n', help: 'select next'},
232 {key: 'Ctrl-m n', help: 'select next'},
228 {key: 'Ctrl-m i', help: 'interrupt kernel'},
233 {key: 'Ctrl-m i', help: 'interrupt kernel'},
229 {key: 'Ctrl-m .', help: 'restart kernel'},
234 {key: 'Ctrl-m .', help: 'restart kernel'},
230 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
235 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
231 ];
236 ];
232 for (var i=0; i<shortcuts.length; i++) {
237 for (var i=0; i<shortcuts.length; i++) {
233 dialog.append($('<div>').
238 dialog.append($('<div>').
234 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
239 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
235 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
240 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
236 );
241 );
237 };
242 };
238 dialog.bind('dialogclose', function(event) {
243 dialog.bind('dialogclose', function(event) {
239 // dialog has been closed, allow it to be drawn again.
244 // dialog has been closed, allow it to be drawn again.
240 that.shortcut_dialog = null;
245 that.shortcut_dialog = null;
241 });
246 });
242 dialog.dialog({title: 'Keyboard shortcuts'});
247 dialog.dialog({title: 'Keyboard shortcuts'});
243 };
248 };
244
249
245
250
246 Notebook.prototype.scroll_to_bottom = function () {
251 Notebook.prototype.scroll_to_bottom = function () {
247 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
252 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
248 };
253 };
249
254
250
255
251 Notebook.prototype.scroll_to_top = function () {
256 Notebook.prototype.scroll_to_top = function () {
252 this.element.animate({scrollTop:0}, 0);
257 this.element.animate({scrollTop:0}, 0);
253 };
258 };
254
259
255
260
256 // Cell indexing, retrieval, etc.
261 // Cell indexing, retrieval, etc.
257
262
258
263
259 Notebook.prototype.cell_elements = function () {
264 Notebook.prototype.cell_elements = function () {
260 return this.element.children("div.cell");
265 return this.element.children("div.cell");
261 }
266 }
262
267
263
268
264 Notebook.prototype.ncells = function (cell) {
269 Notebook.prototype.ncells = function (cell) {
265 return this.cell_elements().length;
270 return this.cell_elements().length;
266 }
271 }
267
272
268
273
269 // TODO: we are often calling cells as cells()[i], which we should optimize
274 // TODO: we are often calling cells as cells()[i], which we should optimize
270 // to cells(i) or a new method.
275 // to cells(i) or a new method.
271 Notebook.prototype.cells = function () {
276 Notebook.prototype.cells = function () {
272 return this.cell_elements().toArray().map(function (e) {
277 return this.cell_elements().toArray().map(function (e) {
273 return $(e).data("cell");
278 return $(e).data("cell");
274 });
279 });
275 }
280 }
276
281
277
282
278 Notebook.prototype.find_cell_index = function (cell) {
283 Notebook.prototype.find_cell_index = function (cell) {
279 var result = null;
284 var result = null;
280 this.cell_elements().filter(function (index) {
285 this.cell_elements().filter(function (index) {
281 if ($(this).data("cell") === cell) {
286 if ($(this).data("cell") === cell) {
282 result = index;
287 result = index;
283 };
288 };
284 });
289 });
285 return result;
290 return result;
286 };
291 };
287
292
288
293
289 Notebook.prototype.index_or_selected = function (index) {
294 Notebook.prototype.index_or_selected = function (index) {
290 return index || this.selected_index() || 0;
295 return index || this.selected_index() || 0;
291 }
296 }
292
297
293
298
294 Notebook.prototype.select = function (index) {
299 Notebook.prototype.select = function (index) {
295 if (index !== undefined && index >= 0 && index < this.ncells()) {
300 if (index !== undefined && index >= 0 && index < this.ncells()) {
296 if (this.selected_index() !== null) {
301 if (this.selected_index() !== null) {
297 this.selected_cell().unselect();
302 this.selected_cell().unselect();
298 };
303 };
299 this.cells()[index].select();
304 this.cells()[index].select();
300 };
305 };
301 return this;
306 return this;
302 };
307 };
303
308
304
309
305 Notebook.prototype.select_next = function () {
310 Notebook.prototype.select_next = function () {
306 var index = this.selected_index();
311 var index = this.selected_index();
307 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
312 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
308 this.select(index+1);
313 this.select(index+1);
309 };
314 };
310 return this;
315 return this;
311 };
316 };
312
317
313
318
314 Notebook.prototype.select_prev = function () {
319 Notebook.prototype.select_prev = function () {
315 var index = this.selected_index();
320 var index = this.selected_index();
316 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
321 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
317 this.select(index-1);
322 this.select(index-1);
318 };
323 };
319 return this;
324 return this;
320 };
325 };
321
326
322
327
323 Notebook.prototype.selected_index = function () {
328 Notebook.prototype.selected_index = function () {
324 var result = null;
329 var result = null;
325 this.cell_elements().filter(function (index) {
330 this.cell_elements().filter(function (index) {
326 if ($(this).data("cell").selected === true) {
331 if ($(this).data("cell").selected === true) {
327 result = index;
332 result = index;
328 };
333 };
329 });
334 });
330 return result;
335 return result;
331 };
336 };
332
337
333
338
334 Notebook.prototype.cell_for_msg = function (msg_id) {
339 Notebook.prototype.cell_for_msg = function (msg_id) {
335 var cell_id = this.msg_cell_map[msg_id];
340 var cell_id = this.msg_cell_map[msg_id];
336 var result = null;
341 var result = null;
337 this.cell_elements().filter(function (index) {
342 this.cell_elements().filter(function (index) {
338 cell = $(this).data("cell");
343 cell = $(this).data("cell");
339 if (cell.cell_id === cell_id) {
344 if (cell.cell_id === cell_id) {
340 result = cell;
345 result = cell;
341 };
346 };
342 });
347 });
343 return result;
348 return result;
344 };
349 };
345
350
346
351
347 Notebook.prototype.selected_cell = function () {
352 Notebook.prototype.selected_cell = function () {
348 return this.cell_elements().eq(this.selected_index()).data("cell");
353 return this.cell_elements().eq(this.selected_index()).data("cell");
349 }
354 }
350
355
351
356
352 // Cell insertion, deletion and moving.
357 // Cell insertion, deletion and moving.
353
358
354
359
355 Notebook.prototype.delete_cell = function (index) {
360 Notebook.prototype.delete_cell = function (index) {
356 var i = index || this.selected_index();
361 var i = index || this.selected_index();
357 if (i !== null && i >= 0 && i < this.ncells()) {
362 if (i !== null && i >= 0 && i < this.ncells()) {
358 this.cell_elements().eq(i).remove();
363 this.cell_elements().eq(i).remove();
359 if (i === (this.ncells())) {
364 if (i === (this.ncells())) {
360 this.select(i-1);
365 this.select(i-1);
361 } else {
366 } else {
362 this.select(i);
367 this.select(i);
363 };
368 };
364 };
369 };
365 this.dirty = true;
370 this.dirty = true;
366 return this;
371 return this;
367 };
372 };
368
373
369
374
370 Notebook.prototype.append_cell = function (cell) {
375 Notebook.prototype.append_cell = function (cell) {
371 this.element.find('div.end_space').before(cell.element);
376 this.element.find('div.end_space').before(cell.element);
372 this.dirty = true;
377 this.dirty = true;
373 return this;
378 return this;
374 };
379 };
375
380
376
381
377 Notebook.prototype.insert_cell_below = function (cell, index) {
382 Notebook.prototype.insert_cell_below = function (cell, index) {
378 var ncells = this.ncells();
383 var ncells = this.ncells();
379 if (ncells === 0) {
384 if (ncells === 0) {
380 this.append_cell(cell);
385 this.append_cell(cell);
381 return this;
386 return this;
382 };
387 };
383 if (index >= 0 && index < ncells) {
388 if (index >= 0 && index < ncells) {
384 this.cell_elements().eq(index).after(cell.element);
389 this.cell_elements().eq(index).after(cell.element);
385 };
390 };
386 this.dirty = true;
391 this.dirty = true;
387 return this
392 return this
388 };
393 };
389
394
390
395
391 Notebook.prototype.insert_cell_above = function (cell, index) {
396 Notebook.prototype.insert_cell_above = function (cell, index) {
392 var ncells = this.ncells();
397 var ncells = this.ncells();
393 if (ncells === 0) {
398 if (ncells === 0) {
394 this.append_cell(cell);
399 this.append_cell(cell);
395 return this;
400 return this;
396 };
401 };
397 if (index >= 0 && index < ncells) {
402 if (index >= 0 && index < ncells) {
398 this.cell_elements().eq(index).before(cell.element);
403 this.cell_elements().eq(index).before(cell.element);
399 };
404 };
400 this.dirty = true;
405 this.dirty = true;
401 return this;
406 return this;
402 };
407 };
403
408
404
409
405 Notebook.prototype.move_cell_up = function (index) {
410 Notebook.prototype.move_cell_up = function (index) {
406 var i = index || this.selected_index();
411 var i = index || this.selected_index();
407 if (i !== null && i < this.ncells() && i > 0) {
412 if (i !== null && i < this.ncells() && i > 0) {
408 var pivot = this.cell_elements().eq(i-1);
413 var pivot = this.cell_elements().eq(i-1);
409 var tomove = this.cell_elements().eq(i);
414 var tomove = this.cell_elements().eq(i);
410 if (pivot !== null && tomove !== null) {
415 if (pivot !== null && tomove !== null) {
411 tomove.detach();
416 tomove.detach();
412 pivot.before(tomove);
417 pivot.before(tomove);
413 this.select(i-1);
418 this.select(i-1);
414 };
419 };
415 };
420 };
416 this.dirty = true;
421 this.dirty = true;
417 return this;
422 return this;
418 }
423 }
419
424
420
425
421 Notebook.prototype.move_cell_down = function (index) {
426 Notebook.prototype.move_cell_down = function (index) {
422 var i = index || this.selected_index();
427 var i = index || this.selected_index();
423 if (i !== null && i < (this.ncells()-1) && i >= 0) {
428 if (i !== null && i < (this.ncells()-1) && i >= 0) {
424 var pivot = this.cell_elements().eq(i+1)
429 var pivot = this.cell_elements().eq(i+1)
425 var tomove = this.cell_elements().eq(i)
430 var tomove = this.cell_elements().eq(i)
426 if (pivot !== null && tomove !== null) {
431 if (pivot !== null && tomove !== null) {
427 tomove.detach();
432 tomove.detach();
428 pivot.after(tomove);
433 pivot.after(tomove);
429 this.select(i+1);
434 this.select(i+1);
430 };
435 };
431 };
436 };
432 this.dirty = true;
437 this.dirty = true;
433 return this;
438 return this;
434 }
439 }
435
440
436
441
437 Notebook.prototype.sort_cells = function () {
442 Notebook.prototype.sort_cells = function () {
438 var ncells = this.ncells();
443 var ncells = this.ncells();
439 var sindex = this.selected_index();
444 var sindex = this.selected_index();
440 var swapped;
445 var swapped;
441 do {
446 do {
442 swapped = false
447 swapped = false
443 for (var i=1; i<ncells; i++) {
448 for (var i=1; i<ncells; i++) {
444 current = this.cell_elements().eq(i).data("cell");
449 current = this.cell_elements().eq(i).data("cell");
445 previous = this.cell_elements().eq(i-1).data("cell");
450 previous = this.cell_elements().eq(i-1).data("cell");
446 if (previous.input_prompt_number > current.input_prompt_number) {
451 if (previous.input_prompt_number > current.input_prompt_number) {
447 this.move_cell_up(i);
452 this.move_cell_up(i);
448 swapped = true;
453 swapped = true;
449 };
454 };
450 };
455 };
451 } while (swapped);
456 } while (swapped);
452 this.select(sindex);
457 this.select(sindex);
453 return this;
458 return this;
454 };
459 };
455
460
456
461
457 Notebook.prototype.insert_code_cell_above = function (index) {
462 Notebook.prototype.insert_code_cell_above = function (index) {
458 // TODO: Bounds check for i
463 // TODO: Bounds check for i
459 var i = this.index_or_selected(index);
464 var i = this.index_or_selected(index);
460 var cell = new IPython.CodeCell(this);
465 var cell = new IPython.CodeCell(this);
461 cell.set_input_prompt();
466 cell.set_input_prompt();
462 this.insert_cell_above(cell, i);
467 this.insert_cell_above(cell, i);
463 this.select(this.find_cell_index(cell));
468 this.select(this.find_cell_index(cell));
464 return cell;
469 return cell;
465 }
470 }
466
471
467
472
468 Notebook.prototype.insert_code_cell_below = function (index) {
473 Notebook.prototype.insert_code_cell_below = function (index) {
469 // TODO: Bounds check for i
474 // TODO: Bounds check for i
470 var i = this.index_or_selected(index);
475 var i = this.index_or_selected(index);
471 var cell = new IPython.CodeCell(this);
476 var cell = new IPython.CodeCell(this);
472 cell.set_input_prompt();
477 cell.set_input_prompt();
473 this.insert_cell_below(cell, i);
478 this.insert_cell_below(cell, i);
474 this.select(this.find_cell_index(cell));
479 this.select(this.find_cell_index(cell));
475 return cell;
480 return cell;
476 }
481 }
477
482
478
483
479 Notebook.prototype.insert_html_cell_above = function (index) {
484 Notebook.prototype.insert_html_cell_above = function (index) {
480 // TODO: Bounds check for i
485 // TODO: Bounds check for i
481 var i = this.index_or_selected(index);
486 var i = this.index_or_selected(index);
482 var cell = new IPython.HTMLCell(this);
487 var cell = new IPython.HTMLCell(this);
483 cell.config_mathjax();
488 cell.config_mathjax();
484 this.insert_cell_above(cell, i);
489 this.insert_cell_above(cell, i);
485 this.select(this.find_cell_index(cell));
490 this.select(this.find_cell_index(cell));
486 return cell;
491 return cell;
487 }
492 }
488
493
489
494
490 Notebook.prototype.insert_html_cell_below = function (index) {
495 Notebook.prototype.insert_html_cell_below = function (index) {
491 // TODO: Bounds check for i
496 // TODO: Bounds check for i
492 var i = this.index_or_selected(index);
497 var i = this.index_or_selected(index);
493 var cell = new IPython.HTMLCell(this);
498 var cell = new IPython.HTMLCell(this);
494 cell.config_mathjax();
499 cell.config_mathjax();
495 this.insert_cell_below(cell, i);
500 this.insert_cell_below(cell, i);
496 this.select(this.find_cell_index(cell));
501 this.select(this.find_cell_index(cell));
497 return cell;
502 return cell;
498 }
503 }
499
504
500
505
501 Notebook.prototype.insert_markdown_cell_above = function (index) {
506 Notebook.prototype.insert_markdown_cell_above = function (index) {
502 // TODO: Bounds check for i
507 // TODO: Bounds check for i
503 var i = this.index_or_selected(index);
508 var i = this.index_or_selected(index);
504 var cell = new IPython.MarkdownCell(this);
509 var cell = new IPython.MarkdownCell(this);
505 cell.config_mathjax();
510 cell.config_mathjax();
506 this.insert_cell_above(cell, i);
511 this.insert_cell_above(cell, i);
507 this.select(this.find_cell_index(cell));
512 this.select(this.find_cell_index(cell));
508 return cell;
513 return cell;
509 }
514 }
510
515
511
516
512 Notebook.prototype.insert_markdown_cell_below = function (index) {
517 Notebook.prototype.insert_markdown_cell_below = function (index) {
513 // TODO: Bounds check for i
518 // TODO: Bounds check for i
514 var i = this.index_or_selected(index);
519 var i = this.index_or_selected(index);
515 var cell = new IPython.MarkdownCell(this);
520 var cell = new IPython.MarkdownCell(this);
516 cell.config_mathjax();
521 cell.config_mathjax();
517 this.insert_cell_below(cell, i);
522 this.insert_cell_below(cell, i);
518 this.select(this.find_cell_index(cell));
523 this.select(this.find_cell_index(cell));
519 return cell;
524 return cell;
520 }
525 }
521
526
522
527
523 Notebook.prototype.to_code = function (index) {
528 Notebook.prototype.to_code = function (index) {
524 // TODO: Bounds check for i
529 // TODO: Bounds check for i
525 var i = this.index_or_selected(index);
530 var i = this.index_or_selected(index);
526 var source_element = this.cell_elements().eq(i);
531 var source_element = this.cell_elements().eq(i);
527 var source_cell = source_element.data("cell");
532 var source_cell = source_element.data("cell");
528 if (source_cell instanceof IPython.HTMLCell ||
533 if (source_cell instanceof IPython.HTMLCell ||
529 source_cell instanceof IPython.MarkdownCell) {
534 source_cell instanceof IPython.MarkdownCell) {
530 this.insert_code_cell_below(i);
535 this.insert_code_cell_below(i);
531 var target_cell = this.cells()[i+1];
536 var target_cell = this.cells()[i+1];
532 target_cell.set_code(source_cell.get_source());
537 target_cell.set_code(source_cell.get_source());
533 source_element.remove();
538 source_element.remove();
534 target_cell.select();
539 target_cell.select();
535 };
540 };
536 this.dirty = true;
541 this.dirty = true;
537 };
542 };
538
543
539
544
540 Notebook.prototype.to_markdown = function (index) {
545 Notebook.prototype.to_markdown = function (index) {
541 // TODO: Bounds check for i
546 // TODO: Bounds check for i
542 var i = this.index_or_selected(index);
547 var i = this.index_or_selected(index);
543 var source_element = this.cell_elements().eq(i);
548 var source_element = this.cell_elements().eq(i);
544 var source_cell = source_element.data("cell");
549 var source_cell = source_element.data("cell");
545 var target_cell = null;
550 var target_cell = null;
546 if (source_cell instanceof IPython.CodeCell) {
551 if (source_cell instanceof IPython.CodeCell) {
547 this.insert_markdown_cell_below(i);
552 this.insert_markdown_cell_below(i);
548 var target_cell = this.cells()[i+1];
553 var target_cell = this.cells()[i+1];
549 var text = source_cell.get_code();
554 var text = source_cell.get_code();
550 } else if (source_cell instanceof IPython.HTMLCell) {
555 } else if (source_cell instanceof IPython.HTMLCell) {
551 this.insert_markdown_cell_below(i);
556 this.insert_markdown_cell_below(i);
552 var target_cell = this.cells()[i+1];
557 var target_cell = this.cells()[i+1];
553 var text = source_cell.get_source();
558 var text = source_cell.get_source();
554 if (text === source_cell.placeholder) {
559 if (text === source_cell.placeholder) {
555 text = target_cell.placeholder;
560 text = target_cell.placeholder;
556 }
561 }
557 }
562 }
558 if (target_cell !== null) {
563 if (target_cell !== null) {
559 if (text === "") {text = target_cell.placeholder;};
564 if (text === "") {text = target_cell.placeholder;};
560 target_cell.set_source(text);
565 target_cell.set_source(text);
561 source_element.remove();
566 source_element.remove();
562 target_cell.edit();
567 target_cell.edit();
563 }
568 }
564 this.dirty = true;
569 this.dirty = true;
565 };
570 };
566
571
567
572
568 Notebook.prototype.to_html = function (index) {
573 Notebook.prototype.to_html = function (index) {
569 // TODO: Bounds check for i
574 // TODO: Bounds check for i
570 var i = this.index_or_selected(index);
575 var i = this.index_or_selected(index);
571 var source_element = this.cell_elements().eq(i);
576 var source_element = this.cell_elements().eq(i);
572 var source_cell = source_element.data("cell");
577 var source_cell = source_element.data("cell");
573 var target_cell = null;
578 var target_cell = null;
574 if (source_cell instanceof IPython.CodeCell) {
579 if (source_cell instanceof IPython.CodeCell) {
575 this.insert_html_cell_below(i);
580 this.insert_html_cell_below(i);
576 var target_cell = this.cells()[i+1];
581 var target_cell = this.cells()[i+1];
577 var text = source_cell.get_code();
582 var text = source_cell.get_code();
578 } else if (source_cell instanceof IPython.MarkdownCell) {
583 } else if (source_cell instanceof IPython.MarkdownCell) {
579 this.insert_html_cell_below(i);
584 this.insert_html_cell_below(i);
580 var target_cell = this.cells()[i+1];
585 var target_cell = this.cells()[i+1];
581 var text = source_cell.get_source();
586 var text = source_cell.get_source();
582 if (text === source_cell.placeholder) {
587 if (text === source_cell.placeholder) {
583 text = target_cell.placeholder;
588 text = target_cell.placeholder;
584 }
589 }
585 }
590 }
586 if (target_cell !== null) {
591 if (target_cell !== null) {
587 if (text === "") {text = target_cell.placeholder;};
592 if (text === "") {text = target_cell.placeholder;};
588 target_cell.set_source(text);
593 target_cell.set_source(text);
589 source_element.remove();
594 source_element.remove();
590 target_cell.edit();
595 target_cell.edit();
591 }
596 }
592 this.dirty = true;
597 this.dirty = true;
593 };
598 };
594
599
595
600
596 // Cell collapsing and output clearing
601 // Cell collapsing and output clearing
597
602
598 Notebook.prototype.collapse = function (index) {
603 Notebook.prototype.collapse = function (index) {
599 var i = this.index_or_selected(index);
604 var i = this.index_or_selected(index);
600 this.cells()[i].collapse();
605 this.cells()[i].collapse();
601 this.dirty = true;
606 this.dirty = true;
602 };
607 };
603
608
604
609
605 Notebook.prototype.expand = function (index) {
610 Notebook.prototype.expand = function (index) {
606 var i = this.index_or_selected(index);
611 var i = this.index_or_selected(index);
607 this.cells()[i].expand();
612 this.cells()[i].expand();
608 this.dirty = true;
613 this.dirty = true;
609 };
614 };
610
615
611
616
612 Notebook.prototype.toggle_output = function (index) {
617 Notebook.prototype.toggle_output = function (index) {
613 var i = this.index_or_selected(index);
618 var i = this.index_or_selected(index);
614 this.cells()[i].toggle_output();
619 this.cells()[i].toggle_output();
615 this.dirty = true;
620 this.dirty = true;
616 };
621 };
617
622
618
623
619 Notebook.prototype.set_autoindent = function (state) {
624 Notebook.prototype.set_autoindent = function (state) {
620 var cells = this.cells();
625 var cells = this.cells();
621 len = cells.length;
626 len = cells.length;
622 for (var i=0; i<len; i++) {
627 for (var i=0; i<len; i++) {
623 cells[i].set_autoindent(state)
628 cells[i].set_autoindent(state)
624 };
629 };
625 };
630 };
626
631
627
632
628 Notebook.prototype.clear_all_output = function () {
633 Notebook.prototype.clear_all_output = function () {
629 var ncells = this.ncells();
634 var ncells = this.ncells();
630 var cells = this.cells();
635 var cells = this.cells();
631 for (var i=0; i<ncells; i++) {
636 for (var i=0; i<ncells; i++) {
632 if (cells[i] instanceof IPython.CodeCell) {
637 if (cells[i] instanceof IPython.CodeCell) {
633 cells[i].clear_output(true,true,true);
638 cells[i].clear_output(true,true,true);
634 }
639 }
635 };
640 };
636 this.dirty = true;
641 this.dirty = true;
637 };
642 };
638
643
639 // Other cell functions: line numbers, ...
644 // Other cell functions: line numbers, ...
640
645
641 Notebook.prototype.cell_toggle_line_numbers = function() {
646 Notebook.prototype.cell_toggle_line_numbers = function() {
642 this.selected_cell().toggle_line_numbers()
647 this.selected_cell().toggle_line_numbers()
643 };
648 };
644
649
645 // Kernel related things
650 // Kernel related things
646
651
647 Notebook.prototype.start_kernel = function () {
652 Notebook.prototype.start_kernel = function () {
648 this.kernel = new IPython.Kernel();
653 this.kernel = new IPython.Kernel();
649 var notebook_id = IPython.save_widget.get_notebook_id();
654 var notebook_id = IPython.save_widget.get_notebook_id();
650 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
655 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
651 };
656 };
652
657
653
658
654 Notebook.prototype.restart_kernel = function () {
659 Notebook.prototype.restart_kernel = function () {
655 var that = this;
660 var that = this;
656 var notebook_id = IPython.save_widget.get_notebook_id();
661 var notebook_id = IPython.save_widget.get_notebook_id();
657
662
658 var dialog = $('<div/>');
663 var dialog = $('<div/>');
659 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
664 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
660 $(document).append(dialog);
665 $(document).append(dialog);
661 dialog.dialog({
666 dialog.dialog({
662 resizable: false,
667 resizable: false,
663 modal: true,
668 modal: true,
664 title: "Restart kernel or continue running?",
669 title: "Restart kernel or continue running?",
665 buttons : {
670 buttons : {
666 "Restart": function () {
671 "Restart": function () {
667 that.kernel.restart($.proxy(that.kernel_started, that));
672 that.kernel.restart($.proxy(that.kernel_started, that));
668 $(this).dialog('close');
673 $(this).dialog('close');
669 },
674 },
670 "Continue running": function () {
675 "Continue running": function () {
671 $(this).dialog('close');
676 $(this).dialog('close');
672 }
677 }
673 }
678 }
674 });
679 });
675 };
680 };
676
681
677
682
678 Notebook.prototype.kernel_started = function () {
683 Notebook.prototype.kernel_started = function () {
679 console.log("Kernel started: ", this.kernel.kernel_id);
684 console.log("Kernel started: ", this.kernel.kernel_id);
680 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
685 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
681 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
686 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
682 };
687 };
683
688
684
689
685 Notebook.prototype.handle_shell_reply = function (e) {
690 Notebook.prototype.handle_shell_reply = function (e) {
686 reply = $.parseJSON(e.data);
691 reply = $.parseJSON(e.data);
687 var header = reply.header;
692 var header = reply.header;
688 var content = reply.content;
693 var content = reply.content;
689 var msg_type = header.msg_type;
694 var msg_type = header.msg_type;
690 // console.log(reply);
695 // console.log(reply);
691 var cell = this.cell_for_msg(reply.parent_header.msg_id);
696 var cell = this.cell_for_msg(reply.parent_header.msg_id);
692 if (msg_type === "execute_reply") {
697 if (msg_type === "execute_reply") {
693 cell.set_input_prompt(content.execution_count);
698 cell.set_input_prompt(content.execution_count);
694 cell.element.removeClass("running");
699 cell.element.removeClass("running");
695 this.dirty = true;
700 this.dirty = true;
696 } else if (msg_type === "complete_reply") {
701 } else if (msg_type === "complete_reply") {
697 cell.finish_completing(content.matched_text, content.matches);
702 cell.finish_completing(content.matched_text, content.matches);
698 };
703 };
699 var payload = content.payload || [];
704 var payload = content.payload || [];
700 this.handle_payload(cell, payload);
705 this.handle_payload(cell, payload);
701 };
706 };
702
707
703
708
704 Notebook.prototype.handle_payload = function (cell, payload) {
709 Notebook.prototype.handle_payload = function (cell, payload) {
705 var l = payload.length;
710 var l = payload.length;
706 for (var i=0; i<l; i++) {
711 for (var i=0; i<l; i++) {
707 if (payload[i].source === 'IPython.zmq.page.page') {
712 if (payload[i].source === 'IPython.zmq.page.page') {
708 if (payload[i].text.trim() !== '') {
713 if (payload[i].text.trim() !== '') {
709 IPython.pager.clear();
714 IPython.pager.clear();
710 IPython.pager.expand();
715 IPython.pager.expand();
711 IPython.pager.append_text(payload[i].text);
716 IPython.pager.append_text(payload[i].text);
712 }
717 }
713 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
718 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
714 var index = this.find_cell_index(cell);
719 var index = this.find_cell_index(cell);
715 var new_cell = this.insert_code_cell_below(index);
720 var new_cell = this.insert_code_cell_below(index);
716 new_cell.set_code(payload[i].text);
721 new_cell.set_code(payload[i].text);
717 this.dirty = true;
722 this.dirty = true;
718 }
723 }
719 };
724 };
720 };
725 };
721
726
722
727
723 Notebook.prototype.handle_iopub_reply = function (e) {
728 Notebook.prototype.handle_iopub_reply = function (e) {
724 reply = $.parseJSON(e.data);
729 reply = $.parseJSON(e.data);
725 var content = reply.content;
730 var content = reply.content;
726 // console.log(reply);
731 // console.log(reply);
727 var msg_type = reply.header.msg_type;
732 var msg_type = reply.header.msg_type;
728 var cell = this.cell_for_msg(reply.parent_header.msg_id);
733 var cell = this.cell_for_msg(reply.parent_header.msg_id);
729 var output_types = ['stream','display_data','pyout','pyerr'];
734 var output_types = ['stream','display_data','pyout','pyerr'];
730 if (output_types.indexOf(msg_type) >= 0) {
735 if (output_types.indexOf(msg_type) >= 0) {
731 this.handle_output(cell, msg_type, content);
736 this.handle_output(cell, msg_type, content);
732 } else if (msg_type === 'status') {
737 } else if (msg_type === 'status') {
733 if (content.execution_state === 'busy') {
738 if (content.execution_state === 'busy') {
734 IPython.kernel_status_widget.status_busy();
739 IPython.kernel_status_widget.status_busy();
735 } else if (content.execution_state === 'idle') {
740 } else if (content.execution_state === 'idle') {
736 IPython.kernel_status_widget.status_idle();
741 IPython.kernel_status_widget.status_idle();
737 } else if (content.execution_state === 'dead') {
742 } else if (content.execution_state === 'dead') {
738 this.handle_status_dead();
743 this.handle_status_dead();
739 };
744 };
740 } else if (msg_type === 'clear_output') {
745 } else if (msg_type === 'clear_output') {
741 cell.clear_output(content.stdout, content.stderr, content.other);
746 cell.clear_output(content.stdout, content.stderr, content.other);
742 };
747 };
743 };
748 };
744
749
745
750
746 Notebook.prototype.handle_status_dead = function () {
751 Notebook.prototype.handle_status_dead = function () {
747 var that = this;
752 var that = this;
748 this.kernel.stop_channels();
753 this.kernel.stop_channels();
749 var dialog = $('<div/>');
754 var dialog = $('<div/>');
750 dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.');
755 dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.');
751 $(document).append(dialog);
756 $(document).append(dialog);
752 dialog.dialog({
757 dialog.dialog({
753 resizable: false,
758 resizable: false,
754 modal: true,
759 modal: true,
755 title: "Dead kernel",
760 title: "Dead kernel",
756 buttons : {
761 buttons : {
757 "Restart": function () {
762 "Restart": function () {
758 that.start_kernel();
763 that.start_kernel();
759 $(this).dialog('close');
764 $(this).dialog('close');
760 },
765 },
761 "Continue running": function () {
766 "Continue running": function () {
762 $(this).dialog('close');
767 $(this).dialog('close');
763 }
768 }
764 }
769 }
765 });
770 });
766 };
771 };
767
772
768
773
769 Notebook.prototype.handle_output = function (cell, msg_type, content) {
774 Notebook.prototype.handle_output = function (cell, msg_type, content) {
770 var json = {};
775 var json = {};
771 json.output_type = msg_type;
776 json.output_type = msg_type;
772 if (msg_type === "stream") {
777 if (msg_type === "stream") {
773 json.text = utils.fixConsole(content.data);
778 json.text = utils.fixConsole(content.data);
774 json.stream = content.name;
779 json.stream = content.name;
775 } else if (msg_type === "display_data") {
780 } else if (msg_type === "display_data") {
776 json = this.convert_mime_types(json, content.data);
781 json = this.convert_mime_types(json, content.data);
777 } else if (msg_type === "pyout") {
782 } else if (msg_type === "pyout") {
778 json.prompt_number = content.execution_count;
783 json.prompt_number = content.execution_count;
779 json = this.convert_mime_types(json, content.data);
784 json = this.convert_mime_types(json, content.data);
780 } else if (msg_type === "pyerr") {
785 } else if (msg_type === "pyerr") {
781 json.ename = content.ename;
786 json.ename = content.ename;
782 json.evalue = content.evalue;
787 json.evalue = content.evalue;
783 var traceback = [];
788 var traceback = [];
784 for (var i=0; i<content.traceback.length; i++) {
789 for (var i=0; i<content.traceback.length; i++) {
785 traceback.push(utils.fixConsole(content.traceback[i]));
790 traceback.push(utils.fixConsole(content.traceback[i]));
786 }
791 }
787 json.traceback = traceback;
792 json.traceback = traceback;
788 };
793 };
789 cell.append_output(json);
794 cell.append_output(json);
790 this.dirty = true;
795 this.dirty = true;
791 };
796 };
792
797
793
798
794 Notebook.prototype.convert_mime_types = function (json, data) {
799 Notebook.prototype.convert_mime_types = function (json, data) {
795 if (data['text/plain'] !== undefined) {
800 if (data['text/plain'] !== undefined) {
796 json.text = utils.fixConsole(data['text/plain']);
801 json.text = utils.fixConsole(data['text/plain']);
797 };
802 };
798 if (data['text/html'] !== undefined) {
803 if (data['text/html'] !== undefined) {
799 json.html = data['text/html'];
804 json.html = data['text/html'];
800 };
805 };
801 if (data['image/svg+xml'] !== undefined) {
806 if (data['image/svg+xml'] !== undefined) {
802 json.svg = data['image/svg+xml'];
807 json.svg = data['image/svg+xml'];
803 };
808 };
804 if (data['image/png'] !== undefined) {
809 if (data['image/png'] !== undefined) {
805 json.png = data['image/png'];
810 json.png = data['image/png'];
806 };
811 };
807 if (data['image/jpeg'] !== undefined) {
812 if (data['image/jpeg'] !== undefined) {
808 json.jpeg = data['image/jpeg'];
813 json.jpeg = data['image/jpeg'];
809 };
814 };
810 if (data['text/latex'] !== undefined) {
815 if (data['text/latex'] !== undefined) {
811 json.latex = data['text/latex'];
816 json.latex = data['text/latex'];
812 };
817 };
813 if (data['application/json'] !== undefined) {
818 if (data['application/json'] !== undefined) {
814 json.json = data['application/json'];
819 json.json = data['application/json'];
815 };
820 };
816 if (data['application/javascript'] !== undefined) {
821 if (data['application/javascript'] !== undefined) {
817 json.javascript = data['application/javascript'];
822 json.javascript = data['application/javascript'];
818 }
823 }
819 return json;
824 return json;
820 };
825 };
821
826
822
827
823 Notebook.prototype.execute_selected_cell = function (options) {
828 Notebook.prototype.execute_selected_cell = function (options) {
824 // add_new: should a new cell be added if we are at the end of the nb
829 // add_new: should a new cell be added if we are at the end of the nb
825 // terminal: execute in terminal mode, which stays in the current cell
830 // terminal: execute in terminal mode, which stays in the current cell
826 default_options = {terminal: false, add_new: true}
831 default_options = {terminal: false, add_new: true}
827 $.extend(default_options, options)
832 $.extend(default_options, options)
828 var that = this;
833 var that = this;
829 var cell = that.selected_cell();
834 var cell = that.selected_cell();
830 var cell_index = that.find_cell_index(cell);
835 var cell_index = that.find_cell_index(cell);
831 if (cell instanceof IPython.CodeCell) {
836 if (cell instanceof IPython.CodeCell) {
832 cell.clear_output(true, true, true);
837 cell.clear_output(true, true, true);
833 cell.set_input_prompt('*');
838 cell.set_input_prompt('*');
834 cell.element.addClass("running");
839 cell.element.addClass("running");
835 var code = cell.get_code();
840 var code = cell.get_code();
836 var msg_id = that.kernel.execute(cell.get_code());
841 var msg_id = that.kernel.execute(cell.get_code());
837 that.msg_cell_map[msg_id] = cell.cell_id;
842 that.msg_cell_map[msg_id] = cell.cell_id;
838 } else if (cell instanceof IPython.HTMLCell) {
843 } else if (cell instanceof IPython.HTMLCell) {
839 cell.render();
844 cell.render();
840 }
845 }
841 if (default_options.terminal) {
846 if (default_options.terminal) {
842 cell.select_all();
847 cell.select_all();
843 } else {
848 } else {
844 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
849 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
845 that.insert_code_cell_below();
850 that.insert_code_cell_below();
846 // If we are adding a new cell at the end, scroll down to show it.
851 // If we are adding a new cell at the end, scroll down to show it.
847 that.scroll_to_bottom();
852 that.scroll_to_bottom();
848 } else {
853 } else {
849 that.select(cell_index+1);
854 that.select(cell_index+1);
850 };
855 };
851 };
856 };
852 this.dirty = true;
857 this.dirty = true;
853 };
858 };
854
859
855
860
856 Notebook.prototype.execute_all_cells = function () {
861 Notebook.prototype.execute_all_cells = function () {
857 var ncells = this.ncells();
862 var ncells = this.ncells();
858 for (var i=0; i<ncells; i++) {
863 for (var i=0; i<ncells; i++) {
859 this.select(i);
864 this.select(i);
860 this.execute_selected_cell({add_new:false});
865 this.execute_selected_cell({add_new:false});
861 };
866 };
862 this.scroll_to_bottom();
867 this.scroll_to_bottom();
863 };
868 };
864
869
865
870
866 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
871 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
867 var msg_id = this.kernel.complete(line, cursor_pos);
872 var msg_id = this.kernel.complete(line, cursor_pos);
868 this.msg_cell_map[msg_id] = cell.cell_id;
873 this.msg_cell_map[msg_id] = cell.cell_id;
869 };
874 };
870
875
871 // Persistance and loading
876 // Persistance and loading
872
877
873
878
874 Notebook.prototype.fromJSON = function (data) {
879 Notebook.prototype.fromJSON = function (data) {
875 var ncells = this.ncells();
880 var ncells = this.ncells();
876 for (var i=0; i<ncells; i++) {
881 for (var i=0; i<ncells; i++) {
877 // Always delete cell 0 as they get renumbered as they are deleted.
882 // Always delete cell 0 as they get renumbered as they are deleted.
878 this.delete_cell(0);
883 this.delete_cell(0);
879 };
884 };
880 // Save the metadata
885 // Save the metadata
881 this.metadata = data.metadata;
886 this.metadata = data.metadata;
882 // Only handle 1 worksheet for now.
887 // Only handle 1 worksheet for now.
883 var worksheet = data.worksheets[0];
888 var worksheet = data.worksheets[0];
884 if (worksheet !== undefined) {
889 if (worksheet !== undefined) {
885 var new_cells = worksheet.cells;
890 var new_cells = worksheet.cells;
886 ncells = new_cells.length;
891 ncells = new_cells.length;
887 var cell_data = null;
892 var cell_data = null;
888 var new_cell = null;
893 var new_cell = null;
889 for (var i=0; i<ncells; i++) {
894 for (var i=0; i<ncells; i++) {
890 cell_data = new_cells[i];
895 cell_data = new_cells[i];
891 if (cell_data.cell_type == 'code') {
896 if (cell_data.cell_type == 'code') {
892 new_cell = this.insert_code_cell_below();
897 new_cell = this.insert_code_cell_below();
893 new_cell.fromJSON(cell_data);
898 new_cell.fromJSON(cell_data);
894 } else if (cell_data.cell_type === 'html') {
899 } else if (cell_data.cell_type === 'html') {
895 new_cell = this.insert_html_cell_below();
900 new_cell = this.insert_html_cell_below();
896 new_cell.fromJSON(cell_data);
901 new_cell.fromJSON(cell_data);
897 } else if (cell_data.cell_type === 'markdown') {
902 } else if (cell_data.cell_type === 'markdown') {
898 new_cell = this.insert_markdown_cell_below();
903 new_cell = this.insert_markdown_cell_below();
899 new_cell.fromJSON(cell_data);
904 new_cell.fromJSON(cell_data);
900 };
905 };
901 };
906 };
902 };
907 };
903 };
908 };
904
909
905
910
906 Notebook.prototype.toJSON = function () {
911 Notebook.prototype.toJSON = function () {
907 var cells = this.cells();
912 var cells = this.cells();
908 var ncells = cells.length;
913 var ncells = cells.length;
909 cell_array = new Array(ncells);
914 cell_array = new Array(ncells);
910 for (var i=0; i<ncells; i++) {
915 for (var i=0; i<ncells; i++) {
911 cell_array[i] = cells[i].toJSON();
916 cell_array[i] = cells[i].toJSON();
912 };
917 };
913 data = {
918 data = {
914 // Only handle 1 worksheet for now.
919 // Only handle 1 worksheet for now.
915 worksheets : [{cells:cell_array}],
920 worksheets : [{cells:cell_array}],
916 metadata : this.metadata
921 metadata : this.metadata
917 }
922 }
918 return data
923 return data
919 };
924 };
920
925
921 Notebook.prototype.save_notebook = function () {
926 Notebook.prototype.save_notebook = function () {
922 if (IPython.save_widget.test_notebook_name()) {
927 if (IPython.save_widget.test_notebook_name()) {
923 var notebook_id = IPython.save_widget.get_notebook_id();
928 var notebook_id = IPython.save_widget.get_notebook_id();
924 var nbname = IPython.save_widget.get_notebook_name();
929 var nbname = IPython.save_widget.get_notebook_name();
925 // We may want to move the name/id/nbformat logic inside toJSON?
930 // We may want to move the name/id/nbformat logic inside toJSON?
926 var data = this.toJSON();
931 var data = this.toJSON();
927 data.metadata.name = nbname;
932 data.metadata.name = nbname;
928 data.nbformat = 2;
933 data.nbformat = 2;
929 // We do the call with settings so we can set cache to false.
934 // We do the call with settings so we can set cache to false.
930 var settings = {
935 var settings = {
931 processData : false,
936 processData : false,
932 cache : false,
937 cache : false,
933 type : "PUT",
938 type : "PUT",
934 data : JSON.stringify(data),
939 data : JSON.stringify(data),
935 headers : {'Content-Type': 'application/json'},
940 headers : {'Content-Type': 'application/json'},
936 success : $.proxy(this.notebook_saved,this),
941 success : $.proxy(this.notebook_saved,this),
937 error : $.proxy(this.notebook_save_failed,this)
942 error : $.proxy(this.notebook_save_failed,this)
938 };
943 };
939 IPython.save_widget.status_saving();
944 IPython.save_widget.status_saving();
940 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id
945 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id
941 $.ajax(url, settings);
946 $.ajax(url, settings);
942 };
947 };
943 };
948 };
944
949
945
950
946 Notebook.prototype.notebook_saved = function (data, status, xhr) {
951 Notebook.prototype.notebook_saved = function (data, status, xhr) {
947 this.dirty = false;
952 this.dirty = false;
948 IPython.save_widget.notebook_saved();
953 IPython.save_widget.notebook_saved();
949 IPython.save_widget.status_save();
954 IPython.save_widget.status_save();
950 }
955 }
951
956
952
957
953 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
958 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
954 // Notify the user and reset the save button
959 // Notify the user and reset the save button
955 // TODO: Handle different types of errors (timeout etc.)
960 // TODO: Handle different types of errors (timeout etc.)
956 alert('An unexpected error occured while saving the notebook.');
961 alert('An unexpected error occured while saving the notebook.');
957 IPython.save_widget.reset_status();
962 IPython.save_widget.reset_status();
958 }
963 }
959
964
960
965
961 Notebook.prototype.load_notebook = function (callback) {
966 Notebook.prototype.load_notebook = function (callback) {
962 var that = this;
967 var that = this;
963 var notebook_id = IPython.save_widget.get_notebook_id();
968 var notebook_id = IPython.save_widget.get_notebook_id();
964 // We do the call with settings so we can set cache to false.
969 // We do the call with settings so we can set cache to false.
965 var settings = {
970 var settings = {
966 processData : false,
971 processData : false,
967 cache : false,
972 cache : false,
968 type : "GET",
973 type : "GET",
969 dataType : "json",
974 dataType : "json",
970 success : function (data, status, xhr) {
975 success : function (data, status, xhr) {
971 that.notebook_loaded(data, status, xhr);
976 that.notebook_loaded(data, status, xhr);
972 if (callback !== undefined) {
977 if (callback !== undefined) {
973 callback();
978 callback();
974 };
979 };
975 }
980 }
976 };
981 };
977 IPython.save_widget.status_loading();
982 IPython.save_widget.status_loading();
978 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id
983 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id
979 $.ajax(url, settings);
984 $.ajax(url, settings);
980 }
985 }
981
986
982
987
983 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
988 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
984 var allowed = xhr.getResponseHeader('Allow');
989 var allowed = xhr.getResponseHeader('Allow');
985 this.fromJSON(data);
990 this.fromJSON(data);
986 if (this.ncells() === 0) {
991 if (this.ncells() === 0) {
987 this.insert_code_cell_below();
992 this.insert_code_cell_below();
988 };
993 };
989 IPython.save_widget.status_save();
994 IPython.save_widget.status_save();
990 IPython.save_widget.set_notebook_name(data.metadata.name);
995 IPython.save_widget.set_notebook_name(data.metadata.name);
991 this.dirty = false;
996 this.dirty = false;
992 if (! this.read_only) {
997 if (! this.read_only) {
993 this.start_kernel();
998 this.start_kernel();
994 }
999 }
995 // fromJSON always selects the last cell inserted. We need to wait
1000 // fromJSON always selects the last cell inserted. We need to wait
996 // until that is done before scrolling to the top.
1001 // until that is done before scrolling to the top.
997 setTimeout(function () {
1002 setTimeout(function () {
998 IPython.notebook.select(0);
1003 IPython.notebook.select(0);
999 IPython.notebook.scroll_to_top();
1004 IPython.notebook.scroll_to_top();
1000 }, 50);
1005 }, 50);
1001 };
1006 };
1002
1007
1003 IPython.Notebook = Notebook;
1008 IPython.Notebook = Notebook;
1004
1009
1005
1010
1006 return IPython;
1011 return IPython;
1007
1012
1008 }(IPython));
1013 }(IPython));
1009
1014
General Comments 0
You need to be logged in to leave comments. Login now