##// END OF EJS Templates
Merge pull request #2400 from Carreau/scroll_to_cell...
Bussonnier Matthias -
r8434:a52d09c8 merge
parent child Browse files
Show More
@@ -1,1295 +1,1305 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notebook
9 // Notebook
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15 var key = IPython.utils.keycodes;
15 var key = IPython.utils.keycodes;
16
16
17 var Notebook = function (selector) {
17 var Notebook = function (selector) {
18 this.read_only = IPython.read_only;
18 this.read_only = IPython.read_only;
19 this.element = $(selector);
19 this.element = $(selector);
20 this.element.scroll();
20 this.element.scroll();
21 this.element.data("notebook", this);
21 this.element.data("notebook", this);
22 this.next_prompt_number = 1;
22 this.next_prompt_number = 1;
23 this.kernel = null;
23 this.kernel = null;
24 this.clipboard = null;
24 this.clipboard = null;
25 this.paste_enabled = false;
25 this.paste_enabled = false;
26 this.dirty = false;
26 this.dirty = false;
27 this.metadata = {};
27 this.metadata = {};
28 // 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 (/\S/.test(that.get_selected_cell().get_text()) == true) {
121 if (/\S/.test(that.get_selected_cell().get_text()) == 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 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
308 var cells = this.get_cells();
309 var time = time || 0;
310 cell_number = Math.min(cells.length-1,cell_number);
311 cell_number = Math.max(0 ,cell_number);
312 scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
313 this.element.animate({scrollTop:scroll_value}, time);
314 return scroll_value;
315 };
316
307
317
308 Notebook.prototype.scroll_to_bottom = function () {
318 Notebook.prototype.scroll_to_bottom = function () {
309 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
319 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
310 };
320 };
311
321
312
322
313 Notebook.prototype.scroll_to_top = function () {
323 Notebook.prototype.scroll_to_top = function () {
314 this.element.animate({scrollTop:0}, 0);
324 this.element.animate({scrollTop:0}, 0);
315 };
325 };
316
326
317
327
318 // Cell indexing, retrieval, etc.
328 // Cell indexing, retrieval, etc.
319
329
320 Notebook.prototype.get_cell_elements = function () {
330 Notebook.prototype.get_cell_elements = function () {
321 return this.element.children("div.cell");
331 return this.element.children("div.cell");
322 };
332 };
323
333
324
334
325 Notebook.prototype.get_cell_element = function (index) {
335 Notebook.prototype.get_cell_element = function (index) {
326 var result = null;
336 var result = null;
327 var e = this.get_cell_elements().eq(index);
337 var e = this.get_cell_elements().eq(index);
328 if (e.length !== 0) {
338 if (e.length !== 0) {
329 result = e;
339 result = e;
330 }
340 }
331 return result;
341 return result;
332 };
342 };
333
343
334
344
335 Notebook.prototype.ncells = function (cell) {
345 Notebook.prototype.ncells = function (cell) {
336 return this.get_cell_elements().length;
346 return this.get_cell_elements().length;
337 };
347 };
338
348
339
349
340 // TODO: we are often calling cells as cells()[i], which we should optimize
350 // TODO: we are often calling cells as cells()[i], which we should optimize
341 // to cells(i) or a new method.
351 // to cells(i) or a new method.
342 Notebook.prototype.get_cells = function () {
352 Notebook.prototype.get_cells = function () {
343 return this.get_cell_elements().toArray().map(function (e) {
353 return this.get_cell_elements().toArray().map(function (e) {
344 return $(e).data("cell");
354 return $(e).data("cell");
345 });
355 });
346 };
356 };
347
357
348
358
349 Notebook.prototype.get_cell = function (index) {
359 Notebook.prototype.get_cell = function (index) {
350 var result = null;
360 var result = null;
351 var ce = this.get_cell_element(index);
361 var ce = this.get_cell_element(index);
352 if (ce !== null) {
362 if (ce !== null) {
353 result = ce.data('cell');
363 result = ce.data('cell');
354 }
364 }
355 return result;
365 return result;
356 }
366 }
357
367
358
368
359 Notebook.prototype.get_next_cell = function (cell) {
369 Notebook.prototype.get_next_cell = function (cell) {
360 var result = null;
370 var result = null;
361 var index = this.find_cell_index(cell);
371 var index = this.find_cell_index(cell);
362 if (index !== null && index < this.ncells()) {
372 if (index !== null && index < this.ncells()) {
363 result = this.get_cell(index+1);
373 result = this.get_cell(index+1);
364 }
374 }
365 return result;
375 return result;
366 }
376 }
367
377
368
378
369 Notebook.prototype.get_prev_cell = function (cell) {
379 Notebook.prototype.get_prev_cell = function (cell) {
370 var result = null;
380 var result = null;
371 var index = this.find_cell_index(cell);
381 var index = this.find_cell_index(cell);
372 if (index !== null && index > 1) {
382 if (index !== null && index > 1) {
373 result = this.get_cell(index-1);
383 result = this.get_cell(index-1);
374 }
384 }
375 return result;
385 return result;
376 }
386 }
377
387
378 Notebook.prototype.find_cell_index = function (cell) {
388 Notebook.prototype.find_cell_index = function (cell) {
379 var result = null;
389 var result = null;
380 this.get_cell_elements().filter(function (index) {
390 this.get_cell_elements().filter(function (index) {
381 if ($(this).data("cell") === cell) {
391 if ($(this).data("cell") === cell) {
382 result = index;
392 result = index;
383 };
393 };
384 });
394 });
385 return result;
395 return result;
386 };
396 };
387
397
388
398
389 Notebook.prototype.index_or_selected = function (index) {
399 Notebook.prototype.index_or_selected = function (index) {
390 var i;
400 var i;
391 if (index === undefined || index === null) {
401 if (index === undefined || index === null) {
392 i = this.get_selected_index();
402 i = this.get_selected_index();
393 if (i === null) {
403 if (i === null) {
394 i = 0;
404 i = 0;
395 }
405 }
396 } else {
406 } else {
397 i = index;
407 i = index;
398 }
408 }
399 return i;
409 return i;
400 };
410 };
401
411
402
412
403 Notebook.prototype.get_selected_cell = function () {
413 Notebook.prototype.get_selected_cell = function () {
404 var index = this.get_selected_index();
414 var index = this.get_selected_index();
405 return this.get_cell(index);
415 return this.get_cell(index);
406 };
416 };
407
417
408
418
409 Notebook.prototype.is_valid_cell_index = function (index) {
419 Notebook.prototype.is_valid_cell_index = function (index) {
410 if (index !== null && index >= 0 && index < this.ncells()) {
420 if (index !== null && index >= 0 && index < this.ncells()) {
411 return true;
421 return true;
412 } else {
422 } else {
413 return false;
423 return false;
414 };
424 };
415 }
425 }
416
426
417 Notebook.prototype.get_selected_index = function () {
427 Notebook.prototype.get_selected_index = function () {
418 var result = null;
428 var result = null;
419 this.get_cell_elements().filter(function (index) {
429 this.get_cell_elements().filter(function (index) {
420 if ($(this).data("cell").selected === true) {
430 if ($(this).data("cell").selected === true) {
421 result = index;
431 result = index;
422 };
432 };
423 });
433 });
424 return result;
434 return result;
425 };
435 };
426
436
427
437
428 // Cell selection.
438 // Cell selection.
429
439
430 Notebook.prototype.select = function (index) {
440 Notebook.prototype.select = function (index) {
431 if (index !== undefined && index >= 0 && index < this.ncells()) {
441 if (index !== undefined && index >= 0 && index < this.ncells()) {
432 sindex = this.get_selected_index()
442 sindex = this.get_selected_index()
433 if (sindex !== null && index !== sindex) {
443 if (sindex !== null && index !== sindex) {
434 this.get_cell(sindex).unselect();
444 this.get_cell(sindex).unselect();
435 };
445 };
436 var cell = this.get_cell(index)
446 var cell = this.get_cell(index)
437 cell.select();
447 cell.select();
438 if (cell.cell_type === 'heading') {
448 if (cell.cell_type === 'heading') {
439 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
449 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
440 {'cell_type':cell.cell_type,level:cell.level}
450 {'cell_type':cell.cell_type,level:cell.level}
441 );
451 );
442 } else {
452 } else {
443 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
453 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
444 {'cell_type':cell.cell_type}
454 {'cell_type':cell.cell_type}
445 );
455 );
446 };
456 };
447 };
457 };
448 return this;
458 return this;
449 };
459 };
450
460
451
461
452 Notebook.prototype.select_next = function () {
462 Notebook.prototype.select_next = function () {
453 var index = this.get_selected_index();
463 var index = this.get_selected_index();
454 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
464 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
455 this.select(index+1);
465 this.select(index+1);
456 };
466 };
457 return this;
467 return this;
458 };
468 };
459
469
460
470
461 Notebook.prototype.select_prev = function () {
471 Notebook.prototype.select_prev = function () {
462 var index = this.get_selected_index();
472 var index = this.get_selected_index();
463 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
473 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
464 this.select(index-1);
474 this.select(index-1);
465 };
475 };
466 return this;
476 return this;
467 };
477 };
468
478
469
479
470 // Cell movement
480 // Cell movement
471
481
472 Notebook.prototype.move_cell_up = function (index) {
482 Notebook.prototype.move_cell_up = function (index) {
473 var i = this.index_or_selected();
483 var i = this.index_or_selected();
474 if (i !== null && i < this.ncells() && i > 0) {
484 if (i !== null && i < this.ncells() && i > 0) {
475 var pivot = this.get_cell_element(i-1);
485 var pivot = this.get_cell_element(i-1);
476 var tomove = this.get_cell_element(i);
486 var tomove = this.get_cell_element(i);
477 if (pivot !== null && tomove !== null) {
487 if (pivot !== null && tomove !== null) {
478 tomove.detach();
488 tomove.detach();
479 pivot.before(tomove);
489 pivot.before(tomove);
480 this.select(i-1);
490 this.select(i-1);
481 };
491 };
482 };
492 };
483 this.dirty = true;
493 this.dirty = true;
484 return this;
494 return this;
485 };
495 };
486
496
487
497
488 Notebook.prototype.move_cell_down = function (index) {
498 Notebook.prototype.move_cell_down = function (index) {
489 var i = this.index_or_selected();
499 var i = this.index_or_selected();
490 if (i !== null && i < (this.ncells()-1) && i >= 0) {
500 if (i !== null && i < (this.ncells()-1) && i >= 0) {
491 var pivot = this.get_cell_element(i+1);
501 var pivot = this.get_cell_element(i+1);
492 var tomove = this.get_cell_element(i);
502 var tomove = this.get_cell_element(i);
493 if (pivot !== null && tomove !== null) {
503 if (pivot !== null && tomove !== null) {
494 tomove.detach();
504 tomove.detach();
495 pivot.after(tomove);
505 pivot.after(tomove);
496 this.select(i+1);
506 this.select(i+1);
497 };
507 };
498 };
508 };
499 this.dirty = true;
509 this.dirty = true;
500 return this;
510 return this;
501 };
511 };
502
512
503
513
504 Notebook.prototype.sort_cells = function () {
514 Notebook.prototype.sort_cells = function () {
505 // This is not working right now. Calling this will actually crash
515 // This is not working right now. Calling this will actually crash
506 // the browser. I think there is an infinite loop in here...
516 // the browser. I think there is an infinite loop in here...
507 var ncells = this.ncells();
517 var ncells = this.ncells();
508 var sindex = this.get_selected_index();
518 var sindex = this.get_selected_index();
509 var swapped;
519 var swapped;
510 do {
520 do {
511 swapped = false;
521 swapped = false;
512 for (var i=1; i<ncells; i++) {
522 for (var i=1; i<ncells; i++) {
513 current = this.get_cell(i);
523 current = this.get_cell(i);
514 previous = this.get_cell(i-1);
524 previous = this.get_cell(i-1);
515 if (previous.input_prompt_number > current.input_prompt_number) {
525 if (previous.input_prompt_number > current.input_prompt_number) {
516 this.move_cell_up(i);
526 this.move_cell_up(i);
517 swapped = true;
527 swapped = true;
518 };
528 };
519 };
529 };
520 } while (swapped);
530 } while (swapped);
521 this.select(sindex);
531 this.select(sindex);
522 return this;
532 return this;
523 };
533 };
524
534
525 // Insertion, deletion.
535 // Insertion, deletion.
526
536
527 Notebook.prototype.delete_cell = function (index) {
537 Notebook.prototype.delete_cell = function (index) {
528 var i = this.index_or_selected(index);
538 var i = this.index_or_selected(index);
529 if (this.is_valid_cell_index(i)) {
539 if (this.is_valid_cell_index(i)) {
530 var ce = this.get_cell_element(i);
540 var ce = this.get_cell_element(i);
531 ce.remove();
541 ce.remove();
532 if (i === (this.ncells())) {
542 if (i === (this.ncells())) {
533 this.select(i-1);
543 this.select(i-1);
534 } else {
544 } else {
535 this.select(i);
545 this.select(i);
536 };
546 };
537 this.dirty = true;
547 this.dirty = true;
538 };
548 };
539 return this;
549 return this;
540 };
550 };
541
551
542
552
543 Notebook.prototype.insert_cell_below = function (type, index) {
553 Notebook.prototype.insert_cell_below = function (type, index) {
544 // type = ('code','html','markdown')
554 // type = ('code','html','markdown')
545 // index = cell index or undefined to insert below selected
555 // index = cell index or undefined to insert below selected
546 index = this.index_or_selected(index);
556 index = this.index_or_selected(index);
547 var cell = null;
557 var cell = null;
548 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
558 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
549 if (type === 'code') {
559 if (type === 'code') {
550 cell = new IPython.CodeCell(this.kernel);
560 cell = new IPython.CodeCell(this.kernel);
551 cell.set_input_prompt();
561 cell.set_input_prompt();
552 } else if (type === 'markdown') {
562 } else if (type === 'markdown') {
553 cell = new IPython.MarkdownCell();
563 cell = new IPython.MarkdownCell();
554 } else if (type === 'html') {
564 } else if (type === 'html') {
555 cell = new IPython.HTMLCell();
565 cell = new IPython.HTMLCell();
556 } else if (type === 'raw') {
566 } else if (type === 'raw') {
557 cell = new IPython.RawCell();
567 cell = new IPython.RawCell();
558 } else if (type === 'heading') {
568 } else if (type === 'heading') {
559 cell = new IPython.HeadingCell();
569 cell = new IPython.HeadingCell();
560 };
570 };
561 if (cell !== null) {
571 if (cell !== null) {
562 if (this.ncells() === 0) {
572 if (this.ncells() === 0) {
563 this.element.find('div.end_space').before(cell.element);
573 this.element.find('div.end_space').before(cell.element);
564 } else if (this.is_valid_cell_index(index)) {
574 } else if (this.is_valid_cell_index(index)) {
565 this.get_cell_element(index).after(cell.element);
575 this.get_cell_element(index).after(cell.element);
566 };
576 };
567 cell.render();
577 cell.render();
568 this.select(this.find_cell_index(cell));
578 this.select(this.find_cell_index(cell));
569 this.dirty = true;
579 this.dirty = true;
570 return cell;
580 return cell;
571 };
581 };
572 };
582 };
573 return cell;
583 return cell;
574 };
584 };
575
585
576
586
577 Notebook.prototype.insert_cell_above = function (type, index) {
587 Notebook.prototype.insert_cell_above = function (type, index) {
578 // type = ('code','html','markdown')
588 // type = ('code','html','markdown')
579 // index = cell index or undefined to insert above selected
589 // index = cell index or undefined to insert above selected
580 index = this.index_or_selected(index);
590 index = this.index_or_selected(index);
581 var cell = null;
591 var cell = null;
582 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
592 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
583 if (type === 'code') {
593 if (type === 'code') {
584 cell = new IPython.CodeCell(this.kernel);
594 cell = new IPython.CodeCell(this.kernel);
585 cell.set_input_prompt();
595 cell.set_input_prompt();
586 } else if (type === 'markdown') {
596 } else if (type === 'markdown') {
587 cell = new IPython.MarkdownCell();
597 cell = new IPython.MarkdownCell();
588 } else if (type === 'html') {
598 } else if (type === 'html') {
589 cell = new IPython.HTMLCell();
599 cell = new IPython.HTMLCell();
590 } else if (type === 'raw') {
600 } else if (type === 'raw') {
591 cell = new IPython.RawCell();
601 cell = new IPython.RawCell();
592 } else if (type === 'heading') {
602 } else if (type === 'heading') {
593 cell = new IPython.HeadingCell();
603 cell = new IPython.HeadingCell();
594 };
604 };
595 if (cell !== null) {
605 if (cell !== null) {
596 if (this.ncells() === 0) {
606 if (this.ncells() === 0) {
597 this.element.find('div.end_space').before(cell.element);
607 this.element.find('div.end_space').before(cell.element);
598 } else if (this.is_valid_cell_index(index)) {
608 } else if (this.is_valid_cell_index(index)) {
599 this.get_cell_element(index).before(cell.element);
609 this.get_cell_element(index).before(cell.element);
600 };
610 };
601 cell.render();
611 cell.render();
602 this.select(this.find_cell_index(cell));
612 this.select(this.find_cell_index(cell));
603 this.dirty = true;
613 this.dirty = true;
604 return cell;
614 return cell;
605 };
615 };
606 };
616 };
607 return cell;
617 return cell;
608 };
618 };
609
619
610
620
611 Notebook.prototype.to_code = function (index) {
621 Notebook.prototype.to_code = function (index) {
612 var i = this.index_or_selected(index);
622 var i = this.index_or_selected(index);
613 if (this.is_valid_cell_index(i)) {
623 if (this.is_valid_cell_index(i)) {
614 var source_element = this.get_cell_element(i);
624 var source_element = this.get_cell_element(i);
615 var source_cell = source_element.data("cell");
625 var source_cell = source_element.data("cell");
616 if (!(source_cell instanceof IPython.CodeCell)) {
626 if (!(source_cell instanceof IPython.CodeCell)) {
617 target_cell = this.insert_cell_below('code',i);
627 target_cell = this.insert_cell_below('code',i);
618 var text = source_cell.get_text();
628 var text = source_cell.get_text();
619 if (text === source_cell.placeholder) {
629 if (text === source_cell.placeholder) {
620 text = '';
630 text = '';
621 }
631 }
622 target_cell.set_text(text);
632 target_cell.set_text(text);
623 // make this value the starting point, so that we can only undo
633 // make this value the starting point, so that we can only undo
624 // to this state, instead of a blank cell
634 // to this state, instead of a blank cell
625 target_cell.code_mirror.clearHistory();
635 target_cell.code_mirror.clearHistory();
626 source_element.remove();
636 source_element.remove();
627 this.dirty = true;
637 this.dirty = true;
628 };
638 };
629 };
639 };
630 };
640 };
631
641
632
642
633 Notebook.prototype.to_markdown = function (index) {
643 Notebook.prototype.to_markdown = function (index) {
634 var i = this.index_or_selected(index);
644 var i = this.index_or_selected(index);
635 if (this.is_valid_cell_index(i)) {
645 if (this.is_valid_cell_index(i)) {
636 var source_element = this.get_cell_element(i);
646 var source_element = this.get_cell_element(i);
637 var source_cell = source_element.data("cell");
647 var source_cell = source_element.data("cell");
638 if (!(source_cell instanceof IPython.MarkdownCell)) {
648 if (!(source_cell instanceof IPython.MarkdownCell)) {
639 target_cell = this.insert_cell_below('markdown',i);
649 target_cell = this.insert_cell_below('markdown',i);
640 var text = source_cell.get_text();
650 var text = source_cell.get_text();
641 if (text === source_cell.placeholder) {
651 if (text === source_cell.placeholder) {
642 text = '';
652 text = '';
643 };
653 };
644 // The edit must come before the set_text.
654 // The edit must come before the set_text.
645 target_cell.edit();
655 target_cell.edit();
646 target_cell.set_text(text);
656 target_cell.set_text(text);
647 // make this value the starting point, so that we can only undo
657 // make this value the starting point, so that we can only undo
648 // to this state, instead of a blank cell
658 // to this state, instead of a blank cell
649 target_cell.code_mirror.clearHistory();
659 target_cell.code_mirror.clearHistory();
650 source_element.remove();
660 source_element.remove();
651 this.dirty = true;
661 this.dirty = true;
652 };
662 };
653 };
663 };
654 };
664 };
655
665
656
666
657 Notebook.prototype.to_html = function (index) {
667 Notebook.prototype.to_html = function (index) {
658 var i = this.index_or_selected(index);
668 var i = this.index_or_selected(index);
659 if (this.is_valid_cell_index(i)) {
669 if (this.is_valid_cell_index(i)) {
660 var source_element = this.get_cell_element(i);
670 var source_element = this.get_cell_element(i);
661 var source_cell = source_element.data("cell");
671 var source_cell = source_element.data("cell");
662 var target_cell = null;
672 var target_cell = null;
663 if (!(source_cell instanceof IPython.HTMLCell)) {
673 if (!(source_cell instanceof IPython.HTMLCell)) {
664 target_cell = this.insert_cell_below('html',i);
674 target_cell = this.insert_cell_below('html',i);
665 var text = source_cell.get_text();
675 var text = source_cell.get_text();
666 if (text === source_cell.placeholder) {
676 if (text === source_cell.placeholder) {
667 text = '';
677 text = '';
668 };
678 };
669 // The edit must come before the set_text.
679 // The edit must come before the set_text.
670 target_cell.edit();
680 target_cell.edit();
671 target_cell.set_text(text);
681 target_cell.set_text(text);
672 // make this value the starting point, so that we can only undo
682 // make this value the starting point, so that we can only undo
673 // to this state, instead of a blank cell
683 // to this state, instead of a blank cell
674 target_cell.code_mirror.clearHistory();
684 target_cell.code_mirror.clearHistory();
675 source_element.remove();
685 source_element.remove();
676 this.dirty = true;
686 this.dirty = true;
677 };
687 };
678 };
688 };
679 };
689 };
680
690
681
691
682 Notebook.prototype.to_raw = function (index) {
692 Notebook.prototype.to_raw = function (index) {
683 var i = this.index_or_selected(index);
693 var i = this.index_or_selected(index);
684 if (this.is_valid_cell_index(i)) {
694 if (this.is_valid_cell_index(i)) {
685 var source_element = this.get_cell_element(i);
695 var source_element = this.get_cell_element(i);
686 var source_cell = source_element.data("cell");
696 var source_cell = source_element.data("cell");
687 var target_cell = null;
697 var target_cell = null;
688 if (!(source_cell instanceof IPython.RawCell)) {
698 if (!(source_cell instanceof IPython.RawCell)) {
689 target_cell = this.insert_cell_below('raw',i);
699 target_cell = this.insert_cell_below('raw',i);
690 var text = source_cell.get_text();
700 var text = source_cell.get_text();
691 if (text === source_cell.placeholder) {
701 if (text === source_cell.placeholder) {
692 text = '';
702 text = '';
693 };
703 };
694 // The edit must come before the set_text.
704 // The edit must come before the set_text.
695 target_cell.edit();
705 target_cell.edit();
696 target_cell.set_text(text);
706 target_cell.set_text(text);
697 // make this value the starting point, so that we can only undo
707 // make this value the starting point, so that we can only undo
698 // to this state, instead of a blank cell
708 // to this state, instead of a blank cell
699 target_cell.code_mirror.clearHistory();
709 target_cell.code_mirror.clearHistory();
700 source_element.remove();
710 source_element.remove();
701 this.dirty = true;
711 this.dirty = true;
702 };
712 };
703 };
713 };
704 };
714 };
705
715
706
716
707 Notebook.prototype.to_heading = function (index, level) {
717 Notebook.prototype.to_heading = function (index, level) {
708 level = level || 1;
718 level = level || 1;
709 var i = this.index_or_selected(index);
719 var i = this.index_or_selected(index);
710 if (this.is_valid_cell_index(i)) {
720 if (this.is_valid_cell_index(i)) {
711 var source_element = this.get_cell_element(i);
721 var source_element = this.get_cell_element(i);
712 var source_cell = source_element.data("cell");
722 var source_cell = source_element.data("cell");
713 var target_cell = null;
723 var target_cell = null;
714 if (source_cell instanceof IPython.HeadingCell) {
724 if (source_cell instanceof IPython.HeadingCell) {
715 source_cell.set_level(level);
725 source_cell.set_level(level);
716 } else {
726 } else {
717 target_cell = this.insert_cell_below('heading',i);
727 target_cell = this.insert_cell_below('heading',i);
718 var text = source_cell.get_text();
728 var text = source_cell.get_text();
719 if (text === source_cell.placeholder) {
729 if (text === source_cell.placeholder) {
720 text = '';
730 text = '';
721 };
731 };
722 // The edit must come before the set_text.
732 // The edit must come before the set_text.
723 target_cell.set_level(level);
733 target_cell.set_level(level);
724 target_cell.edit();
734 target_cell.edit();
725 target_cell.set_text(text);
735 target_cell.set_text(text);
726 // make this value the starting point, so that we can only undo
736 // make this value the starting point, so that we can only undo
727 // to this state, instead of a blank cell
737 // to this state, instead of a blank cell
728 target_cell.code_mirror.clearHistory();
738 target_cell.code_mirror.clearHistory();
729 source_element.remove();
739 source_element.remove();
730 this.dirty = true;
740 this.dirty = true;
731 };
741 };
732 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
742 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
733 {'cell_type':'heading',level:level}
743 {'cell_type':'heading',level:level}
734 );
744 );
735 };
745 };
736 };
746 };
737
747
738
748
739 // Cut/Copy/Paste
749 // Cut/Copy/Paste
740
750
741 Notebook.prototype.enable_paste = function () {
751 Notebook.prototype.enable_paste = function () {
742 var that = this;
752 var that = this;
743 if (!this.paste_enabled) {
753 if (!this.paste_enabled) {
744 $('#paste_cell').removeClass('ui-state-disabled')
754 $('#paste_cell').removeClass('ui-state-disabled')
745 .on('click', function () {that.paste_cell();});
755 .on('click', function () {that.paste_cell();});
746 $('#paste_cell_above').removeClass('ui-state-disabled')
756 $('#paste_cell_above').removeClass('ui-state-disabled')
747 .on('click', function () {that.paste_cell_above();});
757 .on('click', function () {that.paste_cell_above();});
748 $('#paste_cell_below').removeClass('ui-state-disabled')
758 $('#paste_cell_below').removeClass('ui-state-disabled')
749 .on('click', function () {that.paste_cell_below();});
759 .on('click', function () {that.paste_cell_below();});
750 this.paste_enabled = true;
760 this.paste_enabled = true;
751 };
761 };
752 };
762 };
753
763
754
764
755 Notebook.prototype.disable_paste = function () {
765 Notebook.prototype.disable_paste = function () {
756 if (this.paste_enabled) {
766 if (this.paste_enabled) {
757 $('#paste_cell').addClass('ui-state-disabled').off('click');
767 $('#paste_cell').addClass('ui-state-disabled').off('click');
758 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
768 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
759 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
769 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
760 this.paste_enabled = false;
770 this.paste_enabled = false;
761 };
771 };
762 };
772 };
763
773
764
774
765 Notebook.prototype.cut_cell = function () {
775 Notebook.prototype.cut_cell = function () {
766 this.copy_cell();
776 this.copy_cell();
767 this.delete_cell();
777 this.delete_cell();
768 }
778 }
769
779
770 Notebook.prototype.copy_cell = function () {
780 Notebook.prototype.copy_cell = function () {
771 var cell = this.get_selected_cell();
781 var cell = this.get_selected_cell();
772 this.clipboard = cell.toJSON();
782 this.clipboard = cell.toJSON();
773 this.enable_paste();
783 this.enable_paste();
774 };
784 };
775
785
776
786
777 Notebook.prototype.paste_cell = function () {
787 Notebook.prototype.paste_cell = function () {
778 if (this.clipboard !== null && this.paste_enabled) {
788 if (this.clipboard !== null && this.paste_enabled) {
779 var cell_data = this.clipboard;
789 var cell_data = this.clipboard;
780 var new_cell = this.insert_cell_above(cell_data.cell_type);
790 var new_cell = this.insert_cell_above(cell_data.cell_type);
781 new_cell.fromJSON(cell_data);
791 new_cell.fromJSON(cell_data);
782 old_cell = this.get_next_cell(new_cell);
792 old_cell = this.get_next_cell(new_cell);
783 this.delete_cell(this.find_cell_index(old_cell));
793 this.delete_cell(this.find_cell_index(old_cell));
784 this.select(this.find_cell_index(new_cell));
794 this.select(this.find_cell_index(new_cell));
785 };
795 };
786 };
796 };
787
797
788
798
789 Notebook.prototype.paste_cell_above = function () {
799 Notebook.prototype.paste_cell_above = function () {
790 if (this.clipboard !== null && this.paste_enabled) {
800 if (this.clipboard !== null && this.paste_enabled) {
791 var cell_data = this.clipboard;
801 var cell_data = this.clipboard;
792 var new_cell = this.insert_cell_above(cell_data.cell_type);
802 var new_cell = this.insert_cell_above(cell_data.cell_type);
793 new_cell.fromJSON(cell_data);
803 new_cell.fromJSON(cell_data);
794 };
804 };
795 };
805 };
796
806
797
807
798 Notebook.prototype.paste_cell_below = function () {
808 Notebook.prototype.paste_cell_below = function () {
799 if (this.clipboard !== null && this.paste_enabled) {
809 if (this.clipboard !== null && this.paste_enabled) {
800 var cell_data = this.clipboard;
810 var cell_data = this.clipboard;
801 var new_cell = this.insert_cell_below(cell_data.cell_type);
811 var new_cell = this.insert_cell_below(cell_data.cell_type);
802 new_cell.fromJSON(cell_data);
812 new_cell.fromJSON(cell_data);
803 };
813 };
804 };
814 };
805
815
806
816
807 // Split/merge
817 // Split/merge
808
818
809 Notebook.prototype.split_cell = function () {
819 Notebook.prototype.split_cell = function () {
810 // Todo: implement spliting for other cell types.
820 // Todo: implement spliting for other cell types.
811 var cell = this.get_selected_cell();
821 var cell = this.get_selected_cell();
812 if (cell.is_splittable()) {
822 if (cell.is_splittable()) {
813 texta = cell.get_pre_cursor();
823 texta = cell.get_pre_cursor();
814 textb = cell.get_post_cursor();
824 textb = cell.get_post_cursor();
815 if (cell instanceof IPython.CodeCell) {
825 if (cell instanceof IPython.CodeCell) {
816 cell.set_text(texta);
826 cell.set_text(texta);
817 var new_cell = this.insert_cell_below('code');
827 var new_cell = this.insert_cell_below('code');
818 new_cell.set_text(textb);
828 new_cell.set_text(textb);
819 } else if (cell instanceof IPython.MarkdownCell) {
829 } else if (cell instanceof IPython.MarkdownCell) {
820 cell.set_text(texta);
830 cell.set_text(texta);
821 cell.render();
831 cell.render();
822 var new_cell = this.insert_cell_below('markdown');
832 var new_cell = this.insert_cell_below('markdown');
823 new_cell.edit(); // editor must be visible to call set_text
833 new_cell.edit(); // editor must be visible to call set_text
824 new_cell.set_text(textb);
834 new_cell.set_text(textb);
825 new_cell.render();
835 new_cell.render();
826 } else if (cell instanceof IPython.HTMLCell) {
836 } else if (cell instanceof IPython.HTMLCell) {
827 cell.set_text(texta);
837 cell.set_text(texta);
828 cell.render();
838 cell.render();
829 var new_cell = this.insert_cell_below('html');
839 var new_cell = this.insert_cell_below('html');
830 new_cell.edit(); // editor must be visible to call set_text
840 new_cell.edit(); // editor must be visible to call set_text
831 new_cell.set_text(textb);
841 new_cell.set_text(textb);
832 new_cell.render();
842 new_cell.render();
833 };
843 };
834 };
844 };
835 };
845 };
836
846
837
847
838 Notebook.prototype.merge_cell_above = function () {
848 Notebook.prototype.merge_cell_above = function () {
839 var index = this.get_selected_index();
849 var index = this.get_selected_index();
840 var cell = this.get_cell(index);
850 var cell = this.get_cell(index);
841 if (index > 0) {
851 if (index > 0) {
842 upper_cell = this.get_cell(index-1);
852 upper_cell = this.get_cell(index-1);
843 upper_text = upper_cell.get_text();
853 upper_text = upper_cell.get_text();
844 text = cell.get_text();
854 text = cell.get_text();
845 if (cell instanceof IPython.CodeCell) {
855 if (cell instanceof IPython.CodeCell) {
846 cell.set_text(upper_text+'\n'+text);
856 cell.set_text(upper_text+'\n'+text);
847 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
857 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
848 cell.edit();
858 cell.edit();
849 cell.set_text(upper_text+'\n'+text);
859 cell.set_text(upper_text+'\n'+text);
850 cell.render();
860 cell.render();
851 };
861 };
852 this.delete_cell(index-1);
862 this.delete_cell(index-1);
853 this.select(this.find_cell_index(cell));
863 this.select(this.find_cell_index(cell));
854 };
864 };
855 };
865 };
856
866
857
867
858 Notebook.prototype.merge_cell_below = function () {
868 Notebook.prototype.merge_cell_below = function () {
859 var index = this.get_selected_index();
869 var index = this.get_selected_index();
860 var cell = this.get_cell(index);
870 var cell = this.get_cell(index);
861 if (index < this.ncells()-1) {
871 if (index < this.ncells()-1) {
862 lower_cell = this.get_cell(index+1);
872 lower_cell = this.get_cell(index+1);
863 lower_text = lower_cell.get_text();
873 lower_text = lower_cell.get_text();
864 text = cell.get_text();
874 text = cell.get_text();
865 if (cell instanceof IPython.CodeCell) {
875 if (cell instanceof IPython.CodeCell) {
866 cell.set_text(text+'\n'+lower_text);
876 cell.set_text(text+'\n'+lower_text);
867 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
877 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
868 cell.edit();
878 cell.edit();
869 cell.set_text(text+'\n'+lower_text);
879 cell.set_text(text+'\n'+lower_text);
870 cell.render();
880 cell.render();
871 };
881 };
872 this.delete_cell(index+1);
882 this.delete_cell(index+1);
873 this.select(this.find_cell_index(cell));
883 this.select(this.find_cell_index(cell));
874 };
884 };
875 };
885 };
876
886
877
887
878 // Cell collapsing and output clearing
888 // Cell collapsing and output clearing
879
889
880 Notebook.prototype.collapse = function (index) {
890 Notebook.prototype.collapse = function (index) {
881 var i = this.index_or_selected(index);
891 var i = this.index_or_selected(index);
882 this.get_cell(i).collapse();
892 this.get_cell(i).collapse();
883 this.dirty = true;
893 this.dirty = true;
884 };
894 };
885
895
886
896
887 Notebook.prototype.expand = function (index) {
897 Notebook.prototype.expand = function (index) {
888 var i = this.index_or_selected(index);
898 var i = this.index_or_selected(index);
889 this.get_cell(i).expand();
899 this.get_cell(i).expand();
890 this.dirty = true;
900 this.dirty = true;
891 };
901 };
892
902
893
903
894 Notebook.prototype.toggle_output = function (index) {
904 Notebook.prototype.toggle_output = function (index) {
895 var i = this.index_or_selected(index);
905 var i = this.index_or_selected(index);
896 this.get_cell(i).toggle_output();
906 this.get_cell(i).toggle_output();
897 this.dirty = true;
907 this.dirty = true;
898 };
908 };
899
909
900
910
901 Notebook.prototype.toggle_output_scroll = function (index) {
911 Notebook.prototype.toggle_output_scroll = function (index) {
902 var i = this.index_or_selected(index);
912 var i = this.index_or_selected(index);
903 this.get_cell(i).toggle_output_scroll();
913 this.get_cell(i).toggle_output_scroll();
904 };
914 };
905
915
906
916
907 Notebook.prototype.collapse_all_output = function () {
917 Notebook.prototype.collapse_all_output = function () {
908 var ncells = this.ncells();
918 var ncells = this.ncells();
909 var cells = this.get_cells();
919 var cells = this.get_cells();
910 for (var i=0; i<ncells; i++) {
920 for (var i=0; i<ncells; i++) {
911 if (cells[i] instanceof IPython.CodeCell) {
921 if (cells[i] instanceof IPython.CodeCell) {
912 cells[i].output_area.collapse();
922 cells[i].output_area.collapse();
913 }
923 }
914 };
924 };
915 // this should not be set if the `collapse` key is removed from nbformat
925 // this should not be set if the `collapse` key is removed from nbformat
916 this.dirty = true;
926 this.dirty = true;
917 };
927 };
918
928
919
929
920 Notebook.prototype.scroll_all_output = function () {
930 Notebook.prototype.scroll_all_output = function () {
921 var ncells = this.ncells();
931 var ncells = this.ncells();
922 var cells = this.get_cells();
932 var cells = this.get_cells();
923 for (var i=0; i<ncells; i++) {
933 for (var i=0; i<ncells; i++) {
924 if (cells[i] instanceof IPython.CodeCell) {
934 if (cells[i] instanceof IPython.CodeCell) {
925 cells[i].output_area.expand();
935 cells[i].output_area.expand();
926 cells[i].output_area.scroll_if_long(20);
936 cells[i].output_area.scroll_if_long(20);
927 }
937 }
928 };
938 };
929 // this should not be set if the `collapse` key is removed from nbformat
939 // this should not be set if the `collapse` key is removed from nbformat
930 this.dirty = true;
940 this.dirty = true;
931 };
941 };
932
942
933
943
934 Notebook.prototype.expand_all_output = function () {
944 Notebook.prototype.expand_all_output = function () {
935 var ncells = this.ncells();
945 var ncells = this.ncells();
936 var cells = this.get_cells();
946 var cells = this.get_cells();
937 for (var i=0; i<ncells; i++) {
947 for (var i=0; i<ncells; i++) {
938 if (cells[i] instanceof IPython.CodeCell) {
948 if (cells[i] instanceof IPython.CodeCell) {
939 cells[i].output_area.expand();
949 cells[i].output_area.expand();
940 cells[i].output_area.unscroll_area();
950 cells[i].output_area.unscroll_area();
941 }
951 }
942 };
952 };
943 // this should not be set if the `collapse` key is removed from nbformat
953 // this should not be set if the `collapse` key is removed from nbformat
944 this.dirty = true;
954 this.dirty = true;
945 };
955 };
946
956
947
957
948 Notebook.prototype.clear_all_output = function () {
958 Notebook.prototype.clear_all_output = function () {
949 var ncells = this.ncells();
959 var ncells = this.ncells();
950 var cells = this.get_cells();
960 var cells = this.get_cells();
951 for (var i=0; i<ncells; i++) {
961 for (var i=0; i<ncells; i++) {
952 if (cells[i] instanceof IPython.CodeCell) {
962 if (cells[i] instanceof IPython.CodeCell) {
953 cells[i].clear_output(true,true,true);
963 cells[i].clear_output(true,true,true);
954 // Make all In[] prompts blank, as well
964 // Make all In[] prompts blank, as well
955 // TODO: make this configurable (via checkbox?)
965 // TODO: make this configurable (via checkbox?)
956 cells[i].set_input_prompt();
966 cells[i].set_input_prompt();
957 }
967 }
958 };
968 };
959 this.dirty = true;
969 this.dirty = true;
960 };
970 };
961
971
962
972
963 // Other cell functions: line numbers, ...
973 // Other cell functions: line numbers, ...
964
974
965 Notebook.prototype.cell_toggle_line_numbers = function() {
975 Notebook.prototype.cell_toggle_line_numbers = function() {
966 this.get_selected_cell().toggle_line_numbers();
976 this.get_selected_cell().toggle_line_numbers();
967 };
977 };
968
978
969 // Kernel related things
979 // Kernel related things
970
980
971 Notebook.prototype.start_kernel = function () {
981 Notebook.prototype.start_kernel = function () {
972 var base_url = $('body').data('baseKernelUrl') + "kernels";
982 var base_url = $('body').data('baseKernelUrl') + "kernels";
973 this.kernel = new IPython.Kernel(base_url);
983 this.kernel = new IPython.Kernel(base_url);
974 this.kernel.start(this.notebook_id);
984 this.kernel.start(this.notebook_id);
975 // Now that the kernel has been created, tell the CodeCells about it.
985 // Now that the kernel has been created, tell the CodeCells about it.
976 var ncells = this.ncells();
986 var ncells = this.ncells();
977 for (var i=0; i<ncells; i++) {
987 for (var i=0; i<ncells; i++) {
978 var cell = this.get_cell(i);
988 var cell = this.get_cell(i);
979 if (cell instanceof IPython.CodeCell) {
989 if (cell instanceof IPython.CodeCell) {
980 cell.set_kernel(this.kernel)
990 cell.set_kernel(this.kernel)
981 };
991 };
982 };
992 };
983 };
993 };
984
994
985
995
986 Notebook.prototype.restart_kernel = function () {
996 Notebook.prototype.restart_kernel = function () {
987 var that = this;
997 var that = this;
988 var dialog = $('<div/>');
998 var dialog = $('<div/>');
989 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
999 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
990 $(document).append(dialog);
1000 $(document).append(dialog);
991 dialog.dialog({
1001 dialog.dialog({
992 resizable: false,
1002 resizable: false,
993 modal: true,
1003 modal: true,
994 title: "Restart kernel or continue running?",
1004 title: "Restart kernel or continue running?",
995 closeText: '',
1005 closeText: '',
996 buttons : {
1006 buttons : {
997 "Restart": function () {
1007 "Restart": function () {
998 that.kernel.restart();
1008 that.kernel.restart();
999 $(this).dialog('close');
1009 $(this).dialog('close');
1000 },
1010 },
1001 "Continue running": function () {
1011 "Continue running": function () {
1002 $(this).dialog('close');
1012 $(this).dialog('close');
1003 }
1013 }
1004 }
1014 }
1005 });
1015 });
1006 };
1016 };
1007
1017
1008
1018
1009 Notebook.prototype.execute_selected_cell = function (options) {
1019 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
1020 // 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
1021 // terminal: execute in terminal mode, which stays in the current cell
1012 default_options = {terminal: false, add_new: true};
1022 default_options = {terminal: false, add_new: true};
1013 $.extend(default_options, options);
1023 $.extend(default_options, options);
1014 var that = this;
1024 var that = this;
1015 var cell = that.get_selected_cell();
1025 var cell = that.get_selected_cell();
1016 var cell_index = that.find_cell_index(cell);
1026 var cell_index = that.find_cell_index(cell);
1017 if (cell instanceof IPython.CodeCell) {
1027 if (cell instanceof IPython.CodeCell) {
1018 cell.execute();
1028 cell.execute();
1019 } else if (cell instanceof IPython.HTMLCell) {
1029 } else if (cell instanceof IPython.HTMLCell) {
1020 cell.render();
1030 cell.render();
1021 }
1031 }
1022 if (default_options.terminal) {
1032 if (default_options.terminal) {
1023 cell.select_all();
1033 cell.select_all();
1024 } else {
1034 } else {
1025 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1035 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1026 that.insert_cell_below('code');
1036 that.insert_cell_below('code');
1027 // If we are adding a new cell at the end, scroll down to show it.
1037 // If we are adding a new cell at the end, scroll down to show it.
1028 that.scroll_to_bottom();
1038 that.scroll_to_bottom();
1029 } else {
1039 } else {
1030 that.select(cell_index+1);
1040 that.select(cell_index+1);
1031 };
1041 };
1032 };
1042 };
1033 this.dirty = true;
1043 this.dirty = true;
1034 };
1044 };
1035
1045
1036
1046
1037 Notebook.prototype.execute_all_cells = function () {
1047 Notebook.prototype.execute_all_cells = function () {
1038 var ncells = this.ncells();
1048 var ncells = this.ncells();
1039 for (var i=0; i<ncells; i++) {
1049 for (var i=0; i<ncells; i++) {
1040 this.select(i);
1050 this.select(i);
1041 this.execute_selected_cell({add_new:false});
1051 this.execute_selected_cell({add_new:false});
1042 };
1052 };
1043 this.scroll_to_bottom();
1053 this.scroll_to_bottom();
1044 };
1054 };
1045
1055
1046 // Persistance and loading
1056 // Persistance and loading
1047
1057
1048 Notebook.prototype.get_notebook_id = function () {
1058 Notebook.prototype.get_notebook_id = function () {
1049 return this.notebook_id;
1059 return this.notebook_id;
1050 };
1060 };
1051
1061
1052
1062
1053 Notebook.prototype.get_notebook_name = function () {
1063 Notebook.prototype.get_notebook_name = function () {
1054 return this.notebook_name;
1064 return this.notebook_name;
1055 };
1065 };
1056
1066
1057
1067
1058 Notebook.prototype.set_notebook_name = function (name) {
1068 Notebook.prototype.set_notebook_name = function (name) {
1059 this.notebook_name = name;
1069 this.notebook_name = name;
1060 };
1070 };
1061
1071
1062
1072
1063 Notebook.prototype.test_notebook_name = function (nbname) {
1073 Notebook.prototype.test_notebook_name = function (nbname) {
1064 nbname = nbname || '';
1074 nbname = nbname || '';
1065 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1075 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1066 return true;
1076 return true;
1067 } else {
1077 } else {
1068 return false;
1078 return false;
1069 };
1079 };
1070 };
1080 };
1071
1081
1072
1082
1073 Notebook.prototype.fromJSON = function (data) {
1083 Notebook.prototype.fromJSON = function (data) {
1074 var ncells = this.ncells();
1084 var ncells = this.ncells();
1075 var i;
1085 var i;
1076 for (i=0; i<ncells; i++) {
1086 for (i=0; i<ncells; i++) {
1077 // Always delete cell 0 as they get renumbered as they are deleted.
1087 // Always delete cell 0 as they get renumbered as they are deleted.
1078 this.delete_cell(0);
1088 this.delete_cell(0);
1079 };
1089 };
1080 // Save the metadata and name.
1090 // Save the metadata and name.
1081 this.metadata = data.metadata;
1091 this.metadata = data.metadata;
1082 this.notebook_name = data.metadata.name;
1092 this.notebook_name = data.metadata.name;
1083 // Only handle 1 worksheet for now.
1093 // Only handle 1 worksheet for now.
1084 var worksheet = data.worksheets[0];
1094 var worksheet = data.worksheets[0];
1085 if (worksheet !== undefined) {
1095 if (worksheet !== undefined) {
1086 if (worksheet.metadata) {
1096 if (worksheet.metadata) {
1087 this.worksheet_metadata = worksheet.metadata;
1097 this.worksheet_metadata = worksheet.metadata;
1088 }
1098 }
1089 var new_cells = worksheet.cells;
1099 var new_cells = worksheet.cells;
1090 ncells = new_cells.length;
1100 ncells = new_cells.length;
1091 var cell_data = null;
1101 var cell_data = null;
1092 var new_cell = null;
1102 var new_cell = null;
1093 for (i=0; i<ncells; i++) {
1103 for (i=0; i<ncells; i++) {
1094 cell_data = new_cells[i];
1104 cell_data = new_cells[i];
1095 // VERSIONHACK: plaintext -> raw
1105 // VERSIONHACK: plaintext -> raw
1096 // handle never-released plaintext name for raw cells
1106 // handle never-released plaintext name for raw cells
1097 if (cell_data.cell_type === 'plaintext'){
1107 if (cell_data.cell_type === 'plaintext'){
1098 cell_data.cell_type = 'raw';
1108 cell_data.cell_type = 'raw';
1099 }
1109 }
1100
1110
1101 new_cell = this.insert_cell_below(cell_data.cell_type);
1111 new_cell = this.insert_cell_below(cell_data.cell_type);
1102 new_cell.fromJSON(cell_data);
1112 new_cell.fromJSON(cell_data);
1103 };
1113 };
1104 };
1114 };
1105 if (data.worksheets.length > 1) {
1115 if (data.worksheets.length > 1) {
1106 var dialog = $('<div/>');
1116 var dialog = $('<div/>');
1107 dialog.html("This notebook has " + data.worksheets.length + " worksheets, " +
1117 dialog.html("This notebook has " + data.worksheets.length + " worksheets, " +
1108 "but this version of IPython can only handle the first. " +
1118 "but this version of IPython can only handle the first. " +
1109 "If you save this notebook, worksheets after the first will be lost."
1119 "If you save this notebook, worksheets after the first will be lost."
1110 );
1120 );
1111 this.element.append(dialog);
1121 this.element.append(dialog);
1112 dialog.dialog({
1122 dialog.dialog({
1113 resizable: false,
1123 resizable: false,
1114 modal: true,
1124 modal: true,
1115 title: "Multiple worksheets",
1125 title: "Multiple worksheets",
1116 closeText: "",
1126 closeText: "",
1117 close: function(event, ui) {$(this).dialog('destroy').remove();},
1127 close: function(event, ui) {$(this).dialog('destroy').remove();},
1118 buttons : {
1128 buttons : {
1119 "OK": function () {
1129 "OK": function () {
1120 $(this).dialog('close');
1130 $(this).dialog('close');
1121 }
1131 }
1122 },
1132 },
1123 width: 400
1133 width: 400
1124 });
1134 });
1125 }
1135 }
1126 };
1136 };
1127
1137
1128
1138
1129 Notebook.prototype.toJSON = function () {
1139 Notebook.prototype.toJSON = function () {
1130 var cells = this.get_cells();
1140 var cells = this.get_cells();
1131 var ncells = cells.length;
1141 var ncells = cells.length;
1132 var cell_array = new Array(ncells);
1142 var cell_array = new Array(ncells);
1133 for (var i=0; i<ncells; i++) {
1143 for (var i=0; i<ncells; i++) {
1134 cell_array[i] = cells[i].toJSON();
1144 cell_array[i] = cells[i].toJSON();
1135 };
1145 };
1136 var data = {
1146 var data = {
1137 // Only handle 1 worksheet for now.
1147 // Only handle 1 worksheet for now.
1138 worksheets : [{
1148 worksheets : [{
1139 cells: cell_array,
1149 cells: cell_array,
1140 metadata: this.worksheet_metadata
1150 metadata: this.worksheet_metadata
1141 }],
1151 }],
1142 metadata : this.metadata
1152 metadata : this.metadata
1143 };
1153 };
1144 return data;
1154 return data;
1145 };
1155 };
1146
1156
1147 Notebook.prototype.save_notebook = function () {
1157 Notebook.prototype.save_notebook = function () {
1148 // We may want to move the name/id/nbformat logic inside toJSON?
1158 // We may want to move the name/id/nbformat logic inside toJSON?
1149 var data = this.toJSON();
1159 var data = this.toJSON();
1150 data.metadata.name = this.notebook_name;
1160 data.metadata.name = this.notebook_name;
1151 data.nbformat = this.nbformat;
1161 data.nbformat = this.nbformat;
1152 data.nbformat_minor = this.nbformat_minor;
1162 data.nbformat_minor = this.nbformat_minor;
1153 // We do the call with settings so we can set cache to false.
1163 // We do the call with settings so we can set cache to false.
1154 var settings = {
1164 var settings = {
1155 processData : false,
1165 processData : false,
1156 cache : false,
1166 cache : false,
1157 type : "PUT",
1167 type : "PUT",
1158 data : JSON.stringify(data),
1168 data : JSON.stringify(data),
1159 headers : {'Content-Type': 'application/json'},
1169 headers : {'Content-Type': 'application/json'},
1160 success : $.proxy(this.save_notebook_success,this),
1170 success : $.proxy(this.save_notebook_success,this),
1161 error : $.proxy(this.save_notebook_error,this)
1171 error : $.proxy(this.save_notebook_error,this)
1162 };
1172 };
1163 $([IPython.events]).trigger('notebook_saving.Notebook');
1173 $([IPython.events]).trigger('notebook_saving.Notebook');
1164 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1174 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1165 $.ajax(url, settings);
1175 $.ajax(url, settings);
1166 };
1176 };
1167
1177
1168
1178
1169 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1179 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1170 this.dirty = false;
1180 this.dirty = false;
1171 $([IPython.events]).trigger('notebook_saved.Notebook');
1181 $([IPython.events]).trigger('notebook_saved.Notebook');
1172 };
1182 };
1173
1183
1174
1184
1175 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1185 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1176 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1186 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1177 };
1187 };
1178
1188
1179
1189
1180 Notebook.prototype.load_notebook = function (notebook_id) {
1190 Notebook.prototype.load_notebook = function (notebook_id) {
1181 var that = this;
1191 var that = this;
1182 this.notebook_id = notebook_id;
1192 this.notebook_id = notebook_id;
1183 // We do the call with settings so we can set cache to false.
1193 // We do the call with settings so we can set cache to false.
1184 var settings = {
1194 var settings = {
1185 processData : false,
1195 processData : false,
1186 cache : false,
1196 cache : false,
1187 type : "GET",
1197 type : "GET",
1188 dataType : "json",
1198 dataType : "json",
1189 success : $.proxy(this.load_notebook_success,this),
1199 success : $.proxy(this.load_notebook_success,this),
1190 error : $.proxy(this.load_notebook_error,this),
1200 error : $.proxy(this.load_notebook_error,this),
1191 };
1201 };
1192 $([IPython.events]).trigger('notebook_loading.Notebook');
1202 $([IPython.events]).trigger('notebook_loading.Notebook');
1193 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1203 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1194 $.ajax(url, settings);
1204 $.ajax(url, settings);
1195 };
1205 };
1196
1206
1197
1207
1198 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1208 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1199 this.fromJSON(data);
1209 this.fromJSON(data);
1200 if (this.ncells() === 0) {
1210 if (this.ncells() === 0) {
1201 this.insert_cell_below('code');
1211 this.insert_cell_below('code');
1202 };
1212 };
1203 this.dirty = false;
1213 this.dirty = false;
1204 this.select(0);
1214 this.select(0);
1205 this.scroll_to_top();
1215 this.scroll_to_top();
1206 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1216 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1207 msg = "This notebook has been converted from an older " +
1217 msg = "This notebook has been converted from an older " +
1208 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1218 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1209 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1219 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1210 "newer notebook format will be used and older verions of IPython " +
1220 "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 " +
1221 "may not be able to read it. To keep the older version, close the " +
1212 "notebook without saving it.";
1222 "notebook without saving it.";
1213 var dialog = $('<div/>');
1223 var dialog = $('<div/>');
1214 dialog.html(msg);
1224 dialog.html(msg);
1215 this.element.append(dialog);
1225 this.element.append(dialog);
1216 dialog.dialog({
1226 dialog.dialog({
1217 resizable: false,
1227 resizable: false,
1218 modal: true,
1228 modal: true,
1219 title: "Notebook converted",
1229 title: "Notebook converted",
1220 closeText: "",
1230 closeText: "",
1221 close: function(event, ui) {$(this).dialog('destroy').remove();},
1231 close: function(event, ui) {$(this).dialog('destroy').remove();},
1222 buttons : {
1232 buttons : {
1223 "OK": function () {
1233 "OK": function () {
1224 $(this).dialog('close');
1234 $(this).dialog('close');
1225 }
1235 }
1226 },
1236 },
1227 width: 400
1237 width: 400
1228 });
1238 });
1229 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1239 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1230 var that = this;
1240 var that = this;
1231 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1241 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1232 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1242 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1233 msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1243 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 " +
1244 this_vs + ". You can still work with this notebook, but some features " +
1235 "introduced in later notebook versions may not be available."
1245 "introduced in later notebook versions may not be available."
1236
1246
1237 var dialog = $('<div/>');
1247 var dialog = $('<div/>');
1238 dialog.html(msg);
1248 dialog.html(msg);
1239 this.element.append(dialog);
1249 this.element.append(dialog);
1240 dialog.dialog({
1250 dialog.dialog({
1241 resizable: false,
1251 resizable: false,
1242 modal: true,
1252 modal: true,
1243 title: "Newer Notebook",
1253 title: "Newer Notebook",
1244 closeText: "",
1254 closeText: "",
1245 close: function(event, ui) {$(this).dialog('destroy').remove();},
1255 close: function(event, ui) {$(this).dialog('destroy').remove();},
1246 buttons : {
1256 buttons : {
1247 "OK": function () {
1257 "OK": function () {
1248 $(this).dialog('close');
1258 $(this).dialog('close');
1249 }
1259 }
1250 },
1260 },
1251 width: 400
1261 width: 400
1252 });
1262 });
1253
1263
1254 }
1264 }
1255 // Create the kernel after the notebook is completely loaded to prevent
1265 // Create the kernel after the notebook is completely loaded to prevent
1256 // code execution upon loading, which is a security risk.
1266 // code execution upon loading, which is a security risk.
1257 if (! this.read_only) {
1267 if (! this.read_only) {
1258 this.start_kernel();
1268 this.start_kernel();
1259 }
1269 }
1260 $([IPython.events]).trigger('notebook_loaded.Notebook');
1270 $([IPython.events]).trigger('notebook_loaded.Notebook');
1261 };
1271 };
1262
1272
1263
1273
1264 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1274 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1265 if (xhr.status === 500) {
1275 if (xhr.status === 500) {
1266 msg = "An error occurred while loading this notebook. Most likely " +
1276 msg = "An error occurred while loading this notebook. Most likely " +
1267 "this notebook is in a newer format than is supported by this " +
1277 "this notebook is in a newer format than is supported by this " +
1268 "version of IPython. This version can load notebook formats " +
1278 "version of IPython. This version can load notebook formats " +
1269 "v"+this.nbformat+" or earlier.";
1279 "v"+this.nbformat+" or earlier.";
1270 var dialog = $('<div/>');
1280 var dialog = $('<div/>');
1271 dialog.html(msg);
1281 dialog.html(msg);
1272 this.element.append(dialog);
1282 this.element.append(dialog);
1273 dialog.dialog({
1283 dialog.dialog({
1274 resizable: false,
1284 resizable: false,
1275 modal: true,
1285 modal: true,
1276 title: "Error loading notebook",
1286 title: "Error loading notebook",
1277 closeText: "",
1287 closeText: "",
1278 close: function(event, ui) {$(this).dialog('destroy').remove();},
1288 close: function(event, ui) {$(this).dialog('destroy').remove();},
1279 buttons : {
1289 buttons : {
1280 "OK": function () {
1290 "OK": function () {
1281 $(this).dialog('close');
1291 $(this).dialog('close');
1282 }
1292 }
1283 },
1293 },
1284 width: 400
1294 width: 400
1285 });
1295 });
1286 }
1296 }
1287 }
1297 }
1288
1298
1289 IPython.Notebook = Notebook;
1299 IPython.Notebook = Notebook;
1290
1300
1291
1301
1292 return IPython;
1302 return IPython;
1293
1303
1294 }(IPython));
1304 }(IPython));
1295
1305
General Comments 0
You need to be logged in to leave comments. Login now