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