##// END OF EJS Templates
Added checking for emptiness of cell below.
v923z -
Show More
@@ -1,1295 +1,1295
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notebook
9 // Notebook
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15 var key = IPython.utils.keycodes;
15 var key = IPython.utils.keycodes;
16
16
17 var Notebook = function (selector) {
17 var Notebook = function (selector) {
18 this.read_only = IPython.read_only;
18 this.read_only = IPython.read_only;
19 this.element = $(selector);
19 this.element = $(selector);
20 this.element.scroll();
20 this.element.scroll();
21 this.element.data("notebook", this);
21 this.element.data("notebook", this);
22 this.next_prompt_number = 1;
22 this.next_prompt_number = 1;
23 this.kernel = null;
23 this.kernel = null;
24 this.clipboard = null;
24 this.clipboard = null;
25 this.paste_enabled = false;
25 this.paste_enabled = false;
26 this.dirty = false;
26 this.dirty = false;
27 this.metadata = {};
27 this.metadata = {};
28 // single worksheet for now
28 // single worksheet for now
29 this.worksheet_metadata = {};
29 this.worksheet_metadata = {};
30 this.control_key_active = false;
30 this.control_key_active = false;
31 this.notebook_id = null;
31 this.notebook_id = null;
32 this.notebook_name = null;
32 this.notebook_name = null;
33 this.notebook_name_blacklist_re = /[\/\\:]/;
33 this.notebook_name_blacklist_re = /[\/\\:]/;
34 this.nbformat = 3 // Increment this when changing the nbformat
34 this.nbformat = 3 // Increment this when changing the nbformat
35 this.nbformat_minor = 0 // Increment this when changing the nbformat
35 this.nbformat_minor = 0 // Increment this when changing the nbformat
36 this.style();
36 this.style();
37 this.create_elements();
37 this.create_elements();
38 this.bind_events();
38 this.bind_events();
39 };
39 };
40
40
41
41
42 Notebook.prototype.style = function () {
42 Notebook.prototype.style = function () {
43 $('div#notebook').addClass('border-box-sizing');
43 $('div#notebook').addClass('border-box-sizing');
44 };
44 };
45
45
46
46
47 Notebook.prototype.create_elements = function () {
47 Notebook.prototype.create_elements = function () {
48 // We add this end_space div to the end of the notebook div to:
48 // We add this end_space div to the end of the notebook div to:
49 // i) provide a margin between the last cell and the end of the notebook
49 // i) provide a margin between the last cell and the end of the notebook
50 // ii) to prevent the div from scrolling up when the last cell is being
50 // ii) to prevent the div from scrolling up when the last cell is being
51 // edited, but is too low on the page, which browsers will do automatically.
51 // edited, but is too low on the page, which browsers will do automatically.
52 var that = this;
52 var that = this;
53 var end_space = $('<div/>').addClass('end_space').height("30%");
53 var end_space = $('<div/>').addClass('end_space').height("30%");
54 end_space.dblclick(function (e) {
54 end_space.dblclick(function (e) {
55 if (that.read_only) return;
55 if (that.read_only) return;
56 var ncells = that.ncells();
56 var ncells = that.ncells();
57 that.insert_cell_below('code',ncells-1);
57 that.insert_cell_below('code',ncells-1);
58 });
58 });
59 this.element.append(end_space);
59 this.element.append(end_space);
60 $('div#notebook').addClass('border-box-sizing');
60 $('div#notebook').addClass('border-box-sizing');
61 };
61 };
62
62
63
63
64 Notebook.prototype.bind_events = function () {
64 Notebook.prototype.bind_events = function () {
65 var that = this;
65 var that = this;
66
66
67 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
67 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
68 var index = that.find_cell_index(data.cell);
68 var index = that.find_cell_index(data.cell);
69 var new_cell = that.insert_cell_below('code',index);
69 var new_cell = that.insert_cell_below('code',index);
70 new_cell.set_text(data.text);
70 new_cell.set_text(data.text);
71 that.dirty = true;
71 that.dirty = true;
72 });
72 });
73
73
74 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
74 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
75 that.dirty = data.value;
75 that.dirty = data.value;
76 });
76 });
77
77
78 $([IPython.events]).on('select.Cell', function (event, data) {
78 $([IPython.events]).on('select.Cell', function (event, data) {
79 var index = that.find_cell_index(data.cell);
79 var index = that.find_cell_index(data.cell);
80 that.select(index);
80 that.select(index);
81 });
81 });
82
82
83
83
84 $(document).keydown(function (event) {
84 $(document).keydown(function (event) {
85 // console.log(event);
85 // console.log(event);
86 if (that.read_only) return true;
86 if (that.read_only) return true;
87
87
88 // Save (CTRL+S) or (AppleKey+S)
88 // Save (CTRL+S) or (AppleKey+S)
89 //metaKey = applekey on mac
89 //metaKey = applekey on mac
90 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
90 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
91 that.save_notebook();
91 that.save_notebook();
92 event.preventDefault();
92 event.preventDefault();
93 return false;
93 return false;
94 } else if (event.which === key.ESC) {
94 } else if (event.which === key.ESC) {
95 // Intercept escape at highest level to avoid closing
95 // Intercept escape at highest level to avoid closing
96 // websocket connection with firefox
96 // websocket connection with firefox
97 event.preventDefault();
97 event.preventDefault();
98 } else if (event.which === key.SHIFT) {
98 } else if (event.which === key.SHIFT) {
99 // ignore shift keydown
99 // ignore shift keydown
100 return true;
100 return true;
101 }
101 }
102 if (event.which === key.UPARROW && !event.shiftKey) {
102 if (event.which === key.UPARROW && !event.shiftKey) {
103 var cell = that.get_selected_cell();
103 var cell = that.get_selected_cell();
104 if (cell.at_top()) {
104 if (cell.at_top()) {
105 event.preventDefault();
105 event.preventDefault();
106 that.select_prev();
106 that.select_prev();
107 };
107 };
108 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
108 } else if (event.which === key.DOWNARROW && !event.shiftKey) {
109 var cell = that.get_selected_cell();
109 var cell = that.get_selected_cell();
110 if (cell.at_bottom()) {
110 if (cell.at_bottom()) {
111 event.preventDefault();
111 event.preventDefault();
112 that.select_next();
112 that.select_next();
113 };
113 };
114 } else if (event.which === key.ENTER && event.shiftKey) {
114 } else if (event.which === key.ENTER && event.shiftKey) {
115 that.execute_selected_cell();
115 that.execute_selected_cell();
116 return false;
116 return false;
117 } else if (event.which === key.ENTER && event.altKey) {
117 } else if (event.which === key.ENTER && event.altKey) {
118 // Execute code cell, and insert new in place
118 // Execute code cell, and insert new in place
119 that.execute_selected_cell();
119 that.execute_selected_cell();
120 // Only insert a new cell, if we ended up in an already populated cell
120 // Only insert a new cell, if we ended up in an already populated cell
121 if (that.get_selected_cell().toJSON().input !== "") {
121 if (/\S/.test(that.get_selected_cell().toJSON().input) == true) {
122 that.insert_cell_above('code');
122 that.insert_cell_above('code');
123 }
123 }
124 return false;
124 return false;
125 } else if (event.which === key.ENTER && event.ctrlKey) {
125 } else if (event.which === key.ENTER && event.ctrlKey) {
126 that.execute_selected_cell({terminal:true});
126 that.execute_selected_cell({terminal:true});
127 return false;
127 return false;
128 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
128 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
129 that.control_key_active = true;
129 that.control_key_active = true;
130 return false;
130 return false;
131 } else if (event.which === 88 && that.control_key_active) {
131 } else if (event.which === 88 && that.control_key_active) {
132 // Cut selected cell = x
132 // Cut selected cell = x
133 that.cut_cell();
133 that.cut_cell();
134 that.control_key_active = false;
134 that.control_key_active = false;
135 return false;
135 return false;
136 } else if (event.which === 67 && that.control_key_active) {
136 } else if (event.which === 67 && that.control_key_active) {
137 // Copy selected cell = c
137 // Copy selected cell = c
138 that.copy_cell();
138 that.copy_cell();
139 that.control_key_active = false;
139 that.control_key_active = false;
140 return false;
140 return false;
141 } else if (event.which === 86 && that.control_key_active) {
141 } else if (event.which === 86 && that.control_key_active) {
142 // Paste selected cell = v
142 // Paste selected cell = v
143 that.paste_cell();
143 that.paste_cell();
144 that.control_key_active = false;
144 that.control_key_active = false;
145 return false;
145 return false;
146 } else if (event.which === 68 && that.control_key_active) {
146 } else if (event.which === 68 && that.control_key_active) {
147 // Delete selected cell = d
147 // Delete selected cell = d
148 that.delete_cell();
148 that.delete_cell();
149 that.control_key_active = false;
149 that.control_key_active = false;
150 return false;
150 return false;
151 } else if (event.which === 65 && that.control_key_active) {
151 } else if (event.which === 65 && that.control_key_active) {
152 // Insert code cell above selected = a
152 // Insert code cell above selected = a
153 that.insert_cell_above('code');
153 that.insert_cell_above('code');
154 that.control_key_active = false;
154 that.control_key_active = false;
155 return false;
155 return false;
156 } else if (event.which === 66 && that.control_key_active) {
156 } else if (event.which === 66 && that.control_key_active) {
157 // Insert code cell below selected = b
157 // Insert code cell below selected = b
158 that.insert_cell_below('code');
158 that.insert_cell_below('code');
159 that.control_key_active = false;
159 that.control_key_active = false;
160 return false;
160 return false;
161 } else if (event.which === 89 && that.control_key_active) {
161 } else if (event.which === 89 && that.control_key_active) {
162 // To code = y
162 // To code = y
163 that.to_code();
163 that.to_code();
164 that.control_key_active = false;
164 that.control_key_active = false;
165 return false;
165 return false;
166 } else if (event.which === 77 && that.control_key_active) {
166 } else if (event.which === 77 && that.control_key_active) {
167 // To markdown = m
167 // To markdown = m
168 that.to_markdown();
168 that.to_markdown();
169 that.control_key_active = false;
169 that.control_key_active = false;
170 return false;
170 return false;
171 } else if (event.which === 84 && that.control_key_active) {
171 } else if (event.which === 84 && that.control_key_active) {
172 // To Raw = t
172 // To Raw = t
173 that.to_raw();
173 that.to_raw();
174 that.control_key_active = false;
174 that.control_key_active = false;
175 return false;
175 return false;
176 } else if (event.which === 49 && that.control_key_active) {
176 } else if (event.which === 49 && that.control_key_active) {
177 // To Heading 1 = 1
177 // To Heading 1 = 1
178 that.to_heading(undefined, 1);
178 that.to_heading(undefined, 1);
179 that.control_key_active = false;
179 that.control_key_active = false;
180 return false;
180 return false;
181 } else if (event.which === 50 && that.control_key_active) {
181 } else if (event.which === 50 && that.control_key_active) {
182 // To Heading 2 = 2
182 // To Heading 2 = 2
183 that.to_heading(undefined, 2);
183 that.to_heading(undefined, 2);
184 that.control_key_active = false;
184 that.control_key_active = false;
185 return false;
185 return false;
186 } else if (event.which === 51 && that.control_key_active) {
186 } else if (event.which === 51 && that.control_key_active) {
187 // To Heading 3 = 3
187 // To Heading 3 = 3
188 that.to_heading(undefined, 3);
188 that.to_heading(undefined, 3);
189 that.control_key_active = false;
189 that.control_key_active = false;
190 return false;
190 return false;
191 } else if (event.which === 52 && that.control_key_active) {
191 } else if (event.which === 52 && that.control_key_active) {
192 // To Heading 4 = 4
192 // To Heading 4 = 4
193 that.to_heading(undefined, 4);
193 that.to_heading(undefined, 4);
194 that.control_key_active = false;
194 that.control_key_active = false;
195 return false;
195 return false;
196 } else if (event.which === 53 && that.control_key_active) {
196 } else if (event.which === 53 && that.control_key_active) {
197 // To Heading 5 = 5
197 // To Heading 5 = 5
198 that.to_heading(undefined, 5);
198 that.to_heading(undefined, 5);
199 that.control_key_active = false;
199 that.control_key_active = false;
200 return false;
200 return false;
201 } else if (event.which === 54 && that.control_key_active) {
201 } else if (event.which === 54 && that.control_key_active) {
202 // To Heading 6 = 6
202 // To Heading 6 = 6
203 that.to_heading(undefined, 6);
203 that.to_heading(undefined, 6);
204 that.control_key_active = false;
204 that.control_key_active = false;
205 return false;
205 return false;
206 } else if (event.which === 79 && that.control_key_active) {
206 } else if (event.which === 79 && that.control_key_active) {
207 // Toggle output = o
207 // Toggle output = o
208 if (event.shiftKey){
208 if (event.shiftKey){
209 that.toggle_output_scroll();
209 that.toggle_output_scroll();
210 } else {
210 } else {
211 that.toggle_output();
211 that.toggle_output();
212 }
212 }
213 that.control_key_active = false;
213 that.control_key_active = false;
214 return false;
214 return false;
215 } else if (event.which === 83 && that.control_key_active) {
215 } else if (event.which === 83 && that.control_key_active) {
216 // Save notebook = s
216 // Save notebook = s
217 that.save_notebook();
217 that.save_notebook();
218 that.control_key_active = false;
218 that.control_key_active = false;
219 return false;
219 return false;
220 } else if (event.which === 74 && that.control_key_active) {
220 } else if (event.which === 74 && that.control_key_active) {
221 // Move cell down = j
221 // Move cell down = j
222 that.move_cell_down();
222 that.move_cell_down();
223 that.control_key_active = false;
223 that.control_key_active = false;
224 return false;
224 return false;
225 } else if (event.which === 75 && that.control_key_active) {
225 } else if (event.which === 75 && that.control_key_active) {
226 // Move cell up = k
226 // Move cell up = k
227 that.move_cell_up();
227 that.move_cell_up();
228 that.control_key_active = false;
228 that.control_key_active = false;
229 return false;
229 return false;
230 } else if (event.which === 80 && that.control_key_active) {
230 } else if (event.which === 80 && that.control_key_active) {
231 // Select previous = p
231 // Select previous = p
232 that.select_prev();
232 that.select_prev();
233 that.control_key_active = false;
233 that.control_key_active = false;
234 return false;
234 return false;
235 } else if (event.which === 78 && that.control_key_active) {
235 } else if (event.which === 78 && that.control_key_active) {
236 // Select next = n
236 // Select next = n
237 that.select_next();
237 that.select_next();
238 that.control_key_active = false;
238 that.control_key_active = false;
239 return false;
239 return false;
240 } else if (event.which === 76 && that.control_key_active) {
240 } else if (event.which === 76 && that.control_key_active) {
241 // Toggle line numbers = l
241 // Toggle line numbers = l
242 that.cell_toggle_line_numbers();
242 that.cell_toggle_line_numbers();
243 that.control_key_active = false;
243 that.control_key_active = false;
244 return false;
244 return false;
245 } else if (event.which === 73 && that.control_key_active) {
245 } else if (event.which === 73 && that.control_key_active) {
246 // Interrupt kernel = i
246 // Interrupt kernel = i
247 that.kernel.interrupt();
247 that.kernel.interrupt();
248 that.control_key_active = false;
248 that.control_key_active = false;
249 return false;
249 return false;
250 } else if (event.which === 190 && that.control_key_active) {
250 } else if (event.which === 190 && that.control_key_active) {
251 // Restart kernel = . # matches qt console
251 // Restart kernel = . # matches qt console
252 that.restart_kernel();
252 that.restart_kernel();
253 that.control_key_active = false;
253 that.control_key_active = false;
254 return false;
254 return false;
255 } else if (event.which === 72 && that.control_key_active) {
255 } else if (event.which === 72 && that.control_key_active) {
256 // Show keyboard shortcuts = h
256 // Show keyboard shortcuts = h
257 IPython.quick_help.show_keyboard_shortcuts();
257 IPython.quick_help.show_keyboard_shortcuts();
258 that.control_key_active = false;
258 that.control_key_active = false;
259 return false;
259 return false;
260 } else if (that.control_key_active) {
260 } else if (that.control_key_active) {
261 that.control_key_active = false;
261 that.control_key_active = false;
262 return true;
262 return true;
263 };
263 };
264 return true;
264 return true;
265 });
265 });
266
266
267 var collapse_time = function(time){
267 var collapse_time = function(time){
268 var app_height = $('div#main_app').height(); // content height
268 var app_height = $('div#main_app').height(); // content height
269 var splitter_height = $('div#pager_splitter').outerHeight(true);
269 var splitter_height = $('div#pager_splitter').outerHeight(true);
270 var new_height = app_height - splitter_height;
270 var new_height = app_height - splitter_height;
271 that.element.animate({height : new_height + 'px'}, time);
271 that.element.animate({height : new_height + 'px'}, time);
272 }
272 }
273
273
274 this.element.bind('collapse_pager', function (event,extrap) {
274 this.element.bind('collapse_pager', function (event,extrap) {
275 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
275 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
276 collapse_time(time);
276 collapse_time(time);
277 });
277 });
278
278
279 var expand_time = function(time) {
279 var expand_time = function(time) {
280 var app_height = $('div#main_app').height(); // content height
280 var app_height = $('div#main_app').height(); // content height
281 var splitter_height = $('div#pager_splitter').outerHeight(true);
281 var splitter_height = $('div#pager_splitter').outerHeight(true);
282 var pager_height = $('div#pager').outerHeight(true);
282 var pager_height = $('div#pager').outerHeight(true);
283 var new_height = app_height - pager_height - splitter_height;
283 var new_height = app_height - pager_height - splitter_height;
284 that.element.animate({height : new_height + 'px'}, time);
284 that.element.animate({height : new_height + 'px'}, time);
285 }
285 }
286
286
287 this.element.bind('expand_pager', function (event, extrap) {
287 this.element.bind('expand_pager', function (event, extrap) {
288 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
288 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
289 expand_time(time);
289 expand_time(time);
290 });
290 });
291
291
292 $(window).bind('beforeunload', function () {
292 $(window).bind('beforeunload', function () {
293 // TODO: Make killing the kernel configurable.
293 // TODO: Make killing the kernel configurable.
294 var kill_kernel = false;
294 var kill_kernel = false;
295 if (kill_kernel) {
295 if (kill_kernel) {
296 that.kernel.kill();
296 that.kernel.kill();
297 }
297 }
298 if (that.dirty && ! that.read_only) {
298 if (that.dirty && ! that.read_only) {
299 return "You have unsaved changes that will be lost if you leave this page.";
299 return "You have unsaved changes that will be lost if you leave this page.";
300 };
300 };
301 // Null is the *only* return value that will make the browser not
301 // Null is the *only* return value that will make the browser not
302 // pop up the "don't leave" dialog.
302 // pop up the "don't leave" dialog.
303 return null;
303 return null;
304 });
304 });
305 };
305 };
306
306
307
307
308 Notebook.prototype.scroll_to_bottom = function () {
308 Notebook.prototype.scroll_to_bottom = function () {
309 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
309 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
310 };
310 };
311
311
312
312
313 Notebook.prototype.scroll_to_top = function () {
313 Notebook.prototype.scroll_to_top = function () {
314 this.element.animate({scrollTop:0}, 0);
314 this.element.animate({scrollTop:0}, 0);
315 };
315 };
316
316
317
317
318 // Cell indexing, retrieval, etc.
318 // Cell indexing, retrieval, etc.
319
319
320 Notebook.prototype.get_cell_elements = function () {
320 Notebook.prototype.get_cell_elements = function () {
321 return this.element.children("div.cell");
321 return this.element.children("div.cell");
322 };
322 };
323
323
324
324
325 Notebook.prototype.get_cell_element = function (index) {
325 Notebook.prototype.get_cell_element = function (index) {
326 var result = null;
326 var result = null;
327 var e = this.get_cell_elements().eq(index);
327 var e = this.get_cell_elements().eq(index);
328 if (e.length !== 0) {
328 if (e.length !== 0) {
329 result = e;
329 result = e;
330 }
330 }
331 return result;
331 return result;
332 };
332 };
333
333
334
334
335 Notebook.prototype.ncells = function (cell) {
335 Notebook.prototype.ncells = function (cell) {
336 return this.get_cell_elements().length;
336 return this.get_cell_elements().length;
337 };
337 };
338
338
339
339
340 // TODO: we are often calling cells as cells()[i], which we should optimize
340 // TODO: we are often calling cells as cells()[i], which we should optimize
341 // to cells(i) or a new method.
341 // to cells(i) or a new method.
342 Notebook.prototype.get_cells = function () {
342 Notebook.prototype.get_cells = function () {
343 return this.get_cell_elements().toArray().map(function (e) {
343 return this.get_cell_elements().toArray().map(function (e) {
344 return $(e).data("cell");
344 return $(e).data("cell");
345 });
345 });
346 };
346 };
347
347
348
348
349 Notebook.prototype.get_cell = function (index) {
349 Notebook.prototype.get_cell = function (index) {
350 var result = null;
350 var result = null;
351 var ce = this.get_cell_element(index);
351 var ce = this.get_cell_element(index);
352 if (ce !== null) {
352 if (ce !== null) {
353 result = ce.data('cell');
353 result = ce.data('cell');
354 }
354 }
355 return result;
355 return result;
356 }
356 }
357
357
358
358
359 Notebook.prototype.get_next_cell = function (cell) {
359 Notebook.prototype.get_next_cell = function (cell) {
360 var result = null;
360 var result = null;
361 var index = this.find_cell_index(cell);
361 var index = this.find_cell_index(cell);
362 if (index !== null && index < this.ncells()) {
362 if (index !== null && index < this.ncells()) {
363 result = this.get_cell(index+1);
363 result = this.get_cell(index+1);
364 }
364 }
365 return result;
365 return result;
366 }
366 }
367
367
368
368
369 Notebook.prototype.get_prev_cell = function (cell) {
369 Notebook.prototype.get_prev_cell = function (cell) {
370 var result = null;
370 var result = null;
371 var index = this.find_cell_index(cell);
371 var index = this.find_cell_index(cell);
372 if (index !== null && index > 1) {
372 if (index !== null && index > 1) {
373 result = this.get_cell(index-1);
373 result = this.get_cell(index-1);
374 }
374 }
375 return result;
375 return result;
376 }
376 }
377
377
378 Notebook.prototype.find_cell_index = function (cell) {
378 Notebook.prototype.find_cell_index = function (cell) {
379 var result = null;
379 var result = null;
380 this.get_cell_elements().filter(function (index) {
380 this.get_cell_elements().filter(function (index) {
381 if ($(this).data("cell") === cell) {
381 if ($(this).data("cell") === cell) {
382 result = index;
382 result = index;
383 };
383 };
384 });
384 });
385 return result;
385 return result;
386 };
386 };
387
387
388
388
389 Notebook.prototype.index_or_selected = function (index) {
389 Notebook.prototype.index_or_selected = function (index) {
390 var i;
390 var i;
391 if (index === undefined || index === null) {
391 if (index === undefined || index === null) {
392 i = this.get_selected_index();
392 i = this.get_selected_index();
393 if (i === null) {
393 if (i === null) {
394 i = 0;
394 i = 0;
395 }
395 }
396 } else {
396 } else {
397 i = index;
397 i = index;
398 }
398 }
399 return i;
399 return i;
400 };
400 };
401
401
402
402
403 Notebook.prototype.get_selected_cell = function () {
403 Notebook.prototype.get_selected_cell = function () {
404 var index = this.get_selected_index();
404 var index = this.get_selected_index();
405 return this.get_cell(index);
405 return this.get_cell(index);
406 };
406 };
407
407
408
408
409 Notebook.prototype.is_valid_cell_index = function (index) {
409 Notebook.prototype.is_valid_cell_index = function (index) {
410 if (index !== null && index >= 0 && index < this.ncells()) {
410 if (index !== null && index >= 0 && index < this.ncells()) {
411 return true;
411 return true;
412 } else {
412 } else {
413 return false;
413 return false;
414 };
414 };
415 }
415 }
416
416
417 Notebook.prototype.get_selected_index = function () {
417 Notebook.prototype.get_selected_index = function () {
418 var result = null;
418 var result = null;
419 this.get_cell_elements().filter(function (index) {
419 this.get_cell_elements().filter(function (index) {
420 if ($(this).data("cell").selected === true) {
420 if ($(this).data("cell").selected === true) {
421 result = index;
421 result = index;
422 };
422 };
423 });
423 });
424 return result;
424 return result;
425 };
425 };
426
426
427
427
428 // Cell selection.
428 // Cell selection.
429
429
430 Notebook.prototype.select = function (index) {
430 Notebook.prototype.select = function (index) {
431 if (index !== undefined && index >= 0 && index < this.ncells()) {
431 if (index !== undefined && index >= 0 && index < this.ncells()) {
432 sindex = this.get_selected_index()
432 sindex = this.get_selected_index()
433 if (sindex !== null && index !== sindex) {
433 if (sindex !== null && index !== sindex) {
434 this.get_cell(sindex).unselect();
434 this.get_cell(sindex).unselect();
435 };
435 };
436 var cell = this.get_cell(index)
436 var cell = this.get_cell(index)
437 cell.select();
437 cell.select();
438 if (cell.cell_type === 'heading') {
438 if (cell.cell_type === 'heading') {
439 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
439 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
440 {'cell_type':cell.cell_type,level:cell.level}
440 {'cell_type':cell.cell_type,level:cell.level}
441 );
441 );
442 } else {
442 } else {
443 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
443 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
444 {'cell_type':cell.cell_type}
444 {'cell_type':cell.cell_type}
445 );
445 );
446 };
446 };
447 };
447 };
448 return this;
448 return this;
449 };
449 };
450
450
451
451
452 Notebook.prototype.select_next = function () {
452 Notebook.prototype.select_next = function () {
453 var index = this.get_selected_index();
453 var index = this.get_selected_index();
454 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
454 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
455 this.select(index+1);
455 this.select(index+1);
456 };
456 };
457 return this;
457 return this;
458 };
458 };
459
459
460
460
461 Notebook.prototype.select_prev = function () {
461 Notebook.prototype.select_prev = function () {
462 var index = this.get_selected_index();
462 var index = this.get_selected_index();
463 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
463 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
464 this.select(index-1);
464 this.select(index-1);
465 };
465 };
466 return this;
466 return this;
467 };
467 };
468
468
469
469
470 // Cell movement
470 // Cell movement
471
471
472 Notebook.prototype.move_cell_up = function (index) {
472 Notebook.prototype.move_cell_up = function (index) {
473 var i = this.index_or_selected();
473 var i = this.index_or_selected();
474 if (i !== null && i < this.ncells() && i > 0) {
474 if (i !== null && i < this.ncells() && i > 0) {
475 var pivot = this.get_cell_element(i-1);
475 var pivot = this.get_cell_element(i-1);
476 var tomove = this.get_cell_element(i);
476 var tomove = this.get_cell_element(i);
477 if (pivot !== null && tomove !== null) {
477 if (pivot !== null && tomove !== null) {
478 tomove.detach();
478 tomove.detach();
479 pivot.before(tomove);
479 pivot.before(tomove);
480 this.select(i-1);
480 this.select(i-1);
481 };
481 };
482 };
482 };
483 this.dirty = true;
483 this.dirty = true;
484 return this;
484 return this;
485 };
485 };
486
486
487
487
488 Notebook.prototype.move_cell_down = function (index) {
488 Notebook.prototype.move_cell_down = function (index) {
489 var i = this.index_or_selected();
489 var i = this.index_or_selected();
490 if (i !== null && i < (this.ncells()-1) && i >= 0) {
490 if (i !== null && i < (this.ncells()-1) && i >= 0) {
491 var pivot = this.get_cell_element(i+1);
491 var pivot = this.get_cell_element(i+1);
492 var tomove = this.get_cell_element(i);
492 var tomove = this.get_cell_element(i);
493 if (pivot !== null && tomove !== null) {
493 if (pivot !== null && tomove !== null) {
494 tomove.detach();
494 tomove.detach();
495 pivot.after(tomove);
495 pivot.after(tomove);
496 this.select(i+1);
496 this.select(i+1);
497 };
497 };
498 };
498 };
499 this.dirty = true;
499 this.dirty = true;
500 return this;
500 return this;
501 };
501 };
502
502
503
503
504 Notebook.prototype.sort_cells = function () {
504 Notebook.prototype.sort_cells = function () {
505 // This is not working right now. Calling this will actually crash
505 // This is not working right now. Calling this will actually crash
506 // the browser. I think there is an infinite loop in here...
506 // the browser. I think there is an infinite loop in here...
507 var ncells = this.ncells();
507 var ncells = this.ncells();
508 var sindex = this.get_selected_index();
508 var sindex = this.get_selected_index();
509 var swapped;
509 var swapped;
510 do {
510 do {
511 swapped = false;
511 swapped = false;
512 for (var i=1; i<ncells; i++) {
512 for (var i=1; i<ncells; i++) {
513 current = this.get_cell(i);
513 current = this.get_cell(i);
514 previous = this.get_cell(i-1);
514 previous = this.get_cell(i-1);
515 if (previous.input_prompt_number > current.input_prompt_number) {
515 if (previous.input_prompt_number > current.input_prompt_number) {
516 this.move_cell_up(i);
516 this.move_cell_up(i);
517 swapped = true;
517 swapped = true;
518 };
518 };
519 };
519 };
520 } while (swapped);
520 } while (swapped);
521 this.select(sindex);
521 this.select(sindex);
522 return this;
522 return this;
523 };
523 };
524
524
525 // Insertion, deletion.
525 // Insertion, deletion.
526
526
527 Notebook.prototype.delete_cell = function (index) {
527 Notebook.prototype.delete_cell = function (index) {
528 var i = this.index_or_selected(index);
528 var i = this.index_or_selected(index);
529 if (this.is_valid_cell_index(i)) {
529 if (this.is_valid_cell_index(i)) {
530 var ce = this.get_cell_element(i);
530 var ce = this.get_cell_element(i);
531 ce.remove();
531 ce.remove();
532 if (i === (this.ncells())) {
532 if (i === (this.ncells())) {
533 this.select(i-1);
533 this.select(i-1);
534 } else {
534 } else {
535 this.select(i);
535 this.select(i);
536 };
536 };
537 this.dirty = true;
537 this.dirty = true;
538 };
538 };
539 return this;
539 return this;
540 };
540 };
541
541
542
542
543 Notebook.prototype.insert_cell_below = function (type, index) {
543 Notebook.prototype.insert_cell_below = function (type, index) {
544 // type = ('code','html','markdown')
544 // type = ('code','html','markdown')
545 // index = cell index or undefined to insert below selected
545 // index = cell index or undefined to insert below selected
546 index = this.index_or_selected(index);
546 index = this.index_or_selected(index);
547 var cell = null;
547 var cell = null;
548 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
548 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
549 if (type === 'code') {
549 if (type === 'code') {
550 cell = new IPython.CodeCell(this.kernel);
550 cell = new IPython.CodeCell(this.kernel);
551 cell.set_input_prompt();
551 cell.set_input_prompt();
552 } else if (type === 'markdown') {
552 } else if (type === 'markdown') {
553 cell = new IPython.MarkdownCell();
553 cell = new IPython.MarkdownCell();
554 } else if (type === 'html') {
554 } else if (type === 'html') {
555 cell = new IPython.HTMLCell();
555 cell = new IPython.HTMLCell();
556 } else if (type === 'raw') {
556 } else if (type === 'raw') {
557 cell = new IPython.RawCell();
557 cell = new IPython.RawCell();
558 } else if (type === 'heading') {
558 } else if (type === 'heading') {
559 cell = new IPython.HeadingCell();
559 cell = new IPython.HeadingCell();
560 };
560 };
561 if (cell !== null) {
561 if (cell !== null) {
562 if (this.ncells() === 0) {
562 if (this.ncells() === 0) {
563 this.element.find('div.end_space').before(cell.element);
563 this.element.find('div.end_space').before(cell.element);
564 } else if (this.is_valid_cell_index(index)) {
564 } else if (this.is_valid_cell_index(index)) {
565 this.get_cell_element(index).after(cell.element);
565 this.get_cell_element(index).after(cell.element);
566 };
566 };
567 cell.render();
567 cell.render();
568 this.select(this.find_cell_index(cell));
568 this.select(this.find_cell_index(cell));
569 this.dirty = true;
569 this.dirty = true;
570 return cell;
570 return cell;
571 };
571 };
572 };
572 };
573 return cell;
573 return cell;
574 };
574 };
575
575
576
576
577 Notebook.prototype.insert_cell_above = function (type, index) {
577 Notebook.prototype.insert_cell_above = function (type, index) {
578 // type = ('code','html','markdown')
578 // type = ('code','html','markdown')
579 // index = cell index or undefined to insert above selected
579 // index = cell index or undefined to insert above selected
580 index = this.index_or_selected(index);
580 index = this.index_or_selected(index);
581 var cell = null;
581 var cell = null;
582 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
582 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
583 if (type === 'code') {
583 if (type === 'code') {
584 cell = new IPython.CodeCell(this.kernel);
584 cell = new IPython.CodeCell(this.kernel);
585 cell.set_input_prompt();
585 cell.set_input_prompt();
586 } else if (type === 'markdown') {
586 } else if (type === 'markdown') {
587 cell = new IPython.MarkdownCell();
587 cell = new IPython.MarkdownCell();
588 } else if (type === 'html') {
588 } else if (type === 'html') {
589 cell = new IPython.HTMLCell();
589 cell = new IPython.HTMLCell();
590 } else if (type === 'raw') {
590 } else if (type === 'raw') {
591 cell = new IPython.RawCell();
591 cell = new IPython.RawCell();
592 } else if (type === 'heading') {
592 } else if (type === 'heading') {
593 cell = new IPython.HeadingCell();
593 cell = new IPython.HeadingCell();
594 };
594 };
595 if (cell !== null) {
595 if (cell !== null) {
596 if (this.ncells() === 0) {
596 if (this.ncells() === 0) {
597 this.element.find('div.end_space').before(cell.element);
597 this.element.find('div.end_space').before(cell.element);
598 } else if (this.is_valid_cell_index(index)) {
598 } else if (this.is_valid_cell_index(index)) {
599 this.get_cell_element(index).before(cell.element);
599 this.get_cell_element(index).before(cell.element);
600 };
600 };
601 cell.render();
601 cell.render();
602 this.select(this.find_cell_index(cell));
602 this.select(this.find_cell_index(cell));
603 this.dirty = true;
603 this.dirty = true;
604 return cell;
604 return cell;
605 };
605 };
606 };
606 };
607 return cell;
607 return cell;
608 };
608 };
609
609
610
610
611 Notebook.prototype.to_code = function (index) {
611 Notebook.prototype.to_code = function (index) {
612 var i = this.index_or_selected(index);
612 var i = this.index_or_selected(index);
613 if (this.is_valid_cell_index(i)) {
613 if (this.is_valid_cell_index(i)) {
614 var source_element = this.get_cell_element(i);
614 var source_element = this.get_cell_element(i);
615 var source_cell = source_element.data("cell");
615 var source_cell = source_element.data("cell");
616 if (!(source_cell instanceof IPython.CodeCell)) {
616 if (!(source_cell instanceof IPython.CodeCell)) {
617 target_cell = this.insert_cell_below('code',i);
617 target_cell = this.insert_cell_below('code',i);
618 var text = source_cell.get_text();
618 var text = source_cell.get_text();
619 if (text === source_cell.placeholder) {
619 if (text === source_cell.placeholder) {
620 text = '';
620 text = '';
621 }
621 }
622 target_cell.set_text(text);
622 target_cell.set_text(text);
623 // make this value the starting point, so that we can only undo
623 // make this value the starting point, so that we can only undo
624 // to this state, instead of a blank cell
624 // to this state, instead of a blank cell
625 target_cell.code_mirror.clearHistory();
625 target_cell.code_mirror.clearHistory();
626 source_element.remove();
626 source_element.remove();
627 this.dirty = true;
627 this.dirty = true;
628 };
628 };
629 };
629 };
630 };
630 };
631
631
632
632
633 Notebook.prototype.to_markdown = function (index) {
633 Notebook.prototype.to_markdown = function (index) {
634 var i = this.index_or_selected(index);
634 var i = this.index_or_selected(index);
635 if (this.is_valid_cell_index(i)) {
635 if (this.is_valid_cell_index(i)) {
636 var source_element = this.get_cell_element(i);
636 var source_element = this.get_cell_element(i);
637 var source_cell = source_element.data("cell");
637 var source_cell = source_element.data("cell");
638 if (!(source_cell instanceof IPython.MarkdownCell)) {
638 if (!(source_cell instanceof IPython.MarkdownCell)) {
639 target_cell = this.insert_cell_below('markdown',i);
639 target_cell = this.insert_cell_below('markdown',i);
640 var text = source_cell.get_text();
640 var text = source_cell.get_text();
641 if (text === source_cell.placeholder) {
641 if (text === source_cell.placeholder) {
642 text = '';
642 text = '';
643 };
643 };
644 // The edit must come before the set_text.
644 // The edit must come before the set_text.
645 target_cell.edit();
645 target_cell.edit();
646 target_cell.set_text(text);
646 target_cell.set_text(text);
647 // make this value the starting point, so that we can only undo
647 // make this value the starting point, so that we can only undo
648 // to this state, instead of a blank cell
648 // to this state, instead of a blank cell
649 target_cell.code_mirror.clearHistory();
649 target_cell.code_mirror.clearHistory();
650 source_element.remove();
650 source_element.remove();
651 this.dirty = true;
651 this.dirty = true;
652 };
652 };
653 };
653 };
654 };
654 };
655
655
656
656
657 Notebook.prototype.to_html = function (index) {
657 Notebook.prototype.to_html = function (index) {
658 var i = this.index_or_selected(index);
658 var i = this.index_or_selected(index);
659 if (this.is_valid_cell_index(i)) {
659 if (this.is_valid_cell_index(i)) {
660 var source_element = this.get_cell_element(i);
660 var source_element = this.get_cell_element(i);
661 var source_cell = source_element.data("cell");
661 var source_cell = source_element.data("cell");
662 var target_cell = null;
662 var target_cell = null;
663 if (!(source_cell instanceof IPython.HTMLCell)) {
663 if (!(source_cell instanceof IPython.HTMLCell)) {
664 target_cell = this.insert_cell_below('html',i);
664 target_cell = this.insert_cell_below('html',i);
665 var text = source_cell.get_text();
665 var text = source_cell.get_text();
666 if (text === source_cell.placeholder) {
666 if (text === source_cell.placeholder) {
667 text = '';
667 text = '';
668 };
668 };
669 // The edit must come before the set_text.
669 // The edit must come before the set_text.
670 target_cell.edit();
670 target_cell.edit();
671 target_cell.set_text(text);
671 target_cell.set_text(text);
672 // make this value the starting point, so that we can only undo
672 // make this value the starting point, so that we can only undo
673 // to this state, instead of a blank cell
673 // to this state, instead of a blank cell
674 target_cell.code_mirror.clearHistory();
674 target_cell.code_mirror.clearHistory();
675 source_element.remove();
675 source_element.remove();
676 this.dirty = true;
676 this.dirty = true;
677 };
677 };
678 };
678 };
679 };
679 };
680
680
681
681
682 Notebook.prototype.to_raw = function (index) {
682 Notebook.prototype.to_raw = function (index) {
683 var i = this.index_or_selected(index);
683 var i = this.index_or_selected(index);
684 if (this.is_valid_cell_index(i)) {
684 if (this.is_valid_cell_index(i)) {
685 var source_element = this.get_cell_element(i);
685 var source_element = this.get_cell_element(i);
686 var source_cell = source_element.data("cell");
686 var source_cell = source_element.data("cell");
687 var target_cell = null;
687 var target_cell = null;
688 if (!(source_cell instanceof IPython.RawCell)) {
688 if (!(source_cell instanceof IPython.RawCell)) {
689 target_cell = this.insert_cell_below('raw',i);
689 target_cell = this.insert_cell_below('raw',i);
690 var text = source_cell.get_text();
690 var text = source_cell.get_text();
691 if (text === source_cell.placeholder) {
691 if (text === source_cell.placeholder) {
692 text = '';
692 text = '';
693 };
693 };
694 // The edit must come before the set_text.
694 // The edit must come before the set_text.
695 target_cell.edit();
695 target_cell.edit();
696 target_cell.set_text(text);
696 target_cell.set_text(text);
697 // make this value the starting point, so that we can only undo
697 // make this value the starting point, so that we can only undo
698 // to this state, instead of a blank cell
698 // to this state, instead of a blank cell
699 target_cell.code_mirror.clearHistory();
699 target_cell.code_mirror.clearHistory();
700 source_element.remove();
700 source_element.remove();
701 this.dirty = true;
701 this.dirty = true;
702 };
702 };
703 };
703 };
704 };
704 };
705
705
706
706
707 Notebook.prototype.to_heading = function (index, level) {
707 Notebook.prototype.to_heading = function (index, level) {
708 level = level || 1;
708 level = level || 1;
709 var i = this.index_or_selected(index);
709 var i = this.index_or_selected(index);
710 if (this.is_valid_cell_index(i)) {
710 if (this.is_valid_cell_index(i)) {
711 var source_element = this.get_cell_element(i);
711 var source_element = this.get_cell_element(i);
712 var source_cell = source_element.data("cell");
712 var source_cell = source_element.data("cell");
713 var target_cell = null;
713 var target_cell = null;
714 if (source_cell instanceof IPython.HeadingCell) {
714 if (source_cell instanceof IPython.HeadingCell) {
715 source_cell.set_level(level);
715 source_cell.set_level(level);
716 } else {
716 } else {
717 target_cell = this.insert_cell_below('heading',i);
717 target_cell = this.insert_cell_below('heading',i);
718 var text = source_cell.get_text();
718 var text = source_cell.get_text();
719 if (text === source_cell.placeholder) {
719 if (text === source_cell.placeholder) {
720 text = '';
720 text = '';
721 };
721 };
722 // The edit must come before the set_text.
722 // The edit must come before the set_text.
723 target_cell.set_level(level);
723 target_cell.set_level(level);
724 target_cell.edit();
724 target_cell.edit();
725 target_cell.set_text(text);
725 target_cell.set_text(text);
726 // make this value the starting point, so that we can only undo
726 // make this value the starting point, so that we can only undo
727 // to this state, instead of a blank cell
727 // to this state, instead of a blank cell
728 target_cell.code_mirror.clearHistory();
728 target_cell.code_mirror.clearHistory();
729 source_element.remove();
729 source_element.remove();
730 this.dirty = true;
730 this.dirty = true;
731 };
731 };
732 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
732 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
733 {'cell_type':'heading',level:level}
733 {'cell_type':'heading',level:level}
734 );
734 );
735 };
735 };
736 };
736 };
737
737
738
738
739 // Cut/Copy/Paste
739 // Cut/Copy/Paste
740
740
741 Notebook.prototype.enable_paste = function () {
741 Notebook.prototype.enable_paste = function () {
742 var that = this;
742 var that = this;
743 if (!this.paste_enabled) {
743 if (!this.paste_enabled) {
744 $('#paste_cell').removeClass('ui-state-disabled')
744 $('#paste_cell').removeClass('ui-state-disabled')
745 .on('click', function () {that.paste_cell();});
745 .on('click', function () {that.paste_cell();});
746 $('#paste_cell_above').removeClass('ui-state-disabled')
746 $('#paste_cell_above').removeClass('ui-state-disabled')
747 .on('click', function () {that.paste_cell_above();});
747 .on('click', function () {that.paste_cell_above();});
748 $('#paste_cell_below').removeClass('ui-state-disabled')
748 $('#paste_cell_below').removeClass('ui-state-disabled')
749 .on('click', function () {that.paste_cell_below();});
749 .on('click', function () {that.paste_cell_below();});
750 this.paste_enabled = true;
750 this.paste_enabled = true;
751 };
751 };
752 };
752 };
753
753
754
754
755 Notebook.prototype.disable_paste = function () {
755 Notebook.prototype.disable_paste = function () {
756 if (this.paste_enabled) {
756 if (this.paste_enabled) {
757 $('#paste_cell').addClass('ui-state-disabled').off('click');
757 $('#paste_cell').addClass('ui-state-disabled').off('click');
758 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
758 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
759 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
759 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
760 this.paste_enabled = false;
760 this.paste_enabled = false;
761 };
761 };
762 };
762 };
763
763
764
764
765 Notebook.prototype.cut_cell = function () {
765 Notebook.prototype.cut_cell = function () {
766 this.copy_cell();
766 this.copy_cell();
767 this.delete_cell();
767 this.delete_cell();
768 }
768 }
769
769
770 Notebook.prototype.copy_cell = function () {
770 Notebook.prototype.copy_cell = function () {
771 var cell = this.get_selected_cell();
771 var cell = this.get_selected_cell();
772 this.clipboard = cell.toJSON();
772 this.clipboard = cell.toJSON();
773 this.enable_paste();
773 this.enable_paste();
774 };
774 };
775
775
776
776
777 Notebook.prototype.paste_cell = function () {
777 Notebook.prototype.paste_cell = function () {
778 if (this.clipboard !== null && this.paste_enabled) {
778 if (this.clipboard !== null && this.paste_enabled) {
779 var cell_data = this.clipboard;
779 var cell_data = this.clipboard;
780 var new_cell = this.insert_cell_above(cell_data.cell_type);
780 var new_cell = this.insert_cell_above(cell_data.cell_type);
781 new_cell.fromJSON(cell_data);
781 new_cell.fromJSON(cell_data);
782 old_cell = this.get_next_cell(new_cell);
782 old_cell = this.get_next_cell(new_cell);
783 this.delete_cell(this.find_cell_index(old_cell));
783 this.delete_cell(this.find_cell_index(old_cell));
784 this.select(this.find_cell_index(new_cell));
784 this.select(this.find_cell_index(new_cell));
785 };
785 };
786 };
786 };
787
787
788
788
789 Notebook.prototype.paste_cell_above = function () {
789 Notebook.prototype.paste_cell_above = function () {
790 if (this.clipboard !== null && this.paste_enabled) {
790 if (this.clipboard !== null && this.paste_enabled) {
791 var cell_data = this.clipboard;
791 var cell_data = this.clipboard;
792 var new_cell = this.insert_cell_above(cell_data.cell_type);
792 var new_cell = this.insert_cell_above(cell_data.cell_type);
793 new_cell.fromJSON(cell_data);
793 new_cell.fromJSON(cell_data);
794 };
794 };
795 };
795 };
796
796
797
797
798 Notebook.prototype.paste_cell_below = function () {
798 Notebook.prototype.paste_cell_below = function () {
799 if (this.clipboard !== null && this.paste_enabled) {
799 if (this.clipboard !== null && this.paste_enabled) {
800 var cell_data = this.clipboard;
800 var cell_data = this.clipboard;
801 var new_cell = this.insert_cell_below(cell_data.cell_type);
801 var new_cell = this.insert_cell_below(cell_data.cell_type);
802 new_cell.fromJSON(cell_data);
802 new_cell.fromJSON(cell_data);
803 };
803 };
804 };
804 };
805
805
806
806
807 // Split/merge
807 // Split/merge
808
808
809 Notebook.prototype.split_cell = function () {
809 Notebook.prototype.split_cell = function () {
810 // Todo: implement spliting for other cell types.
810 // Todo: implement spliting for other cell types.
811 var cell = this.get_selected_cell();
811 var cell = this.get_selected_cell();
812 if (cell.is_splittable()) {
812 if (cell.is_splittable()) {
813 texta = cell.get_pre_cursor();
813 texta = cell.get_pre_cursor();
814 textb = cell.get_post_cursor();
814 textb = cell.get_post_cursor();
815 if (cell instanceof IPython.CodeCell) {
815 if (cell instanceof IPython.CodeCell) {
816 cell.set_text(texta);
816 cell.set_text(texta);
817 var new_cell = this.insert_cell_below('code');
817 var new_cell = this.insert_cell_below('code');
818 new_cell.set_text(textb);
818 new_cell.set_text(textb);
819 } else if (cell instanceof IPython.MarkdownCell) {
819 } else if (cell instanceof IPython.MarkdownCell) {
820 cell.set_text(texta);
820 cell.set_text(texta);
821 cell.render();
821 cell.render();
822 var new_cell = this.insert_cell_below('markdown');
822 var new_cell = this.insert_cell_below('markdown');
823 new_cell.edit(); // editor must be visible to call set_text
823 new_cell.edit(); // editor must be visible to call set_text
824 new_cell.set_text(textb);
824 new_cell.set_text(textb);
825 new_cell.render();
825 new_cell.render();
826 } else if (cell instanceof IPython.HTMLCell) {
826 } else if (cell instanceof IPython.HTMLCell) {
827 cell.set_text(texta);
827 cell.set_text(texta);
828 cell.render();
828 cell.render();
829 var new_cell = this.insert_cell_below('html');
829 var new_cell = this.insert_cell_below('html');
830 new_cell.edit(); // editor must be visible to call set_text
830 new_cell.edit(); // editor must be visible to call set_text
831 new_cell.set_text(textb);
831 new_cell.set_text(textb);
832 new_cell.render();
832 new_cell.render();
833 };
833 };
834 };
834 };
835 };
835 };
836
836
837
837
838 Notebook.prototype.merge_cell_above = function () {
838 Notebook.prototype.merge_cell_above = function () {
839 var index = this.get_selected_index();
839 var index = this.get_selected_index();
840 var cell = this.get_cell(index);
840 var cell = this.get_cell(index);
841 if (index > 0) {
841 if (index > 0) {
842 upper_cell = this.get_cell(index-1);
842 upper_cell = this.get_cell(index-1);
843 upper_text = upper_cell.get_text();
843 upper_text = upper_cell.get_text();
844 text = cell.get_text();
844 text = cell.get_text();
845 if (cell instanceof IPython.CodeCell) {
845 if (cell instanceof IPython.CodeCell) {
846 cell.set_text(upper_text+'\n'+text);
846 cell.set_text(upper_text+'\n'+text);
847 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
847 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
848 cell.edit();
848 cell.edit();
849 cell.set_text(upper_text+'\n'+text);
849 cell.set_text(upper_text+'\n'+text);
850 cell.render();
850 cell.render();
851 };
851 };
852 this.delete_cell(index-1);
852 this.delete_cell(index-1);
853 this.select(this.find_cell_index(cell));
853 this.select(this.find_cell_index(cell));
854 };
854 };
855 };
855 };
856
856
857
857
858 Notebook.prototype.merge_cell_below = function () {
858 Notebook.prototype.merge_cell_below = function () {
859 var index = this.get_selected_index();
859 var index = this.get_selected_index();
860 var cell = this.get_cell(index);
860 var cell = this.get_cell(index);
861 if (index < this.ncells()-1) {
861 if (index < this.ncells()-1) {
862 lower_cell = this.get_cell(index+1);
862 lower_cell = this.get_cell(index+1);
863 lower_text = lower_cell.get_text();
863 lower_text = lower_cell.get_text();
864 text = cell.get_text();
864 text = cell.get_text();
865 if (cell instanceof IPython.CodeCell) {
865 if (cell instanceof IPython.CodeCell) {
866 cell.set_text(text+'\n'+lower_text);
866 cell.set_text(text+'\n'+lower_text);
867 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
867 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
868 cell.edit();
868 cell.edit();
869 cell.set_text(text+'\n'+lower_text);
869 cell.set_text(text+'\n'+lower_text);
870 cell.render();
870 cell.render();
871 };
871 };
872 this.delete_cell(index+1);
872 this.delete_cell(index+1);
873 this.select(this.find_cell_index(cell));
873 this.select(this.find_cell_index(cell));
874 };
874 };
875 };
875 };
876
876
877
877
878 // Cell collapsing and output clearing
878 // Cell collapsing and output clearing
879
879
880 Notebook.prototype.collapse = function (index) {
880 Notebook.prototype.collapse = function (index) {
881 var i = this.index_or_selected(index);
881 var i = this.index_or_selected(index);
882 this.get_cell(i).collapse();
882 this.get_cell(i).collapse();
883 this.dirty = true;
883 this.dirty = true;
884 };
884 };
885
885
886
886
887 Notebook.prototype.expand = function (index) {
887 Notebook.prototype.expand = function (index) {
888 var i = this.index_or_selected(index);
888 var i = this.index_or_selected(index);
889 this.get_cell(i).expand();
889 this.get_cell(i).expand();
890 this.dirty = true;
890 this.dirty = true;
891 };
891 };
892
892
893
893
894 Notebook.prototype.toggle_output = function (index) {
894 Notebook.prototype.toggle_output = function (index) {
895 var i = this.index_or_selected(index);
895 var i = this.index_or_selected(index);
896 this.get_cell(i).toggle_output();
896 this.get_cell(i).toggle_output();
897 this.dirty = true;
897 this.dirty = true;
898 };
898 };
899
899
900
900
901 Notebook.prototype.toggle_output_scroll = function (index) {
901 Notebook.prototype.toggle_output_scroll = function (index) {
902 var i = this.index_or_selected(index);
902 var i = this.index_or_selected(index);
903 this.get_cell(i).toggle_output_scroll();
903 this.get_cell(i).toggle_output_scroll();
904 };
904 };
905
905
906
906
907 Notebook.prototype.collapse_all_output = function () {
907 Notebook.prototype.collapse_all_output = function () {
908 var ncells = this.ncells();
908 var ncells = this.ncells();
909 var cells = this.get_cells();
909 var cells = this.get_cells();
910 for (var i=0; i<ncells; i++) {
910 for (var i=0; i<ncells; i++) {
911 if (cells[i] instanceof IPython.CodeCell) {
911 if (cells[i] instanceof IPython.CodeCell) {
912 cells[i].output_area.collapse();
912 cells[i].output_area.collapse();
913 }
913 }
914 };
914 };
915 // this should not be set if the `collapse` key is removed from nbformat
915 // this should not be set if the `collapse` key is removed from nbformat
916 this.dirty = true;
916 this.dirty = true;
917 };
917 };
918
918
919
919
920 Notebook.prototype.scroll_all_output = function () {
920 Notebook.prototype.scroll_all_output = function () {
921 var ncells = this.ncells();
921 var ncells = this.ncells();
922 var cells = this.get_cells();
922 var cells = this.get_cells();
923 for (var i=0; i<ncells; i++) {
923 for (var i=0; i<ncells; i++) {
924 if (cells[i] instanceof IPython.CodeCell) {
924 if (cells[i] instanceof IPython.CodeCell) {
925 cells[i].output_area.expand();
925 cells[i].output_area.expand();
926 cells[i].output_area.scroll_if_long(20);
926 cells[i].output_area.scroll_if_long(20);
927 }
927 }
928 };
928 };
929 // this should not be set if the `collapse` key is removed from nbformat
929 // this should not be set if the `collapse` key is removed from nbformat
930 this.dirty = true;
930 this.dirty = true;
931 };
931 };
932
932
933
933
934 Notebook.prototype.expand_all_output = function () {
934 Notebook.prototype.expand_all_output = function () {
935 var ncells = this.ncells();
935 var ncells = this.ncells();
936 var cells = this.get_cells();
936 var cells = this.get_cells();
937 for (var i=0; i<ncells; i++) {
937 for (var i=0; i<ncells; i++) {
938 if (cells[i] instanceof IPython.CodeCell) {
938 if (cells[i] instanceof IPython.CodeCell) {
939 cells[i].output_area.expand();
939 cells[i].output_area.expand();
940 cells[i].output_area.unscroll_area();
940 cells[i].output_area.unscroll_area();
941 }
941 }
942 };
942 };
943 // this should not be set if the `collapse` key is removed from nbformat
943 // this should not be set if the `collapse` key is removed from nbformat
944 this.dirty = true;
944 this.dirty = true;
945 };
945 };
946
946
947
947
948 Notebook.prototype.clear_all_output = function () {
948 Notebook.prototype.clear_all_output = function () {
949 var ncells = this.ncells();
949 var ncells = this.ncells();
950 var cells = this.get_cells();
950 var cells = this.get_cells();
951 for (var i=0; i<ncells; i++) {
951 for (var i=0; i<ncells; i++) {
952 if (cells[i] instanceof IPython.CodeCell) {
952 if (cells[i] instanceof IPython.CodeCell) {
953 cells[i].clear_output(true,true,true);
953 cells[i].clear_output(true,true,true);
954 // Make all In[] prompts blank, as well
954 // Make all In[] prompts blank, as well
955 // TODO: make this configurable (via checkbox?)
955 // TODO: make this configurable (via checkbox?)
956 cells[i].set_input_prompt();
956 cells[i].set_input_prompt();
957 }
957 }
958 };
958 };
959 this.dirty = true;
959 this.dirty = true;
960 };
960 };
961
961
962
962
963 // Other cell functions: line numbers, ...
963 // Other cell functions: line numbers, ...
964
964
965 Notebook.prototype.cell_toggle_line_numbers = function() {
965 Notebook.prototype.cell_toggle_line_numbers = function() {
966 this.get_selected_cell().toggle_line_numbers();
966 this.get_selected_cell().toggle_line_numbers();
967 };
967 };
968
968
969 // Kernel related things
969 // Kernel related things
970
970
971 Notebook.prototype.start_kernel = function () {
971 Notebook.prototype.start_kernel = function () {
972 var base_url = $('body').data('baseKernelUrl') + "kernels";
972 var base_url = $('body').data('baseKernelUrl') + "kernels";
973 this.kernel = new IPython.Kernel(base_url);
973 this.kernel = new IPython.Kernel(base_url);
974 this.kernel.start(this.notebook_id);
974 this.kernel.start(this.notebook_id);
975 // Now that the kernel has been created, tell the CodeCells about it.
975 // Now that the kernel has been created, tell the CodeCells about it.
976 var ncells = this.ncells();
976 var ncells = this.ncells();
977 for (var i=0; i<ncells; i++) {
977 for (var i=0; i<ncells; i++) {
978 var cell = this.get_cell(i);
978 var cell = this.get_cell(i);
979 if (cell instanceof IPython.CodeCell) {
979 if (cell instanceof IPython.CodeCell) {
980 cell.set_kernel(this.kernel)
980 cell.set_kernel(this.kernel)
981 };
981 };
982 };
982 };
983 };
983 };
984
984
985
985
986 Notebook.prototype.restart_kernel = function () {
986 Notebook.prototype.restart_kernel = function () {
987 var that = this;
987 var that = this;
988 var dialog = $('<div/>');
988 var dialog = $('<div/>');
989 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
989 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
990 $(document).append(dialog);
990 $(document).append(dialog);
991 dialog.dialog({
991 dialog.dialog({
992 resizable: false,
992 resizable: false,
993 modal: true,
993 modal: true,
994 title: "Restart kernel or continue running?",
994 title: "Restart kernel or continue running?",
995 closeText: '',
995 closeText: '',
996 buttons : {
996 buttons : {
997 "Restart": function () {
997 "Restart": function () {
998 that.kernel.restart();
998 that.kernel.restart();
999 $(this).dialog('close');
999 $(this).dialog('close');
1000 },
1000 },
1001 "Continue running": function () {
1001 "Continue running": function () {
1002 $(this).dialog('close');
1002 $(this).dialog('close');
1003 }
1003 }
1004 }
1004 }
1005 });
1005 });
1006 };
1006 };
1007
1007
1008
1008
1009 Notebook.prototype.execute_selected_cell = function (options) {
1009 Notebook.prototype.execute_selected_cell = function (options) {
1010 // add_new: should a new cell be added if we are at the end of the nb
1010 // add_new: should a new cell be added if we are at the end of the nb
1011 // terminal: execute in terminal mode, which stays in the current cell
1011 // terminal: execute in terminal mode, which stays in the current cell
1012 default_options = {terminal: false, add_new: true};
1012 default_options = {terminal: false, add_new: true};
1013 $.extend(default_options, options);
1013 $.extend(default_options, options);
1014 var that = this;
1014 var that = this;
1015 var cell = that.get_selected_cell();
1015 var cell = that.get_selected_cell();
1016 var cell_index = that.find_cell_index(cell);
1016 var cell_index = that.find_cell_index(cell);
1017 if (cell instanceof IPython.CodeCell) {
1017 if (cell instanceof IPython.CodeCell) {
1018 cell.execute();
1018 cell.execute();
1019 } else if (cell instanceof IPython.HTMLCell) {
1019 } else if (cell instanceof IPython.HTMLCell) {
1020 cell.render();
1020 cell.render();
1021 }
1021 }
1022 if (default_options.terminal) {
1022 if (default_options.terminal) {
1023 cell.select_all();
1023 cell.select_all();
1024 } else {
1024 } else {
1025 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1025 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1026 that.insert_cell_below('code');
1026 that.insert_cell_below('code');
1027 // If we are adding a new cell at the end, scroll down to show it.
1027 // If we are adding a new cell at the end, scroll down to show it.
1028 that.scroll_to_bottom();
1028 that.scroll_to_bottom();
1029 } else {
1029 } else {
1030 that.select(cell_index+1);
1030 that.select(cell_index+1);
1031 };
1031 };
1032 };
1032 };
1033 this.dirty = true;
1033 this.dirty = true;
1034 };
1034 };
1035
1035
1036
1036
1037 Notebook.prototype.execute_all_cells = function () {
1037 Notebook.prototype.execute_all_cells = function () {
1038 var ncells = this.ncells();
1038 var ncells = this.ncells();
1039 for (var i=0; i<ncells; i++) {
1039 for (var i=0; i<ncells; i++) {
1040 this.select(i);
1040 this.select(i);
1041 this.execute_selected_cell({add_new:false});
1041 this.execute_selected_cell({add_new:false});
1042 };
1042 };
1043 this.scroll_to_bottom();
1043 this.scroll_to_bottom();
1044 };
1044 };
1045
1045
1046 // Persistance and loading
1046 // Persistance and loading
1047
1047
1048 Notebook.prototype.get_notebook_id = function () {
1048 Notebook.prototype.get_notebook_id = function () {
1049 return this.notebook_id;
1049 return this.notebook_id;
1050 };
1050 };
1051
1051
1052
1052
1053 Notebook.prototype.get_notebook_name = function () {
1053 Notebook.prototype.get_notebook_name = function () {
1054 return this.notebook_name;
1054 return this.notebook_name;
1055 };
1055 };
1056
1056
1057
1057
1058 Notebook.prototype.set_notebook_name = function (name) {
1058 Notebook.prototype.set_notebook_name = function (name) {
1059 this.notebook_name = name;
1059 this.notebook_name = name;
1060 };
1060 };
1061
1061
1062
1062
1063 Notebook.prototype.test_notebook_name = function (nbname) {
1063 Notebook.prototype.test_notebook_name = function (nbname) {
1064 nbname = nbname || '';
1064 nbname = nbname || '';
1065 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1065 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1066 return true;
1066 return true;
1067 } else {
1067 } else {
1068 return false;
1068 return false;
1069 };
1069 };
1070 };
1070 };
1071
1071
1072
1072
1073 Notebook.prototype.fromJSON = function (data) {
1073 Notebook.prototype.fromJSON = function (data) {
1074 var ncells = this.ncells();
1074 var ncells = this.ncells();
1075 var i;
1075 var i;
1076 for (i=0; i<ncells; i++) {
1076 for (i=0; i<ncells; i++) {
1077 // Always delete cell 0 as they get renumbered as they are deleted.
1077 // Always delete cell 0 as they get renumbered as they are deleted.
1078 this.delete_cell(0);
1078 this.delete_cell(0);
1079 };
1079 };
1080 // Save the metadata and name.
1080 // Save the metadata and name.
1081 this.metadata = data.metadata;
1081 this.metadata = data.metadata;
1082 this.notebook_name = data.metadata.name;
1082 this.notebook_name = data.metadata.name;
1083 // Only handle 1 worksheet for now.
1083 // Only handle 1 worksheet for now.
1084 var worksheet = data.worksheets[0];
1084 var worksheet = data.worksheets[0];
1085 if (worksheet !== undefined) {
1085 if (worksheet !== undefined) {
1086 if (worksheet.metadata) {
1086 if (worksheet.metadata) {
1087 this.worksheet_metadata = worksheet.metadata;
1087 this.worksheet_metadata = worksheet.metadata;
1088 }
1088 }
1089 var new_cells = worksheet.cells;
1089 var new_cells = worksheet.cells;
1090 ncells = new_cells.length;
1090 ncells = new_cells.length;
1091 var cell_data = null;
1091 var cell_data = null;
1092 var new_cell = null;
1092 var new_cell = null;
1093 for (i=0; i<ncells; i++) {
1093 for (i=0; i<ncells; i++) {
1094 cell_data = new_cells[i];
1094 cell_data = new_cells[i];
1095 // VERSIONHACK: plaintext -> raw
1095 // VERSIONHACK: plaintext -> raw
1096 // handle never-released plaintext name for raw cells
1096 // handle never-released plaintext name for raw cells
1097 if (cell_data.cell_type === 'plaintext'){
1097 if (cell_data.cell_type === 'plaintext'){
1098 cell_data.cell_type = 'raw';
1098 cell_data.cell_type = 'raw';
1099 }
1099 }
1100
1100
1101 new_cell = this.insert_cell_below(cell_data.cell_type);
1101 new_cell = this.insert_cell_below(cell_data.cell_type);
1102 new_cell.fromJSON(cell_data);
1102 new_cell.fromJSON(cell_data);
1103 };
1103 };
1104 };
1104 };
1105 if (data.worksheets.length > 1) {
1105 if (data.worksheets.length > 1) {
1106 var dialog = $('<div/>');
1106 var dialog = $('<div/>');
1107 dialog.html("This notebook has " + data.worksheets.length + " worksheets, " +
1107 dialog.html("This notebook has " + data.worksheets.length + " worksheets, " +
1108 "but this version of IPython can only handle the first. " +
1108 "but this version of IPython can only handle the first. " +
1109 "If you save this notebook, worksheets after the first will be lost."
1109 "If you save this notebook, worksheets after the first will be lost."
1110 );
1110 );
1111 this.element.append(dialog);
1111 this.element.append(dialog);
1112 dialog.dialog({
1112 dialog.dialog({
1113 resizable: false,
1113 resizable: false,
1114 modal: true,
1114 modal: true,
1115 title: "Multiple worksheets",
1115 title: "Multiple worksheets",
1116 closeText: "",
1116 closeText: "",
1117 close: function(event, ui) {$(this).dialog('destroy').remove();},
1117 close: function(event, ui) {$(this).dialog('destroy').remove();},
1118 buttons : {
1118 buttons : {
1119 "OK": function () {
1119 "OK": function () {
1120 $(this).dialog('close');
1120 $(this).dialog('close');
1121 }
1121 }
1122 },
1122 },
1123 width: 400
1123 width: 400
1124 });
1124 });
1125 }
1125 }
1126 };
1126 };
1127
1127
1128
1128
1129 Notebook.prototype.toJSON = function () {
1129 Notebook.prototype.toJSON = function () {
1130 var cells = this.get_cells();
1130 var cells = this.get_cells();
1131 var ncells = cells.length;
1131 var ncells = cells.length;
1132 var cell_array = new Array(ncells);
1132 var cell_array = new Array(ncells);
1133 for (var i=0; i<ncells; i++) {
1133 for (var i=0; i<ncells; i++) {
1134 cell_array[i] = cells[i].toJSON();
1134 cell_array[i] = cells[i].toJSON();
1135 };
1135 };
1136 var data = {
1136 var data = {
1137 // Only handle 1 worksheet for now.
1137 // Only handle 1 worksheet for now.
1138 worksheets : [{
1138 worksheets : [{
1139 cells: cell_array,
1139 cells: cell_array,
1140 metadata: this.worksheet_metadata
1140 metadata: this.worksheet_metadata
1141 }],
1141 }],
1142 metadata : this.metadata
1142 metadata : this.metadata
1143 };
1143 };
1144 return data;
1144 return data;
1145 };
1145 };
1146
1146
1147 Notebook.prototype.save_notebook = function () {
1147 Notebook.prototype.save_notebook = function () {
1148 // We may want to move the name/id/nbformat logic inside toJSON?
1148 // We may want to move the name/id/nbformat logic inside toJSON?
1149 var data = this.toJSON();
1149 var data = this.toJSON();
1150 data.metadata.name = this.notebook_name;
1150 data.metadata.name = this.notebook_name;
1151 data.nbformat = this.nbformat;
1151 data.nbformat = this.nbformat;
1152 data.nbformat_minor = this.nbformat_minor;
1152 data.nbformat_minor = this.nbformat_minor;
1153 // We do the call with settings so we can set cache to false.
1153 // We do the call with settings so we can set cache to false.
1154 var settings = {
1154 var settings = {
1155 processData : false,
1155 processData : false,
1156 cache : false,
1156 cache : false,
1157 type : "PUT",
1157 type : "PUT",
1158 data : JSON.stringify(data),
1158 data : JSON.stringify(data),
1159 headers : {'Content-Type': 'application/json'},
1159 headers : {'Content-Type': 'application/json'},
1160 success : $.proxy(this.save_notebook_success,this),
1160 success : $.proxy(this.save_notebook_success,this),
1161 error : $.proxy(this.save_notebook_error,this)
1161 error : $.proxy(this.save_notebook_error,this)
1162 };
1162 };
1163 $([IPython.events]).trigger('notebook_saving.Notebook');
1163 $([IPython.events]).trigger('notebook_saving.Notebook');
1164 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1164 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1165 $.ajax(url, settings);
1165 $.ajax(url, settings);
1166 };
1166 };
1167
1167
1168
1168
1169 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1169 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1170 this.dirty = false;
1170 this.dirty = false;
1171 $([IPython.events]).trigger('notebook_saved.Notebook');
1171 $([IPython.events]).trigger('notebook_saved.Notebook');
1172 };
1172 };
1173
1173
1174
1174
1175 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1175 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1176 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1176 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1177 };
1177 };
1178
1178
1179
1179
1180 Notebook.prototype.load_notebook = function (notebook_id) {
1180 Notebook.prototype.load_notebook = function (notebook_id) {
1181 var that = this;
1181 var that = this;
1182 this.notebook_id = notebook_id;
1182 this.notebook_id = notebook_id;
1183 // We do the call with settings so we can set cache to false.
1183 // We do the call with settings so we can set cache to false.
1184 var settings = {
1184 var settings = {
1185 processData : false,
1185 processData : false,
1186 cache : false,
1186 cache : false,
1187 type : "GET",
1187 type : "GET",
1188 dataType : "json",
1188 dataType : "json",
1189 success : $.proxy(this.load_notebook_success,this),
1189 success : $.proxy(this.load_notebook_success,this),
1190 error : $.proxy(this.load_notebook_error,this),
1190 error : $.proxy(this.load_notebook_error,this),
1191 };
1191 };
1192 $([IPython.events]).trigger('notebook_loading.Notebook');
1192 $([IPython.events]).trigger('notebook_loading.Notebook');
1193 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1193 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1194 $.ajax(url, settings);
1194 $.ajax(url, settings);
1195 };
1195 };
1196
1196
1197
1197
1198 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1198 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1199 this.fromJSON(data);
1199 this.fromJSON(data);
1200 if (this.ncells() === 0) {
1200 if (this.ncells() === 0) {
1201 this.insert_cell_below('code');
1201 this.insert_cell_below('code');
1202 };
1202 };
1203 this.dirty = false;
1203 this.dirty = false;
1204 this.select(0);
1204 this.select(0);
1205 this.scroll_to_top();
1205 this.scroll_to_top();
1206 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1206 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1207 msg = "This notebook has been converted from an older " +
1207 msg = "This notebook has been converted from an older " +
1208 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1208 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1209 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1209 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1210 "newer notebook format will be used and older verions of IPython " +
1210 "newer notebook format will be used and older verions of IPython " +
1211 "may not be able to read it. To keep the older version, close the " +
1211 "may not be able to read it. To keep the older version, close the " +
1212 "notebook without saving it.";
1212 "notebook without saving it.";
1213 var dialog = $('<div/>');
1213 var dialog = $('<div/>');
1214 dialog.html(msg);
1214 dialog.html(msg);
1215 this.element.append(dialog);
1215 this.element.append(dialog);
1216 dialog.dialog({
1216 dialog.dialog({
1217 resizable: false,
1217 resizable: false,
1218 modal: true,
1218 modal: true,
1219 title: "Notebook converted",
1219 title: "Notebook converted",
1220 closeText: "",
1220 closeText: "",
1221 close: function(event, ui) {$(this).dialog('destroy').remove();},
1221 close: function(event, ui) {$(this).dialog('destroy').remove();},
1222 buttons : {
1222 buttons : {
1223 "OK": function () {
1223 "OK": function () {
1224 $(this).dialog('close');
1224 $(this).dialog('close');
1225 }
1225 }
1226 },
1226 },
1227 width: 400
1227 width: 400
1228 });
1228 });
1229 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1229 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1230 var that = this;
1230 var that = this;
1231 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1231 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1232 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1232 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1233 msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1233 msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1234 this_vs + ". You can still work with this notebook, but some features " +
1234 this_vs + ". You can still work with this notebook, but some features " +
1235 "introduced in later notebook versions may not be available."
1235 "introduced in later notebook versions may not be available."
1236
1236
1237 var dialog = $('<div/>');
1237 var dialog = $('<div/>');
1238 dialog.html(msg);
1238 dialog.html(msg);
1239 this.element.append(dialog);
1239 this.element.append(dialog);
1240 dialog.dialog({
1240 dialog.dialog({
1241 resizable: false,
1241 resizable: false,
1242 modal: true,
1242 modal: true,
1243 title: "Newer Notebook",
1243 title: "Newer Notebook",
1244 closeText: "",
1244 closeText: "",
1245 close: function(event, ui) {$(this).dialog('destroy').remove();},
1245 close: function(event, ui) {$(this).dialog('destroy').remove();},
1246 buttons : {
1246 buttons : {
1247 "OK": function () {
1247 "OK": function () {
1248 $(this).dialog('close');
1248 $(this).dialog('close');
1249 }
1249 }
1250 },
1250 },
1251 width: 400
1251 width: 400
1252 });
1252 });
1253
1253
1254 }
1254 }
1255 // Create the kernel after the notebook is completely loaded to prevent
1255 // Create the kernel after the notebook is completely loaded to prevent
1256 // code execution upon loading, which is a security risk.
1256 // code execution upon loading, which is a security risk.
1257 if (! this.read_only) {
1257 if (! this.read_only) {
1258 this.start_kernel();
1258 this.start_kernel();
1259 }
1259 }
1260 $([IPython.events]).trigger('notebook_loaded.Notebook');
1260 $([IPython.events]).trigger('notebook_loaded.Notebook');
1261 };
1261 };
1262
1262
1263
1263
1264 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1264 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1265 if (xhr.status === 500) {
1265 if (xhr.status === 500) {
1266 msg = "An error occurred while loading this notebook. Most likely " +
1266 msg = "An error occurred while loading this notebook. Most likely " +
1267 "this notebook is in a newer format than is supported by this " +
1267 "this notebook is in a newer format than is supported by this " +
1268 "version of IPython. This version can load notebook formats " +
1268 "version of IPython. This version can load notebook formats " +
1269 "v"+this.nbformat+" or earlier.";
1269 "v"+this.nbformat+" or earlier.";
1270 var dialog = $('<div/>');
1270 var dialog = $('<div/>');
1271 dialog.html(msg);
1271 dialog.html(msg);
1272 this.element.append(dialog);
1272 this.element.append(dialog);
1273 dialog.dialog({
1273 dialog.dialog({
1274 resizable: false,
1274 resizable: false,
1275 modal: true,
1275 modal: true,
1276 title: "Error loading notebook",
1276 title: "Error loading notebook",
1277 closeText: "",
1277 closeText: "",
1278 close: function(event, ui) {$(this).dialog('destroy').remove();},
1278 close: function(event, ui) {$(this).dialog('destroy').remove();},
1279 buttons : {
1279 buttons : {
1280 "OK": function () {
1280 "OK": function () {
1281 $(this).dialog('close');
1281 $(this).dialog('close');
1282 }
1282 }
1283 },
1283 },
1284 width: 400
1284 width: 400
1285 });
1285 });
1286 }
1286 }
1287 }
1287 }
1288
1288
1289 IPython.Notebook = Notebook;
1289 IPython.Notebook = Notebook;
1290
1290
1291
1291
1292 return IPython;
1292 return IPython;
1293
1293
1294 }(IPython));
1294 }(IPython));
1295
1295
General Comments 0
You need to be logged in to leave comments. Login now