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