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