##// END OF EJS Templates
Merge pull request #1490 from minrk/raw...
Fernando Perez -
r6480:a0e0f391 merge
parent child Browse files
Show More
@@ -1,178 +1,178
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 this.element.addClass('border-box-sizing');
26 26 $('ul#menus').menubar({
27 27 select : function (event, ui) {
28 28 // The selected cell loses focus when the menu is entered, so we
29 29 // re-select it upon selection.
30 30 var i = IPython.notebook.get_selected_index();
31 31 IPython.notebook.select(i);
32 32 }
33 33 });
34 34 };
35 35
36 36
37 37 MenuBar.prototype.bind_events = function () {
38 38 // File
39 39 this.element.find('#new_notebook').click(function () {
40 40 window.open($('body').data('baseProjectUrl')+'new');
41 41 });
42 42 this.element.find('#open_notebook').click(function () {
43 43 window.open($('body').data('baseProjectUrl'));
44 44 });
45 45 this.element.find('#rename_notebook').click(function () {
46 46 IPython.save_widget.rename_notebook();
47 47 });
48 48 this.element.find('#copy_notebook').click(function () {
49 49 var notebook_id = IPython.notebook.get_notebook_id();
50 50 var url = $('body').data('baseProjectUrl') + notebook_id + '/copy';
51 51 window.open(url,'_newtab');
52 52 });
53 53 this.element.find('#save_notebook').click(function () {
54 54 IPython.notebook.save_notebook();
55 55 });
56 56 this.element.find('#download_ipynb').click(function () {
57 57 var notebook_id = IPython.notebook.get_notebook_id();
58 58 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
59 59 notebook_id + '?format=json';
60 60 window.open(url,'_newtab');
61 61 });
62 62 this.element.find('#download_py').click(function () {
63 63 var notebook_id = IPython.notebook.get_notebook_id();
64 64 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
65 65 notebook_id + '?format=py';
66 66 window.open(url,'_newtab');
67 67 });
68 68 this.element.find('button#print_notebook').click(function () {
69 69 IPython.print_widget.print_notebook();
70 70 });
71 71 // Edit
72 72 this.element.find('#cut_cell').click(function () {
73 73 IPython.notebook.cut_cell();
74 74 });
75 75 this.element.find('#copy_cell').click(function () {
76 76 IPython.notebook.copy_cell();
77 77 });
78 78 this.element.find('#delete_cell').click(function () {
79 79 IPython.notebook.delete_cell();
80 80 });
81 81 this.element.find('#split_cell').click(function () {
82 82 IPython.notebook.split_cell();
83 83 });
84 84 this.element.find('#merge_cell_above').click(function () {
85 85 IPython.notebook.merge_cell_above();
86 86 });
87 87 this.element.find('#merge_cell_below').click(function () {
88 88 IPython.notebook.merge_cell_below();
89 89 });
90 90 this.element.find('#move_cell_up').click(function () {
91 91 IPython.notebook.move_cell_up();
92 92 });
93 93 this.element.find('#move_cell_down').click(function () {
94 94 IPython.notebook.move_cell_down();
95 95 });
96 96 this.element.find('#select_previous').click(function () {
97 97 IPython.notebook.select_prev();
98 98 });
99 99 this.element.find('#select_next').click(function () {
100 100 IPython.notebook.select_next();
101 101 });
102 102 // View
103 103 this.element.find('#toggle_header').click(function () {
104 104 $('div#header').toggle();
105 105 IPython.layout_manager.do_resize();
106 106 });
107 107 this.element.find('#toggle_toolbar').click(function () {
108 108 IPython.toolbar.toggle();
109 109 });
110 110 // Insert
111 111 this.element.find('#insert_cell_above').click(function () {
112 112 IPython.notebook.insert_cell_above('code');
113 113 });
114 114 this.element.find('#insert_cell_below').click(function () {
115 115 IPython.notebook.insert_cell_below('code');
116 116 });
117 117 // Cell
118 118 this.element.find('#run_cell').click(function () {
119 119 IPython.notebook.execute_selected_cell();
120 120 });
121 121 this.element.find('#run_cell_in_place').click(function () {
122 122 IPython.notebook.execute_selected_cell({terminal:true});
123 123 });
124 124 this.element.find('#run_all_cells').click(function () {
125 125 IPython.notebook.execute_all_cells();
126 126 });
127 127 this.element.find('#to_code').click(function () {
128 128 IPython.notebook.to_code();
129 129 });
130 130 this.element.find('#to_markdown').click(function () {
131 131 IPython.notebook.to_markdown();
132 132 });
133 this.element.find('#to_plaintext').click(function () {
134 IPython.notebook.to_plaintext();
133 this.element.find('#to_raw').click(function () {
134 IPython.notebook.to_raw();
135 135 });
136 136 this.element.find('#to_heading1').click(function () {
137 137 IPython.notebook.to_heading(undefined, 1);
138 138 });
139 139 this.element.find('#to_heading2').click(function () {
140 140 IPython.notebook.to_heading(undefined, 2);
141 141 });
142 142 this.element.find('#to_heading3').click(function () {
143 143 IPython.notebook.to_heading(undefined, 3);
144 144 });
145 145 this.element.find('#to_heading4').click(function () {
146 146 IPython.notebook.to_heading(undefined, 4);
147 147 });
148 148 this.element.find('#to_heading5').click(function () {
149 149 IPython.notebook.to_heading(undefined, 5);
150 150 });
151 151 this.element.find('#to_heading6').click(function () {
152 152 IPython.notebook.to_heading(undefined, 6);
153 153 });
154 154 this.element.find('#toggle_output').click(function () {
155 155 IPython.notebook.toggle_output();
156 156 });
157 157 this.element.find('#clear_all_output').click(function () {
158 158 IPython.notebook.clear_all_output();
159 159 });
160 160 // Kernel
161 161 this.element.find('#int_kernel').click(function () {
162 162 IPython.notebook.kernel.interrupt();
163 163 });
164 164 this.element.find('#restart_kernel').click(function () {
165 165 IPython.notebook.restart_kernel();
166 166 });
167 167 // Help
168 168 this.element.find('#keyboard_shortcuts').click(function () {
169 169 IPython.quick_help.show_keyboard_shortcuts();
170 170 });
171 171 };
172 172
173 173
174 174 IPython.MenuBar = MenuBar;
175 175
176 176 return IPython;
177 177
178 178 }(IPython));
@@ -1,1342 +1,1348
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.notebook_id = null;
30 30 this.notebook_name = null;
31 31 this.notebook_name_blacklist_re = /[\/\\]/;
32 32 this.nbformat = 3 // Increment this when changing the nbformat
33 33 this.style();
34 34 this.create_elements();
35 35 this.bind_events();
36 36 this.set_tooltipontab(true);
37 37 this.set_smartcompleter(true);
38 38 this.set_timebeforetooltip(1200);
39 39 };
40 40
41 41
42 42 Notebook.prototype.style = function () {
43 43 $('div#notebook').addClass('border-box-sizing');
44 44 };
45 45
46 46
47 47 Notebook.prototype.create_elements = function () {
48 48 // We add this end_space div to the end of the notebook div to:
49 49 // i) provide a margin between the last cell and the end of the notebook
50 50 // ii) to prevent the div from scrolling up when the last cell is being
51 51 // edited, but is too low on the page, which browsers will do automatically.
52 52 var that = this;
53 53 var end_space = $('<div/>').addClass('end_space').height("30%");
54 54 end_space.dblclick(function (e) {
55 55 if (that.read_only) return;
56 56 var ncells = that.ncells();
57 57 that.insert_cell_below('code',ncells-1);
58 58 });
59 59 this.element.append(end_space);
60 60 $('div#notebook').addClass('border-box-sizing');
61 61 };
62 62
63 63
64 64 Notebook.prototype.bind_events = function () {
65 65 var that = this;
66 66 $(document).keydown(function (event) {
67 67 // console.log(event);
68 68 if (that.read_only) return true;
69 69
70 70 // Save (CTRL+S) or (AppleKey+S)
71 71 //metaKey = applekey on mac
72 72 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
73 73 that.save_notebook();
74 74 event.preventDefault();
75 75 return false;
76 76 } else if (event.which === 27) {
77 77 // Intercept escape at highest level to avoid closing
78 78 // websocket connection with firefox
79 79 event.preventDefault();
80 80 }
81 81 if (event.which === 38 && !event.shiftKey) {
82 82 var cell = that.get_selected_cell();
83 83 if (cell.at_top()) {
84 84 event.preventDefault();
85 85 that.select_prev();
86 86 };
87 87 } else if (event.which === 40 && !event.shiftKey) {
88 88 var cell = that.get_selected_cell();
89 89 if (cell.at_bottom()) {
90 90 event.preventDefault();
91 91 that.select_next();
92 92 };
93 93 } else if (event.which === 13 && event.shiftKey) {
94 94 that.execute_selected_cell();
95 95 return false;
96 96 } else if (event.which === 13 && event.ctrlKey) {
97 97 that.execute_selected_cell({terminal:true});
98 98 return false;
99 99 } else if (event.which === 77 && event.ctrlKey && that.control_key_active == false) {
100 100 that.control_key_active = true;
101 101 return false;
102 102 } else if (event.which === 88 && that.control_key_active) {
103 103 // Cut selected cell = x
104 104 that.cut_cell();
105 105 that.control_key_active = false;
106 106 return false;
107 107 } else if (event.which === 67 && that.control_key_active) {
108 108 // Copy selected cell = c
109 109 that.copy_cell();
110 110 that.control_key_active = false;
111 111 return false;
112 112 } else if (event.which === 86 && that.control_key_active) {
113 113 // Paste selected cell = v
114 114 that.paste_cell();
115 115 that.control_key_active = false;
116 116 return false;
117 117 } else if (event.which === 68 && that.control_key_active) {
118 118 // Delete selected cell = d
119 119 that.delete_cell();
120 120 that.control_key_active = false;
121 121 return false;
122 122 } else if (event.which === 65 && that.control_key_active) {
123 123 // Insert code cell above selected = a
124 124 that.insert_cell_above('code');
125 125 that.control_key_active = false;
126 126 return false;
127 127 } else if (event.which === 66 && that.control_key_active) {
128 128 // Insert code cell below selected = b
129 129 that.insert_cell_below('code');
130 130 that.control_key_active = false;
131 131 return false;
132 132 } else if (event.which === 89 && that.control_key_active) {
133 133 // To code = y
134 134 that.to_code();
135 135 that.control_key_active = false;
136 136 return false;
137 137 } else if (event.which === 77 && that.control_key_active) {
138 138 // To markdown = m
139 139 that.to_markdown();
140 140 that.control_key_active = false;
141 141 return false;
142 142 } else if (event.which === 84 && that.control_key_active) {
143 // To Plaintext = t
144 that.to_plaintext();
143 // To Raw = t
144 that.to_raw();
145 145 that.control_key_active = false;
146 146 return false;
147 147 } else if (event.which === 49 && that.control_key_active) {
148 148 // To Heading 1 = 1
149 149 that.to_heading(undefined, 1);
150 150 that.control_key_active = false;
151 151 return false;
152 152 } else if (event.which === 50 && that.control_key_active) {
153 153 // To Heading 2 = 2
154 154 that.to_heading(undefined, 2);
155 155 that.control_key_active = false;
156 156 return false;
157 157 } else if (event.which === 51 && that.control_key_active) {
158 158 // To Heading 3 = 3
159 159 that.to_heading(undefined, 3);
160 160 that.control_key_active = false;
161 161 return false;
162 162 } else if (event.which === 52 && that.control_key_active) {
163 163 // To Heading 4 = 4
164 164 that.to_heading(undefined, 4);
165 165 that.control_key_active = false;
166 166 return false;
167 167 } else if (event.which === 53 && that.control_key_active) {
168 168 // To Heading 5 = 5
169 169 that.to_heading(undefined, 5);
170 170 that.control_key_active = false;
171 171 return false;
172 172 } else if (event.which === 54 && that.control_key_active) {
173 173 // To Heading 6 = 6
174 174 that.to_heading(undefined, 6);
175 175 that.control_key_active = false;
176 176 return false;
177 177 } else if (event.which === 79 && that.control_key_active) {
178 178 // Toggle output = o
179 179 that.toggle_output();
180 180 that.control_key_active = false;
181 181 return false;
182 182 } else if (event.which === 83 && that.control_key_active) {
183 183 // Save notebook = s
184 184 that.save_notebook();
185 185 that.control_key_active = false;
186 186 return false;
187 187 } else if (event.which === 74 && that.control_key_active) {
188 188 // Move cell down = j
189 189 that.move_cell_down();
190 190 that.control_key_active = false;
191 191 return false;
192 192 } else if (event.which === 75 && that.control_key_active) {
193 193 // Move cell up = k
194 194 that.move_cell_up();
195 195 that.control_key_active = false;
196 196 return false;
197 197 } else if (event.which === 80 && that.control_key_active) {
198 198 // Select previous = p
199 199 that.select_prev();
200 200 that.control_key_active = false;
201 201 return false;
202 202 } else if (event.which === 78 && that.control_key_active) {
203 203 // Select next = n
204 204 that.select_next();
205 205 that.control_key_active = false;
206 206 return false;
207 207 } else if (event.which === 76 && that.control_key_active) {
208 208 // Toggle line numbers = l
209 209 that.cell_toggle_line_numbers();
210 210 that.control_key_active = false;
211 211 return false;
212 212 } else if (event.which === 73 && that.control_key_active) {
213 213 // Interrupt kernel = i
214 214 that.kernel.interrupt();
215 215 that.control_key_active = false;
216 216 return false;
217 217 } else if (event.which === 190 && that.control_key_active) {
218 218 // Restart kernel = . # matches qt console
219 219 that.restart_kernel();
220 220 that.control_key_active = false;
221 221 return false;
222 222 } else if (event.which === 72 && that.control_key_active) {
223 223 // Show keyboard shortcuts = h
224 224 IPython.quick_help.show_keyboard_shortcuts();
225 225 that.control_key_active = false;
226 226 return false;
227 227 } else if (that.control_key_active) {
228 228 that.control_key_active = false;
229 229 return true;
230 230 };
231 231 return true;
232 232 });
233 233
234 234 this.element.bind('collapse_pager', function () {
235 235 var app_height = $('div#main_app').height(); // content height
236 236 var splitter_height = $('div#pager_splitter').outerHeight(true);
237 237 var new_height = app_height - splitter_height;
238 238 that.element.animate({height : new_height + 'px'}, 'fast');
239 239 });
240 240
241 241 this.element.bind('expand_pager', function () {
242 242 var app_height = $('div#main_app').height(); // content height
243 243 var splitter_height = $('div#pager_splitter').outerHeight(true);
244 244 var pager_height = $('div#pager').outerHeight(true);
245 245 var new_height = app_height - pager_height - splitter_height;
246 246 that.element.animate({height : new_height + 'px'}, 'fast');
247 247 });
248 248
249 249 $(window).bind('beforeunload', function () {
250 250 // TODO: Make killing the kernel configurable.
251 251 var kill_kernel = false;
252 252 if (kill_kernel) {
253 253 that.kernel.kill();
254 254 }
255 255 if (that.dirty && ! that.read_only) {
256 256 return "You have unsaved changes that will be lost if you leave this page.";
257 257 };
258 258 // Null is the *only* return value that will make the browser not
259 259 // pop up the "don't leave" dialog.
260 260 return null;
261 261 });
262 262 };
263 263
264 264
265 265 Notebook.prototype.scroll_to_bottom = function () {
266 266 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
267 267 };
268 268
269 269
270 270 Notebook.prototype.scroll_to_top = function () {
271 271 this.element.animate({scrollTop:0}, 0);
272 272 };
273 273
274 274
275 275 // Cell indexing, retrieval, etc.
276 276
277 277 Notebook.prototype.get_cell_elements = function () {
278 278 return this.element.children("div.cell");
279 279 };
280 280
281 281
282 282 Notebook.prototype.get_cell_element = function (index) {
283 283 var result = null;
284 284 var e = this.get_cell_elements().eq(index);
285 285 if (e.length !== 0) {
286 286 result = e;
287 287 }
288 288 return result;
289 289 };
290 290
291 291
292 292 Notebook.prototype.ncells = function (cell) {
293 293 return this.get_cell_elements().length;
294 294 };
295 295
296 296
297 297 // TODO: we are often calling cells as cells()[i], which we should optimize
298 298 // to cells(i) or a new method.
299 299 Notebook.prototype.get_cells = function () {
300 300 return this.get_cell_elements().toArray().map(function (e) {
301 301 return $(e).data("cell");
302 302 });
303 303 };
304 304
305 305
306 306 Notebook.prototype.get_cell = function (index) {
307 307 var result = null;
308 308 var ce = this.get_cell_element(index);
309 309 if (ce !== null) {
310 310 result = ce.data('cell');
311 311 }
312 312 return result;
313 313 }
314 314
315 315
316 316 Notebook.prototype.get_next_cell = function (cell) {
317 317 var result = null;
318 318 var index = this.find_cell_index(cell);
319 319 if (index !== null && index < this.ncells()) {
320 320 result = this.get_cell(index+1);
321 321 }
322 322 return result;
323 323 }
324 324
325 325
326 326 Notebook.prototype.get_prev_cell = function (cell) {
327 327 var result = null;
328 328 var index = this.find_cell_index(cell);
329 329 if (index !== null && index > 1) {
330 330 result = this.get_cell(index-1);
331 331 }
332 332 return result;
333 333 }
334 334
335 335 Notebook.prototype.find_cell_index = function (cell) {
336 336 var result = null;
337 337 this.get_cell_elements().filter(function (index) {
338 338 if ($(this).data("cell") === cell) {
339 339 result = index;
340 340 };
341 341 });
342 342 return result;
343 343 };
344 344
345 345
346 346 Notebook.prototype.index_or_selected = function (index) {
347 347 var i;
348 348 if (index === undefined || index === null) {
349 349 i = this.get_selected_index();
350 350 if (i === null) {
351 351 i = 0;
352 352 }
353 353 } else {
354 354 i = index;
355 355 }
356 356 return i;
357 357 };
358 358
359 359
360 360 Notebook.prototype.get_selected_cell = function () {
361 361 var index = this.get_selected_index();
362 362 return this.get_cell(index);
363 363 };
364 364
365 365
366 366 Notebook.prototype.is_valid_cell_index = function (index) {
367 367 if (index !== null && index >= 0 && index < this.ncells()) {
368 368 return true;
369 369 } else {
370 370 return false;
371 371 };
372 372 }
373 373
374 374 Notebook.prototype.get_selected_index = function () {
375 375 var result = null;
376 376 this.get_cell_elements().filter(function (index) {
377 377 if ($(this).data("cell").selected === true) {
378 378 result = index;
379 379 };
380 380 });
381 381 return result;
382 382 };
383 383
384 384
385 385 Notebook.prototype.cell_for_msg = function (msg_id) {
386 386 var cell_id = this.msg_cell_map[msg_id];
387 387 var result = null;
388 388 this.get_cell_elements().filter(function (index) {
389 389 cell = $(this).data("cell");
390 390 if (cell.cell_id === cell_id) {
391 391 result = cell;
392 392 };
393 393 });
394 394 return result;
395 395 };
396 396
397 397
398 398 // Cell selection.
399 399
400 400 Notebook.prototype.select = function (index) {
401 401 if (index !== undefined && index >= 0 && index < this.ncells()) {
402 402 sindex = this.get_selected_index()
403 403 if (sindex !== null && index !== sindex) {
404 404 this.get_cell(sindex).unselect();
405 405 };
406 406 var cell = this.get_cell(index)
407 407 cell.select();
408 408 if (cell.cell_type === 'heading') {
409 409 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
410 410 {'cell_type':cell.cell_type,level:cell.level}
411 411 );
412 412 } else {
413 413 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
414 414 {'cell_type':cell.cell_type}
415 415 );
416 416 };
417 417 };
418 418 return this;
419 419 };
420 420
421 421
422 422 Notebook.prototype.select_next = function () {
423 423 var index = this.get_selected_index();
424 424 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
425 425 this.select(index+1);
426 426 };
427 427 return this;
428 428 };
429 429
430 430
431 431 Notebook.prototype.select_prev = function () {
432 432 var index = this.get_selected_index();
433 433 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
434 434 this.select(index-1);
435 435 };
436 436 return this;
437 437 };
438 438
439 439
440 440 // Cell movement
441 441
442 442 Notebook.prototype.move_cell_up = function (index) {
443 443 var i = this.index_or_selected();
444 444 if (i !== null && i < this.ncells() && i > 0) {
445 445 var pivot = this.get_cell_element(i-1);
446 446 var tomove = this.get_cell_element(i);
447 447 if (pivot !== null && tomove !== null) {
448 448 tomove.detach();
449 449 pivot.before(tomove);
450 450 this.select(i-1);
451 451 };
452 452 };
453 453 this.dirty = true;
454 454 return this;
455 455 };
456 456
457 457
458 458 Notebook.prototype.move_cell_down = function (index) {
459 459 var i = this.index_or_selected();
460 460 if (i !== null && i < (this.ncells()-1) && i >= 0) {
461 461 var pivot = this.get_cell_element(i+1);
462 462 var tomove = this.get_cell_element(i);
463 463 if (pivot !== null && tomove !== null) {
464 464 tomove.detach();
465 465 pivot.after(tomove);
466 466 this.select(i+1);
467 467 };
468 468 };
469 469 this.dirty = true;
470 470 return this;
471 471 };
472 472
473 473
474 474 Notebook.prototype.sort_cells = function () {
475 475 // This is not working right now. Calling this will actually crash
476 476 // the browser. I think there is an infinite loop in here...
477 477 var ncells = this.ncells();
478 478 var sindex = this.get_selected_index();
479 479 var swapped;
480 480 do {
481 481 swapped = false;
482 482 for (var i=1; i<ncells; i++) {
483 483 current = this.get_cell(i);
484 484 previous = this.get_cell(i-1);
485 485 if (previous.input_prompt_number > current.input_prompt_number) {
486 486 this.move_cell_up(i);
487 487 swapped = true;
488 488 };
489 489 };
490 490 } while (swapped);
491 491 this.select(sindex);
492 492 return this;
493 493 };
494 494
495 495 // Insertion, deletion.
496 496
497 497 Notebook.prototype.delete_cell = function (index) {
498 498 var i = this.index_or_selected(index);
499 499 if (this.is_valid_cell_index(i)) {
500 500 var ce = this.get_cell_element(i);
501 501 ce.remove();
502 502 if (i === (this.ncells())) {
503 503 this.select(i-1);
504 504 } else {
505 505 this.select(i);
506 506 };
507 507 this.dirty = true;
508 508 };
509 509 return this;
510 510 };
511 511
512 512
513 513 Notebook.prototype.insert_cell_below = function (type, index) {
514 514 // type = ('code','html','markdown')
515 515 // index = cell index or undefined to insert below selected
516 516 index = this.index_or_selected(index);
517 517 var cell = null;
518 518 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
519 519 if (type === 'code') {
520 520 cell = new IPython.CodeCell(this);
521 521 cell.set_input_prompt();
522 522 } else if (type === 'markdown') {
523 523 cell = new IPython.MarkdownCell(this);
524 524 } else if (type === 'html') {
525 525 cell = new IPython.HTMLCell(this);
526 } else if (type === 'plaintext') {
527 cell = new IPython.PlaintextCell(this);
526 } else if (type === 'raw') {
527 cell = new IPython.RawCell(this);
528 528 } else if (type === 'heading') {
529 529 cell = new IPython.HeadingCell(this);
530 530 };
531 531 if (cell !== null) {
532 532 if (this.ncells() === 0) {
533 533 this.element.find('div.end_space').before(cell.element);
534 534 } else if (this.is_valid_cell_index(index)) {
535 535 this.get_cell_element(index).after(cell.element);
536 536 };
537 537 cell.render();
538 538 this.select(this.find_cell_index(cell));
539 539 this.dirty = true;
540 540 return cell;
541 541 };
542 542 };
543 543 return cell;
544 544 };
545 545
546 546
547 547 Notebook.prototype.insert_cell_above = function (type, index) {
548 548 // type = ('code','html','markdown')
549 549 // index = cell index or undefined to insert above selected
550 550 index = this.index_or_selected(index);
551 551 var cell = null;
552 552 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
553 553 if (type === 'code') {
554 554 cell = new IPython.CodeCell(this);
555 555 cell.set_input_prompt();
556 556 } else if (type === 'markdown') {
557 557 cell = new IPython.MarkdownCell(this);
558 558 } else if (type === 'html') {
559 559 cell = new IPython.HTMLCell(this);
560 } else if (type === 'plaintext') {
561 cell = new IPython.PlaintextCell(this);
560 } else if (type === 'raw') {
561 cell = new IPython.RawCell(this);
562 562 } else if (type === 'heading') {
563 563 cell = new IPython.HeadingCell(this);
564 564 };
565 565 if (cell !== null) {
566 566 if (this.ncells() === 0) {
567 567 this.element.find('div.end_space').before(cell.element);
568 568 } else if (this.is_valid_cell_index(index)) {
569 569 this.get_cell_element(index).before(cell.element);
570 570 };
571 571 cell.render();
572 572 this.select(this.find_cell_index(cell));
573 573 this.dirty = true;
574 574 return cell;
575 575 };
576 576 };
577 577 return cell;
578 578 };
579 579
580 580
581 581 Notebook.prototype.to_code = function (index) {
582 582 var i = this.index_or_selected(index);
583 583 if (this.is_valid_cell_index(i)) {
584 584 var source_element = this.get_cell_element(i);
585 585 var source_cell = source_element.data("cell");
586 586 if (!(source_cell instanceof IPython.CodeCell)) {
587 587 target_cell = this.insert_cell_below('code',i);
588 588 var text = source_cell.get_text();
589 589 if (text === source_cell.placeholder) {
590 590 text = '';
591 591 }
592 592 target_cell.set_text(text);
593 593 source_element.remove();
594 594 this.dirty = true;
595 595 };
596 596 };
597 597 };
598 598
599 599
600 600 Notebook.prototype.to_markdown = function (index) {
601 601 var i = this.index_or_selected(index);
602 602 if (this.is_valid_cell_index(i)) {
603 603 var source_element = this.get_cell_element(i);
604 604 var source_cell = source_element.data("cell");
605 605 if (!(source_cell instanceof IPython.MarkdownCell)) {
606 606 target_cell = this.insert_cell_below('markdown',i);
607 607 var text = source_cell.get_text();
608 608 if (text === source_cell.placeholder) {
609 609 text = '';
610 610 };
611 611 // The edit must come before the set_text.
612 612 target_cell.edit();
613 613 target_cell.set_text(text);
614 614 source_element.remove();
615 615 this.dirty = true;
616 616 };
617 617 };
618 618 };
619 619
620 620
621 621 Notebook.prototype.to_html = function (index) {
622 622 var i = this.index_or_selected(index);
623 623 if (this.is_valid_cell_index(i)) {
624 624 var source_element = this.get_cell_element(i);
625 625 var source_cell = source_element.data("cell");
626 626 var target_cell = null;
627 627 if (!(source_cell instanceof IPython.HTMLCell)) {
628 628 target_cell = this.insert_cell_below('html',i);
629 629 var text = source_cell.get_text();
630 630 if (text === source_cell.placeholder) {
631 631 text = '';
632 632 };
633 633 // The edit must come before the set_text.
634 634 target_cell.edit();
635 635 target_cell.set_text(text);
636 636 source_element.remove();
637 637 this.dirty = true;
638 638 };
639 639 };
640 640 };
641 641
642 642
643 Notebook.prototype.to_plaintext = function (index) {
643 Notebook.prototype.to_raw = function (index) {
644 644 var i = this.index_or_selected(index);
645 645 if (this.is_valid_cell_index(i)) {
646 646 var source_element = this.get_cell_element(i);
647 647 var source_cell = source_element.data("cell");
648 648 var target_cell = null;
649 if (!(source_cell instanceof IPython.PlaintextCell)) {
650 target_cell = this.insert_cell_below('plaintext',i);
649 if (!(source_cell instanceof IPython.RawCell)) {
650 target_cell = this.insert_cell_below('raw',i);
651 651 var text = source_cell.get_text();
652 652 if (text === source_cell.placeholder) {
653 653 text = '';
654 654 };
655 655 // The edit must come before the set_text.
656 656 target_cell.edit();
657 657 target_cell.set_text(text);
658 658 source_element.remove();
659 659 this.dirty = true;
660 660 };
661 661 };
662 662 };
663 663
664 664
665 665 Notebook.prototype.to_heading = function (index, level) {
666 666 level = level || 1;
667 667 var i = this.index_or_selected(index);
668 668 if (this.is_valid_cell_index(i)) {
669 669 var source_element = this.get_cell_element(i);
670 670 var source_cell = source_element.data("cell");
671 671 var target_cell = null;
672 672 if (source_cell instanceof IPython.HeadingCell) {
673 673 source_cell.set_level(level);
674 674 } else {
675 675 target_cell = this.insert_cell_below('heading',i);
676 676 var text = source_cell.get_text();
677 677 if (text === source_cell.placeholder) {
678 678 text = '';
679 679 };
680 680 // The edit must come before the set_text.
681 681 target_cell.set_level(level);
682 682 target_cell.edit();
683 683 target_cell.set_text(text);
684 684 source_element.remove();
685 685 this.dirty = true;
686 686 };
687 687 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
688 688 {'cell_type':'heading',level:level}
689 689 );
690 690 };
691 691 };
692 692
693 693
694 694 // Cut/Copy/Paste
695 695
696 696 Notebook.prototype.enable_paste = function () {
697 697 var that = this;
698 698 if (!this.paste_enabled) {
699 699 $('#paste_cell').removeClass('ui-state-disabled')
700 700 .on('click', function () {that.paste_cell();});
701 701 $('#paste_cell_above').removeClass('ui-state-disabled')
702 702 .on('click', function () {that.paste_cell_above();});
703 703 $('#paste_cell_below').removeClass('ui-state-disabled')
704 704 .on('click', function () {that.paste_cell_below();});
705 705 this.paste_enabled = true;
706 706 };
707 707 };
708 708
709 709
710 710 Notebook.prototype.disable_paste = function () {
711 711 if (this.paste_enabled) {
712 712 $('#paste_cell').addClass('ui-state-disabled').off('click');
713 713 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
714 714 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
715 715 this.paste_enabled = false;
716 716 };
717 717 };
718 718
719 719
720 720 Notebook.prototype.cut_cell = function () {
721 721 this.copy_cell();
722 722 this.delete_cell();
723 723 }
724 724
725 725 Notebook.prototype.copy_cell = function () {
726 726 var cell = this.get_selected_cell();
727 727 this.clipboard = cell.toJSON();
728 728 this.enable_paste();
729 729 };
730 730
731 731
732 732 Notebook.prototype.paste_cell = function () {
733 733 if (this.clipboard !== null && this.paste_enabled) {
734 734 var cell_data = this.clipboard;
735 735 var new_cell = this.insert_cell_above(cell_data.cell_type);
736 736 new_cell.fromJSON(cell_data);
737 737 old_cell = this.get_next_cell(new_cell);
738 738 this.delete_cell(this.find_cell_index(old_cell));
739 739 this.select(this.find_cell_index(new_cell));
740 740 };
741 741 };
742 742
743 743
744 744 Notebook.prototype.paste_cell_above = function () {
745 745 if (this.clipboard !== null && this.paste_enabled) {
746 746 var cell_data = this.clipboard;
747 747 var new_cell = this.insert_cell_above(cell_data.cell_type);
748 748 new_cell.fromJSON(cell_data);
749 749 };
750 750 };
751 751
752 752
753 753 Notebook.prototype.paste_cell_below = function () {
754 754 if (this.clipboard !== null && this.paste_enabled) {
755 755 var cell_data = this.clipboard;
756 756 var new_cell = this.insert_cell_below(cell_data.cell_type);
757 757 new_cell.fromJSON(cell_data);
758 758 };
759 759 };
760 760
761 761
762 762 // Split/merge
763 763
764 764 Notebook.prototype.split_cell = function () {
765 765 // Todo: implement spliting for other cell types.
766 766 var cell = this.get_selected_cell();
767 767 if (cell.is_splittable()) {
768 768 texta = cell.get_pre_cursor();
769 769 textb = cell.get_post_cursor();
770 770 if (cell instanceof IPython.CodeCell) {
771 771 cell.set_text(texta);
772 772 var new_cell = this.insert_cell_below('code');
773 773 new_cell.set_text(textb);
774 774 } else if (cell instanceof IPython.MarkdownCell) {
775 775 cell.set_text(texta);
776 776 cell.render();
777 777 var new_cell = this.insert_cell_below('markdown');
778 778 new_cell.edit(); // editor must be visible to call set_text
779 779 new_cell.set_text(textb);
780 780 new_cell.render();
781 781 } else if (cell instanceof IPython.HTMLCell) {
782 782 cell.set_text(texta);
783 783 cell.render();
784 784 var new_cell = this.insert_cell_below('html');
785 785 new_cell.edit(); // editor must be visible to call set_text
786 786 new_cell.set_text(textb);
787 787 new_cell.render();
788 788 };
789 789 };
790 790 };
791 791
792 792
793 793 Notebook.prototype.merge_cell_above = function () {
794 794 var index = this.get_selected_index();
795 795 var cell = this.get_cell(index);
796 796 if (index > 0) {
797 797 upper_cell = this.get_cell(index-1);
798 798 upper_text = upper_cell.get_text();
799 799 text = cell.get_text();
800 800 if (cell instanceof IPython.CodeCell) {
801 801 cell.set_text(upper_text+'\n'+text);
802 802 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
803 803 cell.edit();
804 804 cell.set_text(upper_text+'\n'+text);
805 805 cell.render();
806 806 };
807 807 this.delete_cell(index-1);
808 808 this.select(this.find_cell_index(cell));
809 809 };
810 810 };
811 811
812 812
813 813 Notebook.prototype.merge_cell_below = function () {
814 814 var index = this.get_selected_index();
815 815 var cell = this.get_cell(index);
816 816 if (index < this.ncells()-1) {
817 817 lower_cell = this.get_cell(index+1);
818 818 lower_text = lower_cell.get_text();
819 819 text = cell.get_text();
820 820 if (cell instanceof IPython.CodeCell) {
821 821 cell.set_text(text+'\n'+lower_text);
822 822 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
823 823 cell.edit();
824 824 cell.set_text(text+'\n'+lower_text);
825 825 cell.render();
826 826 };
827 827 this.delete_cell(index+1);
828 828 this.select(this.find_cell_index(cell));
829 829 };
830 830 };
831 831
832 832
833 833 // Cell collapsing and output clearing
834 834
835 835 Notebook.prototype.collapse = function (index) {
836 836 var i = this.index_or_selected(index);
837 837 this.get_cell(i).collapse();
838 838 this.dirty = true;
839 839 };
840 840
841 841
842 842 Notebook.prototype.expand = function (index) {
843 843 var i = this.index_or_selected(index);
844 844 this.get_cell(i).expand();
845 845 this.dirty = true;
846 846 };
847 847
848 848
849 849 Notebook.prototype.toggle_output = function (index) {
850 850 var i = this.index_or_selected(index);
851 851 this.get_cell(i).toggle_output();
852 852 this.dirty = true;
853 853 };
854 854
855 855
856 856 Notebook.prototype.set_timebeforetooltip = function (time) {
857 857 this.time_before_tooltip = time;
858 858 };
859 859
860 860
861 861 Notebook.prototype.set_tooltipontab = function (state) {
862 862 this.tooltip_on_tab = state;
863 863 };
864 864
865 865
866 866 Notebook.prototype.set_smartcompleter = function (state) {
867 867 this.smart_completer = state;
868 868 };
869 869
870 870
871 871 Notebook.prototype.clear_all_output = function () {
872 872 var ncells = this.ncells();
873 873 var cells = this.get_cells();
874 874 for (var i=0; i<ncells; i++) {
875 875 if (cells[i] instanceof IPython.CodeCell) {
876 876 cells[i].clear_output(true,true,true);
877 877 }
878 878 };
879 879 this.dirty = true;
880 880 };
881 881
882 882
883 883 // Other cell functions: line numbers, ...
884 884
885 885 Notebook.prototype.cell_toggle_line_numbers = function() {
886 886 this.get_selected_cell().toggle_line_numbers();
887 887 };
888 888
889 889 // Kernel related things
890 890
891 891 Notebook.prototype.start_kernel = function () {
892 892 this.kernel = new IPython.Kernel();
893 893 this.kernel.start(this.notebook_id, $.proxy(this.kernel_started, this));
894 894 };
895 895
896 896
897 897 Notebook.prototype.restart_kernel = function () {
898 898 var that = this;
899 899 var dialog = $('<div/>');
900 900 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
901 901 $(document).append(dialog);
902 902 dialog.dialog({
903 903 resizable: false,
904 904 modal: true,
905 905 title: "Restart kernel or continue running?",
906 906 closeText: '',
907 907 buttons : {
908 908 "Restart": function () {
909 909 that.kernel.restart($.proxy(that.kernel_started, that));
910 910 $(this).dialog('close');
911 911 },
912 912 "Continue running": function () {
913 913 $(this).dialog('close');
914 914 }
915 915 }
916 916 });
917 917 };
918 918
919 919
920 920 Notebook.prototype.kernel_started = function () {
921 921 console.log("Kernel started: ", this.kernel.kernel_id);
922 922 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
923 923 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
924 924 };
925 925
926 926
927 927 Notebook.prototype.handle_shell_reply = function (e) {
928 928 reply = $.parseJSON(e.data);
929 929 var header = reply.header;
930 930 var content = reply.content;
931 931 var msg_type = header.msg_type;
932 932 // console.log(reply);
933 933 var cell = this.cell_for_msg(reply.parent_header.msg_id);
934 934 if (msg_type === "execute_reply") {
935 935 cell.set_input_prompt(content.execution_count);
936 936 cell.element.removeClass("running");
937 937 this.dirty = true;
938 938 } else if (msg_type === "complete_reply") {
939 939 cell.finish_completing(content.matched_text, content.matches);
940 940 } else if (msg_type === "object_info_reply"){
941 941 //console.log('back from object_info_request : ')
942 942 rep = reply.content;
943 943 if(rep.found)
944 944 {
945 945 cell.finish_tooltip(rep);
946 946 }
947 947 } else {
948 948 //console.log("unknown reply:"+msg_type);
949 949 }
950 950 // when having a rely from object_info_reply,
951 951 // no payload so no nned to handle it
952 952 if(typeof(content.payload)!='undefined') {
953 953 var payload = content.payload || [];
954 954 this.handle_payload(cell, payload);
955 955 }
956 956 };
957 957
958 958
959 959 Notebook.prototype.handle_payload = function (cell, payload) {
960 960 var l = payload.length;
961 961 for (var i=0; i<l; i++) {
962 962 if (payload[i].source === 'IPython.zmq.page.page') {
963 963 if (payload[i].text.trim() !== '') {
964 964 IPython.pager.clear();
965 965 IPython.pager.expand();
966 966 IPython.pager.append_text(payload[i].text);
967 967 }
968 968 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
969 969 var index = this.find_cell_index(cell);
970 970 var new_cell = this.insert_cell_below('code',index);
971 971 new_cell.set_text(payload[i].text);
972 972 this.dirty = true;
973 973 }
974 974 };
975 975 };
976 976
977 977
978 978 Notebook.prototype.handle_iopub_reply = function (e) {
979 979 reply = $.parseJSON(e.data);
980 980 var content = reply.content;
981 981 // console.log(reply);
982 982 var msg_type = reply.header.msg_type;
983 983 var cell = this.cell_for_msg(reply.parent_header.msg_id);
984 984 if (msg_type !== 'status' && !cell){
985 985 // message not from this notebook, but should be attached to a cell
986 986 // console.log("Received IOPub message not caused by one of my cells");
987 987 // console.log(reply);
988 988 return;
989 989 }
990 990 var output_types = ['stream','display_data','pyout','pyerr'];
991 991 if (output_types.indexOf(msg_type) >= 0) {
992 992 this.handle_output(cell, msg_type, content);
993 993 } else if (msg_type === 'status') {
994 994 if (content.execution_state === 'busy') {
995 995 $([IPython.events]).trigger('status_busy.Kernel');
996 996 } else if (content.execution_state === 'idle') {
997 997 $([IPython.events]).trigger('status_idle.Kernel');
998 998 } else if (content.execution_state === 'dead') {
999 999 this.handle_status_dead();
1000 1000 };
1001 1001 } else if (msg_type === 'clear_output') {
1002 1002 cell.clear_output(content.stdout, content.stderr, content.other);
1003 1003 };
1004 1004 };
1005 1005
1006 1006
1007 1007 Notebook.prototype.handle_status_dead = function () {
1008 1008 var that = this;
1009 1009 this.kernel.stop_channels();
1010 1010 var dialog = $('<div/>');
1011 1011 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.');
1012 1012 $(document).append(dialog);
1013 1013 dialog.dialog({
1014 1014 resizable: false,
1015 1015 modal: true,
1016 1016 title: "Dead kernel",
1017 1017 buttons : {
1018 1018 "Restart": function () {
1019 1019 that.start_kernel();
1020 1020 $(this).dialog('close');
1021 1021 },
1022 1022 "Continue running": function () {
1023 1023 $(this).dialog('close');
1024 1024 }
1025 1025 }
1026 1026 });
1027 1027 };
1028 1028
1029 1029
1030 1030 Notebook.prototype.handle_output = function (cell, msg_type, content) {
1031 1031 var json = {};
1032 1032 json.output_type = msg_type;
1033 1033 if (msg_type === "stream") {
1034 1034 json.text = content.data;
1035 1035 json.stream = content.name;
1036 1036 } else if (msg_type === "display_data") {
1037 1037 json = this.convert_mime_types(json, content.data);
1038 1038 } else if (msg_type === "pyout") {
1039 1039 json.prompt_number = content.execution_count;
1040 1040 json = this.convert_mime_types(json, content.data);
1041 1041 } else if (msg_type === "pyerr") {
1042 1042 json.ename = content.ename;
1043 1043 json.evalue = content.evalue;
1044 1044 json.traceback = content.traceback;
1045 1045 };
1046 1046 // append with dynamic=true
1047 1047 cell.append_output(json, true);
1048 1048 this.dirty = true;
1049 1049 };
1050 1050
1051 1051
1052 1052 Notebook.prototype.convert_mime_types = function (json, data) {
1053 1053 if (data['text/plain'] !== undefined) {
1054 1054 json.text = data['text/plain'];
1055 1055 };
1056 1056 if (data['text/html'] !== undefined) {
1057 1057 json.html = data['text/html'];
1058 1058 };
1059 1059 if (data['image/svg+xml'] !== undefined) {
1060 1060 json.svg = data['image/svg+xml'];
1061 1061 };
1062 1062 if (data['image/png'] !== undefined) {
1063 1063 json.png = data['image/png'];
1064 1064 };
1065 1065 if (data['image/jpeg'] !== undefined) {
1066 1066 json.jpeg = data['image/jpeg'];
1067 1067 };
1068 1068 if (data['text/latex'] !== undefined) {
1069 1069 json.latex = data['text/latex'];
1070 1070 };
1071 1071 if (data['application/json'] !== undefined) {
1072 1072 json.json = data['application/json'];
1073 1073 };
1074 1074 if (data['application/javascript'] !== undefined) {
1075 1075 json.javascript = data['application/javascript'];
1076 1076 }
1077 1077 return json;
1078 1078 };
1079 1079
1080 1080
1081 1081 Notebook.prototype.execute_selected_cell = function (options) {
1082 1082 // add_new: should a new cell be added if we are at the end of the nb
1083 1083 // terminal: execute in terminal mode, which stays in the current cell
1084 1084 default_options = {terminal: false, add_new: true};
1085 1085 $.extend(default_options, options);
1086 1086 var that = this;
1087 1087 var cell = that.get_selected_cell();
1088 1088 var cell_index = that.find_cell_index(cell);
1089 1089 if (cell instanceof IPython.CodeCell) {
1090 1090 cell.clear_output(true, true, true);
1091 1091 cell.set_input_prompt('*');
1092 1092 cell.element.addClass("running");
1093 1093 var code = cell.get_text();
1094 1094 var msg_id = that.kernel.execute(cell.get_text());
1095 1095 that.msg_cell_map[msg_id] = cell.cell_id;
1096 1096 } else if (cell instanceof IPython.HTMLCell) {
1097 1097 cell.render();
1098 1098 }
1099 1099 if (default_options.terminal) {
1100 1100 cell.select_all();
1101 1101 } else {
1102 1102 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1103 1103 that.insert_cell_below('code');
1104 1104 // If we are adding a new cell at the end, scroll down to show it.
1105 1105 that.scroll_to_bottom();
1106 1106 } else {
1107 1107 that.select(cell_index+1);
1108 1108 };
1109 1109 };
1110 1110 this.dirty = true;
1111 1111 };
1112 1112
1113 1113
1114 1114 Notebook.prototype.execute_all_cells = function () {
1115 1115 var ncells = this.ncells();
1116 1116 for (var i=0; i<ncells; i++) {
1117 1117 this.select(i);
1118 1118 this.execute_selected_cell({add_new:false});
1119 1119 };
1120 1120 this.scroll_to_bottom();
1121 1121 };
1122 1122
1123 1123
1124 1124 Notebook.prototype.request_tool_tip = function (cell,func) {
1125 1125 // Feel free to shorten this logic if you are better
1126 1126 // than me in regEx
1127 1127 // basicaly you shoul be able to get xxx.xxx.xxx from
1128 1128 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
1129 1129 // remove everything between matchin bracket (need to iterate)
1130 1130 matchBracket = /\([^\(\)]+\)/g;
1131 1131 oldfunc = func;
1132 1132 func = func.replace(matchBracket,"");
1133 1133 while( oldfunc != func )
1134 1134 {
1135 1135 oldfunc = func;
1136 1136 func = func.replace(matchBracket,"");
1137 1137 }
1138 1138 // remove everythin after last open bracket
1139 1139 endBracket = /\([^\(]*$/g;
1140 1140 func = func.replace(endBracket,"");
1141 1141 var re = /[a-zA-Z._]+$/g;
1142 1142 var msg_id = this.kernel.object_info_request(re.exec(func));
1143 1143 if(typeof(msg_id)!='undefined'){
1144 1144 this.msg_cell_map[msg_id] = cell.cell_id;
1145 1145 }
1146 1146 };
1147 1147
1148 1148 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
1149 1149 var msg_id = this.kernel.complete(line, cursor_pos);
1150 1150 this.msg_cell_map[msg_id] = cell.cell_id;
1151 1151 };
1152 1152
1153 1153
1154 1154 // Persistance and loading
1155 1155
1156 1156 Notebook.prototype.get_notebook_id = function () {
1157 1157 return this.notebook_id;
1158 1158 };
1159 1159
1160 1160
1161 1161 Notebook.prototype.get_notebook_name = function () {
1162 1162 return this.notebook_name;
1163 1163 };
1164 1164
1165 1165
1166 1166 Notebook.prototype.set_notebook_name = function (name) {
1167 1167 this.notebook_name = name;
1168 1168 };
1169 1169
1170 1170
1171 1171 Notebook.prototype.test_notebook_name = function (nbname) {
1172 1172 nbname = nbname || '';
1173 1173 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1174 1174 return true;
1175 1175 } else {
1176 1176 return false;
1177 1177 };
1178 1178 };
1179 1179
1180 1180
1181 1181 Notebook.prototype.fromJSON = function (data) {
1182 1182 var ncells = this.ncells();
1183 1183 var i;
1184 1184 for (i=0; i<ncells; i++) {
1185 1185 // Always delete cell 0 as they get renumbered as they are deleted.
1186 1186 this.delete_cell(0);
1187 1187 };
1188 1188 // Save the metadata and name.
1189 1189 this.metadata = data.metadata;
1190 1190 this.notebook_name = data.metadata.name;
1191 1191 // Only handle 1 worksheet for now.
1192 1192 var worksheet = data.worksheets[0];
1193 1193 if (worksheet !== undefined) {
1194 1194 var new_cells = worksheet.cells;
1195 1195 ncells = new_cells.length;
1196 1196 var cell_data = null;
1197 1197 var new_cell = null;
1198 1198 for (i=0; i<ncells; i++) {
1199 1199 cell_data = new_cells[i];
1200 // VERSIONHACK: plaintext -> raw
1201 // handle never-released plaintext name for raw cells
1202 if (cell_data.cell_type === 'plaintext'){
1203 cell_data.cell_type = 'raw';
1204 }
1205
1200 1206 new_cell = this.insert_cell_below(cell_data.cell_type);
1201 1207 new_cell.fromJSON(cell_data);
1202 1208 };
1203 1209 };
1204 1210 };
1205 1211
1206 1212
1207 1213 Notebook.prototype.toJSON = function () {
1208 1214 var cells = this.get_cells();
1209 1215 var ncells = cells.length;
1210 1216 cell_array = new Array(ncells);
1211 1217 for (var i=0; i<ncells; i++) {
1212 1218 cell_array[i] = cells[i].toJSON();
1213 1219 };
1214 1220 data = {
1215 1221 // Only handle 1 worksheet for now.
1216 1222 worksheets : [{cells:cell_array}],
1217 1223 metadata : this.metadata
1218 1224 };
1219 1225 return data;
1220 1226 };
1221 1227
1222 1228 Notebook.prototype.save_notebook = function () {
1223 1229 // We may want to move the name/id/nbformat logic inside toJSON?
1224 1230 var data = this.toJSON();
1225 1231 data.metadata.name = this.notebook_name;
1226 1232 data.nbformat = this.nbformat;
1227 1233 // We do the call with settings so we can set cache to false.
1228 1234 var settings = {
1229 1235 processData : false,
1230 1236 cache : false,
1231 1237 type : "PUT",
1232 1238 data : JSON.stringify(data),
1233 1239 headers : {'Content-Type': 'application/json'},
1234 1240 success : $.proxy(this.save_notebook_success,this),
1235 1241 error : $.proxy(this.save_notebook_error,this)
1236 1242 };
1237 1243 $([IPython.events]).trigger('notebook_saving.Notebook');
1238 1244 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1239 1245 $.ajax(url, settings);
1240 1246 };
1241 1247
1242 1248
1243 1249 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1244 1250 this.dirty = false;
1245 1251 $([IPython.events]).trigger('notebook_saved.Notebook');
1246 1252 };
1247 1253
1248 1254
1249 1255 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1250 1256 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1251 1257 };
1252 1258
1253 1259
1254 1260 Notebook.prototype.load_notebook = function (notebook_id) {
1255 1261 var that = this;
1256 1262 this.notebook_id = notebook_id;
1257 1263 // We do the call with settings so we can set cache to false.
1258 1264 var settings = {
1259 1265 processData : false,
1260 1266 cache : false,
1261 1267 type : "GET",
1262 1268 dataType : "json",
1263 1269 success : $.proxy(this.load_notebook_success,this),
1264 1270 error : $.proxy(this.load_notebook_error,this),
1265 1271 };
1266 1272 $([IPython.events]).trigger('notebook_loading.Notebook');
1267 1273 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1268 1274 $.ajax(url, settings);
1269 1275 };
1270 1276
1271 1277
1272 1278 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1273 1279 this.fromJSON(data);
1274 1280 if (this.ncells() === 0) {
1275 1281 this.insert_cell_below('code');
1276 1282 };
1277 1283 this.dirty = false;
1278 1284 if (! this.read_only) {
1279 1285 this.start_kernel();
1280 1286 }
1281 1287 this.select(0);
1282 1288 this.scroll_to_top();
1283 1289 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1284 1290 msg = "This notebook has been converted from an older " +
1285 1291 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1286 1292 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1287 1293 "newer notebook format will be used and older verions of IPython " +
1288 1294 "may not be able to read it. To keep the older version, close the " +
1289 1295 "notebook without saving it.";
1290 1296 var dialog = $('<div/>');
1291 1297 dialog.html(msg);
1292 1298 this.element.append(dialog);
1293 1299 dialog.dialog({
1294 1300 resizable: false,
1295 1301 modal: true,
1296 1302 title: "Notebook converted",
1297 1303 closeText: "",
1298 1304 close: function(event, ui) {$(this).dialog('destroy').remove();},
1299 1305 buttons : {
1300 1306 "OK": function () {
1301 1307 $(this).dialog('close');
1302 1308 }
1303 1309 },
1304 1310 width: 400
1305 1311 });
1306 1312 }
1307 1313 $([IPython.events]).trigger('notebook_loaded.Notebook');
1308 1314 };
1309 1315
1310 1316
1311 1317 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1312 1318 if (xhr.status === 500) {
1313 1319 msg = "An error occurred while loading this notebook. Most likely " +
1314 1320 "this notebook is in a newer format than is supported by this " +
1315 1321 "version of IPython. This version can load notebook formats " +
1316 1322 "v"+this.nbformat+" or earlier.";
1317 1323 var dialog = $('<div/>');
1318 1324 dialog.html(msg);
1319 1325 this.element.append(dialog);
1320 1326 dialog.dialog({
1321 1327 resizable: false,
1322 1328 modal: true,
1323 1329 title: "Error loading notebook",
1324 1330 closeText: "",
1325 1331 close: function(event, ui) {$(this).dialog('destroy').remove();},
1326 1332 buttons : {
1327 1333 "OK": function () {
1328 1334 $(this).dialog('close');
1329 1335 }
1330 1336 },
1331 1337 width: 400
1332 1338 });
1333 1339 }
1334 1340 }
1335 1341
1336 1342 IPython.Notebook = Notebook;
1337 1343
1338 1344
1339 1345 return IPython;
1340 1346
1341 1347 }(IPython));
1342 1348
@@ -1,70 +1,70
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 // QuickHelp button
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var QuickHelp = function (selector) {
15 15 };
16 16
17 17 QuickHelp.prototype.show_keyboard_shortcuts = function () {
18 18 // toggles display of keyboard shortcut dialog
19 19 var that = this;
20 20 if ( this.shortcut_dialog ){
21 21 // if dialog is already shown, close it
22 22 this.shortcut_dialog.dialog("close");
23 23 this.shortcut_dialog = null;
24 24 return;
25 25 }
26 26 var dialog = $('<div/>');
27 27 this.shortcut_dialog = dialog;
28 28 var shortcuts = [
29 29 {key: 'Shift-Enter', help: 'run cell'},
30 30 {key: 'Ctrl-Enter', help: 'run cell in-place'},
31 31 {key: 'Ctrl-m x', help: 'cut cell'},
32 32 {key: 'Ctrl-m c', help: 'copy cell'},
33 33 {key: 'Ctrl-m v', help: 'paste cell'},
34 34 {key: 'Ctrl-m d', help: 'delete cell'},
35 35 {key: 'Ctrl-m a', help: 'insert cell above'},
36 36 {key: 'Ctrl-m b', help: 'insert cell below'},
37 37 {key: 'Ctrl-m o', help: 'toggle output'},
38 38 {key: 'Ctrl-m l', help: 'toggle line numbers'},
39 39 {key: 'Ctrl-m s', help: 'save notebook'},
40 40 {key: 'Ctrl-m j', help: 'move cell down'},
41 41 {key: 'Ctrl-m k', help: 'move cell up'},
42 42 {key: 'Ctrl-m y', help: 'code cell'},
43 43 {key: 'Ctrl-m m', help: 'markdown cell'},
44 {key: 'Ctrl-m t', help: 'plaintext cell'},
44 {key: 'Ctrl-m t', help: 'raw cell'},
45 45 {key: 'Ctrl-m 1-6', help: 'heading 1-6 cell'},
46 46 {key: 'Ctrl-m p', help: 'select previous'},
47 47 {key: 'Ctrl-m n', help: 'select next'},
48 48 {key: 'Ctrl-m i', help: 'interrupt kernel'},
49 49 {key: 'Ctrl-m .', help: 'restart kernel'},
50 50 {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
51 51 ];
52 52 for (var i=0; i<shortcuts.length; i++) {
53 53 dialog.append($('<div>').
54 54 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
55 55 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
56 56 );
57 57 };
58 58 dialog.bind('dialogclose', function(event) {
59 59 // dialog has been closed, allow it to be drawn again.
60 60 that.shortcut_dialog = null;
61 61 });
62 62 dialog.dialog({title: 'Keyboard shortcuts', closeText: ''});
63 63 };
64 64
65 65 // Set module variables
66 66 IPython.QuickHelp = QuickHelp;
67 67
68 68 return IPython;
69 69
70 70 }(IPython));
@@ -1,363 +1,363
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 // TextCell
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 // TextCell base class
15 15
16 16 var TextCell = function (notebook) {
17 17 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
18 18 IPython.Cell.apply(this, arguments);
19 19 this.rendered = false;
20 20 this.cell_type = this.cell_type || 'text';
21 21 };
22 22
23 23
24 24 TextCell.prototype = new IPython.Cell();
25 25
26 26
27 27 TextCell.prototype.create_element = function () {
28 28 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
29 29 cell.attr('tabindex','2');
30 30 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
31 31 this.code_mirror = CodeMirror(input_area.get(0), {
32 32 indentUnit : 4,
33 33 mode: this.code_mirror_mode,
34 34 theme: 'default',
35 35 value: this.placeholder,
36 36 readOnly: this.read_only,
37 37 lineWrapping : true,
38 38 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
39 39 });
40 40 // The tabindex=-1 makes this div focusable.
41 41 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
42 42 addClass('rendered_html').attr('tabindex','-1');
43 43 cell.append(input_area).append(render_area);
44 44 this.element = cell;
45 45 };
46 46
47 47
48 48 TextCell.prototype.bind_events = function () {
49 49 IPython.Cell.prototype.bind_events.apply(this);
50 50 var that = this;
51 51 this.element.keydown(function (event) {
52 52 if (event.which === 13 && !event.shiftKey) {
53 53 if (that.rendered) {
54 54 that.edit();
55 55 return false;
56 56 };
57 57 };
58 58 });
59 59 this.element.dblclick(function () {
60 60 that.edit();
61 61 });
62 62 };
63 63
64 64
65 65 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
66 66 // This method gets called in CodeMirror's onKeyDown/onKeyPress
67 67 // handlers and is used to provide custom key handling. Its return
68 68 // value is used to determine if CodeMirror should ignore the event:
69 69 // true = ignore, false = don't ignore.
70 70
71 71 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
72 72 // Always ignore shift-enter in CodeMirror as we handle it.
73 73 return true;
74 74 }
75 75 return false;
76 76 };
77 77
78 78
79 79 TextCell.prototype.select = function () {
80 80 IPython.Cell.prototype.select.apply(this);
81 81 var output = this.element.find("div.text_cell_render");
82 82 output.trigger('focus');
83 83 };
84 84
85 85
86 86 TextCell.prototype.unselect = function() {
87 87 // render on selection of another cell
88 88 this.render();
89 89 IPython.Cell.prototype.unselect.apply(this);
90 90 };
91 91
92 92
93 93 TextCell.prototype.edit = function () {
94 94 if ( this.read_only ) return;
95 95 if (this.rendered === true) {
96 96 var text_cell = this.element;
97 97 var output = text_cell.find("div.text_cell_render");
98 98 output.hide();
99 99 text_cell.find('div.text_cell_input').show();
100 100 this.code_mirror.refresh();
101 101 this.code_mirror.focus();
102 102 // We used to need an additional refresh() after the focus, but
103 103 // it appears that this has been fixed in CM. This bug would show
104 104 // up on FF when a newly loaded markdown cell was edited.
105 105 this.rendered = false;
106 106 if (this.get_text() === this.placeholder) {
107 107 this.set_text('');
108 108 this.refresh();
109 109 }
110 110 }
111 111 };
112 112
113 113
114 114 // Subclasses must define render.
115 115 TextCell.prototype.render = function () {};
116 116
117 117
118 118 TextCell.prototype.get_text = function() {
119 119 return this.code_mirror.getValue();
120 120 };
121 121
122 122
123 123 TextCell.prototype.set_text = function(text) {
124 124 this.code_mirror.setValue(text);
125 125 this.code_mirror.refresh();
126 126 };
127 127
128 128
129 129 TextCell.prototype.get_rendered = function() {
130 130 return this.element.find('div.text_cell_render').html();
131 131 };
132 132
133 133
134 134 TextCell.prototype.set_rendered = function(text) {
135 135 this.element.find('div.text_cell_render').html(text);
136 136 };
137 137
138 138
139 139 TextCell.prototype.at_top = function () {
140 140 if (this.rendered) {
141 141 return true;
142 142 } else {
143 143 return false;
144 144 }
145 145 };
146 146
147 147
148 148 TextCell.prototype.at_bottom = function () {
149 149 if (this.rendered) {
150 150 return true;
151 151 } else {
152 152 return false;
153 153 }
154 154 };
155 155
156 156
157 157 TextCell.prototype.fromJSON = function (data) {
158 158 if (data.cell_type === this.cell_type) {
159 159 if (data.source !== undefined) {
160 160 this.set_text(data.source);
161 161 this.set_rendered(data.rendered || '');
162 162 this.rendered = false;
163 163 this.render();
164 164 }
165 165 }
166 166 };
167 167
168 168
169 169 TextCell.prototype.toJSON = function () {
170 170 var data = {};
171 171 data.cell_type = this.cell_type;
172 172 data.source = this.get_text();
173 173 return data;
174 174 };
175 175
176 176
177 177 // HTMLCell
178 178
179 179 var HTMLCell = function (notebook) {
180 180 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
181 181 IPython.TextCell.apply(this, arguments);
182 182 this.cell_type = 'html';
183 183 };
184 184
185 185
186 186 HTMLCell.prototype = new TextCell();
187 187
188 188
189 189 HTMLCell.prototype.render = function () {
190 190 if (this.rendered === false) {
191 191 var text = this.get_text();
192 192 if (text === "") { text = this.placeholder; }
193 193 this.set_rendered(text);
194 194 this.typeset();
195 195 this.element.find('div.text_cell_input').hide();
196 196 this.element.find("div.text_cell_render").show();
197 197 this.rendered = true;
198 198 }
199 199 };
200 200
201 201
202 202 // MarkdownCell
203 203
204 204 var MarkdownCell = function (notebook) {
205 205 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
206 206 IPython.TextCell.apply(this, arguments);
207 207 this.cell_type = 'markdown';
208 208 };
209 209
210 210
211 211 MarkdownCell.prototype = new TextCell();
212 212
213 213
214 214 MarkdownCell.prototype.render = function () {
215 215 if (this.rendered === false) {
216 216 var text = this.get_text();
217 217 if (text === "") { text = this.placeholder; }
218 218 var html = IPython.markdown_converter.makeHtml(text);
219 219 this.set_rendered(html);
220 220 this.typeset()
221 221 this.element.find('div.text_cell_input').hide();
222 222 this.element.find("div.text_cell_render").show();
223 223 var code_snippets = this.element.find("pre > code");
224 224 code_snippets.replaceWith(function () {
225 225 var code = $(this).html();
226 226 /* Substitute br for newlines and &nbsp; for spaces
227 227 before highlighting, since prettify doesn't
228 228 preserve those on all browsers */
229 229 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
230 230 code = code.replace(/ /gm, '&nbsp;');
231 231 code = prettyPrintOne(code);
232 232
233 233 return '<code class="prettyprint">' + code + '</code>';
234 234 });
235 235 this.rendered = true;
236 236 }
237 237 };
238 238
239 239
240 // PlaintextCell
240 // RawCell
241 241
242 var PlaintextCell = function (notebook) {
242 var RawCell = function (notebook) {
243 243 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
244 244 this.code_mirror_mode = 'rst';
245 245 IPython.TextCell.apply(this, arguments);
246 this.cell_type = 'plaintext';
246 this.cell_type = 'raw';
247 247 };
248 248
249 249
250 PlaintextCell.prototype = new TextCell();
250 RawCell.prototype = new TextCell();
251 251
252 252
253 PlaintextCell.prototype.render = function () {
253 RawCell.prototype.render = function () {
254 254 this.rendered = true;
255 255 this.edit();
256 256 };
257 257
258 258
259 PlaintextCell.prototype.select = function () {
259 RawCell.prototype.select = function () {
260 260 IPython.Cell.prototype.select.apply(this);
261 261 this.code_mirror.refresh();
262 262 this.code_mirror.focus();
263 263 };
264 264
265 265
266 PlaintextCell.prototype.at_top = function () {
266 RawCell.prototype.at_top = function () {
267 267 var cursor = this.code_mirror.getCursor();
268 268 if (cursor.line === 0) {
269 269 return true;
270 270 } else {
271 271 return false;
272 272 }
273 273 };
274 274
275 275
276 PlaintextCell.prototype.at_bottom = function () {
276 RawCell.prototype.at_bottom = function () {
277 277 var cursor = this.code_mirror.getCursor();
278 278 if (cursor.line === (this.code_mirror.lineCount()-1)) {
279 279 return true;
280 280 } else {
281 281 return false;
282 282 }
283 283 };
284 284
285 285
286 286 // HTMLCell
287 287
288 288 var HeadingCell = function (notebook) {
289 289 this.placeholder = "Type Heading Here";
290 290 IPython.TextCell.apply(this, arguments);
291 291 this.cell_type = 'heading';
292 292 this.level = 1;
293 293 };
294 294
295 295
296 296 HeadingCell.prototype = new TextCell();
297 297
298 298
299 299 HeadingCell.prototype.fromJSON = function (data) {
300 300 if (data.level != undefined){
301 301 this.level = data.level;
302 302 }
303 303 IPython.TextCell.prototype.fromJSON.apply(this, arguments);
304 304 };
305 305
306 306
307 307 HeadingCell.prototype.toJSON = function () {
308 308 var data = IPython.TextCell.prototype.toJSON.apply(this);
309 309 data.level = this.get_level();
310 310 return data;
311 311 };
312 312
313 313
314 314 HeadingCell.prototype.set_level = function (level) {
315 315 this.level = level;
316 316 if (this.rendered) {
317 317 this.rendered = false;
318 318 this.render();
319 319 };
320 320 };
321 321
322 322
323 323 HeadingCell.prototype.get_level = function () {
324 324 return this.level;
325 325 };
326 326
327 327
328 328 HeadingCell.prototype.set_rendered = function (text) {
329 329 var r = this.element.find("div.text_cell_render");
330 330 r.empty();
331 331 r.append($('<h'+this.level+'/>').html(text));
332 332 };
333 333
334 334
335 335 HeadingCell.prototype.get_rendered = function () {
336 336 var r = this.element.find("div.text_cell_render");
337 337 return r.children().first().html();
338 338 };
339 339
340 340
341 341 HeadingCell.prototype.render = function () {
342 342 if (this.rendered === false) {
343 343 var text = this.get_text();
344 344 if (text === "") { text = this.placeholder; }
345 345 this.set_rendered(text);
346 346 this.typeset();
347 347 this.element.find('div.text_cell_input').hide();
348 348 this.element.find("div.text_cell_render").show();
349 349 this.rendered = true;
350 350 };
351 351 };
352 352
353 353 IPython.TextCell = TextCell;
354 354 IPython.HTMLCell = HTMLCell;
355 355 IPython.MarkdownCell = MarkdownCell;
356 IPython.PlaintextCell = PlaintextCell;
356 IPython.RawCell = RawCell;
357 357 IPython.HeadingCell = HeadingCell;
358 358
359 359
360 360 return IPython;
361 361
362 362 }(IPython));
363 363
@@ -1,152 +1,152
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 // ToolBar
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var ToolBar = 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 ToolBar.prototype.style = function () {
25 25 this.element.addClass('border-box-sizing').
26 26 addClass('ui-widget ui-widget-content').
27 27 css('border-top-style','none').
28 28 css('border-left-style','none').
29 29 css('border-right-style','none');
30 30 this.element.find('#cell_type').addClass('ui-widget ui-widget-content');
31 31 this.element.find('#save_b').button({
32 32 icons : {primary: 'ui-icon-disk'},
33 33 text : false
34 34 });
35 35 this.element.find('#cut_b').button({
36 36 icons: {primary: 'ui-icon-scissors'},
37 37 text : false
38 38 });
39 39 this.element.find('#copy_b').button({
40 40 icons: {primary: 'ui-icon-copy'},
41 41 text : false
42 42 });
43 43 this.element.find('#paste_b').button({
44 44 icons: {primary: 'ui-icon-clipboard'},
45 45 text : false
46 46 });
47 47 this.element.find('#cut_copy_paste').buttonset();
48 48 this.element.find('#move_up_b').button({
49 49 icons: {primary: 'ui-icon-arrowthick-1-n'},
50 50 text : false
51 51 });
52 52 this.element.find('#move_down_b').button({
53 53 icons: {primary: 'ui-icon-arrowthick-1-s'},
54 54 text : false
55 55 });
56 56 this.element.find('#move_up_down').buttonset();
57 57 this.element.find('#insert_above_b').button({
58 58 icons: {primary: 'ui-icon-arrowthickstop-1-n'},
59 59 text : false
60 60 });
61 61 this.element.find('#insert_below_b').button({
62 62 icons: {primary: 'ui-icon-arrowthickstop-1-s'},
63 63 text : false
64 64 });
65 65 this.element.find('#insert_above_below').buttonset();
66 66 this.element.find('#run_b').button({
67 67 icons: {primary: 'ui-icon-play'},
68 68 text : false
69 69 });
70 70 this.element.find('#interrupt_b').button({
71 71 icons: {primary: 'ui-icon-stop'},
72 72 text : false
73 73 });
74 74 this.element.find('#run_int').buttonset();
75 75 };
76 76
77 77
78 78 ToolBar.prototype.bind_events = function () {
79 79 var that = this;
80 80 this.element.find('#save_b').click(function () {
81 81 IPython.notebook.save_notebook();
82 82 });
83 83 this.element.find('#cut_b').click(function () {
84 84 IPython.notebook.cut_cell();
85 85 });
86 86 this.element.find('#copy_b').click(function () {
87 87 IPython.notebook.copy_cell();
88 88 });
89 89 this.element.find('#paste_b').click(function () {
90 90 IPython.notebook.paste_cell();
91 91 });
92 92 this.element.find('#move_up_b').click(function () {
93 93 IPython.notebook.move_cell_up();
94 94 });
95 95 this.element.find('#move_down_b').click(function () {
96 96 IPython.notebook.move_cell_down();
97 97 });
98 98 this.element.find('#insert_above_b').click(function () {
99 99 IPython.notebook.insert_cell_above('code');
100 100 });
101 101 this.element.find('#insert_below_b').click(function () {
102 102 IPython.notebook.insert_cell_below('code');
103 103 });
104 104 this.element.find('#run_b').click(function () {
105 105 IPython.notebook.execute_selected_cell();
106 106 });
107 107 this.element.find('#interrupt_b').click(function () {
108 108 IPython.notebook.kernel.interrupt();
109 109 });
110 110 this.element.find('#cell_type').change(function () {
111 111 var cell_type = $(this).val();
112 112 if (cell_type === 'code') {
113 113 IPython.notebook.to_code();
114 114 } else if (cell_type === 'markdown') {
115 115 IPython.notebook.to_markdown();
116 } else if (cell_type === 'plaintext') {
117 IPython.notebook.to_plaintext();
116 } else if (cell_type === 'raw') {
117 IPython.notebook.to_raw();
118 118 } else if (cell_type === 'heading1') {
119 119 IPython.notebook.to_heading(undefined, 1);
120 120 } else if (cell_type === 'heading2') {
121 121 IPython.notebook.to_heading(undefined, 2);
122 122 } else if (cell_type === 'heading3') {
123 123 IPython.notebook.to_heading(undefined, 3);
124 124 } else if (cell_type === 'heading4') {
125 125 IPython.notebook.to_heading(undefined, 4);
126 126 } else if (cell_type === 'heading5') {
127 127 IPython.notebook.to_heading(undefined, 5);
128 128 } else if (cell_type === 'heading6') {
129 129 IPython.notebook.to_heading(undefined, 6);
130 130 };
131 131 });
132 132 $([IPython.events]).on('selected_cell_type_changed.Notebook', function (event, data) {
133 133 if (data.cell_type === 'heading') {
134 134 that.element.find('#cell_type').val(data.cell_type+data.level);
135 135 } else {
136 136 that.element.find('#cell_type').val(data.cell_type);
137 137 }
138 138 });
139 139 };
140 140
141 141
142 142 ToolBar.prototype.toggle = function () {
143 143 this.element.toggle();
144 144 IPython.layout_manager.do_resize();
145 145 };
146 146
147 147
148 148 IPython.ToolBar = ToolBar;
149 149
150 150 return IPython;
151 151
152 152 }(IPython));
@@ -1,233 +1,233
1 1 {% extends page.html %}
2 2
3 3 {% block stylesheet %}
4 4
5 5 {% if mathjax_url %}
6 6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
7 7 {% end %}
8 8 <script type="text/javascript">
9 9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 10 // where it will be undefined, and should prompt a dialog later.
11 11 window.mathjax_url = "{{mathjax_url}}";
12 12 </script>
13 13
14 14 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
15 15 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
16 16
17 17 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
18 18
19 19 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
20 20 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
21 21
22 22 {% end %}
23 23
24 24
25 25 {% block params %}
26 26
27 27 data-project={{project}}
28 28 data-base-project-url={{base_project_url}}
29 29 data-base-kernel-url={{base_kernel_url}}
30 30 data-read-only={{read_only and not logged_in}}
31 31 data-notebook-id={{notebook_id}}
32 32
33 33 {% end %}
34 34
35 35
36 36 {% block header %}
37 37
38 38 <span id="save_widget">
39 39 <span id="notebook_name"></span>
40 40 <span id="save_status"></span>
41 41 </span>
42 42
43 43 {% end %}
44 44
45 45
46 46 {% block site %}
47 47
48 48 <div id="menubar_container">
49 49 <div id="menubar">
50 50 <ul id="menus">
51 51 <li><a href="#">File</a>
52 52 <ul>
53 53 <li id="new_notebook"><a href="#">New</a></li>
54 54 <li id="open_notebook"><a href="#">Open...</a></li>
55 55 <hr/>
56 56 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
57 57 <li id="rename_notebook"><a href="#">Rename...</a></li>
58 58 <li id="save_notebook"><a href="#">Save</a></li>
59 59 <hr/>
60 60 <li><a href="#">Download as</a>
61 61 <ul>
62 62 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
63 63 <li id="download_py"><a href="#">Python (.py)</a></li>
64 64 </ul>
65 65 </li>
66 66 <hr/>
67 67 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
68 68 </ul>
69 69 </li>
70 70 <li><a href="#">Edit</a>
71 71 <ul>
72 72 <li id="cut_cell"><a href="#">Cut Cell</a></li>
73 73 <li id="copy_cell"><a href="#">Copy Cell</a></li>
74 74 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
75 75 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
76 76 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
77 77 <li id="delete_cell"><a href="#">Delete</a></li>
78 78 <hr/>
79 79 <li id="split_cell"><a href="#">Split Cell</a></li>
80 80 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
81 81 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
82 82 <hr/>
83 83 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
84 84 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
85 85 <hr/>
86 86 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
87 87 <li id="select_next"><a href="#">Select Next Cell</a></li>
88 88 </ul>
89 89 </li>
90 90 <li><a href="#">View</a>
91 91 <ul>
92 92 <li id="toggle_header"><a href="#">Toggle Header</a></li>
93 93 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
94 94 </ul>
95 95 </li>
96 96 <li><a href="#">Insert</a>
97 97 <ul>
98 98 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
99 99 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
100 100 </ul>
101 101 </li>
102 102 <li><a href="#">Cell</a>
103 103 <ul>
104 104 <li id="run_cell"><a href="#">Run</a></li>
105 105 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
106 106 <li id="run_all_cells"><a href="#">Run All</a></li>
107 107 <hr/>
108 108 <li id="to_code"><a href="#">Code</a></li>
109 109 <li id="to_markdown"><a href="#">Markdown </a></li>
110 <li id="to_plaintext"><a href="#">Plaintext</a></li>
110 <li id="to_raw"><a href="#">Raw Text</a></li>
111 111 <li id="to_heading1"><a href="#">Heading 1</a></li>
112 112 <li id="to_heading2"><a href="#">Heading 2</a></li>
113 113 <li id="to_heading3"><a href="#">Heading 3</a></li>
114 114 <li id="to_heading4"><a href="#">Heading 4</a></li>
115 115 <li id="to_heading5"><a href="#">Heading 5</a></li>
116 116 <li id="to_heading6"><a href="#">Heading 6</a></li>
117 117 <hr/>
118 118 <li id="toggle_output"><a href="#">Toggle Output</a></li>
119 119 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
120 120 </ul>
121 121 </li>
122 122 <li><a href="#">Kernel</a>
123 123 <ul>
124 124 <li id="int_kernel"><a href="#">Interrupt</a></li>
125 125 <li id="restart_kernel"><a href="#">Restart</a></li>
126 126 </ul>
127 127 </li>
128 128 <li><a href="#">Help</a>
129 129 <ul>
130 130 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
131 131 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
132 132 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
133 133 <hr/>
134 134 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
135 135 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
136 136 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
137 137 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
138 138 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
139 139 </ul>
140 140 </li>
141 141 </ul>
142 142
143 143 </div>
144 144 <div id="notification"></div>
145 145 </div>
146 146
147 147
148 148 <div id="toolbar">
149 149
150 150 <span>
151 151 <button id="save_b">Save</button>
152 152 </span>
153 153 <span id="cut_copy_paste">
154 154 <button id="cut_b" title="Cut Cell">Cut Cell</button>
155 155 <button id="copy_b" title="Copy Cell">Copy Cell</button>
156 156 <button id="paste_b" title="Paste Cell">Paste Cell</button>
157 157 </span>
158 158 <span id="move_up_down">
159 159 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
160 160 <button id="move_down_b" title="Move Cell Down">Move Down</button>
161 161 </span>
162 162 <span id="insert_above_below">
163 163 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
164 164 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
165 165 </span>
166 166 <span id="run_int">
167 167 <button id="run_b" title="Run Cell">Run Cell</button>
168 168 <button id="interrupt_b" title="Interrupt">Interrupt</button>
169 169 </span>
170 170 <span>
171 171 <select id="cell_type">
172 172 <option value="code">Code</option>
173 173 <option value="markdown">Markdown</option>
174 <option value="plaintext">Plaintext</option>
174 <option value="raw">Raw Text</option>
175 175 <option value="heading1">Heading 1</option>
176 176 <option value="heading2">Heading 2</option>
177 177 <option value="heading3">Heading 3</option>
178 178 <option value="heading4">Heading 4</option>
179 179 <option value="heading5">Heading 5</option>
180 180 <option value="heading6">Heading 6</option>
181 181 </select>
182 182 </span>
183 183
184 184 </div>
185 185
186 186 <div id="main_app">
187 187
188 188 <div id="notebook_panel">
189 189 <div id="notebook"></div>
190 190 <div id="pager_splitter"></div>
191 191 <div id="pager"></div>
192 192 </div>
193 193
194 194 </div>
195 195
196 196 {% end %}
197 197
198 198
199 199 {% block script %}
200 200
201 201 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
202 202 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
203 203 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
204 204 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
205 205 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
206 206 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
207 207 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
208 208 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
209 209
210 210 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
211 211
212 212 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
213 213 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
214 214
215 215 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
216 216 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
217 217 <script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
218 218 <script src="{{ static_url("js/initmathjax.js") }}" type="text/javascript" charset="utf-8"></script>
219 219 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
220 220 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
221 221 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
222 222 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
223 223 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
224 224 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
225 225 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
226 226 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
227 227 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
228 228 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
229 229 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
230 230 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
231 231
232 232 {% end %}
233 233
@@ -1,196 +1,200
1 1 """The basic dict based notebook format.
2 2
3 3 The Python representation of a notebook is a nested structure of
4 4 dictionary subclasses that support attribute access
5 5 (IPython.utils.ipstruct.Struct). The functions in this module are merely
6 6 helpers to build the structs in the right form.
7 7
8 8 Authors:
9 9
10 10 * Brian Granger
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import pprint
25 25 import uuid
26 26
27 27 from IPython.utils.ipstruct import Struct
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Code
31 31 #-----------------------------------------------------------------------------
32 32
33 33 # Change this when incrementing the nbformat version
34 34 nbformat = 3
35 35
36 36 class NotebookNode(Struct):
37 37 pass
38 38
39 39
40 40 def from_dict(d):
41 41 if isinstance(d, dict):
42 42 newd = NotebookNode()
43 43 for k,v in d.items():
44 44 newd[k] = from_dict(v)
45 45 return newd
46 46 elif isinstance(d, (tuple, list)):
47 47 return [from_dict(i) for i in d]
48 48 else:
49 49 return d
50 50
51 51
52 52 def new_output(output_type=None, output_text=None, output_png=None,
53 53 output_html=None, output_svg=None, output_latex=None, output_json=None,
54 54 output_javascript=None, output_jpeg=None, prompt_number=None,
55 55 etype=None, evalue=None, traceback=None):
56 56 """Create a new code cell with input and output"""
57 57 output = NotebookNode()
58 58 if output_type is not None:
59 59 output.output_type = unicode(output_type)
60 60
61 61 if output_type != 'pyerr':
62 62 if output_text is not None:
63 63 output.text = unicode(output_text)
64 64 if output_png is not None:
65 65 output.png = bytes(output_png)
66 66 if output_jpeg is not None:
67 67 output.jpeg = bytes(output_jpeg)
68 68 if output_html is not None:
69 69 output.html = unicode(output_html)
70 70 if output_svg is not None:
71 71 output.svg = unicode(output_svg)
72 72 if output_latex is not None:
73 73 output.latex = unicode(output_latex)
74 74 if output_json is not None:
75 75 output.json = unicode(output_json)
76 76 if output_javascript is not None:
77 77 output.javascript = unicode(output_javascript)
78 78
79 79 if output_type == u'pyout':
80 80 if prompt_number is not None:
81 81 output.prompt_number = int(prompt_number)
82 82
83 83 if output_type == u'pyerr':
84 84 if etype is not None:
85 85 output.etype = unicode(etype)
86 86 if evalue is not None:
87 87 output.evalue = unicode(evalue)
88 88 if traceback is not None:
89 89 output.traceback = [unicode(frame) for frame in list(traceback)]
90 90
91 91 return output
92 92
93 93
94 94 def new_code_cell(input=None, prompt_number=None, outputs=None,
95 95 language=u'python', collapsed=False):
96 96 """Create a new code cell with input and output"""
97 97 cell = NotebookNode()
98 98 cell.cell_type = u'code'
99 99 if language is not None:
100 100 cell.language = unicode(language)
101 101 if input is not None:
102 102 cell.input = unicode(input)
103 103 if prompt_number is not None:
104 104 cell.prompt_number = int(prompt_number)
105 105 if outputs is None:
106 106 cell.outputs = []
107 107 else:
108 108 cell.outputs = outputs
109 109 if collapsed is not None:
110 110 cell.collapsed = bool(collapsed)
111 111
112 112 return cell
113 113
114 114 def new_text_cell(cell_type, source=None, rendered=None):
115 115 """Create a new text cell."""
116 116 cell = NotebookNode()
117 # VERSIONHACK: plaintext -> raw
118 # handle never-released plaintext name for raw cells
119 if cell_type == 'plaintext':
120 cell_type = 'raw'
117 121 if source is not None:
118 122 cell.source = unicode(source)
119 123 if rendered is not None:
120 124 cell.rendered = unicode(rendered)
121 125 cell.cell_type = cell_type
122 126 return cell
123 127
124 128
125 129 def new_heading_cell(source=None, rendered=None, level=1):
126 130 """Create a new section cell with a given integer level."""
127 131 cell = NotebookNode()
128 132 cell.cell_type = u'heading'
129 133 if source is not None:
130 134 cell.source = unicode(source)
131 135 if rendered is not None:
132 136 cell.rendered = unicode(rendered)
133 137 cell.level = int(level)
134 138 return cell
135 139
136 140
137 141 def new_worksheet(name=None, cells=None):
138 142 """Create a worksheet by name with with a list of cells."""
139 143 ws = NotebookNode()
140 144 if name is not None:
141 145 ws.name = unicode(name)
142 146 if cells is None:
143 147 ws.cells = []
144 148 else:
145 149 ws.cells = list(cells)
146 150 return ws
147 151
148 152
149 153 def new_notebook(name=None, metadata=None, worksheets=None):
150 154 """Create a notebook by name, id and a list of worksheets."""
151 155 nb = NotebookNode()
152 156 nb.nbformat = nbformat
153 157 if worksheets is None:
154 158 nb.worksheets = []
155 159 else:
156 160 nb.worksheets = list(worksheets)
157 161 if metadata is None:
158 162 nb.metadata = new_metadata()
159 163 else:
160 164 nb.metadata = NotebookNode(metadata)
161 165 if name is not None:
162 166 nb.metadata.name = unicode(name)
163 167 return nb
164 168
165 169
166 170 def new_metadata(name=None, authors=None, license=None, created=None,
167 171 modified=None, gistid=None):
168 172 """Create a new metadata node."""
169 173 metadata = NotebookNode()
170 174 if name is not None:
171 175 metadata.name = unicode(name)
172 176 if authors is not None:
173 177 metadata.authors = list(authors)
174 178 if created is not None:
175 179 metadata.created = unicode(created)
176 180 if modified is not None:
177 181 metadata.modified = unicode(modified)
178 182 if license is not None:
179 183 metadata.license = unicode(license)
180 184 if gistid is not None:
181 185 metadata.gistid = unicode(gistid)
182 186 return metadata
183 187
184 188 def new_author(name=None, email=None, affiliation=None, url=None):
185 189 """Create a new author."""
186 190 author = NotebookNode()
187 191 if name is not None:
188 192 author.name = unicode(name)
189 193 if email is not None:
190 194 author.email = unicode(email)
191 195 if affiliation is not None:
192 196 author.affiliation = unicode(affiliation)
193 197 if url is not None:
194 198 author.url = unicode(url)
195 199 return author
196 200
@@ -1,200 +1,201
1 1 """Read and write notebooks as regular .py files.
2 2
3 3 Authors:
4 4
5 5 * Brian Granger
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import re
20 20 from .rwbase import NotebookReader, NotebookWriter
21 21 from .nbbase import (
22 22 new_code_cell, new_text_cell, new_worksheet,
23 23 new_notebook, new_heading_cell, nbformat
24 24 )
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Code
28 28 #-----------------------------------------------------------------------------
29 29
30 30 _encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)")
31 31
32 32 class PyReaderError(Exception):
33 33 pass
34 34
35 35
36 36 class PyReader(NotebookReader):
37 37
38 38 def reads(self, s, **kwargs):
39 39 return self.to_notebook(s,**kwargs)
40 40
41 41 def to_notebook(self, s, **kwargs):
42 42 lines = s.splitlines()
43 43 cells = []
44 44 cell_lines = []
45 45 kwargs = {}
46 46 state = u'codecell'
47 47 for line in lines:
48 48 if line.startswith(u'# <nbformat>') or _encoding_declaration_re.match(line):
49 49 pass
50 50 elif line.startswith(u'# <codecell>'):
51 51 cell = self.new_cell(state, cell_lines, **kwargs)
52 52 if cell is not None:
53 53 cells.append(cell)
54 54 state = u'codecell'
55 55 cell_lines = []
56 56 kwargs = {}
57 57 elif line.startswith(u'# <htmlcell>'):
58 58 cell = self.new_cell(state, cell_lines, **kwargs)
59 59 if cell is not None:
60 60 cells.append(cell)
61 61 state = u'htmlcell'
62 62 cell_lines = []
63 63 kwargs = {}
64 64 elif line.startswith(u'# <markdowncell>'):
65 65 cell = self.new_cell(state, cell_lines, **kwargs)
66 66 if cell is not None:
67 67 cells.append(cell)
68 68 state = u'markdowncell'
69 69 cell_lines = []
70 70 kwargs = {}
71 elif line.startswith(u'# <plaintextcell>'):
71 # VERSIONHACK: plaintext -> raw
72 elif line.startswith(u'# <rawcell>') or line.startswith(u'# <plaintextcell>'):
72 73 cell = self.new_cell(state, cell_lines, **kwargs)
73 74 if cell is not None:
74 75 cells.append(cell)
75 state = u'plaintextcell'
76 state = u'rawcell'
76 77 cell_lines = []
77 78 kwargs = {}
78 79 elif line.startswith(u'# <headingcell'):
79 80 cell = self.new_cell(state, cell_lines, **kwargs)
80 81 if cell is not None:
81 82 cells.append(cell)
82 83 cell_lines = []
83 84 m = re.match(r'# <headingcell level=(?P<level>\d)>',line)
84 85 if m is not None:
85 86 state = u'headingcell'
86 87 kwargs = {}
87 88 kwargs['level'] = int(m.group('level'))
88 89 else:
89 90 state = u'codecell'
90 91 kwargs = {}
91 92 cell_lines = []
92 93 else:
93 94 cell_lines.append(line)
94 95 if cell_lines and state == u'codecell':
95 96 cell = self.new_cell(state, cell_lines)
96 97 if cell is not None:
97 98 cells.append(cell)
98 99 ws = new_worksheet(cells=cells)
99 100 nb = new_notebook(worksheets=[ws])
100 101 return nb
101 102
102 103 def new_cell(self, state, lines, **kwargs):
103 104 if state == u'codecell':
104 105 input = u'\n'.join(lines)
105 106 input = input.strip(u'\n')
106 107 if input:
107 108 return new_code_cell(input=input)
108 109 elif state == u'htmlcell':
109 110 text = self._remove_comments(lines)
110 111 if text:
111 112 return new_text_cell(u'html',source=text)
112 113 elif state == u'markdowncell':
113 114 text = self._remove_comments(lines)
114 115 if text:
115 116 return new_text_cell(u'markdown',source=text)
116 elif state == u'plaintextcell':
117 elif state == u'rawcell':
117 118 text = self._remove_comments(lines)
118 119 if text:
119 return new_text_cell(u'plaintext',source=text)
120 return new_text_cell(u'raw',source=text)
120 121 elif state == u'headingcell':
121 122 text = self._remove_comments(lines)
122 123 level = kwargs.get('level',1)
123 124 if text:
124 125 return new_heading_cell(source=text,level=level)
125 126
126 127 def _remove_comments(self, lines):
127 128 new_lines = []
128 129 for line in lines:
129 130 if line.startswith(u'#'):
130 131 new_lines.append(line[2:])
131 132 else:
132 133 new_lines.append(line)
133 134 text = u'\n'.join(new_lines)
134 135 text = text.strip(u'\n')
135 136 return text
136 137
137 138 def split_lines_into_blocks(self, lines):
138 139 if len(lines) == 1:
139 140 yield lines[0]
140 141 raise StopIteration()
141 142 import ast
142 143 source = '\n'.join(lines)
143 144 code = ast.parse(source)
144 145 starts = [x.lineno-1 for x in code.body]
145 146 for i in range(len(starts)-1):
146 147 yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n')
147 148 yield '\n'.join(lines[starts[-1]:]).strip('\n')
148 149
149 150
150 151 class PyWriter(NotebookWriter):
151 152
152 153 def writes(self, nb, **kwargs):
153 154 lines = [u'# -*- coding: utf-8 -*-']
154 155 lines.extend([u'# <nbformat>%i</nbformat>' % nbformat,''])
155 156 for ws in nb.worksheets:
156 157 for cell in ws.cells:
157 158 if cell.cell_type == u'code':
158 159 input = cell.get(u'input')
159 160 if input is not None:
160 161 lines.extend([u'# <codecell>',u''])
161 162 lines.extend(input.splitlines())
162 163 lines.append(u'')
163 164 elif cell.cell_type == u'html':
164 165 input = cell.get(u'source')
165 166 if input is not None:
166 167 lines.extend([u'# <htmlcell>',u''])
167 168 lines.extend([u'# ' + line for line in input.splitlines()])
168 169 lines.append(u'')
169 170 elif cell.cell_type == u'markdown':
170 171 input = cell.get(u'source')
171 172 if input is not None:
172 173 lines.extend([u'# <markdowncell>',u''])
173 174 lines.extend([u'# ' + line for line in input.splitlines()])
174 175 lines.append(u'')
175 elif cell.cell_type == u'plaintext':
176 elif cell.cell_type == u'raw':
176 177 input = cell.get(u'source')
177 178 if input is not None:
178 lines.extend([u'# <plaintextcell>',u''])
179 lines.extend([u'# <rawcell>',u''])
179 180 lines.extend([u'# ' + line for line in input.splitlines()])
180 181 lines.append(u'')
181 182 elif cell.cell_type == u'heading':
182 183 input = cell.get(u'source')
183 184 level = cell.get(u'level',1)
184 185 if input is not None:
185 186 lines.extend([u'# <headingcell level=%s>' % level,u''])
186 187 lines.extend([u'# ' + line for line in input.splitlines()])
187 188 lines.append(u'')
188 189 lines.append('')
189 190 return unicode('\n'.join(lines))
190 191
191 192
192 193 _reader = PyReader()
193 194 _writer = PyWriter()
194 195
195 196 reads = _reader.reads
196 197 read = _reader.read
197 198 to_notebook = _reader.to_notebook
198 199 write = _writer.write
199 200 writes = _writer.writes
200 201
@@ -1,147 +1,147
1 1 # -*- coding: utf-8 -*-
2 2
3 3 import os
4 4 from base64 import encodestring
5 5
6 6 from ..nbbase import (
7 7 NotebookNode,
8 8 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
9 9 new_metadata, new_author, new_heading_cell, nbformat
10 10 )
11 11
12 12 # some random base64-encoded *bytes*
13 13 png = encodestring(os.urandom(5))
14 14 jpeg = encodestring(os.urandom(6))
15 15
16 16 ws = new_worksheet(name='worksheet1')
17 17
18 18 ws.cells.append(new_text_cell(
19 19 u'html',
20 20 source='Some NumPy Examples',
21 21 rendered='Some NumPy Examples'
22 22 ))
23 23
24 24
25 25 ws.cells.append(new_code_cell(
26 26 input='import numpy',
27 27 prompt_number=1,
28 28 collapsed=False
29 29 ))
30 30
31 31 ws.cells.append(new_text_cell(
32 32 u'markdown',
33 33 source='A random array',
34 34 rendered='A random array'
35 35 ))
36 36
37 37 ws.cells.append(new_text_cell(
38 u'plaintext',
38 u'raw',
39 39 source='A random array',
40 40 ))
41 41
42 42 ws.cells.append(new_heading_cell(
43 43 u'My Heading',
44 44 level=2
45 45 ))
46 46
47 47 ws.cells.append(new_code_cell(
48 48 input='a = numpy.random.rand(100)',
49 49 prompt_number=2,
50 50 collapsed=True
51 51 ))
52 52 ws.cells.append(new_code_cell(
53 53 input='a = 10\nb = 5\n',
54 54 prompt_number=3,
55 55 ))
56 56 ws.cells.append(new_code_cell(
57 57 input='a = 10\nb = 5',
58 58 prompt_number=4,
59 59 ))
60 60
61 61 ws.cells.append(new_code_cell(
62 62 input=u'print "ünîcødé"',
63 63 prompt_number=3,
64 64 collapsed=False,
65 65 outputs=[new_output(
66 66 output_type=u'pyout',
67 67 output_text=u'<array a>',
68 68 output_html=u'The HTML rep',
69 69 output_latex=u'$a$',
70 70 output_png=png,
71 71 output_jpeg=jpeg,
72 72 output_svg=u'<svg>',
73 73 output_json=u'json data',
74 74 output_javascript=u'var i=0;',
75 75 prompt_number=3
76 76 ),new_output(
77 77 output_type=u'display_data',
78 78 output_text=u'<array a>',
79 79 output_html=u'The HTML rep',
80 80 output_latex=u'$a$',
81 81 output_png=png,
82 82 output_jpeg=jpeg,
83 83 output_svg=u'<svg>',
84 84 output_json=u'json data',
85 85 output_javascript=u'var i=0;'
86 86 ),new_output(
87 87 output_type=u'pyerr',
88 88 etype=u'NameError',
89 89 evalue=u'NameError was here',
90 90 traceback=[u'frame 0', u'frame 1', u'frame 2']
91 91 )]
92 92 ))
93 93
94 94 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com',
95 95 affiliation=u'Fox',url=u'http://www.fox.com')]
96 96 md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here',
97 97 modified=u'8601_goes_here',gistid=u'21341231',authors=authors)
98 98
99 99 nb0 = new_notebook(
100 100 worksheets=[ws, new_worksheet(name='worksheet2')],
101 101 metadata=md
102 102 )
103 103
104 104 nb0_py = u"""# -*- coding: utf-8 -*-
105 105 # <nbformat>%i</nbformat>
106 106
107 107 # <htmlcell>
108 108
109 109 # Some NumPy Examples
110 110
111 111 # <codecell>
112 112
113 113 import numpy
114 114
115 115 # <markdowncell>
116 116
117 117 # A random array
118 118
119 # <plaintextcell>
119 # <rawcell>
120 120
121 121 # A random array
122 122
123 123 # <headingcell level=2>
124 124
125 125 # My Heading
126 126
127 127 # <codecell>
128 128
129 129 a = numpy.random.rand(100)
130 130
131 131 # <codecell>
132 132
133 133 a = 10
134 134 b = 5
135 135
136 136 # <codecell>
137 137
138 138 a = 10
139 139 b = 5
140 140
141 141 # <codecell>
142 142
143 143 print "ünîcødé"
144 144
145 145 """ % nbformat
146 146
147 147
@@ -1,143 +1,143
1 1 from unittest import TestCase
2 2
3 3 from ..nbbase import (
4 4 NotebookNode,
5 5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
6 6 new_author, new_metadata, new_heading_cell, nbformat
7 7 )
8 8
9 9 class TestCell(TestCase):
10 10
11 11 def test_empty_code_cell(self):
12 12 cc = new_code_cell()
13 13 self.assertEquals(cc.cell_type,u'code')
14 14 self.assertEquals(u'input' not in cc, True)
15 15 self.assertEquals(u'prompt_number' not in cc, True)
16 16 self.assertEquals(cc.outputs, [])
17 17 self.assertEquals(cc.collapsed, False)
18 18
19 19 def test_code_cell(self):
20 20 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
21 21 cc.outputs = [new_output(output_type=u'pyout',
22 22 output_svg=u'foo',output_text=u'10',prompt_number=0)]
23 23 self.assertEquals(cc.input, u'a=10')
24 24 self.assertEquals(cc.prompt_number, 0)
25 25 self.assertEquals(cc.language, u'python')
26 26 self.assertEquals(cc.outputs[0].svg, u'foo')
27 27 self.assertEquals(cc.outputs[0].text, u'10')
28 28 self.assertEquals(cc.outputs[0].prompt_number, 0)
29 29 self.assertEquals(cc.collapsed, True)
30 30
31 31 def test_pyerr(self):
32 32 o = new_output(output_type=u'pyerr', etype=u'NameError',
33 33 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
34 34 )
35 35 self.assertEquals(o.output_type, u'pyerr')
36 36 self.assertEquals(o.etype, u'NameError')
37 37 self.assertEquals(o.evalue, u'Name not found')
38 38 self.assertEquals(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
39 39
40 40 def test_empty_html_cell(self):
41 41 tc = new_text_cell(u'html')
42 42 self.assertEquals(tc.cell_type, u'html')
43 43 self.assertEquals(u'source' not in tc, True)
44 44 self.assertEquals(u'rendered' not in tc, True)
45 45
46 46 def test_html_cell(self):
47 47 tc = new_text_cell(u'html', 'hi', 'hi')
48 48 self.assertEquals(tc.source, u'hi')
49 49 self.assertEquals(tc.rendered, u'hi')
50 50
51 51 def test_empty_markdown_cell(self):
52 52 tc = new_text_cell(u'markdown')
53 53 self.assertEquals(tc.cell_type, u'markdown')
54 54 self.assertEquals(u'source' not in tc, True)
55 55 self.assertEquals(u'rendered' not in tc, True)
56 56
57 57 def test_markdown_cell(self):
58 58 tc = new_text_cell(u'markdown', 'hi', 'hi')
59 59 self.assertEquals(tc.source, u'hi')
60 60 self.assertEquals(tc.rendered, u'hi')
61 61
62 def test_empty_plaintext_cell(self):
63 tc = new_text_cell(u'plaintext')
64 self.assertEquals(tc.cell_type, u'plaintext')
62 def test_empty_raw_cell(self):
63 tc = new_text_cell(u'raw')
64 self.assertEquals(tc.cell_type, u'raw')
65 65 self.assertEquals(u'source' not in tc, True)
66 66 self.assertEquals(u'rendered' not in tc, True)
67 67
68 def test_plaintext_cell(self):
69 tc = new_text_cell(u'plaintext', 'hi', 'hi')
68 def test_raw_cell(self):
69 tc = new_text_cell(u'raw', 'hi', 'hi')
70 70 self.assertEquals(tc.source, u'hi')
71 71 self.assertEquals(tc.rendered, u'hi')
72 72
73 73 def test_empty_heading_cell(self):
74 74 tc = new_heading_cell()
75 75 self.assertEquals(tc.cell_type, u'heading')
76 76 self.assertEquals(u'source' not in tc, True)
77 77 self.assertEquals(u'rendered' not in tc, True)
78 78
79 79 def test_heading_cell(self):
80 80 tc = new_heading_cell(u'hi', u'hi', level=2)
81 81 self.assertEquals(tc.source, u'hi')
82 82 self.assertEquals(tc.rendered, u'hi')
83 83 self.assertEquals(tc.level, 2)
84 84
85 85
86 86 class TestWorksheet(TestCase):
87 87
88 88 def test_empty_worksheet(self):
89 89 ws = new_worksheet()
90 90 self.assertEquals(ws.cells,[])
91 91 self.assertEquals(u'name' not in ws, True)
92 92
93 93 def test_worksheet(self):
94 94 cells = [new_code_cell(), new_text_cell(u'html')]
95 95 ws = new_worksheet(cells=cells,name=u'foo')
96 96 self.assertEquals(ws.cells,cells)
97 97 self.assertEquals(ws.name,u'foo')
98 98
99 99 class TestNotebook(TestCase):
100 100
101 101 def test_empty_notebook(self):
102 102 nb = new_notebook()
103 103 self.assertEquals(nb.worksheets, [])
104 104 self.assertEquals(nb.metadata, NotebookNode())
105 105 self.assertEquals(nb.nbformat,nbformat)
106 106
107 107 def test_notebook(self):
108 108 worksheets = [new_worksheet(),new_worksheet()]
109 109 metadata = new_metadata(name=u'foo')
110 110 nb = new_notebook(metadata=metadata,worksheets=worksheets)
111 111 self.assertEquals(nb.metadata.name,u'foo')
112 112 self.assertEquals(nb.worksheets,worksheets)
113 113 self.assertEquals(nb.nbformat,nbformat)
114 114
115 115 def test_notebook_name(self):
116 116 worksheets = [new_worksheet(),new_worksheet()]
117 117 nb = new_notebook(name='foo',worksheets=worksheets)
118 118 self.assertEquals(nb.metadata.name,u'foo')
119 119 self.assertEquals(nb.worksheets,worksheets)
120 120 self.assertEquals(nb.nbformat,nbformat)
121 121
122 122 class TestMetadata(TestCase):
123 123
124 124 def test_empty_metadata(self):
125 125 md = new_metadata()
126 126 self.assertEquals(u'name' not in md, True)
127 127 self.assertEquals(u'authors' not in md, True)
128 128 self.assertEquals(u'license' not in md, True)
129 129 self.assertEquals(u'saved' not in md, True)
130 130 self.assertEquals(u'modified' not in md, True)
131 131 self.assertEquals(u'gistid' not in md, True)
132 132
133 133 def test_metadata(self):
134 134 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')]
135 135 md = new_metadata(name=u'foo',license=u'BSD',created=u'today',
136 136 modified=u'now',gistid=u'21341231',authors=authors)
137 137 self.assertEquals(md.name, u'foo')
138 138 self.assertEquals(md.license, u'BSD')
139 139 self.assertEquals(md.created, u'today')
140 140 self.assertEquals(md.modified, u'now')
141 141 self.assertEquals(md.gistid, u'21341231')
142 142 self.assertEquals(md.authors, authors)
143 143
General Comments 0
You need to be logged in to leave comments. Login now