##// END OF EJS Templates
Adding keyboard shortcuts.
Brian E. Granger -
Show More
@@ -1,835 +1,898
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.element = $(selector);
17 this.element = $(selector);
18 this.element.scroll();
18 this.element.scroll();
19 this.element.data("notebook", this);
19 this.element.data("notebook", this);
20 this.next_prompt_number = 1;
20 this.next_prompt_number = 1;
21 this.kernel = null;
21 this.kernel = null;
22 this.dirty = false;
22 this.dirty = false;
23 this.msg_cell_map = {};
23 this.msg_cell_map = {};
24 this.metadata = {};
24 this.metadata = {};
25 this.control_key_active = false;
25 this.style();
26 this.style();
26 this.create_elements();
27 this.create_elements();
27 this.bind_events();
28 this.bind_events();
28 };
29 };
29
30
30
31
31 Notebook.prototype.style = function () {
32 Notebook.prototype.style = function () {
32 $('div#notebook').addClass('border-box-sizing');
33 $('div#notebook').addClass('border-box-sizing');
33 };
34 };
34
35
35
36
36 Notebook.prototype.create_elements = function () {
37 Notebook.prototype.create_elements = function () {
37 // We add this end_space div to the end of the notebook div to:
38 // We add this end_space div to the end of the notebook div to:
38 // i) provide a margin between the last cell and the end of the notebook
39 // i) provide a margin between the last cell and the end of the notebook
39 // ii) to prevent the div from scrolling up when the last cell is being
40 // ii) to prevent the div from scrolling up when the last cell is being
40 // edited, but is too low on the page, which browsers will do automatically.
41 // edited, but is too low on the page, which browsers will do automatically.
41 var that = this;
42 var that = this;
42 var end_space = $('<div class="end_space"></div>').height(150);
43 var end_space = $('<div class="end_space"></div>').height(150);
43 end_space.dblclick(function (e) {
44 end_space.dblclick(function (e) {
44 var ncells = that.ncells();
45 var ncells = that.ncells();
45 that.insert_code_cell_after(ncells-1);
46 that.insert_code_cell_after(ncells-1);
46 });
47 });
47 this.element.append(end_space);
48 this.element.append(end_space);
48 $('div#notebook').addClass('border-box-sizing');
49 $('div#notebook').addClass('border-box-sizing');
49 };
50 };
50
51
51
52
52 Notebook.prototype.bind_events = function () {
53 Notebook.prototype.bind_events = function () {
53 var that = this;
54 var that = this;
54 $(document).keydown(function (event) {
55 $(document).keydown(function (event) {
55 // console.log(event);
56 // console.log(event);
56 if (event.which === 38) {
57 if (event.which === 38) {
57 var cell = that.selected_cell();
58 var cell = that.selected_cell();
58 if (cell.at_top()) {
59 if (cell.at_top()) {
59 event.preventDefault();
60 event.preventDefault();
60 that.select_prev();
61 that.select_prev();
61 };
62 };
62 } else if (event.which === 40) {
63 } else if (event.which === 40) {
63 var cell = that.selected_cell();
64 var cell = that.selected_cell();
64 if (cell.at_bottom()) {
65 if (cell.at_bottom()) {
65 event.preventDefault();
66 event.preventDefault();
66 that.select_next();
67 that.select_next();
67 };
68 };
68 } else if (event.which === 13 && event.shiftKey) {
69 } else if (event.which === 13 && event.shiftKey) {
69 that.execute_selected_cell();
70 that.execute_selected_cell();
70 return false;
71 return false;
71 } else if (event.which === 13 && event.ctrlKey) {
72 } else if (event.which === 13 && event.ctrlKey) {
72 that.execute_selected_cell({terminal:true});
73 that.execute_selected_cell({terminal:true});
73 return false;
74 return false;
75 } else if (event.which === 77 && event.ctrlKey) {
76 console.log("Activating control key")
77 that.control_key_active = true;
78 return false;
79 } else if (event.which === 68 && that.control_key_active) {
80 // Delete selected cell = d
81 that.delete_cell();
82 that.control_key_active = false;
83 return false;
84 } else if (event.which === 65 && that.control_key_active) {
85 // Insert code cell after selected = a
86 that.insert_code_cell_after();
87 that.control_key_active = false;
88 return false;
89 } else if (event.which === 66 && that.control_key_active) {
90 // Insert code cell before selected = a
91 that.insert_code_cell_before();
92 that.control_key_active = false;
93 return false;
94 } else if (event.which === 67 && that.control_key_active) {
95 // To code = c
96 that.to_code();
97 that.control_key_active = false;
98 return false;
99 } else if (event.which === 77 && that.control_key_active) {
100 // To markdown = m
101 that.to_markdown();
102 that.control_key_active = false;
103 return false;
104 } else if (event.which === 84 && that.control_key_active) {
105 // Toggle output = t
106 that.toggle_output();
107 that.control_key_active = false;
108 return false;
109 } else if (event.which === 83 && that.control_key_active) {
110 // Save notebook = s
111 IPython.save_widget.save_notebook();
112 that.control_key_active = false;
113 return false;
114 } else if (event.which === 74 && that.control_key_active) {
115 // Move cell down = j
116 that.move_cell_down();
117 that.control_key_active = false;
118 return false;
119 } else if (event.which === 75 && that.control_key_active) {
120 // Move cell up = k
121 that.move_cell_up();
122 that.control_key_active = false;
123 return false;
124 } else if (event.which === 38 && that.control_key_active) {
125 // Select previous = up arrow
126 that.select_prev();
127 that.control_key_active = false;
128 return false;
129 } else if (event.which === 40 && that.control_key_active) {
130 // Select next = down arrow
131 that.select_next();
132 that.control_key_active = false;
133 return false;
134 } else if (that.control_key_active) {
135 that.control_key_active = false;
136 return true;
74 };
137 };
75 });
138 });
76
139
77 this.element.bind('collapse_pager', function () {
140 this.element.bind('collapse_pager', function () {
78 var app_height = $('div#main_app').height(); // content height
141 var app_height = $('div#main_app').height(); // content height
79 var splitter_height = $('div#pager_splitter').outerHeight(true);
142 var splitter_height = $('div#pager_splitter').outerHeight(true);
80 var new_height = app_height - splitter_height;
143 var new_height = app_height - splitter_height;
81 that.element.animate({height : new_height + 'px'}, 'fast');
144 that.element.animate({height : new_height + 'px'}, 'fast');
82 });
145 });
83
146
84 this.element.bind('expand_pager', function () {
147 this.element.bind('expand_pager', function () {
85 var app_height = $('div#main_app').height(); // content height
148 var app_height = $('div#main_app').height(); // content height
86 var splitter_height = $('div#pager_splitter').outerHeight(true);
149 var splitter_height = $('div#pager_splitter').outerHeight(true);
87 var pager_height = $('div#pager').outerHeight(true);
150 var pager_height = $('div#pager').outerHeight(true);
88 var new_height = app_height - pager_height - splitter_height;
151 var new_height = app_height - pager_height - splitter_height;
89 that.element.animate({height : new_height + 'px'}, 'fast');
152 that.element.animate({height : new_height + 'px'}, 'fast');
90 });
153 });
91
154
92 this.element.bind('collapse_left_panel', function () {
155 this.element.bind('collapse_left_panel', function () {
93 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
156 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
94 var new_margin = splitter_width;
157 var new_margin = splitter_width;
95 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
158 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
96 });
159 });
97
160
98 this.element.bind('expand_left_panel', function () {
161 this.element.bind('expand_left_panel', function () {
99 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
162 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
100 var left_panel_width = IPython.left_panel.width;
163 var left_panel_width = IPython.left_panel.width;
101 var new_margin = splitter_width + left_panel_width;
164 var new_margin = splitter_width + left_panel_width;
102 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
165 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
103 });
166 });
104
167
105 $(window).bind('beforeunload', function () {
168 $(window).bind('beforeunload', function () {
106 var kill_kernel = $('#kill_kernel').prop('checked');
169 var kill_kernel = $('#kill_kernel').prop('checked');
107 if (kill_kernel) {
170 if (kill_kernel) {
108 that.kernel.kill();
171 that.kernel.kill();
109 }
172 }
110 if (that.dirty) {
173 if (that.dirty) {
111 return "You have unsaved changes that will be lost if you leave this page.";
174 return "You have unsaved changes that will be lost if you leave this page.";
112 };
175 };
113 });
176 });
114 };
177 };
115
178
116
179
117 Notebook.prototype.scroll_to_bottom = function () {
180 Notebook.prototype.scroll_to_bottom = function () {
118 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
181 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
119 };
182 };
120
183
121
184
122 Notebook.prototype.scroll_to_top = function () {
185 Notebook.prototype.scroll_to_top = function () {
123 this.element.animate({scrollTop:0}, 0);
186 this.element.animate({scrollTop:0}, 0);
124 };
187 };
125
188
126
189
127 // Cell indexing, retrieval, etc.
190 // Cell indexing, retrieval, etc.
128
191
129
192
130 Notebook.prototype.cell_elements = function () {
193 Notebook.prototype.cell_elements = function () {
131 return this.element.children("div.cell");
194 return this.element.children("div.cell");
132 }
195 }
133
196
134
197
135 Notebook.prototype.ncells = function (cell) {
198 Notebook.prototype.ncells = function (cell) {
136 return this.cell_elements().length;
199 return this.cell_elements().length;
137 }
200 }
138
201
139
202
140 // TODO: we are often calling cells as cells()[i], which we should optimize
203 // TODO: we are often calling cells as cells()[i], which we should optimize
141 // to cells(i) or a new method.
204 // to cells(i) or a new method.
142 Notebook.prototype.cells = function () {
205 Notebook.prototype.cells = function () {
143 return this.cell_elements().toArray().map(function (e) {
206 return this.cell_elements().toArray().map(function (e) {
144 return $(e).data("cell");
207 return $(e).data("cell");
145 });
208 });
146 }
209 }
147
210
148
211
149 Notebook.prototype.find_cell_index = function (cell) {
212 Notebook.prototype.find_cell_index = function (cell) {
150 var result = null;
213 var result = null;
151 this.cell_elements().filter(function (index) {
214 this.cell_elements().filter(function (index) {
152 if ($(this).data("cell") === cell) {
215 if ($(this).data("cell") === cell) {
153 result = index;
216 result = index;
154 };
217 };
155 });
218 });
156 return result;
219 return result;
157 };
220 };
158
221
159
222
160 Notebook.prototype.index_or_selected = function (index) {
223 Notebook.prototype.index_or_selected = function (index) {
161 return index || this.selected_index() || 0;
224 return index || this.selected_index() || 0;
162 }
225 }
163
226
164
227
165 Notebook.prototype.select = function (index) {
228 Notebook.prototype.select = function (index) {
166 if (index !== undefined && index >= 0 && index < this.ncells()) {
229 if (index !== undefined && index >= 0 && index < this.ncells()) {
167 if (this.selected_index() !== null) {
230 if (this.selected_index() !== null) {
168 this.selected_cell().unselect();
231 this.selected_cell().unselect();
169 };
232 };
170 this.cells()[index].select();
233 this.cells()[index].select();
171 };
234 };
172 return this;
235 return this;
173 };
236 };
174
237
175
238
176 Notebook.prototype.select_next = function () {
239 Notebook.prototype.select_next = function () {
177 var index = this.selected_index();
240 var index = this.selected_index();
178 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
241 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
179 this.select(index+1);
242 this.select(index+1);
180 };
243 };
181 return this;
244 return this;
182 };
245 };
183
246
184
247
185 Notebook.prototype.select_prev = function () {
248 Notebook.prototype.select_prev = function () {
186 var index = this.selected_index();
249 var index = this.selected_index();
187 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
250 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
188 this.select(index-1);
251 this.select(index-1);
189 };
252 };
190 return this;
253 return this;
191 };
254 };
192
255
193
256
194 Notebook.prototype.selected_index = function () {
257 Notebook.prototype.selected_index = function () {
195 var result = null;
258 var result = null;
196 this.cell_elements().filter(function (index) {
259 this.cell_elements().filter(function (index) {
197 if ($(this).data("cell").selected === true) {
260 if ($(this).data("cell").selected === true) {
198 result = index;
261 result = index;
199 };
262 };
200 });
263 });
201 return result;
264 return result;
202 };
265 };
203
266
204
267
205 Notebook.prototype.cell_for_msg = function (msg_id) {
268 Notebook.prototype.cell_for_msg = function (msg_id) {
206 var cell_id = this.msg_cell_map[msg_id];
269 var cell_id = this.msg_cell_map[msg_id];
207 var result = null;
270 var result = null;
208 this.cell_elements().filter(function (index) {
271 this.cell_elements().filter(function (index) {
209 cell = $(this).data("cell");
272 cell = $(this).data("cell");
210 if (cell.cell_id === cell_id) {
273 if (cell.cell_id === cell_id) {
211 result = cell;
274 result = cell;
212 };
275 };
213 });
276 });
214 return result;
277 return result;
215 };
278 };
216
279
217
280
218 Notebook.prototype.selected_cell = function () {
281 Notebook.prototype.selected_cell = function () {
219 return this.cell_elements().eq(this.selected_index()).data("cell");
282 return this.cell_elements().eq(this.selected_index()).data("cell");
220 }
283 }
221
284
222
285
223 // Cell insertion, deletion and moving.
286 // Cell insertion, deletion and moving.
224
287
225
288
226 Notebook.prototype.delete_cell = function (index) {
289 Notebook.prototype.delete_cell = function (index) {
227 var i = index || this.selected_index();
290 var i = index || this.selected_index();
228 if (i !== null && i >= 0 && i < this.ncells()) {
291 if (i !== null && i >= 0 && i < this.ncells()) {
229 this.cell_elements().eq(i).remove();
292 this.cell_elements().eq(i).remove();
230 if (i === (this.ncells())) {
293 if (i === (this.ncells())) {
231 this.select(i-1);
294 this.select(i-1);
232 } else {
295 } else {
233 this.select(i);
296 this.select(i);
234 };
297 };
235 };
298 };
236 this.dirty = true;
299 this.dirty = true;
237 return this;
300 return this;
238 };
301 };
239
302
240
303
241 Notebook.prototype.append_cell = function (cell) {
304 Notebook.prototype.append_cell = function (cell) {
242 this.element.find('div.end_space').before(cell.element);
305 this.element.find('div.end_space').before(cell.element);
243 this.dirty = true;
306 this.dirty = true;
244 return this;
307 return this;
245 };
308 };
246
309
247
310
248 Notebook.prototype.insert_cell_after = function (cell, index) {
311 Notebook.prototype.insert_cell_after = function (cell, index) {
249 var ncells = this.ncells();
312 var ncells = this.ncells();
250 if (ncells === 0) {
313 if (ncells === 0) {
251 this.append_cell(cell);
314 this.append_cell(cell);
252 return this;
315 return this;
253 };
316 };
254 if (index >= 0 && index < ncells) {
317 if (index >= 0 && index < ncells) {
255 this.cell_elements().eq(index).after(cell.element);
318 this.cell_elements().eq(index).after(cell.element);
256 };
319 };
257 this.dirty = true;
320 this.dirty = true;
258 return this
321 return this
259 };
322 };
260
323
261
324
262 Notebook.prototype.insert_cell_before = function (cell, index) {
325 Notebook.prototype.insert_cell_before = function (cell, index) {
263 var ncells = this.ncells();
326 var ncells = this.ncells();
264 if (ncells === 0) {
327 if (ncells === 0) {
265 this.append_cell(cell);
328 this.append_cell(cell);
266 return this;
329 return this;
267 };
330 };
268 if (index >= 0 && index < ncells) {
331 if (index >= 0 && index < ncells) {
269 this.cell_elements().eq(index).before(cell.element);
332 this.cell_elements().eq(index).before(cell.element);
270 };
333 };
271 this.dirty = true;
334 this.dirty = true;
272 return this;
335 return this;
273 };
336 };
274
337
275
338
276 Notebook.prototype.move_cell_up = function (index) {
339 Notebook.prototype.move_cell_up = function (index) {
277 var i = index || this.selected_index();
340 var i = index || this.selected_index();
278 if (i !== null && i < this.ncells() && i > 0) {
341 if (i !== null && i < this.ncells() && i > 0) {
279 var pivot = this.cell_elements().eq(i-1);
342 var pivot = this.cell_elements().eq(i-1);
280 var tomove = this.cell_elements().eq(i);
343 var tomove = this.cell_elements().eq(i);
281 if (pivot !== null && tomove !== null) {
344 if (pivot !== null && tomove !== null) {
282 tomove.detach();
345 tomove.detach();
283 pivot.before(tomove);
346 pivot.before(tomove);
284 this.select(i-1);
347 this.select(i-1);
285 };
348 };
286 };
349 };
287 this.dirty = true;
350 this.dirty = true;
288 return this;
351 return this;
289 }
352 }
290
353
291
354
292 Notebook.prototype.move_cell_down = function (index) {
355 Notebook.prototype.move_cell_down = function (index) {
293 var i = index || this.selected_index();
356 var i = index || this.selected_index();
294 if (i !== null && i < (this.ncells()-1) && i >= 0) {
357 if (i !== null && i < (this.ncells()-1) && i >= 0) {
295 var pivot = this.cell_elements().eq(i+1)
358 var pivot = this.cell_elements().eq(i+1)
296 var tomove = this.cell_elements().eq(i)
359 var tomove = this.cell_elements().eq(i)
297 if (pivot !== null && tomove !== null) {
360 if (pivot !== null && tomove !== null) {
298 tomove.detach();
361 tomove.detach();
299 pivot.after(tomove);
362 pivot.after(tomove);
300 this.select(i+1);
363 this.select(i+1);
301 };
364 };
302 };
365 };
303 this.dirty = true;
366 this.dirty = true;
304 return this;
367 return this;
305 }
368 }
306
369
307
370
308 Notebook.prototype.sort_cells = function () {
371 Notebook.prototype.sort_cells = function () {
309 var ncells = this.ncells();
372 var ncells = this.ncells();
310 var sindex = this.selected_index();
373 var sindex = this.selected_index();
311 var swapped;
374 var swapped;
312 do {
375 do {
313 swapped = false
376 swapped = false
314 for (var i=1; i<ncells; i++) {
377 for (var i=1; i<ncells; i++) {
315 current = this.cell_elements().eq(i).data("cell");
378 current = this.cell_elements().eq(i).data("cell");
316 previous = this.cell_elements().eq(i-1).data("cell");
379 previous = this.cell_elements().eq(i-1).data("cell");
317 if (previous.input_prompt_number > current.input_prompt_number) {
380 if (previous.input_prompt_number > current.input_prompt_number) {
318 this.move_cell_up(i);
381 this.move_cell_up(i);
319 swapped = true;
382 swapped = true;
320 };
383 };
321 };
384 };
322 } while (swapped);
385 } while (swapped);
323 this.select(sindex);
386 this.select(sindex);
324 return this;
387 return this;
325 };
388 };
326
389
327
390
328 Notebook.prototype.insert_code_cell_before = function (index) {
391 Notebook.prototype.insert_code_cell_before = function (index) {
329 // TODO: Bounds check for i
392 // TODO: Bounds check for i
330 var i = this.index_or_selected(index);
393 var i = this.index_or_selected(index);
331 var cell = new IPython.CodeCell(this);
394 var cell = new IPython.CodeCell(this);
332 cell.set_input_prompt();
395 cell.set_input_prompt();
333 this.insert_cell_before(cell, i);
396 this.insert_cell_before(cell, i);
334 this.select(this.find_cell_index(cell));
397 this.select(this.find_cell_index(cell));
335 return cell;
398 return cell;
336 }
399 }
337
400
338
401
339 Notebook.prototype.insert_code_cell_after = function (index) {
402 Notebook.prototype.insert_code_cell_after = function (index) {
340 // TODO: Bounds check for i
403 // TODO: Bounds check for i
341 var i = this.index_or_selected(index);
404 var i = this.index_or_selected(index);
342 var cell = new IPython.CodeCell(this);
405 var cell = new IPython.CodeCell(this);
343 cell.set_input_prompt();
406 cell.set_input_prompt();
344 this.insert_cell_after(cell, i);
407 this.insert_cell_after(cell, i);
345 this.select(this.find_cell_index(cell));
408 this.select(this.find_cell_index(cell));
346 return cell;
409 return cell;
347 }
410 }
348
411
349
412
350 Notebook.prototype.insert_html_cell_before = function (index) {
413 Notebook.prototype.insert_html_cell_before = function (index) {
351 // TODO: Bounds check for i
414 // TODO: Bounds check for i
352 var i = this.index_or_selected(index);
415 var i = this.index_or_selected(index);
353 var cell = new IPython.HTMLCell(this);
416 var cell = new IPython.HTMLCell(this);
354 cell.config_mathjax();
417 cell.config_mathjax();
355 this.insert_cell_before(cell, i);
418 this.insert_cell_before(cell, i);
356 this.select(this.find_cell_index(cell));
419 this.select(this.find_cell_index(cell));
357 return cell;
420 return cell;
358 }
421 }
359
422
360
423
361 Notebook.prototype.insert_html_cell_after = function (index) {
424 Notebook.prototype.insert_html_cell_after = function (index) {
362 // TODO: Bounds check for i
425 // TODO: Bounds check for i
363 var i = this.index_or_selected(index);
426 var i = this.index_or_selected(index);
364 var cell = new IPython.HTMLCell(this);
427 var cell = new IPython.HTMLCell(this);
365 cell.config_mathjax();
428 cell.config_mathjax();
366 this.insert_cell_after(cell, i);
429 this.insert_cell_after(cell, i);
367 this.select(this.find_cell_index(cell));
430 this.select(this.find_cell_index(cell));
368 return cell;
431 return cell;
369 }
432 }
370
433
371
434
372 Notebook.prototype.insert_markdown_cell_before = function (index) {
435 Notebook.prototype.insert_markdown_cell_before = function (index) {
373 // TODO: Bounds check for i
436 // TODO: Bounds check for i
374 var i = this.index_or_selected(index);
437 var i = this.index_or_selected(index);
375 var cell = new IPython.MarkdownCell(this);
438 var cell = new IPython.MarkdownCell(this);
376 cell.config_mathjax();
439 cell.config_mathjax();
377 this.insert_cell_before(cell, i);
440 this.insert_cell_before(cell, i);
378 this.select(this.find_cell_index(cell));
441 this.select(this.find_cell_index(cell));
379 return cell;
442 return cell;
380 }
443 }
381
444
382
445
383 Notebook.prototype.insert_markdown_cell_after = function (index) {
446 Notebook.prototype.insert_markdown_cell_after = function (index) {
384 // TODO: Bounds check for i
447 // TODO: Bounds check for i
385 var i = this.index_or_selected(index);
448 var i = this.index_or_selected(index);
386 var cell = new IPython.MarkdownCell(this);
449 var cell = new IPython.MarkdownCell(this);
387 cell.config_mathjax();
450 cell.config_mathjax();
388 this.insert_cell_after(cell, i);
451 this.insert_cell_after(cell, i);
389 this.select(this.find_cell_index(cell));
452 this.select(this.find_cell_index(cell));
390 return cell;
453 return cell;
391 }
454 }
392
455
393
456
394 Notebook.prototype.to_code = function (index) {
457 Notebook.prototype.to_code = function (index) {
395 // TODO: Bounds check for i
458 // TODO: Bounds check for i
396 var i = this.index_or_selected(index);
459 var i = this.index_or_selected(index);
397 var source_element = this.cell_elements().eq(i);
460 var source_element = this.cell_elements().eq(i);
398 var source_cell = source_element.data("cell");
461 var source_cell = source_element.data("cell");
399 if (source_cell instanceof IPython.HTMLCell ||
462 if (source_cell instanceof IPython.HTMLCell ||
400 source_cell instanceof IPython.MarkdownCell) {
463 source_cell instanceof IPython.MarkdownCell) {
401 this.insert_code_cell_after(i);
464 this.insert_code_cell_after(i);
402 var target_cell = this.cells()[i+1];
465 var target_cell = this.cells()[i+1];
403 target_cell.set_code(source_cell.get_source());
466 target_cell.set_code(source_cell.get_source());
404 source_element.remove();
467 source_element.remove();
405 target_cell.select();
468 target_cell.select();
406 };
469 };
407 this.dirty = true;
470 this.dirty = true;
408 };
471 };
409
472
410
473
411 Notebook.prototype.to_markdown = function (index) {
474 Notebook.prototype.to_markdown = function (index) {
412 // TODO: Bounds check for i
475 // TODO: Bounds check for i
413 var i = this.index_or_selected(index);
476 var i = this.index_or_selected(index);
414 var source_element = this.cell_elements().eq(i);
477 var source_element = this.cell_elements().eq(i);
415 var source_cell = source_element.data("cell");
478 var source_cell = source_element.data("cell");
416 var target_cell = null;
479 var target_cell = null;
417 if (source_cell instanceof IPython.CodeCell) {
480 if (source_cell instanceof IPython.CodeCell) {
418 this.insert_markdown_cell_after(i);
481 this.insert_markdown_cell_after(i);
419 var target_cell = this.cells()[i+1];
482 var target_cell = this.cells()[i+1];
420 var text = source_cell.get_code();
483 var text = source_cell.get_code();
421 } else if (source_cell instanceof IPython.HTMLCell) {
484 } else if (source_cell instanceof IPython.HTMLCell) {
422 this.insert_markdown_cell_after(i);
485 this.insert_markdown_cell_after(i);
423 var target_cell = this.cells()[i+1];
486 var target_cell = this.cells()[i+1];
424 var text = source_cell.get_source();
487 var text = source_cell.get_source();
425 if (text === source_cell.placeholder) {
488 if (text === source_cell.placeholder) {
426 text = target_cell.placeholder;
489 text = target_cell.placeholder;
427 }
490 }
428 }
491 }
429 if (target_cell !== null) {
492 if (target_cell !== null) {
430 if (text === "") {text = target_cell.placeholder;};
493 if (text === "") {text = target_cell.placeholder;};
431 target_cell.set_source(text);
494 target_cell.set_source(text);
432 source_element.remove();
495 source_element.remove();
433 target_cell.edit();
496 target_cell.edit();
434 }
497 }
435 this.dirty = true;
498 this.dirty = true;
436 };
499 };
437
500
438
501
439 Notebook.prototype.to_html = function (index) {
502 Notebook.prototype.to_html = function (index) {
440 // TODO: Bounds check for i
503 // TODO: Bounds check for i
441 var i = this.index_or_selected(index);
504 var i = this.index_or_selected(index);
442 var source_element = this.cell_elements().eq(i);
505 var source_element = this.cell_elements().eq(i);
443 var source_cell = source_element.data("cell");
506 var source_cell = source_element.data("cell");
444 var target_cell = null;
507 var target_cell = null;
445 if (source_cell instanceof IPython.CodeCell) {
508 if (source_cell instanceof IPython.CodeCell) {
446 this.insert_html_cell_after(i);
509 this.insert_html_cell_after(i);
447 var target_cell = this.cells()[i+1];
510 var target_cell = this.cells()[i+1];
448 var text = source_cell.get_code();
511 var text = source_cell.get_code();
449 } else if (source_cell instanceof IPython.MarkdownCell) {
512 } else if (source_cell instanceof IPython.MarkdownCell) {
450 this.insert_html_cell_after(i);
513 this.insert_html_cell_after(i);
451 var target_cell = this.cells()[i+1];
514 var target_cell = this.cells()[i+1];
452 var text = source_cell.get_source();
515 var text = source_cell.get_source();
453 if (text === source_cell.placeholder) {
516 if (text === source_cell.placeholder) {
454 text = target_cell.placeholder;
517 text = target_cell.placeholder;
455 }
518 }
456 }
519 }
457 if (target_cell !== null) {
520 if (target_cell !== null) {
458 if (text === "") {text = target_cell.placeholder;};
521 if (text === "") {text = target_cell.placeholder;};
459 target_cell.set_source(text);
522 target_cell.set_source(text);
460 source_element.remove();
523 source_element.remove();
461 target_cell.edit();
524 target_cell.edit();
462 }
525 }
463 this.dirty = true;
526 this.dirty = true;
464 };
527 };
465
528
466
529
467 // Cell collapsing and output clearing
530 // Cell collapsing and output clearing
468
531
469 Notebook.prototype.collapse = function (index) {
532 Notebook.prototype.collapse = function (index) {
470 var i = this.index_or_selected(index);
533 var i = this.index_or_selected(index);
471 this.cells()[i].collapse();
534 this.cells()[i].collapse();
472 this.dirty = true;
535 this.dirty = true;
473 };
536 };
474
537
475
538
476 Notebook.prototype.expand = function (index) {
539 Notebook.prototype.expand = function (index) {
477 var i = this.index_or_selected(index);
540 var i = this.index_or_selected(index);
478 this.cells()[i].expand();
541 this.cells()[i].expand();
479 this.dirty = true;
542 this.dirty = true;
480 };
543 };
481
544
482
545
483 Notebook.prototype.toggle_output = function (index) {
546 Notebook.prototype.toggle_output = function (index) {
484 var i = this.index_or_selected(index);
547 var i = this.index_or_selected(index);
485 this.cells()[i].toggle_output();
548 this.cells()[i].toggle_output();
486 this.dirty = true;
549 this.dirty = true;
487 };
550 };
488
551
489
552
490 Notebook.prototype.set_autoindent = function (state) {
553 Notebook.prototype.set_autoindent = function (state) {
491 var cells = this.cells();
554 var cells = this.cells();
492 len = cells.length;
555 len = cells.length;
493 for (var i=0; i<len; i++) {
556 for (var i=0; i<len; i++) {
494 cells[i].set_autoindent(state)
557 cells[i].set_autoindent(state)
495 };
558 };
496 };
559 };
497
560
498
561
499 Notebook.prototype.clear_all_output = function () {
562 Notebook.prototype.clear_all_output = function () {
500 var ncells = this.ncells();
563 var ncells = this.ncells();
501 var cells = this.cells();
564 var cells = this.cells();
502 for (var i=0; i<ncells; i++) {
565 for (var i=0; i<ncells; i++) {
503 if (cells[i] instanceof IPython.CodeCell) {
566 if (cells[i] instanceof IPython.CodeCell) {
504 cells[i].clear_output();
567 cells[i].clear_output();
505 }
568 }
506 };
569 };
507 this.dirty = true;
570 this.dirty = true;
508 };
571 };
509
572
510
573
511 // Kernel related things
574 // Kernel related things
512
575
513 Notebook.prototype.start_kernel = function () {
576 Notebook.prototype.start_kernel = function () {
514 this.kernel = new IPython.Kernel();
577 this.kernel = new IPython.Kernel();
515 var notebook_id = IPython.save_widget.get_notebook_id();
578 var notebook_id = IPython.save_widget.get_notebook_id();
516 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
579 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
517 };
580 };
518
581
519
582
520 Notebook.prototype.restart_kernel = function () {
583 Notebook.prototype.restart_kernel = function () {
521 var notebook_id = IPython.save_widget.get_notebook_id();
584 var notebook_id = IPython.save_widget.get_notebook_id();
522 this.kernel.restart($.proxy(this.kernel_started, this));
585 this.kernel.restart($.proxy(this.kernel_started, this));
523 };
586 };
524
587
525
588
526 Notebook.prototype.kernel_started = function () {
589 Notebook.prototype.kernel_started = function () {
527 console.log("Kernel started: ", this.kernel.kernel_id);
590 console.log("Kernel started: ", this.kernel.kernel_id);
528 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
591 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
529 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
592 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
530 };
593 };
531
594
532
595
533 Notebook.prototype.handle_shell_reply = function (e) {
596 Notebook.prototype.handle_shell_reply = function (e) {
534 reply = $.parseJSON(e.data);
597 reply = $.parseJSON(e.data);
535 var header = reply.header;
598 var header = reply.header;
536 var content = reply.content;
599 var content = reply.content;
537 var msg_type = header.msg_type;
600 var msg_type = header.msg_type;
538 // console.log(reply);
601 // console.log(reply);
539 var cell = this.cell_for_msg(reply.parent_header.msg_id);
602 var cell = this.cell_for_msg(reply.parent_header.msg_id);
540 if (msg_type === "execute_reply") {
603 if (msg_type === "execute_reply") {
541 cell.set_input_prompt(content.execution_count);
604 cell.set_input_prompt(content.execution_count);
542 this.dirty = true;
605 this.dirty = true;
543 } else if (msg_type === "complete_reply") {
606 } else if (msg_type === "complete_reply") {
544 cell.finish_completing(content.matched_text, content.matches);
607 cell.finish_completing(content.matched_text, content.matches);
545 };
608 };
546 var payload = content.payload || [];
609 var payload = content.payload || [];
547 this.handle_payload(cell, payload);
610 this.handle_payload(cell, payload);
548 };
611 };
549
612
550
613
551 Notebook.prototype.handle_payload = function (cell, payload) {
614 Notebook.prototype.handle_payload = function (cell, payload) {
552 var l = payload.length;
615 var l = payload.length;
553 for (var i=0; i<l; i++) {
616 for (var i=0; i<l; i++) {
554 if (payload[i].source === 'IPython.zmq.page.page') {
617 if (payload[i].source === 'IPython.zmq.page.page') {
555 if (payload[i].text.trim() !== '') {
618 if (payload[i].text.trim() !== '') {
556 IPython.pager.clear();
619 IPython.pager.clear();
557 IPython.pager.expand();
620 IPython.pager.expand();
558 IPython.pager.append_text(payload[i].text);
621 IPython.pager.append_text(payload[i].text);
559 }
622 }
560 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
623 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
561 var index = this.find_cell_index(cell);
624 var index = this.find_cell_index(cell);
562 var new_cell = this.insert_code_cell_after(index);
625 var new_cell = this.insert_code_cell_after(index);
563 new_cell.set_code(payload[i].text);
626 new_cell.set_code(payload[i].text);
564 this.dirty = true;
627 this.dirty = true;
565 }
628 }
566 };
629 };
567 };
630 };
568
631
569
632
570 Notebook.prototype.handle_iopub_reply = function (e) {
633 Notebook.prototype.handle_iopub_reply = function (e) {
571 reply = $.parseJSON(e.data);
634 reply = $.parseJSON(e.data);
572 var content = reply.content;
635 var content = reply.content;
573 // console.log(reply);
636 // console.log(reply);
574 var msg_type = reply.header.msg_type;
637 var msg_type = reply.header.msg_type;
575 var cell = this.cell_for_msg(reply.parent_header.msg_id);
638 var cell = this.cell_for_msg(reply.parent_header.msg_id);
576 var output_types = ['stream','display_data','pyout','pyerr'];
639 var output_types = ['stream','display_data','pyout','pyerr'];
577 if (output_types.indexOf(msg_type) >= 0) {
640 if (output_types.indexOf(msg_type) >= 0) {
578 this.handle_output(cell, msg_type, content);
641 this.handle_output(cell, msg_type, content);
579 } else if (msg_type === 'status') {
642 } else if (msg_type === 'status') {
580 if (content.execution_state === 'busy') {
643 if (content.execution_state === 'busy') {
581 IPython.kernel_status_widget.status_busy();
644 IPython.kernel_status_widget.status_busy();
582 } else if (content.execution_state === 'idle') {
645 } else if (content.execution_state === 'idle') {
583 IPython.kernel_status_widget.status_idle();
646 IPython.kernel_status_widget.status_idle();
584 } else if (content.execution_state === 'dead') {
647 } else if (content.execution_state === 'dead') {
585 this.handle_status_dead();
648 this.handle_status_dead();
586 };
649 };
587 }
650 }
588 };
651 };
589
652
590
653
591 Notebook.prototype.handle_status_dead = function () {
654 Notebook.prototype.handle_status_dead = function () {
592 var that = this;
655 var that = this;
593 this.kernel.stop_channels();
656 this.kernel.stop_channels();
594 var dialog = $('<div/>');
657 var dialog = $('<div/>');
595 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.');
658 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.');
596 $(document).append(dialog);
659 $(document).append(dialog);
597 dialog.dialog({
660 dialog.dialog({
598 resizable: false,
661 resizable: false,
599 modal: true,
662 modal: true,
600 title: "Dead kernel",
663 title: "Dead kernel",
601 buttons : {
664 buttons : {
602 "Yes": function () {
665 "Yes": function () {
603 that.start_kernel();
666 that.start_kernel();
604 $(this).dialog('close');
667 $(this).dialog('close');
605 },
668 },
606 "No": function () {
669 "No": function () {
607 $(this).dialog('close');
670 $(this).dialog('close');
608 }
671 }
609 }
672 }
610 });
673 });
611 };
674 };
612
675
613
676
614 Notebook.prototype.handle_output = function (cell, msg_type, content) {
677 Notebook.prototype.handle_output = function (cell, msg_type, content) {
615 var json = {};
678 var json = {};
616 json.output_type = msg_type;
679 json.output_type = msg_type;
617 if (msg_type === "stream") {
680 if (msg_type === "stream") {
618 json.text = utils.fixConsole(content.data + '\n');
681 json.text = utils.fixConsole(content.data + '\n');
619 } else if (msg_type === "display_data") {
682 } else if (msg_type === "display_data") {
620 json = this.convert_mime_types(json, content.data);
683 json = this.convert_mime_types(json, content.data);
621 } else if (msg_type === "pyout") {
684 } else if (msg_type === "pyout") {
622 json.prompt_number = content.execution_count;
685 json.prompt_number = content.execution_count;
623 json = this.convert_mime_types(json, content.data);
686 json = this.convert_mime_types(json, content.data);
624 } else if (msg_type === "pyerr") {
687 } else if (msg_type === "pyerr") {
625 json.ename = content.ename;
688 json.ename = content.ename;
626 json.evalue = content.evalue;
689 json.evalue = content.evalue;
627 var traceback = [];
690 var traceback = [];
628 for (var i=0; i<content.traceback.length; i++) {
691 for (var i=0; i<content.traceback.length; i++) {
629 traceback.push(utils.fixConsole(content.traceback[i]));
692 traceback.push(utils.fixConsole(content.traceback[i]));
630 }
693 }
631 json.traceback = traceback;
694 json.traceback = traceback;
632 };
695 };
633 cell.append_output(json);
696 cell.append_output(json);
634 this.dirty = true;
697 this.dirty = true;
635 };
698 };
636
699
637
700
638 Notebook.prototype.convert_mime_types = function (json, data) {
701 Notebook.prototype.convert_mime_types = function (json, data) {
639 if (data['text/plain'] !== undefined) {
702 if (data['text/plain'] !== undefined) {
640 json.text = utils.fixConsole(data['text/plain']);
703 json.text = utils.fixConsole(data['text/plain']);
641 };
704 };
642 if (data['text/html'] !== undefined) {
705 if (data['text/html'] !== undefined) {
643 json.html = data['text/html'];
706 json.html = data['text/html'];
644 };
707 };
645 if (data['image/svg+xml'] !== undefined) {
708 if (data['image/svg+xml'] !== undefined) {
646 json.svg = data['image/svg+xml'];
709 json.svg = data['image/svg+xml'];
647 };
710 };
648 if (data['image/png'] !== undefined) {
711 if (data['image/png'] !== undefined) {
649 json.png = data['image/png'];
712 json.png = data['image/png'];
650 };
713 };
651 if (data['image/jpeg'] !== undefined) {
714 if (data['image/jpeg'] !== undefined) {
652 json.jpeg = data['image/jpeg'];
715 json.jpeg = data['image/jpeg'];
653 };
716 };
654 if (data['text/latex'] !== undefined) {
717 if (data['text/latex'] !== undefined) {
655 json.latex = data['text/latex'];
718 json.latex = data['text/latex'];
656 };
719 };
657 if (data['application/json'] !== undefined) {
720 if (data['application/json'] !== undefined) {
658 json.json = data['application/json'];
721 json.json = data['application/json'];
659 };
722 };
660 if (data['application/javascript'] !== undefined) {
723 if (data['application/javascript'] !== undefined) {
661 json.javascript = data['application/javascript'];
724 json.javascript = data['application/javascript'];
662 }
725 }
663 return json;
726 return json;
664 };
727 };
665
728
666
729
667 Notebook.prototype.execute_selected_cell = function (options) {
730 Notebook.prototype.execute_selected_cell = function (options) {
668 // add_new: should a new cell be added if we are at the end of the nb
731 // add_new: should a new cell be added if we are at the end of the nb
669 // terminal: execute in terminal mode, which stays in the current cell
732 // terminal: execute in terminal mode, which stays in the current cell
670 default_options = {terminal: false, add_new: true}
733 default_options = {terminal: false, add_new: true}
671 $.extend(default_options, options)
734 $.extend(default_options, options)
672 var that = this;
735 var that = this;
673 var cell = that.selected_cell();
736 var cell = that.selected_cell();
674 var cell_index = that.find_cell_index(cell);
737 var cell_index = that.find_cell_index(cell);
675 if (cell instanceof IPython.CodeCell) {
738 if (cell instanceof IPython.CodeCell) {
676 cell.clear_output();
739 cell.clear_output();
677 var code = cell.get_code();
740 var code = cell.get_code();
678 var msg_id = that.kernel.execute(cell.get_code());
741 var msg_id = that.kernel.execute(cell.get_code());
679 that.msg_cell_map[msg_id] = cell.cell_id;
742 that.msg_cell_map[msg_id] = cell.cell_id;
680 } else if (cell instanceof IPython.HTMLCell) {
743 } else if (cell instanceof IPython.HTMLCell) {
681 cell.render();
744 cell.render();
682 }
745 }
683 if (default_options.terminal) {
746 if (default_options.terminal) {
684 cell.clear_input();
747 cell.clear_input();
685 } else {
748 } else {
686 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
749 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
687 that.insert_code_cell_after();
750 that.insert_code_cell_after();
688 // If we are adding a new cell at the end, scroll down to show it.
751 // If we are adding a new cell at the end, scroll down to show it.
689 that.scroll_to_bottom();
752 that.scroll_to_bottom();
690 } else {
753 } else {
691 that.select(cell_index+1);
754 that.select(cell_index+1);
692 };
755 };
693 };
756 };
694 this.dirty = true;
757 this.dirty = true;
695 };
758 };
696
759
697
760
698 Notebook.prototype.execute_all_cells = function () {
761 Notebook.prototype.execute_all_cells = function () {
699 var ncells = this.ncells();
762 var ncells = this.ncells();
700 for (var i=0; i<ncells; i++) {
763 for (var i=0; i<ncells; i++) {
701 this.select(i);
764 this.select(i);
702 this.execute_selected_cell({add_new:false});
765 this.execute_selected_cell({add_new:false});
703 };
766 };
704 this.scroll_to_bottom();
767 this.scroll_to_bottom();
705 };
768 };
706
769
707
770
708 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
771 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
709 var msg_id = this.kernel.complete(line, cursor_pos);
772 var msg_id = this.kernel.complete(line, cursor_pos);
710 this.msg_cell_map[msg_id] = cell.cell_id;
773 this.msg_cell_map[msg_id] = cell.cell_id;
711 };
774 };
712
775
713 // Persistance and loading
776 // Persistance and loading
714
777
715
778
716 Notebook.prototype.fromJSON = function (data) {
779 Notebook.prototype.fromJSON = function (data) {
717 var ncells = this.ncells();
780 var ncells = this.ncells();
718 for (var i=0; i<ncells; i++) {
781 for (var i=0; i<ncells; i++) {
719 // Always delete cell 0 as they get renumbered as they are deleted.
782 // Always delete cell 0 as they get renumbered as they are deleted.
720 this.delete_cell(0);
783 this.delete_cell(0);
721 };
784 };
722 // Save the metadata
785 // Save the metadata
723 this.metadata = data.metadata;
786 this.metadata = data.metadata;
724 // Only handle 1 worksheet for now.
787 // Only handle 1 worksheet for now.
725 var worksheet = data.worksheets[0];
788 var worksheet = data.worksheets[0];
726 if (worksheet !== undefined) {
789 if (worksheet !== undefined) {
727 var new_cells = worksheet.cells;
790 var new_cells = worksheet.cells;
728 ncells = new_cells.length;
791 ncells = new_cells.length;
729 var cell_data = null;
792 var cell_data = null;
730 var new_cell = null;
793 var new_cell = null;
731 for (var i=0; i<ncells; i++) {
794 for (var i=0; i<ncells; i++) {
732 cell_data = new_cells[i];
795 cell_data = new_cells[i];
733 if (cell_data.cell_type == 'code') {
796 if (cell_data.cell_type == 'code') {
734 new_cell = this.insert_code_cell_after();
797 new_cell = this.insert_code_cell_after();
735 new_cell.fromJSON(cell_data);
798 new_cell.fromJSON(cell_data);
736 } else if (cell_data.cell_type === 'html') {
799 } else if (cell_data.cell_type === 'html') {
737 new_cell = this.insert_html_cell_after();
800 new_cell = this.insert_html_cell_after();
738 new_cell.fromJSON(cell_data);
801 new_cell.fromJSON(cell_data);
739 } else if (cell_data.cell_type === 'markdown') {
802 } else if (cell_data.cell_type === 'markdown') {
740 new_cell = this.insert_markdown_cell_after();
803 new_cell = this.insert_markdown_cell_after();
741 new_cell.fromJSON(cell_data);
804 new_cell.fromJSON(cell_data);
742 };
805 };
743 };
806 };
744 };
807 };
745 };
808 };
746
809
747
810
748 Notebook.prototype.toJSON = function () {
811 Notebook.prototype.toJSON = function () {
749 var cells = this.cells();
812 var cells = this.cells();
750 var ncells = cells.length;
813 var ncells = cells.length;
751 cell_array = new Array(ncells);
814 cell_array = new Array(ncells);
752 for (var i=0; i<ncells; i++) {
815 for (var i=0; i<ncells; i++) {
753 cell_array[i] = cells[i].toJSON();
816 cell_array[i] = cells[i].toJSON();
754 };
817 };
755 data = {
818 data = {
756 // Only handle 1 worksheet for now.
819 // Only handle 1 worksheet for now.
757 worksheets : [{cells:cell_array}],
820 worksheets : [{cells:cell_array}],
758 metadata : this.metadata
821 metadata : this.metadata
759 }
822 }
760 return data
823 return data
761 };
824 };
762
825
763 Notebook.prototype.save_notebook = function () {
826 Notebook.prototype.save_notebook = function () {
764 if (IPython.save_widget.test_notebook_name()) {
827 if (IPython.save_widget.test_notebook_name()) {
765 var notebook_id = IPython.save_widget.get_notebook_id();
828 var notebook_id = IPython.save_widget.get_notebook_id();
766 var nbname = IPython.save_widget.get_notebook_name();
829 var nbname = IPython.save_widget.get_notebook_name();
767 // We may want to move the name/id/nbformat logic inside toJSON?
830 // We may want to move the name/id/nbformat logic inside toJSON?
768 var data = this.toJSON();
831 var data = this.toJSON();
769 data.metadata.name = nbname;
832 data.metadata.name = nbname;
770 data.nbformat = 2;
833 data.nbformat = 2;
771 // We do the call with settings so we can set cache to false.
834 // We do the call with settings so we can set cache to false.
772 var settings = {
835 var settings = {
773 processData : false,
836 processData : false,
774 cache : false,
837 cache : false,
775 type : "PUT",
838 type : "PUT",
776 data : JSON.stringify(data),
839 data : JSON.stringify(data),
777 headers : {'Content-Type': 'application/json'},
840 headers : {'Content-Type': 'application/json'},
778 success : $.proxy(this.notebook_saved,this)
841 success : $.proxy(this.notebook_saved,this)
779 };
842 };
780 IPython.save_widget.status_saving();
843 IPython.save_widget.status_saving();
781 $.ajax("/notebooks/" + notebook_id, settings);
844 $.ajax("/notebooks/" + notebook_id, settings);
782 };
845 };
783 };
846 };
784
847
785
848
786 Notebook.prototype.notebook_saved = function (data, status, xhr) {
849 Notebook.prototype.notebook_saved = function (data, status, xhr) {
787 this.dirty = false;
850 this.dirty = false;
788 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
851 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
789 }
852 }
790
853
791
854
792 Notebook.prototype.load_notebook = function (callback) {
855 Notebook.prototype.load_notebook = function (callback) {
793 var that = this;
856 var that = this;
794 var notebook_id = IPython.save_widget.get_notebook_id();
857 var notebook_id = IPython.save_widget.get_notebook_id();
795 // We do the call with settings so we can set cache to false.
858 // We do the call with settings so we can set cache to false.
796 var settings = {
859 var settings = {
797 processData : false,
860 processData : false,
798 cache : false,
861 cache : false,
799 type : "GET",
862 type : "GET",
800 dataType : "json",
863 dataType : "json",
801 success : function (data, status, xhr) {
864 success : function (data, status, xhr) {
802 that.notebook_loaded(data, status, xhr);
865 that.notebook_loaded(data, status, xhr);
803 if (callback !== undefined) {
866 if (callback !== undefined) {
804 callback();
867 callback();
805 };
868 };
806 }
869 }
807 };
870 };
808 IPython.save_widget.status_loading();
871 IPython.save_widget.status_loading();
809 $.ajax("/notebooks/" + notebook_id, settings);
872 $.ajax("/notebooks/" + notebook_id, settings);
810 }
873 }
811
874
812
875
813 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
876 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
814 this.fromJSON(data);
877 this.fromJSON(data);
815 if (this.ncells() === 0) {
878 if (this.ncells() === 0) {
816 this.insert_code_cell_after();
879 this.insert_code_cell_after();
817 };
880 };
818 IPython.save_widget.status_save();
881 IPython.save_widget.status_save();
819 IPython.save_widget.set_notebook_name(data.metadata.name);
882 IPython.save_widget.set_notebook_name(data.metadata.name);
820 this.start_kernel();
883 this.start_kernel();
821 this.dirty = false;
884 this.dirty = false;
822 // fromJSON always selects the last cell inserted. We need to wait
885 // fromJSON always selects the last cell inserted. We need to wait
823 // until that is done before scrolling to the top.
886 // until that is done before scrolling to the top.
824 setTimeout(function () {
887 setTimeout(function () {
825 IPython.notebook.select(0);
888 IPython.notebook.select(0);
826 IPython.notebook.scroll_to_top();
889 IPython.notebook.scroll_to_top();
827 }, 50);
890 }, 50);
828 };
891 };
829
892
830 IPython.Notebook = Notebook;
893 IPython.Notebook = Notebook;
831
894
832 return IPython;
895 return IPython;
833
896
834 }(IPython));
897 }(IPython));
835
898
@@ -1,142 +1,147
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 // SaveWidget
9 // SaveWidget
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 SaveWidget = function (selector) {
16 var SaveWidget = function (selector) {
17 this.selector = selector;
17 this.selector = selector;
18 this.notebook_name_re = /[^/\\]+/
18 this.notebook_name_re = /[^/\\]+/
19 this.last_saved_name = '';
19 this.last_saved_name = '';
20 if (this.selector !== undefined) {
20 if (this.selector !== undefined) {
21 this.element = $(selector);
21 this.element = $(selector);
22 this.style();
22 this.style();
23 this.bind_events();
23 this.bind_events();
24 }
24 }
25 };
25 };
26
26
27
27
28 SaveWidget.prototype.style = function () {
28 SaveWidget.prototype.style = function () {
29 this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content');
29 this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content');
30 this.element.find('input#notebook_name').attr('tabindex','1');
30 this.element.find('input#notebook_name').attr('tabindex','1');
31 this.element.find('button#save_notebook').button();
31 this.element.find('button#save_notebook').button();
32 var left_panel_width = $('div#left_panel').outerWidth();
32 var left_panel_width = $('div#left_panel').outerWidth();
33 var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth();
33 var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth();
34 $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width});
34 $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width});
35
35
36 };
36 };
37
37
38
38
39 SaveWidget.prototype.bind_events = function () {
39 SaveWidget.prototype.bind_events = function () {
40 var that = this;
40 var that = this;
41 this.element.find('button#save_notebook').click(function () {
41 this.element.find('button#save_notebook').click(function () {
42 IPython.notebook.save_notebook();
42 that.save_notebook();
43 that.set_document_title();
44 that.last_saved_name = that.get_notebook_name();
45 });
43 });
46 this.element.find('input#notebook_name').keyup(function () {
44 this.element.find('input#notebook_name').keyup(function () {
47 that.is_renaming();
45 that.is_renaming();
48 });
46 });
49 };
47 };
50
48
51
49
50 SaveWidget.prototype.save_notebook = function () {
51 IPython.notebook.save_notebook();
52 this.set_document_title();
53 this.last_saved_name = this.get_notebook_name();
54 };
55
56
52 SaveWidget.prototype.is_renaming = function () {
57 SaveWidget.prototype.is_renaming = function () {
53 if (this.get_notebook_name() !== this.last_saved_name) {
58 if (this.get_notebook_name() !== this.last_saved_name) {
54 this.status_rename();
59 this.status_rename();
55 } else {
60 } else {
56 this.status_save();
61 this.status_save();
57 };
62 };
58 };
63 };
59
64
60
65
61 SaveWidget.prototype.get_notebook_name = function () {
66 SaveWidget.prototype.get_notebook_name = function () {
62 return this.element.find('input#notebook_name').attr('value');
67 return this.element.find('input#notebook_name').attr('value');
63 }
68 }
64
69
65
70
66 SaveWidget.prototype.set_notebook_name = function (nbname) {
71 SaveWidget.prototype.set_notebook_name = function (nbname) {
67 this.element.find('input#notebook_name').attr('value',nbname);
72 this.element.find('input#notebook_name').attr('value',nbname);
68 this.set_document_title();
73 this.set_document_title();
69 this.last_saved_name = nbname;
74 this.last_saved_name = nbname;
70 }
75 }
71
76
72
77
73 SaveWidget.prototype.set_document_title = function () {
78 SaveWidget.prototype.set_document_title = function () {
74 nbname = this.get_notebook_name();
79 nbname = this.get_notebook_name();
75 document.title = 'IPy: ' + nbname;
80 document.title = 'IPy: ' + nbname;
76 };
81 };
77
82
78
83
79 SaveWidget.prototype.get_notebook_id = function () {
84 SaveWidget.prototype.get_notebook_id = function () {
80 return this.element.find('span#notebook_id').text()
85 return this.element.find('span#notebook_id').text()
81 };
86 };
82
87
83
88
84 SaveWidget.prototype.update_url = function () {
89 SaveWidget.prototype.update_url = function () {
85 var notebook_id = this.get_notebook_id();
90 var notebook_id = this.get_notebook_id();
86 if (notebook_id !== '') {
91 if (notebook_id !== '') {
87 window.history.replaceState({}, '', notebook_id);
92 window.history.replaceState({}, '', notebook_id);
88 };
93 };
89 };
94 };
90
95
91
96
92 SaveWidget.prototype.test_notebook_name = function () {
97 SaveWidget.prototype.test_notebook_name = function () {
93 var nbname = this.get_notebook_name();
98 var nbname = this.get_notebook_name();
94 if (this.notebook_name_re.test(nbname)) {
99 if (this.notebook_name_re.test(nbname)) {
95 return true;
100 return true;
96 } else {
101 } else {
97 var bad_name = $('<div/>');
102 var bad_name = $('<div/>');
98 bad_name.html(
103 bad_name.html(
99 "The notebook name you entered (" +
104 "The notebook name you entered (" +
100 nbname +
105 nbname +
101 ") is not valid. Notebook names can contain any characters except / and \\"
106 ") is not valid. Notebook names can contain any characters except / and \\"
102 );
107 );
103 bad_name.dialog({title: 'Invalid name', modal: true});
108 bad_name.dialog({title: 'Invalid name', modal: true});
104 return false;
109 return false;
105 };
110 };
106 };
111 };
107
112
108
113
109 SaveWidget.prototype.status_save = function () {
114 SaveWidget.prototype.status_save = function () {
110 this.element.find('button#save_notebook').button('option', 'label', 'Save');
115 this.element.find('button#save_notebook').button('option', 'label', 'Save');
111 this.element.find('button#save_notebook').button('enable');
116 this.element.find('button#save_notebook').button('enable');
112 IPython.print_widget.enable();
117 IPython.print_widget.enable();
113 };
118 };
114
119
115
120
116 SaveWidget.prototype.status_saving = function () {
121 SaveWidget.prototype.status_saving = function () {
117 this.element.find('button#save_notebook').button('option', 'label', 'Saving');
122 this.element.find('button#save_notebook').button('option', 'label', 'Saving');
118 this.element.find('button#save_notebook').button('disable');
123 this.element.find('button#save_notebook').button('disable');
119 IPython.print_widget.disable();
124 IPython.print_widget.disable();
120 };
125 };
121
126
122
127
123 SaveWidget.prototype.status_loading = function () {
128 SaveWidget.prototype.status_loading = function () {
124 this.element.find('button#save_notebook').button('option', 'label', 'Loading');
129 this.element.find('button#save_notebook').button('option', 'label', 'Loading');
125 this.element.find('button#save_notebook').button('disable');
130 this.element.find('button#save_notebook').button('disable');
126 IPython.print_widget.disable();
131 IPython.print_widget.disable();
127 };
132 };
128
133
129
134
130 SaveWidget.prototype.status_rename = function () {
135 SaveWidget.prototype.status_rename = function () {
131 this.element.find('button#save_notebook').button('option', 'label', 'Rename');
136 this.element.find('button#save_notebook').button('option', 'label', 'Rename');
132 this.element.find('button#save_notebook').button('enable');
137 this.element.find('button#save_notebook').button('enable');
133 IPython.print_widget.enable();
138 IPython.print_widget.enable();
134 };
139 };
135
140
136
141
137 IPython.SaveWidget = SaveWidget;
142 IPython.SaveWidget = SaveWidget;
138
143
139 return IPython;
144 return IPython;
140
145
141 }(IPython));
146 }(IPython));
142
147
General Comments 0
You need to be logged in to leave comments. Login now