##// END OF EJS Templates
Refactor static printing.
Stefan van der Walt -
Show More
@@ -0,0 +1,54 b''
1 var IPython = (function (IPython) {
2
3 var PrintWidget = function (selector) {
4 this.selector = selector;
5 if (this.selector !== undefined) {
6 this.element = $(selector);
7 this.style();
8 this.bind_events();
9 }
10 };
11
12 PrintWidget.prototype.style = function () {
13 this.element.find('button#print_notebook').button();
14 };
15
16 PrintWidget.prototype.bind_events = function () {
17 var that = this;
18 this.element.find('button#print_notebook').click(function () {
19 that.print_notebook();
20 });
21 };
22
23 PrintWidget.prototype.enable = function () {
24 this.element.find('button#print_notebook').button('enable');
25 };
26
27 PrintWidget.prototype.disable = function () {
28 this.element.find('button#print_notebook').button('disable');
29 };
30
31 PrintWidget.prototype.print_notebook = function () {
32 var w = window.open('', '_blank', 'scrollbars=1,menubar=1');
33 var html = '<html><head>' +
34 $('head').clone().html() +
35 '<style type="text/css">' +
36 '@media print { body { overflow: visible !important; } }' +
37 '.ui-widget-content { border: 0px; }' +
38 '</style>' +
39 '</head><body style="overflow: auto;">' +
40 $('#notebook').clone().html() +
41 '</body></html>';
42
43 w.document.open();
44 w.document.write(html);
45 w.document.close();
46
47 return false;
48 };
49
50 IPython.PrintWidget = PrintWidget;
51
52 return IPython;
53
54 }(IPython)); No newline at end of file
@@ -1,833 +1,815 b''
1 1
2 2 //============================================================================
3 3 // Notebook
4 4 //============================================================================
5 5
6 6 var IPython = (function (IPython) {
7 7
8 8 var utils = IPython.utils;
9 9
10 10 var Notebook = function (selector) {
11 11 this.element = $(selector);
12 12 this.element.scroll();
13 13 this.element.data("notebook", this);
14 14 this.next_prompt_number = 1;
15 15 this.kernel = null;
16 16 this.dirty = false;
17 17 this.msg_cell_map = {};
18 18 this.style();
19 19 this.create_elements();
20 20 this.bind_events();
21 21 };
22 22
23 23
24 24 Notebook.prototype.style = function () {
25 25 $('div#notebook').addClass('border-box-sizing');
26 26 };
27 27
28 28
29 29 Notebook.prototype.create_elements = function () {
30 30 // We add this end_space div to the end of the notebook div to:
31 31 // i) provide a margin between the last cell and the end of the notebook
32 32 // ii) to prevent the div from scrolling up when the last cell is being
33 33 // edited, but is too low on the page, which browsers will do automatically.
34 34 this.element.append($('<div class="end_space"></div>').height(150));
35 35 $('div#notebook').addClass('border-box-sizing');
36 36 };
37 37
38 38
39 39 Notebook.prototype.bind_events = function () {
40 40 var that = this;
41 41 $(document).keydown(function (event) {
42 42 // console.log(event);
43 43 if (event.which === 38) {
44 44 var cell = that.selected_cell();
45 45 if (cell.at_top()) {
46 46 event.preventDefault();
47 47 that.select_prev();
48 48 };
49 49 } else if (event.which === 40) {
50 50 var cell = that.selected_cell();
51 51 if (cell.at_bottom()) {
52 52 event.preventDefault();
53 53 that.select_next();
54 54 };
55 55 } else if (event.which === 13 && event.shiftKey) {
56 56 that.execute_selected_cell();
57 57 return false;
58 58 } else if (event.which === 13 && event.ctrlKey) {
59 59 that.execute_selected_cell({terminal:true});
60 60 return false;
61 61 };
62 62 });
63 63
64 64 this.element.bind('collapse_pager', function () {
65 65 var app_height = $('div#main_app').height(); // content height
66 66 var splitter_height = $('div#pager_splitter').outerHeight(true);
67 67 var new_height = app_height - splitter_height;
68 68 that.element.animate({height : new_height + 'px'}, 'fast');
69 69 });
70 70
71 71 this.element.bind('expand_pager', function () {
72 72 var app_height = $('div#main_app').height(); // content height
73 73 var splitter_height = $('div#pager_splitter').outerHeight(true);
74 74 var pager_height = $('div#pager').outerHeight(true);
75 75 var new_height = app_height - pager_height - splitter_height;
76 76 that.element.animate({height : new_height + 'px'}, 'fast');
77 77 });
78 78
79 79 this.element.bind('collapse_left_panel', function () {
80 80 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
81 81 var new_margin = splitter_width;
82 82 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
83 83 });
84 84
85 85 this.element.bind('expand_left_panel', function () {
86 86 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
87 87 var left_panel_width = IPython.left_panel.width;
88 88 var new_margin = splitter_width + left_panel_width;
89 89 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
90 90 });
91 91
92 92 $(window).bind('beforeunload', function () {
93 93 var kill_kernel = $('#kill_kernel').prop('checked');
94 94 if (kill_kernel) {
95 95 that.kernel.kill();
96 96 }
97 97 if (that.dirty) {
98 98 return "You have unsaved changes that will be lost if you leave this page.";
99 99 };
100 100 });
101 101 };
102 102
103 103
104 104 Notebook.prototype.scroll_to_bottom = function () {
105 105 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
106 106 };
107 107
108 108
109 109 Notebook.prototype.scroll_to_top = function () {
110 110 this.element.animate({scrollTop:0}, 0);
111 111 };
112 112
113 113
114 114 // Cell indexing, retrieval, etc.
115 115
116 116
117 117 Notebook.prototype.cell_elements = function () {
118 118 return this.element.children("div.cell");
119 119 }
120 120
121 121
122 122 Notebook.prototype.ncells = function (cell) {
123 123 return this.cell_elements().length;
124 124 }
125 125
126 126
127 127 // TODO: we are often calling cells as cells()[i], which we should optimize
128 128 // to cells(i) or a new method.
129 129 Notebook.prototype.cells = function () {
130 130 return this.cell_elements().toArray().map(function (e) {
131 131 return $(e).data("cell");
132 132 });
133 133 }
134 134
135 135
136 136 Notebook.prototype.find_cell_index = function (cell) {
137 137 var result = null;
138 138 this.cell_elements().filter(function (index) {
139 139 if ($(this).data("cell") === cell) {
140 140 result = index;
141 141 };
142 142 });
143 143 return result;
144 144 };
145 145
146 146
147 147 Notebook.prototype.index_or_selected = function (index) {
148 148 return index || this.selected_index() || 0;
149 149 }
150 150
151 151
152 152 Notebook.prototype.select = function (index) {
153 153 if (index !== undefined && index >= 0 && index < this.ncells()) {
154 154 if (this.selected_index() !== null) {
155 155 this.selected_cell().unselect();
156 156 };
157 157 this.cells()[index].select();
158 158 if (index === (this.ncells()-1)) {
159 159 this.scroll_to_bottom();
160 160 };
161 161 };
162 162 return this;
163 163 };
164 164
165 165
166 166 Notebook.prototype.select_next = function () {
167 167 var index = this.selected_index();
168 168 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
169 169 this.select(index+1);
170 170 };
171 171 return this;
172 172 };
173 173
174 174
175 175 Notebook.prototype.select_prev = function () {
176 176 var index = this.selected_index();
177 177 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
178 178 this.select(index-1);
179 179 };
180 180 return this;
181 181 };
182 182
183 183
184 184 Notebook.prototype.selected_index = function () {
185 185 var result = null;
186 186 this.cell_elements().filter(function (index) {
187 187 if ($(this).data("cell").selected === true) {
188 188 result = index;
189 189 };
190 190 });
191 191 return result;
192 192 };
193 193
194 194
195 195 Notebook.prototype.cell_for_msg = function (msg_id) {
196 196 var cell_id = this.msg_cell_map[msg_id];
197 197 var result = null;
198 198 this.cell_elements().filter(function (index) {
199 199 cell = $(this).data("cell");
200 200 if (cell.cell_id === cell_id) {
201 201 result = cell;
202 202 };
203 203 });
204 204 return result;
205 205 };
206 206
207 207
208 208 Notebook.prototype.selected_cell = function () {
209 209 return this.cell_elements().eq(this.selected_index()).data("cell");
210 210 }
211 211
212 212
213 213 // Cell insertion, deletion and moving.
214 214
215 215
216 216 Notebook.prototype.delete_cell = function (index) {
217 217 var i = index || this.selected_index();
218 218 if (i !== null && i >= 0 && i < this.ncells()) {
219 219 this.cell_elements().eq(i).remove();
220 220 if (i === (this.ncells())) {
221 221 this.select(i-1);
222 222 } else {
223 223 this.select(i);
224 224 };
225 225 };
226 226 this.dirty = true;
227 227 return this;
228 228 };
229 229
230 230
231 231 Notebook.prototype.append_cell = function (cell) {
232 232 this.element.find('div.end_space').before(cell.element);
233 233 this.dirty = true;
234 234 return this;
235 235 };
236 236
237 237
238 238 Notebook.prototype.insert_cell_after = function (cell, index) {
239 239 var ncells = this.ncells();
240 240 if (ncells === 0) {
241 241 this.append_cell(cell);
242 242 return this;
243 243 };
244 244 if (index >= 0 && index < ncells) {
245 245 this.cell_elements().eq(index).after(cell.element);
246 246 };
247 247 this.dirty = true;
248 248 return this
249 249 };
250 250
251 251
252 252 Notebook.prototype.insert_cell_before = function (cell, index) {
253 253 var ncells = this.ncells();
254 254 if (ncells === 0) {
255 255 this.append_cell(cell);
256 256 return this;
257 257 };
258 258 if (index >= 0 && index < ncells) {
259 259 this.cell_elements().eq(index).before(cell.element);
260 260 };
261 261 this.dirty = true;
262 262 return this;
263 263 };
264 264
265 265
266 266 Notebook.prototype.move_cell_up = function (index) {
267 267 var i = index || this.selected_index();
268 268 if (i !== null && i < this.ncells() && i > 0) {
269 269 var pivot = this.cell_elements().eq(i-1);
270 270 var tomove = this.cell_elements().eq(i);
271 271 if (pivot !== null && tomove !== null) {
272 272 tomove.detach();
273 273 pivot.before(tomove);
274 274 this.select(i-1);
275 275 };
276 276 };
277 277 this.dirty = true;
278 278 return this;
279 279 }
280 280
281 281
282 282 Notebook.prototype.move_cell_down = function (index) {
283 283 var i = index || this.selected_index();
284 284 if (i !== null && i < (this.ncells()-1) && i >= 0) {
285 285 var pivot = this.cell_elements().eq(i+1)
286 286 var tomove = this.cell_elements().eq(i)
287 287 if (pivot !== null && tomove !== null) {
288 288 tomove.detach();
289 289 pivot.after(tomove);
290 290 this.select(i+1);
291 291 };
292 292 };
293 293 this.dirty = true;
294 294 return this;
295 295 }
296 296
297 297
298 298 Notebook.prototype.sort_cells = function () {
299 299 var ncells = this.ncells();
300 300 var sindex = this.selected_index();
301 301 var swapped;
302 302 do {
303 303 swapped = false
304 304 for (var i=1; i<ncells; i++) {
305 305 current = this.cell_elements().eq(i).data("cell");
306 306 previous = this.cell_elements().eq(i-1).data("cell");
307 307 if (previous.input_prompt_number > current.input_prompt_number) {
308 308 this.move_cell_up(i);
309 309 swapped = true;
310 310 };
311 311 };
312 312 } while (swapped);
313 313 this.select(sindex);
314 314 return this;
315 315 };
316 316
317 317
318 318 Notebook.prototype.insert_code_cell_before = function (index) {
319 319 // TODO: Bounds check for i
320 320 var i = this.index_or_selected(index);
321 321 var cell = new IPython.CodeCell(this);
322 322 cell.set_input_prompt();
323 323 this.insert_cell_before(cell, i);
324 324 this.select(this.find_cell_index(cell));
325 325 return cell;
326 326 }
327 327
328 328
329 329 Notebook.prototype.insert_code_cell_after = function (index) {
330 330 // TODO: Bounds check for i
331 331 var i = this.index_or_selected(index);
332 332 var cell = new IPython.CodeCell(this);
333 333 cell.set_input_prompt();
334 334 this.insert_cell_after(cell, i);
335 335 this.select(this.find_cell_index(cell));
336 336 return cell;
337 337 }
338 338
339 339
340 340 Notebook.prototype.insert_html_cell_before = function (index) {
341 341 // TODO: Bounds check for i
342 342 var i = this.index_or_selected(index);
343 343 var cell = new IPython.HTMLCell(this);
344 344 cell.config_mathjax();
345 345 this.insert_cell_before(cell, i);
346 346 this.select(this.find_cell_index(cell));
347 347 return cell;
348 348 }
349 349
350 350
351 351 Notebook.prototype.insert_html_cell_after = function (index) {
352 352 // TODO: Bounds check for i
353 353 var i = this.index_or_selected(index);
354 354 var cell = new IPython.HTMLCell(this);
355 355 cell.config_mathjax();
356 356 this.insert_cell_after(cell, i);
357 357 this.select(this.find_cell_index(cell));
358 358 return cell;
359 359 }
360 360
361 361
362 362 Notebook.prototype.insert_markdown_cell_before = function (index) {
363 363 // TODO: Bounds check for i
364 364 var i = this.index_or_selected(index);
365 365 var cell = new IPython.MarkdownCell(this);
366 366 cell.config_mathjax();
367 367 this.insert_cell_before(cell, i);
368 368 this.select(this.find_cell_index(cell));
369 369 return cell;
370 370 }
371 371
372 372
373 373 Notebook.prototype.insert_markdown_cell_after = function (index) {
374 374 // TODO: Bounds check for i
375 375 var i = this.index_or_selected(index);
376 376 var cell = new IPython.MarkdownCell(this);
377 377 cell.config_mathjax();
378 378 this.insert_cell_after(cell, i);
379 379 this.select(this.find_cell_index(cell));
380 380 return cell;
381 381 }
382 382
383 383
384 384 Notebook.prototype.to_code = function (index) {
385 385 // TODO: Bounds check for i
386 386 var i = this.index_or_selected(index);
387 387 var source_element = this.cell_elements().eq(i);
388 388 var source_cell = source_element.data("cell");
389 389 if (source_cell instanceof IPython.HTMLCell ||
390 390 source_cell instanceof IPython.MarkdownCell) {
391 391 this.insert_code_cell_after(i);
392 392 var target_cell = this.cells()[i+1];
393 393 target_cell.set_code(source_cell.get_source());
394 394 source_element.remove();
395 395 target_cell.select();
396 396 };
397 397 this.dirty = true;
398 398 };
399 399
400 400
401 401 Notebook.prototype.to_markdown = function (index) {
402 402 // TODO: Bounds check for i
403 403 var i = this.index_or_selected(index);
404 404 var source_element = this.cell_elements().eq(i);
405 405 var source_cell = source_element.data("cell");
406 406 var target_cell = null;
407 407 if (source_cell instanceof IPython.CodeCell) {
408 408 this.insert_markdown_cell_after(i);
409 409 var target_cell = this.cells()[i+1];
410 410 var text = source_cell.get_code();
411 411 } else if (source_cell instanceof IPython.HTMLCell) {
412 412 this.insert_markdown_cell_after(i);
413 413 var target_cell = this.cells()[i+1];
414 414 var text = source_cell.get_source();
415 415 if (text === source_cell.placeholder) {
416 416 text = target_cell.placeholder;
417 417 }
418 418 }
419 419 if (target_cell !== null) {
420 420 if (text === "") {text = target_cell.placeholder;};
421 421 target_cell.set_source(text);
422 422 source_element.remove();
423 423 target_cell.edit();
424 424 }
425 425 this.dirty = true;
426 426 };
427 427
428 428
429 429 Notebook.prototype.to_html = function (index) {
430 430 // TODO: Bounds check for i
431 431 var i = this.index_or_selected(index);
432 432 var source_element = this.cell_elements().eq(i);
433 433 var source_cell = source_element.data("cell");
434 434 var target_cell = null;
435 435 if (source_cell instanceof IPython.CodeCell) {
436 436 this.insert_html_cell_after(i);
437 437 var target_cell = this.cells()[i+1];
438 438 var text = source_cell.get_code();
439 439 } else if (source_cell instanceof IPython.MarkdownCell) {
440 440 this.insert_html_cell_after(i);
441 441 var target_cell = this.cells()[i+1];
442 442 var text = source_cell.get_source();
443 443 if (text === source_cell.placeholder) {
444 444 text = target_cell.placeholder;
445 445 }
446 446 }
447 447 if (target_cell !== null) {
448 448 if (text === "") {text = target_cell.placeholder;};
449 449 target_cell.set_source(text);
450 450 source_element.remove();
451 451 target_cell.edit();
452 452 }
453 453 this.dirty = true;
454 454 };
455 455
456 456
457 457 // Cell collapsing and output clearing
458 458
459 459 Notebook.prototype.collapse = function (index) {
460 460 var i = this.index_or_selected(index);
461 461 this.cells()[i].collapse();
462 462 this.dirty = true;
463 463 };
464 464
465 465
466 466 Notebook.prototype.expand = function (index) {
467 467 var i = this.index_or_selected(index);
468 468 this.cells()[i].expand();
469 469 this.dirty = true;
470 470 };
471 471
472 472
473 473 Notebook.prototype.set_autoindent = function (state) {
474 474 var cells = this.cells();
475 475 len = cells.length;
476 476 for (var i=0; i<len; i++) {
477 477 cells[i].set_autoindent(state)
478 478 };
479 479 };
480 480
481 481
482 482 Notebook.prototype.clear_all_output = function () {
483 483 var ncells = this.ncells();
484 484 var cells = this.cells();
485 485 for (var i=0; i<ncells; i++) {
486 486 if (cells[i] instanceof IPython.CodeCell) {
487 487 cells[i].clear_output();
488 488 }
489 489 };
490 490 this.dirty = true;
491 491 };
492 492
493 493
494 494 // Kernel related things
495 495
496 496 Notebook.prototype.start_kernel = function () {
497 497 this.kernel = new IPython.Kernel();
498 498 var notebook_id = IPython.save_widget.get_notebook_id();
499 499 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
500 500 };
501 501
502 502
503 503 Notebook.prototype.restart_kernel = function () {
504 504 var notebook_id = IPython.save_widget.get_notebook_id();
505 505 this.kernel.restart($.proxy(this.kernel_started, this));
506 506 };
507 507
508 508
509 509 Notebook.prototype.kernel_started = function () {
510 510 console.log("Kernel started: ", this.kernel.kernel_id);
511 511 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
512 512 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
513 513 };
514 514
515 515
516 516 Notebook.prototype.handle_shell_reply = function (e) {
517 517 reply = $.parseJSON(e.data);
518 518 var header = reply.header;
519 519 var content = reply.content;
520 520 var msg_type = header.msg_type;
521 521 // console.log(reply);
522 522 var cell = this.cell_for_msg(reply.parent_header.msg_id);
523 523 if (msg_type === "execute_reply") {
524 524 cell.set_input_prompt(content.execution_count);
525 525 this.dirty = true;
526 526 } else if (msg_type === "complete_reply") {
527 527 cell.finish_completing(content.matched_text, content.matches);
528 528 };
529 529 var payload = content.payload || [];
530 530 this.handle_payload(cell, payload);
531 531 };
532 532
533 533
534 534 Notebook.prototype.handle_payload = function (cell, payload) {
535 535 var l = payload.length;
536 536 for (var i=0; i<l; i++) {
537 537 if (payload[i].source === 'IPython.zmq.page.page') {
538 538 if (payload[i].text.trim() !== '') {
539 539 IPython.pager.clear();
540 540 IPython.pager.expand();
541 541 IPython.pager.append_text(payload[i].text);
542 542 }
543 543 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
544 544 var index = this.find_cell_index(cell);
545 545 var new_cell = this.insert_code_cell_after(index);
546 546 new_cell.set_code(payload[i].text);
547 547 this.dirty = true;
548 548 }
549 549 };
550 550 };
551 551
552 552
553 553 Notebook.prototype.handle_iopub_reply = function (e) {
554 554 reply = $.parseJSON(e.data);
555 555 var content = reply.content;
556 556 // console.log(reply);
557 557 var msg_type = reply.header.msg_type;
558 558 var cell = this.cell_for_msg(reply.parent_header.msg_id);
559 559 var output_types = ['stream','display_data','pyout','pyerr'];
560 560 if (output_types.indexOf(msg_type) >= 0) {
561 561 this.handle_output(cell, msg_type, content);
562 562 } else if (msg_type === 'status') {
563 563 if (content.execution_state === 'busy') {
564 564 IPython.kernel_status_widget.status_busy();
565 565 } else if (content.execution_state === 'idle') {
566 566 IPython.kernel_status_widget.status_idle();
567 567 } else if (content.execution_state === 'dead') {
568 568 this.handle_status_dead();
569 569 };
570 570 }
571 571 };
572 572
573 573
574 574 Notebook.prototype.handle_status_dead = function () {
575 575 var that = this;
576 576 this.kernel.stop_channels();
577 577 var dialog = $('<div/>');
578 578 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.');
579 579 $(document).append(dialog);
580 580 dialog.dialog({
581 581 resizable: false,
582 582 modal: true,
583 583 title: "Dead kernel",
584 584 buttons : {
585 585 "Yes": function () {
586 586 that.start_kernel();
587 587 $(this).dialog('close');
588 588 },
589 589 "No": function () {
590 590 $(this).dialog('close');
591 591 }
592 592 }
593 593 });
594 594 };
595 595
596 596
597 597 Notebook.prototype.handle_output = function (cell, msg_type, content) {
598 598 var json = {};
599 599 json.output_type = msg_type;
600 600 if (msg_type === "stream") {
601 601 json.text = utils.fixConsole(content.data + '\n');
602 602 } else if (msg_type === "display_data") {
603 603 json = this.convert_mime_types(json, content.data);
604 604 } else if (msg_type === "pyout") {
605 605 json.prompt_number = content.execution_count;
606 606 json = this.convert_mime_types(json, content.data);
607 607 } else if (msg_type === "pyerr") {
608 608 json.ename = content.ename;
609 609 json.evalue = content.evalue;
610 610 var traceback = [];
611 611 for (var i=0; i<content.traceback.length; i++) {
612 612 traceback.push(utils.fixConsole(content.traceback[i]));
613 613 }
614 614 json.traceback = traceback;
615 615 };
616 616 cell.append_output(json);
617 617 this.dirty = true;
618 618 };
619 619
620 620
621 621 Notebook.prototype.convert_mime_types = function (json, data) {
622 622 if (data['text/plain'] !== undefined) {
623 623 json.text = utils.fixConsole(data['text/plain']);
624 624 };
625 625 if (data['text/html'] !== undefined) {
626 626 json.html = data['text/html'];
627 627 };
628 628 if (data['image/svg+xml'] !== undefined) {
629 629 json.svg = data['image/svg+xml'];
630 630 };
631 631 if (data['image/png'] !== undefined) {
632 632 json.png = data['image/png'];
633 633 };
634 634 if (data['image/jpeg'] !== undefined) {
635 635 json.jpeg = data['image/jpeg'];
636 636 };
637 637 if (data['text/latex'] !== undefined) {
638 638 json.latex = data['text/latex'];
639 639 };
640 640 if (data['application/json'] !== undefined) {
641 641 json.json = data['application/json'];
642 642 };
643 643 if (data['application/javascript'] !== undefined) {
644 644 json.javascript = data['application/javascript'];
645 645 }
646 646 return json;
647 647 };
648 648
649 649
650 650 Notebook.prototype.execute_selected_cell = function (options) {
651 651 // add_new: should a new cell be added if we are at the end of the nb
652 652 // terminal: execute in terminal mode, which stays in the current cell
653 653 default_options = {terminal: false, add_new: true}
654 654 $.extend(default_options, options)
655 655 var that = this;
656 656 var cell = that.selected_cell();
657 657 var cell_index = that.find_cell_index(cell);
658 658 if (cell instanceof IPython.CodeCell) {
659 659 cell.clear_output();
660 660 var code = cell.get_code();
661 661 var msg_id = that.kernel.execute(cell.get_code());
662 662 that.msg_cell_map[msg_id] = cell.cell_id;
663 663 } else if (cell instanceof IPython.HTMLCell) {
664 664 cell.render();
665 665 }
666 666 if (default_options.terminal) {
667 667 cell.clear_input();
668 668 } else {
669 669 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
670 670 that.insert_code_cell_after();
671 671 // If we are adding a new cell at the end, scroll down to show it.
672 672 that.scroll_to_bottom();
673 673 } else {
674 674 that.select(cell_index+1);
675 675 };
676 676 };
677 677 this.dirty = true;
678 678 };
679 679
680 680
681 681 Notebook.prototype.execute_all_cells = function () {
682 682 var ncells = this.ncells();
683 683 for (var i=0; i<ncells; i++) {
684 684 this.select(i);
685 685 this.execute_selected_cell({add_new:false});
686 686 };
687 687 this.scroll_to_bottom();
688 688 };
689 689
690 690
691 691 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
692 692 var msg_id = this.kernel.complete(line, cursor_pos);
693 693 this.msg_cell_map[msg_id] = cell.cell_id;
694 694 };
695 695
696 696 // Persistance and loading
697 697
698 698
699 699 Notebook.prototype.fromJSON = function (data) {
700 700 var ncells = this.ncells();
701 701 for (var i=0; i<ncells; i++) {
702 702 // Always delete cell 0 as they get renumbered as they are deleted.
703 703 this.delete_cell(0);
704 704 };
705 705 // Only handle 1 worksheet for now.
706 706 var worksheet = data.worksheets[0];
707 707 if (worksheet !== undefined) {
708 708 var new_cells = worksheet.cells;
709 709 ncells = new_cells.length;
710 710 var cell_data = null;
711 711 var new_cell = null;
712 712 for (var i=0; i<ncells; i++) {
713 713 cell_data = new_cells[i];
714 714 if (cell_data.cell_type == 'code') {
715 715 new_cell = this.insert_code_cell_after();
716 716 new_cell.fromJSON(cell_data);
717 717 } else if (cell_data.cell_type === 'html') {
718 718 new_cell = this.insert_html_cell_after();
719 719 new_cell.fromJSON(cell_data);
720 720 } else if (cell_data.cell_type === 'markdown') {
721 721 new_cell = this.insert_markdown_cell_after();
722 722 new_cell.fromJSON(cell_data);
723 723 };
724 724 };
725 725 };
726 726 };
727 727
728 728
729 729 Notebook.prototype.toJSON = function () {
730 730 var cells = this.cells();
731 731 var ncells = cells.length;
732 732 cell_array = new Array(ncells);
733 733 for (var i=0; i<ncells; i++) {
734 734 cell_array[i] = cells[i].toJSON();
735 735 };
736 736 data = {
737 737 // Only handle 1 worksheet for now.
738 738 worksheets : [{cells:cell_array}]
739 739 }
740 740 return data
741 741 };
742 742
743 743 Notebook.prototype.save_notebook = function () {
744 744 if (IPython.save_widget.test_notebook_name()) {
745 745 var notebook_id = IPython.save_widget.get_notebook_id();
746 746 var nbname = IPython.save_widget.get_notebook_name();
747 747 // We may want to move the name/id/nbformat logic inside toJSON?
748 748 var data = this.toJSON();
749 749 data.name = nbname;
750 750 data.nbformat = 2;
751 751 // We do the call with settings so we can set cache to false.
752 752 var settings = {
753 753 processData : false,
754 754 cache : false,
755 755 type : "PUT",
756 756 data : JSON.stringify(data),
757 757 headers : {'Content-Type': 'application/json'},
758 758 success : $.proxy(this.notebook_saved,this)
759 759 };
760 760 IPython.save_widget.status_saving();
761 761 $.ajax("/notebooks/" + notebook_id, settings);
762 762 };
763 763 };
764 764
765 Notebook.prototype.publish_notebook = function () {
766 var w = window.open('', '_blank', 'scrollbars=1,menubar=1');
767 var html = '<html><head>' +
768 $('head').clone().html() +
769 '<style type="text/css">' +
770 '@media print { body { overflow: visible !important; } }' +
771 '.ui-widget-content { border: 0px; }' +
772 '</style>' +
773 '</head><body style="overflow: auto;">' +
774 $('#notebook').clone().html() +
775 '</body></html>';
776
777 w.document.open();
778 w.document.write(html);
779 w.document.close();
780
781 return false;
782 };
783 765
784 766 Notebook.prototype.notebook_saved = function (data, status, xhr) {
785 767 this.dirty = false;
786 768 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
787 769 }
788 770
789 771
790 772 Notebook.prototype.load_notebook = function (callback) {
791 773 var that = this;
792 774 var notebook_id = IPython.save_widget.get_notebook_id();
793 775 // We do the call with settings so we can set cache to false.
794 776 var settings = {
795 777 processData : false,
796 778 cache : false,
797 779 type : "GET",
798 780 dataType : "json",
799 781 success : function (data, status, xhr) {
800 782 that.notebook_loaded(data, status, xhr);
801 783 if (callback !== undefined) {
802 784 callback();
803 785 };
804 786 }
805 787 };
806 788 IPython.save_widget.status_loading();
807 789 $.ajax("/notebooks/" + notebook_id, settings);
808 790 }
809 791
810 792
811 793 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
812 794 this.fromJSON(data);
813 795 if (this.ncells() === 0) {
814 796 this.insert_code_cell_after();
815 797 };
816 798 IPython.save_widget.status_save();
817 799 IPython.save_widget.set_notebook_name(data.name);
818 800 this.start_kernel();
819 801 this.dirty = false;
820 802 // fromJSON always selects the last cell inserted. We need to wait
821 803 // until that is done before scrolling to the top.
822 804 setTimeout(function () {
823 805 IPython.notebook.select(0);
824 806 IPython.notebook.scroll_to_top();
825 807 }, 50);
826 808 };
827 809
828 810 IPython.Notebook = Notebook;
829 811
830 812 return IPython;
831 813
832 814 }(IPython));
833 815
@@ -1,51 +1,52 b''
1 1
2 2 //============================================================================
3 3 // On document ready
4 4 //============================================================================
5 5
6 6
7 7 $(document).ready(function () {
8 8
9 9 MathJax.Hub.Config({
10 10 tex2jax: {
11 11 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
12 12 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
13 13 },
14 14 displayAlign: 'left', // Change this to 'center' to center equations.
15 15 "HTML-CSS": {
16 16 styles: {'.MathJax_Display': {"margin": 0}}
17 17 }
18 18 });
19 19 IPython.markdown_converter = new Markdown.Converter();
20 20
21 21 $('div#header').addClass('border-box-sizing');
22 22 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
23 23 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
24 24
25 25 IPython.layout_manager = new IPython.LayoutManager();
26 26 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
27 27 IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter');
28 28 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
29 IPython.print_widget = new IPython.PrintWidget('span#print_widget');
29 30 IPython.notebook = new IPython.Notebook('div#notebook');
30 31 IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
31 32 IPython.kernel_status_widget.status_idle();
32 33
33 34 IPython.layout_manager.do_resize();
34 35
35 36 // These have display: none in the css file and are made visible here to prevent FLOUC.
36 37 $('div#header').css('display','block');
37 38 $('div#main_app').css('display','block');
38 39
39 40 // Perform these actions after the notebook has been loaded.
40 41 // We wait 100 milliseconds because the notebook scrolls to the top after a load
41 42 // is completed and we need to wait for that to mostly finish.
42 43 IPython.notebook.load_notebook(function () {
43 44 setTimeout(function () {
44 45 IPython.save_widget.update_url();
45 46 IPython.layout_manager.do_resize();
46 47 IPython.pager.collapse();
47 48 },100);
48 49 });
49 50
50 51 });
51 52
@@ -1,117 +1,112 b''
1 1
2 2 //============================================================================
3 3 // Cell
4 4 //============================================================================
5 5
6 6 var IPython = (function (IPython) {
7 7
8 8 var utils = IPython.utils;
9 9
10 10 var SaveWidget = function (selector) {
11 11 this.selector = selector;
12 12 this.notebook_name_re = /[^/\\]+/
13 13 if (this.selector !== undefined) {
14 14 this.element = $(selector);
15 15 this.style();
16 16 this.bind_events();
17 17 }
18 18 };
19 19
20 20
21 21 SaveWidget.prototype.style = function () {
22 22 this.element.find('input#notebook_name').addClass('ui-widget ui-widget-content');
23 23 this.element.find('button#save_notebook').button();
24 this.element.find('button#publish_notebook').button();
25 24 var left_panel_width = $('div#left_panel').outerWidth();
26 25 var left_panel_splitter_width = $('div#left_panel_splitter').outerWidth();
27 26 $('span#save_widget').css({marginLeft:left_panel_width+left_panel_splitter_width});
28 27 };
29 28
30 29
31 30 SaveWidget.prototype.bind_events = function () {
32 31 var that = this;
33 32 this.element.find('button#save_notebook').click(function () {
34 33 IPython.notebook.save_notebook();
35 34 that.set_document_title();
36 35 });
37
38 this.element.find('button#publish_notebook').click(function () {
39 IPython.notebook.publish_notebook();
40 });
41 36 };
42 37
43 38
44 39 SaveWidget.prototype.get_notebook_name = function () {
45 40 return this.element.find('input#notebook_name').attr('value');
46 41 }
47 42
48 43
49 44 SaveWidget.prototype.set_notebook_name = function (nbname) {
50 45 this.element.find('input#notebook_name').attr('value',nbname);
51 46 this.set_document_title();
52 47 }
53 48
54 49
55 50 SaveWidget.prototype.set_document_title = function () {
56 51 nbname = this.get_notebook_name();
57 52 document.title = 'IPy: ' + nbname;
58 53 };
59 54
60 55
61 56 SaveWidget.prototype.get_notebook_id = function () {
62 57 return this.element.find('span#notebook_id').text()
63 58 };
64 59
65 60
66 61 SaveWidget.prototype.update_url = function () {
67 62 var notebook_id = this.get_notebook_id();
68 63 if (notebook_id !== '') {
69 64 window.history.replaceState({}, '', notebook_id);
70 65 };
71 66 };
72 67
73 68
74 69 SaveWidget.prototype.test_notebook_name = function () {
75 70 var nbname = this.get_notebook_name();
76 71 if (this.notebook_name_re.test(nbname)) {
77 72 return true;
78 73 } else {
79 74 var bad_name = $('<div/>');
80 75 bad_name.html(
81 76 "The notebook name you entered (" +
82 77 nbname +
83 78 ") is not valid. Notebook names can contain any characters except / and \\"
84 79 );
85 80 bad_name.dialog({title: 'Invalid name', modal: true});
86 81 return false;
87 82 };
88 83 };
89 84
90 85
91 86 SaveWidget.prototype.status_save = function () {
92 $('button#save_notebook').button('option', 'label', 'Save');
93 $('button#save_notebook').button('enable');
94 $('button#publish_notebook').button('enable');
87 this.element.find('button#save_notebook').button('option', 'label', 'Save');
88 this.element.find('button#save_notebook').button('enable');
89 IPython.print_widget.enable();
95 90 };
96 91
97 92
98 93 SaveWidget.prototype.status_saving = function () {
99 $('button#save_notebook').button('option', 'label', 'Saving');
100 $('button#save_notebook').button('disable');
101 $('button#publish_notebook').button('disable');
94 this.element.find('button#save_notebook').button('option', 'label', 'Saving');
95 this.element.find('button#save_notebook').button('disable');
96 IPython.print_widget.disable();
102 97 };
103 98
104 99
105 100 SaveWidget.prototype.status_loading = function () {
106 $('button#save_notebook').button('option', 'label', 'Loading');
107 $('button#save_notebook').button('disable');
108 $('button#publish_notebook').button('disable');
101 this.element.find('button#save_notebook').button('option', 'label', 'Loading');
102 this.element.find('button#save_notebook').button('disable');
103 IPython.print_widget.disable();
109 104 };
110 105
111 106
112 107 IPython.SaveWidget = SaveWidget;
113 108
114 109 return IPython;
115 110
116 111 }(IPython));
117 112
@@ -1,225 +1,229 b''
1 1 <!DOCTYPE HTML>
2 2 <html>
3 3
4 4 <head>
5 5 <meta charset="utf-8">
6 6
7 7 <title>IPython Notebook</title>
8 8
9 9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
10 10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
11 11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
12 12
13 13 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script>
14 14 <!-- <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script> -->
15 15 <script type="text/javascript">
16 16 if (typeof MathJax == 'undefined') {
17 17 console.log("Trying to load local copy of MathJax");
18 18 document.write(unescape("%3Cscript type='text/javascript' src='static/mathjax/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
19 19 }
20 20 </script>
21 21
22 22 <link rel="stylesheet" href="static/codemirror-2.12/lib/codemirror.css">
23 23 <link rel="stylesheet" href="static/codemirror-2.12/mode/rst/rst.css">
24 24 <link rel="stylesheet" href="static/codemirror-2.12/theme/ipython.css">
25 25 <link rel="stylesheet" href="static/codemirror-2.12/theme/default.css">
26 26
27 27 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
28 28 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
29 29 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
30 30 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
31 31 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
32 32
33 33
34 34 </head>
35 35
36 36 <body>
37 37
38 38 <div id="header">
39 39 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
40 40 <span id="save_widget">
41 41 <input type="text" id="notebook_name" size="20"></textarea>
42 42 <span id="notebook_id" style="display:none">{{notebook_id}}</span>
43 43 <button id="save_notebook">Save</button>
44 <button id="publish_notebook">Publish</button>
45 44 </span>
46 45 <span id="kernel_status">Idle</span>
47 46 </div>
48 47
49 48 <div id="main_app">
50 49
51 50 <div id="left_panel">
52 51
53 52 <div id="notebook_section">
54 53 <h3 class="section_header">Notebook</h3>
55 54 <div class="section_content">
56 55 <div class="section_row">
57 56 <span id="new_open" class="section_row_buttons">
58 57 <button id="new_notebook">New</button>
59 58 <button id="open_notebook">Open</button>
60 59 </span>
61 60 <span class="section_row_header">Actions</span>
62 61 </div>
63 62 <div class="section_row">
64 63 <span>
65 64 <select id="download_format">
66 65 <option value="xml">xml</option>
67 66 <option value="json">json</option>
68 67 <option value="py">py</option>
69 68 </select>
70 69 </span>
71 70 <span class="section_row_buttons">
71 <span id="print_widget">
72 <button id="print_notebook">Print/HTML</button>
73 </span>
74
72 75 <button id="download_notebook">Export</button>
73 76 </span>
74 77 </div>
75 78 </div>
76 79 </div>
77 80
78 81 <div id="cell_section">
79 82 <h3 class="section_header">Cell</h3>
80 83 <div class="section_content">
81 84 <div class="section_row">
82 85 <span class="section_row_buttons">
83 86 <button id="delete_cell">Delete</button>
84 87 </span>
85 88 <span class="section_row_header">Actions</span>
86 89 </div>
87 90 <div class="section_row">
88 91 <span id="cell_type" class="section_row_buttons">
89 92 <button id="to_code">Code</button>
90 93 <button id="to_html">HTML</button>
91 94 <button id="to_markdown">Markdown</button>
92 95 </span>
93 96 <span class="button_label">Format</span>
94 97 </div>
95 98 <div class="section_row">
96 99 <span id="toggle_output" class="section_row_buttons">
97 100 <button id="collapse_cell">Collapse</button>
98 101 <button id="expand_cell">Expand</button>
99 102 <button id="clear_all_output">ClearAll</button>
100 103 </span>
101 104 <span class="button_label">Output</span>
102 105 </div>
103 106 <div class="section_row">
104 107 <span id="insert" class="section_row_buttons">
105 108 <button id="insert_cell_above">Above</button>
106 109 <button id="insert_cell_below">Below</button>
107 110 </span>
108 111 <span class="button_label">Insert</span>
109 112 </div>
110 113 <div class="section_row">
111 114 <span id="move" class="section_row_buttons">
112 115 <button id="move_cell_up">Up</button>
113 116 <button id="move_cell_down">Down</button>
114 117 </span>
115 118 <span class="button_label">Move</span>
116 119 </div>
117 120 <div class="section_row">
118 121 <span id="run_cells" class="section_row_buttons">
119 122 <button id="run_selected_cell">Selected</button>
120 123 <button id="run_all_cells">All</button>
121 124 </span>
122 125 <span class="button_label">Run</span>
123 126 </div>
124 127 <div class="section_row">
125 128 <span id="autoindent_span">
126 129 <input type="checkbox" id="autoindent" checked="true"></input>
127 130 </span>
128 131 <span class="checkbox_label">Autoindent:</span>
129 132 </div>
130 133 </div>
131 134 </div>
132 135
133 136 <div id="kernel_section">
134 137 <h3 class="section_header">Kernel</h3>
135 138 <div class="section_content">
136 139 <div class="section_row">
137 140 <span id="int_restart" class="section_row_buttons">
138 141 <button id="int_kernel">Interrupt</button>
139 142 <button id="restart_kernel">Restart</button>
140 143 </span>
141 144 <span class="section_row_header">Actions</span>
142 145 </div>
143 146 <div class="section_row">
144 147 <span id="kernel_persist">
145 148 <input type="checkbox" id="kill_kernel"></input>
146 149 </span>
147 150 <span class="checkbox_label">Kill kernel upon exit:</span>
148 151 </div>
149 152 </div>
150 153 </div>
151 154
152 155 <div id="help_section">
153 156 <h3 class="section_header">Help</h3>
154 157 <div class="section_content">
155 158 <div class="section_row">
156 159 <span id="help_buttons0" class="section_row_buttons">
157 160 <button id="python_help"><a href="http://docs.python.org" target="_blank">Python</a></button>
158 161 <button id="ipython_help"><a href="http://ipython.org/documentation.html" target="_blank">IPython</a></button>
159 162 <button id="numpy_help"><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></button>
160 163 </span>
161 164 <span class="section_row_header">Links</span>
162 165 </div>
163 166 <div class="section_row">
164 167 <span id="help_buttons1" class="section_row_buttons">
165 168 <button id="matplotlib_help"><a href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a></button>
166 169 <button id="scipy_help"><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></button>
167 170 <button id="sympy_help"><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></button>
168 171 </span>
169 172 </div>
170 173 <div class="section_row">
171 174 <span class="help_string">run selected cell</span>
172 175 <span class="help_string_label">Shift-Enter |</span>
173 176 </div>
174 177 <div class="section_row">
175 178 <span class="help_string">run in terminal mode</span>
176 179 <span class="help_string_label">Ctrl-Enter |</span>
177 180 </div>
178 181 </div>
179 182 </div>
180 183
181 184 </div>
182 185 <div id="left_panel_splitter"></div>
183 186 <div id="notebook_panel">
184 187 <div id="notebook"></div>
185 188 <div id="pager_splitter"></div>
186 189 <div id="pager"></div>
187 190 </div>
188 191
189 192 </div>
190 193
191 194 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
192 195 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
193 196 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
194 197
195 198 <script src="static/codemirror-2.12/lib/codemirror.js" charset="utf-8"></script>
196 199 <script src="static/codemirror-2.12/mode/python/python.js" charset="utf-8"></script>
197 200 <script src="static/codemirror-2.12/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
198 201 <script src="static/codemirror-2.12/mode/xml/xml.js" charset="utf-8"></script>
199 202 <script src="static/codemirror-2.12/mode/javascript/javascript.js" charset="utf-8"></script>
200 203 <script src="static/codemirror-2.12/mode/css/css.js" charset="utf-8"></script>
201 204 <script src="static/codemirror-2.12/mode/rst/rst.js" charset="utf-8"></script>
202 205
203 206 <script src="static/pagedown/Markdown.Converter.js" charset="utf-8"></script>
204 207
205 208 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
206 209 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
207 210 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
208 211 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
209 212 <script src="static/js/textcell.js" type="text/javascript" charset="utf-8"></script>
210 213 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
211 214 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
212 215 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
213 216 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
214 217 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
215 218 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
219 <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
216 220 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
217 221 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
218 222 <script src="static/js/notebook_main.js" type="text/javascript" charset="utf-8"></script>
219 223
220 224
221 225 </body>
222 226
223 227 </html>
224 228
225 229
General Comments 0
You need to be logged in to leave comments. Login now