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