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