##// END OF EJS Templates
Make : invalid in filenames in the Notebook JS code.
Brian Granger -
Show More
@@ -1,1361 +1,1361
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 this.notebook_name_blacklist_re = /[\/\\]/;
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 143 // To Raw = t
144 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 var collapse_time = function(time){
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'}, time);
239 239 }
240 240
241 241 this.element.bind('collapse_pager', function (event,extrap) {
242 242 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
243 243 collapse_time(time);
244 244 });
245 245
246 246 var expand_time = function(time) {
247 247 var app_height = $('div#main_app').height(); // content height
248 248 var splitter_height = $('div#pager_splitter').outerHeight(true);
249 249 var pager_height = $('div#pager').outerHeight(true);
250 250 var new_height = app_height - pager_height - splitter_height;
251 251 that.element.animate({height : new_height + 'px'}, time);
252 252 }
253 253
254 254 this.element.bind('expand_pager', function (event, extrap) {
255 255 time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
256 256 expand_time(time);
257 257 });
258 258
259 259 $(window).bind('beforeunload', function () {
260 260 // TODO: Make killing the kernel configurable.
261 261 var kill_kernel = false;
262 262 if (kill_kernel) {
263 263 that.kernel.kill();
264 264 }
265 265 if (that.dirty && ! that.read_only) {
266 266 return "You have unsaved changes that will be lost if you leave this page.";
267 267 };
268 268 // Null is the *only* return value that will make the browser not
269 269 // pop up the "don't leave" dialog.
270 270 return null;
271 271 });
272 272 };
273 273
274 274
275 275 Notebook.prototype.scroll_to_bottom = function () {
276 276 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
277 277 };
278 278
279 279
280 280 Notebook.prototype.scroll_to_top = function () {
281 281 this.element.animate({scrollTop:0}, 0);
282 282 };
283 283
284 284
285 285 // Cell indexing, retrieval, etc.
286 286
287 287 Notebook.prototype.get_cell_elements = function () {
288 288 return this.element.children("div.cell");
289 289 };
290 290
291 291
292 292 Notebook.prototype.get_cell_element = function (index) {
293 293 var result = null;
294 294 var e = this.get_cell_elements().eq(index);
295 295 if (e.length !== 0) {
296 296 result = e;
297 297 }
298 298 return result;
299 299 };
300 300
301 301
302 302 Notebook.prototype.ncells = function (cell) {
303 303 return this.get_cell_elements().length;
304 304 };
305 305
306 306
307 307 // TODO: we are often calling cells as cells()[i], which we should optimize
308 308 // to cells(i) or a new method.
309 309 Notebook.prototype.get_cells = function () {
310 310 return this.get_cell_elements().toArray().map(function (e) {
311 311 return $(e).data("cell");
312 312 });
313 313 };
314 314
315 315
316 316 Notebook.prototype.get_cell = function (index) {
317 317 var result = null;
318 318 var ce = this.get_cell_element(index);
319 319 if (ce !== null) {
320 320 result = ce.data('cell');
321 321 }
322 322 return result;
323 323 }
324 324
325 325
326 326 Notebook.prototype.get_next_cell = function (cell) {
327 327 var result = null;
328 328 var index = this.find_cell_index(cell);
329 329 if (index !== null && index < this.ncells()) {
330 330 result = this.get_cell(index+1);
331 331 }
332 332 return result;
333 333 }
334 334
335 335
336 336 Notebook.prototype.get_prev_cell = function (cell) {
337 337 var result = null;
338 338 var index = this.find_cell_index(cell);
339 339 if (index !== null && index > 1) {
340 340 result = this.get_cell(index-1);
341 341 }
342 342 return result;
343 343 }
344 344
345 345 Notebook.prototype.find_cell_index = function (cell) {
346 346 var result = null;
347 347 this.get_cell_elements().filter(function (index) {
348 348 if ($(this).data("cell") === cell) {
349 349 result = index;
350 350 };
351 351 });
352 352 return result;
353 353 };
354 354
355 355
356 356 Notebook.prototype.index_or_selected = function (index) {
357 357 var i;
358 358 if (index === undefined || index === null) {
359 359 i = this.get_selected_index();
360 360 if (i === null) {
361 361 i = 0;
362 362 }
363 363 } else {
364 364 i = index;
365 365 }
366 366 return i;
367 367 };
368 368
369 369
370 370 Notebook.prototype.get_selected_cell = function () {
371 371 var index = this.get_selected_index();
372 372 return this.get_cell(index);
373 373 };
374 374
375 375
376 376 Notebook.prototype.is_valid_cell_index = function (index) {
377 377 if (index !== null && index >= 0 && index < this.ncells()) {
378 378 return true;
379 379 } else {
380 380 return false;
381 381 };
382 382 }
383 383
384 384 Notebook.prototype.get_selected_index = function () {
385 385 var result = null;
386 386 this.get_cell_elements().filter(function (index) {
387 387 if ($(this).data("cell").selected === true) {
388 388 result = index;
389 389 };
390 390 });
391 391 return result;
392 392 };
393 393
394 394
395 395 Notebook.prototype.cell_for_msg = function (msg_id) {
396 396 var cell_id = this.msg_cell_map[msg_id];
397 397 var result = null;
398 398 this.get_cell_elements().filter(function (index) {
399 399 cell = $(this).data("cell");
400 400 if (cell.cell_id === cell_id) {
401 401 result = cell;
402 402 };
403 403 });
404 404 return result;
405 405 };
406 406
407 407
408 408 // Cell selection.
409 409
410 410 Notebook.prototype.select = function (index) {
411 411 if (index !== undefined && index >= 0 && index < this.ncells()) {
412 412 sindex = this.get_selected_index()
413 413 if (sindex !== null && index !== sindex) {
414 414 this.get_cell(sindex).unselect();
415 415 };
416 416 var cell = this.get_cell(index)
417 417 cell.select();
418 418 if (cell.cell_type === 'heading') {
419 419 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
420 420 {'cell_type':cell.cell_type,level:cell.level}
421 421 );
422 422 } else {
423 423 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
424 424 {'cell_type':cell.cell_type}
425 425 );
426 426 };
427 427 };
428 428 return this;
429 429 };
430 430
431 431
432 432 Notebook.prototype.select_next = function () {
433 433 var index = this.get_selected_index();
434 434 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
435 435 this.select(index+1);
436 436 };
437 437 return this;
438 438 };
439 439
440 440
441 441 Notebook.prototype.select_prev = function () {
442 442 var index = this.get_selected_index();
443 443 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
444 444 this.select(index-1);
445 445 };
446 446 return this;
447 447 };
448 448
449 449
450 450 // Cell movement
451 451
452 452 Notebook.prototype.move_cell_up = function (index) {
453 453 var i = this.index_or_selected();
454 454 if (i !== null && i < this.ncells() && i > 0) {
455 455 var pivot = this.get_cell_element(i-1);
456 456 var tomove = this.get_cell_element(i);
457 457 if (pivot !== null && tomove !== null) {
458 458 tomove.detach();
459 459 pivot.before(tomove);
460 460 this.select(i-1);
461 461 };
462 462 };
463 463 this.dirty = true;
464 464 return this;
465 465 };
466 466
467 467
468 468 Notebook.prototype.move_cell_down = function (index) {
469 469 var i = this.index_or_selected();
470 470 if (i !== null && i < (this.ncells()-1) && i >= 0) {
471 471 var pivot = this.get_cell_element(i+1);
472 472 var tomove = this.get_cell_element(i);
473 473 if (pivot !== null && tomove !== null) {
474 474 tomove.detach();
475 475 pivot.after(tomove);
476 476 this.select(i+1);
477 477 };
478 478 };
479 479 this.dirty = true;
480 480 return this;
481 481 };
482 482
483 483
484 484 Notebook.prototype.sort_cells = function () {
485 485 // This is not working right now. Calling this will actually crash
486 486 // the browser. I think there is an infinite loop in here...
487 487 var ncells = this.ncells();
488 488 var sindex = this.get_selected_index();
489 489 var swapped;
490 490 do {
491 491 swapped = false;
492 492 for (var i=1; i<ncells; i++) {
493 493 current = this.get_cell(i);
494 494 previous = this.get_cell(i-1);
495 495 if (previous.input_prompt_number > current.input_prompt_number) {
496 496 this.move_cell_up(i);
497 497 swapped = true;
498 498 };
499 499 };
500 500 } while (swapped);
501 501 this.select(sindex);
502 502 return this;
503 503 };
504 504
505 505 // Insertion, deletion.
506 506
507 507 Notebook.prototype.delete_cell = function (index) {
508 508 var i = this.index_or_selected(index);
509 509 if (this.is_valid_cell_index(i)) {
510 510 var ce = this.get_cell_element(i);
511 511 ce.remove();
512 512 if (i === (this.ncells())) {
513 513 this.select(i-1);
514 514 } else {
515 515 this.select(i);
516 516 };
517 517 this.dirty = true;
518 518 };
519 519 return this;
520 520 };
521 521
522 522
523 523 Notebook.prototype.insert_cell_below = function (type, index) {
524 524 // type = ('code','html','markdown')
525 525 // index = cell index or undefined to insert below selected
526 526 index = this.index_or_selected(index);
527 527 var cell = null;
528 528 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
529 529 if (type === 'code') {
530 530 cell = new IPython.CodeCell(this);
531 531 cell.set_input_prompt();
532 532 } else if (type === 'markdown') {
533 533 cell = new IPython.MarkdownCell(this);
534 534 } else if (type === 'html') {
535 535 cell = new IPython.HTMLCell(this);
536 536 } else if (type === 'raw') {
537 537 cell = new IPython.RawCell(this);
538 538 } else if (type === 'heading') {
539 539 cell = new IPython.HeadingCell(this);
540 540 };
541 541 if (cell !== null) {
542 542 if (this.ncells() === 0) {
543 543 this.element.find('div.end_space').before(cell.element);
544 544 } else if (this.is_valid_cell_index(index)) {
545 545 this.get_cell_element(index).after(cell.element);
546 546 };
547 547 cell.render();
548 548 this.select(this.find_cell_index(cell));
549 549 this.dirty = true;
550 550 return cell;
551 551 };
552 552 };
553 553 return cell;
554 554 };
555 555
556 556
557 557 Notebook.prototype.insert_cell_above = function (type, index) {
558 558 // type = ('code','html','markdown')
559 559 // index = cell index or undefined to insert above selected
560 560 index = this.index_or_selected(index);
561 561 var cell = null;
562 562 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
563 563 if (type === 'code') {
564 564 cell = new IPython.CodeCell(this);
565 565 cell.set_input_prompt();
566 566 } else if (type === 'markdown') {
567 567 cell = new IPython.MarkdownCell(this);
568 568 } else if (type === 'html') {
569 569 cell = new IPython.HTMLCell(this);
570 570 } else if (type === 'raw') {
571 571 cell = new IPython.RawCell(this);
572 572 } else if (type === 'heading') {
573 573 cell = new IPython.HeadingCell(this);
574 574 };
575 575 if (cell !== null) {
576 576 if (this.ncells() === 0) {
577 577 this.element.find('div.end_space').before(cell.element);
578 578 } else if (this.is_valid_cell_index(index)) {
579 579 this.get_cell_element(index).before(cell.element);
580 580 };
581 581 cell.render();
582 582 this.select(this.find_cell_index(cell));
583 583 this.dirty = true;
584 584 return cell;
585 585 };
586 586 };
587 587 return cell;
588 588 };
589 589
590 590
591 591 Notebook.prototype.to_code = function (index) {
592 592 var i = this.index_or_selected(index);
593 593 if (this.is_valid_cell_index(i)) {
594 594 var source_element = this.get_cell_element(i);
595 595 var source_cell = source_element.data("cell");
596 596 if (!(source_cell instanceof IPython.CodeCell)) {
597 597 target_cell = this.insert_cell_below('code',i);
598 598 var text = source_cell.get_text();
599 599 if (text === source_cell.placeholder) {
600 600 text = '';
601 601 }
602 602 target_cell.set_text(text);
603 603 source_element.remove();
604 604 this.dirty = true;
605 605 };
606 606 };
607 607 };
608 608
609 609
610 610 Notebook.prototype.to_markdown = function (index) {
611 611 var i = this.index_or_selected(index);
612 612 if (this.is_valid_cell_index(i)) {
613 613 var source_element = this.get_cell_element(i);
614 614 var source_cell = source_element.data("cell");
615 615 if (!(source_cell instanceof IPython.MarkdownCell)) {
616 616 target_cell = this.insert_cell_below('markdown',i);
617 617 var text = source_cell.get_text();
618 618 if (text === source_cell.placeholder) {
619 619 text = '';
620 620 };
621 621 // The edit must come before the set_text.
622 622 target_cell.edit();
623 623 target_cell.set_text(text);
624 624 source_element.remove();
625 625 this.dirty = true;
626 626 };
627 627 };
628 628 };
629 629
630 630
631 631 Notebook.prototype.to_html = function (index) {
632 632 var i = this.index_or_selected(index);
633 633 if (this.is_valid_cell_index(i)) {
634 634 var source_element = this.get_cell_element(i);
635 635 var source_cell = source_element.data("cell");
636 636 var target_cell = null;
637 637 if (!(source_cell instanceof IPython.HTMLCell)) {
638 638 target_cell = this.insert_cell_below('html',i);
639 639 var text = source_cell.get_text();
640 640 if (text === source_cell.placeholder) {
641 641 text = '';
642 642 };
643 643 // The edit must come before the set_text.
644 644 target_cell.edit();
645 645 target_cell.set_text(text);
646 646 source_element.remove();
647 647 this.dirty = true;
648 648 };
649 649 };
650 650 };
651 651
652 652
653 653 Notebook.prototype.to_raw = function (index) {
654 654 var i = this.index_or_selected(index);
655 655 if (this.is_valid_cell_index(i)) {
656 656 var source_element = this.get_cell_element(i);
657 657 var source_cell = source_element.data("cell");
658 658 var target_cell = null;
659 659 if (!(source_cell instanceof IPython.RawCell)) {
660 660 target_cell = this.insert_cell_below('raw',i);
661 661 var text = source_cell.get_text();
662 662 if (text === source_cell.placeholder) {
663 663 text = '';
664 664 };
665 665 // The edit must come before the set_text.
666 666 target_cell.edit();
667 667 target_cell.set_text(text);
668 668 source_element.remove();
669 669 this.dirty = true;
670 670 };
671 671 };
672 672 };
673 673
674 674
675 675 Notebook.prototype.to_heading = function (index, level) {
676 676 level = level || 1;
677 677 var i = this.index_or_selected(index);
678 678 if (this.is_valid_cell_index(i)) {
679 679 var source_element = this.get_cell_element(i);
680 680 var source_cell = source_element.data("cell");
681 681 var target_cell = null;
682 682 if (source_cell instanceof IPython.HeadingCell) {
683 683 source_cell.set_level(level);
684 684 } else {
685 685 target_cell = this.insert_cell_below('heading',i);
686 686 var text = source_cell.get_text();
687 687 if (text === source_cell.placeholder) {
688 688 text = '';
689 689 };
690 690 // The edit must come before the set_text.
691 691 target_cell.set_level(level);
692 692 target_cell.edit();
693 693 target_cell.set_text(text);
694 694 source_element.remove();
695 695 this.dirty = true;
696 696 };
697 697 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
698 698 {'cell_type':'heading',level:level}
699 699 );
700 700 };
701 701 };
702 702
703 703
704 704 // Cut/Copy/Paste
705 705
706 706 Notebook.prototype.enable_paste = function () {
707 707 var that = this;
708 708 if (!this.paste_enabled) {
709 709 $('#paste_cell').removeClass('ui-state-disabled')
710 710 .on('click', function () {that.paste_cell();});
711 711 $('#paste_cell_above').removeClass('ui-state-disabled')
712 712 .on('click', function () {that.paste_cell_above();});
713 713 $('#paste_cell_below').removeClass('ui-state-disabled')
714 714 .on('click', function () {that.paste_cell_below();});
715 715 this.paste_enabled = true;
716 716 };
717 717 };
718 718
719 719
720 720 Notebook.prototype.disable_paste = function () {
721 721 if (this.paste_enabled) {
722 722 $('#paste_cell').addClass('ui-state-disabled').off('click');
723 723 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
724 724 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
725 725 this.paste_enabled = false;
726 726 };
727 727 };
728 728
729 729
730 730 Notebook.prototype.cut_cell = function () {
731 731 this.copy_cell();
732 732 this.delete_cell();
733 733 }
734 734
735 735 Notebook.prototype.copy_cell = function () {
736 736 var cell = this.get_selected_cell();
737 737 this.clipboard = cell.toJSON();
738 738 this.enable_paste();
739 739 };
740 740
741 741
742 742 Notebook.prototype.paste_cell = function () {
743 743 if (this.clipboard !== null && this.paste_enabled) {
744 744 var cell_data = this.clipboard;
745 745 var new_cell = this.insert_cell_above(cell_data.cell_type);
746 746 new_cell.fromJSON(cell_data);
747 747 old_cell = this.get_next_cell(new_cell);
748 748 this.delete_cell(this.find_cell_index(old_cell));
749 749 this.select(this.find_cell_index(new_cell));
750 750 };
751 751 };
752 752
753 753
754 754 Notebook.prototype.paste_cell_above = function () {
755 755 if (this.clipboard !== null && this.paste_enabled) {
756 756 var cell_data = this.clipboard;
757 757 var new_cell = this.insert_cell_above(cell_data.cell_type);
758 758 new_cell.fromJSON(cell_data);
759 759 };
760 760 };
761 761
762 762
763 763 Notebook.prototype.paste_cell_below = function () {
764 764 if (this.clipboard !== null && this.paste_enabled) {
765 765 var cell_data = this.clipboard;
766 766 var new_cell = this.insert_cell_below(cell_data.cell_type);
767 767 new_cell.fromJSON(cell_data);
768 768 };
769 769 };
770 770
771 771
772 772 // Split/merge
773 773
774 774 Notebook.prototype.split_cell = function () {
775 775 // Todo: implement spliting for other cell types.
776 776 var cell = this.get_selected_cell();
777 777 if (cell.is_splittable()) {
778 778 texta = cell.get_pre_cursor();
779 779 textb = cell.get_post_cursor();
780 780 if (cell instanceof IPython.CodeCell) {
781 781 cell.set_text(texta);
782 782 var new_cell = this.insert_cell_below('code');
783 783 new_cell.set_text(textb);
784 784 } else if (cell instanceof IPython.MarkdownCell) {
785 785 cell.set_text(texta);
786 786 cell.render();
787 787 var new_cell = this.insert_cell_below('markdown');
788 788 new_cell.edit(); // editor must be visible to call set_text
789 789 new_cell.set_text(textb);
790 790 new_cell.render();
791 791 } else if (cell instanceof IPython.HTMLCell) {
792 792 cell.set_text(texta);
793 793 cell.render();
794 794 var new_cell = this.insert_cell_below('html');
795 795 new_cell.edit(); // editor must be visible to call set_text
796 796 new_cell.set_text(textb);
797 797 new_cell.render();
798 798 };
799 799 };
800 800 };
801 801
802 802
803 803 Notebook.prototype.merge_cell_above = function () {
804 804 var index = this.get_selected_index();
805 805 var cell = this.get_cell(index);
806 806 if (index > 0) {
807 807 upper_cell = this.get_cell(index-1);
808 808 upper_text = upper_cell.get_text();
809 809 text = cell.get_text();
810 810 if (cell instanceof IPython.CodeCell) {
811 811 cell.set_text(upper_text+'\n'+text);
812 812 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
813 813 cell.edit();
814 814 cell.set_text(upper_text+'\n'+text);
815 815 cell.render();
816 816 };
817 817 this.delete_cell(index-1);
818 818 this.select(this.find_cell_index(cell));
819 819 };
820 820 };
821 821
822 822
823 823 Notebook.prototype.merge_cell_below = function () {
824 824 var index = this.get_selected_index();
825 825 var cell = this.get_cell(index);
826 826 if (index < this.ncells()-1) {
827 827 lower_cell = this.get_cell(index+1);
828 828 lower_text = lower_cell.get_text();
829 829 text = cell.get_text();
830 830 if (cell instanceof IPython.CodeCell) {
831 831 cell.set_text(text+'\n'+lower_text);
832 832 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
833 833 cell.edit();
834 834 cell.set_text(text+'\n'+lower_text);
835 835 cell.render();
836 836 };
837 837 this.delete_cell(index+1);
838 838 this.select(this.find_cell_index(cell));
839 839 };
840 840 };
841 841
842 842
843 843 // Cell collapsing and output clearing
844 844
845 845 Notebook.prototype.collapse = function (index) {
846 846 var i = this.index_or_selected(index);
847 847 this.get_cell(i).collapse();
848 848 this.dirty = true;
849 849 };
850 850
851 851
852 852 Notebook.prototype.expand = function (index) {
853 853 var i = this.index_or_selected(index);
854 854 this.get_cell(i).expand();
855 855 this.dirty = true;
856 856 };
857 857
858 858
859 859 Notebook.prototype.toggle_output = function (index) {
860 860 var i = this.index_or_selected(index);
861 861 this.get_cell(i).toggle_output();
862 862 this.dirty = true;
863 863 };
864 864
865 865
866 866 Notebook.prototype.set_timebeforetooltip = function (time) {
867 867 this.time_before_tooltip = time;
868 868 };
869 869
870 870
871 871 Notebook.prototype.set_tooltipontab = function (state) {
872 872 this.tooltip_on_tab = state;
873 873 };
874 874
875 875
876 876 Notebook.prototype.set_smartcompleter = function (state) {
877 877 this.smart_completer = state;
878 878 };
879 879
880 880
881 881 Notebook.prototype.clear_all_output = function () {
882 882 var ncells = this.ncells();
883 883 var cells = this.get_cells();
884 884 for (var i=0; i<ncells; i++) {
885 885 if (cells[i] instanceof IPython.CodeCell) {
886 886 cells[i].clear_output(true,true,true);
887 887 // Make all In[] prompts blank, as well
888 888 // TODO: make this configurable (via checkbox?)
889 889 cells[i].set_input_prompt();
890 890 }
891 891 };
892 892 this.dirty = true;
893 893 };
894 894
895 895
896 896 // Other cell functions: line numbers, ...
897 897
898 898 Notebook.prototype.cell_toggle_line_numbers = function() {
899 899 this.get_selected_cell().toggle_line_numbers();
900 900 };
901 901
902 902 // Kernel related things
903 903
904 904 Notebook.prototype.start_kernel = function () {
905 905 this.kernel = new IPython.Kernel();
906 906 this.kernel.start(this.notebook_id, $.proxy(this.kernel_started, this));
907 907 };
908 908
909 909
910 910 Notebook.prototype.restart_kernel = function () {
911 911 var that = this;
912 912 var dialog = $('<div/>');
913 913 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
914 914 $(document).append(dialog);
915 915 dialog.dialog({
916 916 resizable: false,
917 917 modal: true,
918 918 title: "Restart kernel or continue running?",
919 919 closeText: '',
920 920 buttons : {
921 921 "Restart": function () {
922 922 that.kernel.restart($.proxy(that.kernel_started, that));
923 923 $(this).dialog('close');
924 924 },
925 925 "Continue running": function () {
926 926 $(this).dialog('close');
927 927 }
928 928 }
929 929 });
930 930 };
931 931
932 932
933 933 Notebook.prototype.kernel_started = function () {
934 934 console.log("Kernel started: ", this.kernel.kernel_id);
935 935 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
936 936 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
937 937 };
938 938
939 939
940 940 Notebook.prototype.handle_shell_reply = function (e) {
941 941 reply = $.parseJSON(e.data);
942 942 var header = reply.header;
943 943 var content = reply.content;
944 944 var msg_type = header.msg_type;
945 945 // console.log(reply);
946 946 var cell = this.cell_for_msg(reply.parent_header.msg_id);
947 947 if (msg_type === "execute_reply") {
948 948 cell.set_input_prompt(content.execution_count);
949 949 cell.element.removeClass("running");
950 950 this.dirty = true;
951 951 } else if (msg_type === "complete_reply") {
952 952 cell.finish_completing(content.matched_text, content.matches);
953 953 } else if (msg_type === "object_info_reply"){
954 954 //console.log('back from object_info_request : ')
955 955 rep = reply.content;
956 956 if(rep.found)
957 957 {
958 958 cell.finish_tooltip(rep);
959 959 }
960 960 } else {
961 961 //console.log("unknown reply:"+msg_type);
962 962 }
963 963 // when having a rely from object_info_reply,
964 964 // no payload so no nned to handle it
965 965 if(typeof(content.payload)!='undefined') {
966 966 var payload = content.payload || [];
967 967 this.handle_payload(cell, payload);
968 968 }
969 969 };
970 970
971 971
972 972 Notebook.prototype.handle_payload = function (cell, payload) {
973 973 var l = payload.length;
974 974 for (var i=0; i<l; i++) {
975 975 if (payload[i].source === 'IPython.zmq.page.page') {
976 976 if (payload[i].text.trim() !== '') {
977 977 IPython.pager.clear();
978 978 IPython.pager.expand();
979 979 IPython.pager.append_text(payload[i].text);
980 980 }
981 981 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
982 982 var index = this.find_cell_index(cell);
983 983 var new_cell = this.insert_cell_below('code',index);
984 984 new_cell.set_text(payload[i].text);
985 985 this.dirty = true;
986 986 }
987 987 };
988 988 };
989 989
990 990
991 991 Notebook.prototype.handle_iopub_reply = function (e) {
992 992 reply = $.parseJSON(e.data);
993 993 var content = reply.content;
994 994 // console.log(reply);
995 995 var msg_type = reply.header.msg_type;
996 996 var cell = this.cell_for_msg(reply.parent_header.msg_id);
997 997 if (msg_type !== 'status' && !cell){
998 998 // message not from this notebook, but should be attached to a cell
999 999 // console.log("Received IOPub message not caused by one of my cells");
1000 1000 // console.log(reply);
1001 1001 return;
1002 1002 }
1003 1003 var output_types = ['stream','display_data','pyout','pyerr'];
1004 1004 if (output_types.indexOf(msg_type) >= 0) {
1005 1005 this.handle_output(cell, msg_type, content);
1006 1006 } else if (msg_type === 'status') {
1007 1007 if (content.execution_state === 'busy') {
1008 1008 $([IPython.events]).trigger('status_busy.Kernel');
1009 1009 } else if (content.execution_state === 'idle') {
1010 1010 $([IPython.events]).trigger('status_idle.Kernel');
1011 1011 } else if (content.execution_state === 'dead') {
1012 1012 this.handle_status_dead();
1013 1013 };
1014 1014 } else if (msg_type === 'clear_output') {
1015 1015 cell.clear_output(content.stdout, content.stderr, content.other);
1016 1016 };
1017 1017 };
1018 1018
1019 1019
1020 1020 Notebook.prototype.handle_status_dead = function () {
1021 1021 var that = this;
1022 1022 this.kernel.stop_channels();
1023 1023 var dialog = $('<div/>');
1024 1024 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.');
1025 1025 $(document).append(dialog);
1026 1026 dialog.dialog({
1027 1027 resizable: false,
1028 1028 modal: true,
1029 1029 title: "Dead kernel",
1030 1030 buttons : {
1031 1031 "Restart": function () {
1032 1032 that.start_kernel();
1033 1033 $(this).dialog('close');
1034 1034 },
1035 1035 "Continue running": function () {
1036 1036 $(this).dialog('close');
1037 1037 }
1038 1038 }
1039 1039 });
1040 1040 };
1041 1041
1042 1042
1043 1043 Notebook.prototype.handle_output = function (cell, msg_type, content) {
1044 1044 var json = {};
1045 1045 json.output_type = msg_type;
1046 1046 if (msg_type === "stream") {
1047 1047 json.text = content.data;
1048 1048 json.stream = content.name;
1049 1049 } else if (msg_type === "display_data") {
1050 1050 json = this.convert_mime_types(json, content.data);
1051 1051 } else if (msg_type === "pyout") {
1052 1052 json.prompt_number = content.execution_count;
1053 1053 json = this.convert_mime_types(json, content.data);
1054 1054 } else if (msg_type === "pyerr") {
1055 1055 json.ename = content.ename;
1056 1056 json.evalue = content.evalue;
1057 1057 json.traceback = content.traceback;
1058 1058 };
1059 1059 // append with dynamic=true
1060 1060 cell.append_output(json, true);
1061 1061 this.dirty = true;
1062 1062 };
1063 1063
1064 1064
1065 1065 Notebook.prototype.convert_mime_types = function (json, data) {
1066 1066 if (data['text/plain'] !== undefined) {
1067 1067 json.text = data['text/plain'];
1068 1068 };
1069 1069 if (data['text/html'] !== undefined) {
1070 1070 json.html = data['text/html'];
1071 1071 };
1072 1072 if (data['image/svg+xml'] !== undefined) {
1073 1073 json.svg = data['image/svg+xml'];
1074 1074 };
1075 1075 if (data['image/png'] !== undefined) {
1076 1076 json.png = data['image/png'];
1077 1077 };
1078 1078 if (data['image/jpeg'] !== undefined) {
1079 1079 json.jpeg = data['image/jpeg'];
1080 1080 };
1081 1081 if (data['text/latex'] !== undefined) {
1082 1082 json.latex = data['text/latex'];
1083 1083 };
1084 1084 if (data['application/json'] !== undefined) {
1085 1085 json.json = data['application/json'];
1086 1086 };
1087 1087 if (data['application/javascript'] !== undefined) {
1088 1088 json.javascript = data['application/javascript'];
1089 1089 }
1090 1090 return json;
1091 1091 };
1092 1092
1093 1093
1094 1094 Notebook.prototype.execute_selected_cell = function (options) {
1095 1095 // add_new: should a new cell be added if we are at the end of the nb
1096 1096 // terminal: execute in terminal mode, which stays in the current cell
1097 1097 default_options = {terminal: false, add_new: true};
1098 1098 $.extend(default_options, options);
1099 1099 var that = this;
1100 1100 var cell = that.get_selected_cell();
1101 1101 var cell_index = that.find_cell_index(cell);
1102 1102 if (cell instanceof IPython.CodeCell) {
1103 1103 cell.clear_output(true, true, true);
1104 1104 cell.set_input_prompt('*');
1105 1105 cell.element.addClass("running");
1106 1106 var code = cell.get_text();
1107 1107 var msg_id = that.kernel.execute(cell.get_text());
1108 1108 that.msg_cell_map[msg_id] = cell.cell_id;
1109 1109 } else if (cell instanceof IPython.HTMLCell) {
1110 1110 cell.render();
1111 1111 }
1112 1112 if (default_options.terminal) {
1113 1113 cell.select_all();
1114 1114 } else {
1115 1115 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1116 1116 that.insert_cell_below('code');
1117 1117 // If we are adding a new cell at the end, scroll down to show it.
1118 1118 that.scroll_to_bottom();
1119 1119 } else {
1120 1120 that.select(cell_index+1);
1121 1121 };
1122 1122 };
1123 1123 this.dirty = true;
1124 1124 };
1125 1125
1126 1126
1127 1127 Notebook.prototype.execute_all_cells = function () {
1128 1128 var ncells = this.ncells();
1129 1129 for (var i=0; i<ncells; i++) {
1130 1130 this.select(i);
1131 1131 this.execute_selected_cell({add_new:false});
1132 1132 };
1133 1133 this.scroll_to_bottom();
1134 1134 };
1135 1135
1136 1136
1137 1137 Notebook.prototype.request_tool_tip = function (cell,func) {
1138 1138 // Feel free to shorten this logic if you are better
1139 1139 // than me in regEx
1140 1140 // basicaly you shoul be able to get xxx.xxx.xxx from
1141 1141 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
1142 1142 // remove everything between matchin bracket (need to iterate)
1143 1143 matchBracket = /\([^\(\)]+\)/g;
1144 1144 oldfunc = func;
1145 1145 func = func.replace(matchBracket,"");
1146 1146 while( oldfunc != func )
1147 1147 {
1148 1148 oldfunc = func;
1149 1149 func = func.replace(matchBracket,"");
1150 1150 }
1151 1151 // remove everythin after last open bracket
1152 1152 endBracket = /\([^\(]*$/g;
1153 1153 func = func.replace(endBracket,"");
1154 1154 var re = /[a-z_][0-9a-z._]+$/gi; // casse insensitive
1155 1155 var msg_id = this.kernel.object_info_request(re.exec(func));
1156 1156 if(typeof(msg_id)!='undefined'){
1157 1157 this.msg_cell_map[msg_id] = cell.cell_id;
1158 1158 }
1159 1159 };
1160 1160
1161 1161 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
1162 1162 var msg_id = this.kernel.complete(line, cursor_pos);
1163 1163 this.msg_cell_map[msg_id] = cell.cell_id;
1164 1164 };
1165 1165
1166 1166
1167 1167 // Persistance and loading
1168 1168
1169 1169 Notebook.prototype.get_notebook_id = function () {
1170 1170 return this.notebook_id;
1171 1171 };
1172 1172
1173 1173
1174 1174 Notebook.prototype.get_notebook_name = function () {
1175 1175 return this.notebook_name;
1176 1176 };
1177 1177
1178 1178
1179 1179 Notebook.prototype.set_notebook_name = function (name) {
1180 1180 this.notebook_name = name;
1181 1181 };
1182 1182
1183 1183
1184 1184 Notebook.prototype.test_notebook_name = function (nbname) {
1185 1185 nbname = nbname || '';
1186 1186 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1187 1187 return true;
1188 1188 } else {
1189 1189 return false;
1190 1190 };
1191 1191 };
1192 1192
1193 1193
1194 1194 Notebook.prototype.fromJSON = function (data) {
1195 1195 var ncells = this.ncells();
1196 1196 var i;
1197 1197 for (i=0; i<ncells; i++) {
1198 1198 // Always delete cell 0 as they get renumbered as they are deleted.
1199 1199 this.delete_cell(0);
1200 1200 };
1201 1201 // Save the metadata and name.
1202 1202 this.metadata = data.metadata;
1203 1203 this.notebook_name = data.metadata.name;
1204 1204 // Only handle 1 worksheet for now.
1205 1205 var worksheet = data.worksheets[0];
1206 1206 if (worksheet !== undefined) {
1207 1207 var new_cells = worksheet.cells;
1208 1208 ncells = new_cells.length;
1209 1209 var cell_data = null;
1210 1210 var new_cell = null;
1211 1211 for (i=0; i<ncells; i++) {
1212 1212 cell_data = new_cells[i];
1213 1213 // VERSIONHACK: plaintext -> raw
1214 1214 // handle never-released plaintext name for raw cells
1215 1215 if (cell_data.cell_type === 'plaintext'){
1216 1216 cell_data.cell_type = 'raw';
1217 1217 }
1218 1218
1219 1219 new_cell = this.insert_cell_below(cell_data.cell_type);
1220 1220 new_cell.fromJSON(cell_data);
1221 1221 };
1222 1222 };
1223 1223 };
1224 1224
1225 1225
1226 1226 Notebook.prototype.toJSON = function () {
1227 1227 var cells = this.get_cells();
1228 1228 var ncells = cells.length;
1229 1229 cell_array = new Array(ncells);
1230 1230 for (var i=0; i<ncells; i++) {
1231 1231 cell_array[i] = cells[i].toJSON();
1232 1232 };
1233 1233 data = {
1234 1234 // Only handle 1 worksheet for now.
1235 1235 worksheets : [{cells:cell_array}],
1236 1236 metadata : this.metadata
1237 1237 };
1238 1238 return data;
1239 1239 };
1240 1240
1241 1241 Notebook.prototype.save_notebook = function () {
1242 1242 // We may want to move the name/id/nbformat logic inside toJSON?
1243 1243 var data = this.toJSON();
1244 1244 data.metadata.name = this.notebook_name;
1245 1245 data.nbformat = this.nbformat;
1246 1246 // We do the call with settings so we can set cache to false.
1247 1247 var settings = {
1248 1248 processData : false,
1249 1249 cache : false,
1250 1250 type : "PUT",
1251 1251 data : JSON.stringify(data),
1252 1252 headers : {'Content-Type': 'application/json'},
1253 1253 success : $.proxy(this.save_notebook_success,this),
1254 1254 error : $.proxy(this.save_notebook_error,this)
1255 1255 };
1256 1256 $([IPython.events]).trigger('notebook_saving.Notebook');
1257 1257 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1258 1258 $.ajax(url, settings);
1259 1259 };
1260 1260
1261 1261
1262 1262 Notebook.prototype.save_notebook_success = function (data, status, xhr) {
1263 1263 this.dirty = false;
1264 1264 $([IPython.events]).trigger('notebook_saved.Notebook');
1265 1265 };
1266 1266
1267 1267
1268 1268 Notebook.prototype.save_notebook_error = function (xhr, status, error_msg) {
1269 1269 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1270 1270 };
1271 1271
1272 1272
1273 1273 Notebook.prototype.load_notebook = function (notebook_id) {
1274 1274 var that = this;
1275 1275 this.notebook_id = notebook_id;
1276 1276 // We do the call with settings so we can set cache to false.
1277 1277 var settings = {
1278 1278 processData : false,
1279 1279 cache : false,
1280 1280 type : "GET",
1281 1281 dataType : "json",
1282 1282 success : $.proxy(this.load_notebook_success,this),
1283 1283 error : $.proxy(this.load_notebook_error,this),
1284 1284 };
1285 1285 $([IPython.events]).trigger('notebook_loading.Notebook');
1286 1286 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1287 1287 $.ajax(url, settings);
1288 1288 };
1289 1289
1290 1290
1291 1291 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1292 1292 this.fromJSON(data);
1293 1293 if (this.ncells() === 0) {
1294 1294 this.insert_cell_below('code');
1295 1295 };
1296 1296 this.dirty = false;
1297 1297 if (! this.read_only) {
1298 1298 this.start_kernel();
1299 1299 }
1300 1300 this.select(0);
1301 1301 this.scroll_to_top();
1302 1302 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1303 1303 msg = "This notebook has been converted from an older " +
1304 1304 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1305 1305 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1306 1306 "newer notebook format will be used and older verions of IPython " +
1307 1307 "may not be able to read it. To keep the older version, close the " +
1308 1308 "notebook without saving it.";
1309 1309 var dialog = $('<div/>');
1310 1310 dialog.html(msg);
1311 1311 this.element.append(dialog);
1312 1312 dialog.dialog({
1313 1313 resizable: false,
1314 1314 modal: true,
1315 1315 title: "Notebook converted",
1316 1316 closeText: "",
1317 1317 close: function(event, ui) {$(this).dialog('destroy').remove();},
1318 1318 buttons : {
1319 1319 "OK": function () {
1320 1320 $(this).dialog('close');
1321 1321 }
1322 1322 },
1323 1323 width: 400
1324 1324 });
1325 1325 }
1326 1326 $([IPython.events]).trigger('notebook_loaded.Notebook');
1327 1327 };
1328 1328
1329 1329
1330 1330 Notebook.prototype.load_notebook_error = function (xhr, textStatus, errorThrow) {
1331 1331 if (xhr.status === 500) {
1332 1332 msg = "An error occurred while loading this notebook. Most likely " +
1333 1333 "this notebook is in a newer format than is supported by this " +
1334 1334 "version of IPython. This version can load notebook formats " +
1335 1335 "v"+this.nbformat+" or earlier.";
1336 1336 var dialog = $('<div/>');
1337 1337 dialog.html(msg);
1338 1338 this.element.append(dialog);
1339 1339 dialog.dialog({
1340 1340 resizable: false,
1341 1341 modal: true,
1342 1342 title: "Error loading notebook",
1343 1343 closeText: "",
1344 1344 close: function(event, ui) {$(this).dialog('destroy').remove();},
1345 1345 buttons : {
1346 1346 "OK": function () {
1347 1347 $(this).dialog('close');
1348 1348 }
1349 1349 },
1350 1350 width: 400
1351 1351 });
1352 1352 }
1353 1353 }
1354 1354
1355 1355 IPython.Notebook = Notebook;
1356 1356
1357 1357
1358 1358 return IPython;
1359 1359
1360 1360 }(IPython));
1361 1361
@@ -1,139 +1,139
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 // SaveWidget
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var utils = IPython.utils;
15 15
16 16 var SaveWidget = function (selector) {
17 17 this.selector = selector;
18 18 if (this.selector !== undefined) {
19 19 this.element = $(selector);
20 20 this.style();
21 21 this.bind_events();
22 22 }
23 23 };
24 24
25 25
26 26 SaveWidget.prototype.style = function () {
27 27 this.element.find('span#save_widget').addClass('ui-widget');
28 28 this.element.find('span#notebook_name').addClass('ui-widget ui-widget-content');
29 29 this.element.find('span#save_status').addClass('ui-widget ui-widget-content')
30 30 .css({border: 'none', 'margin-left': '20px'});
31 31 };
32 32
33 33
34 34 SaveWidget.prototype.bind_events = function () {
35 35 var that = this;
36 36 this.element.find('span#notebook_name').click(function () {
37 37 that.rename_notebook();
38 38 });
39 39 this.element.find('span#notebook_name').hover(function () {
40 40 $(this).addClass("ui-state-hover");
41 41 }, function () {
42 42 $(this).removeClass("ui-state-hover");
43 43 });
44 44 $([IPython.events]).on('notebook_loaded.Notebook', function () {
45 45 that.set_last_saved();
46 46 that.update_notebook_name();
47 47 that.update_document_title();
48 48 });
49 49 $([IPython.events]).on('notebook_saved.Notebook', function () {
50 50 that.set_last_saved();
51 51 that.update_notebook_name();
52 52 that.update_document_title();
53 53 });
54 54 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
55 55 that.set_save_status('');
56 56 });
57 57 };
58 58
59 59
60 60 SaveWidget.prototype.rename_notebook = function () {
61 61 var that = this;
62 62 var dialog = $('<div/>');
63 63 dialog.append(
64 64 $('<h3/>').html('Enter a new notebook name:')
65 65 .css({'margin-bottom': '10px'})
66 66 );
67 67 dialog.append(
68 68 $('<input/>').attr('type','text').attr('size','25')
69 69 .addClass('ui-widget ui-widget-content')
70 70 .attr('value',IPython.notebook.get_notebook_name())
71 71 );
72 72 // $(document).append(dialog);
73 73 dialog.dialog({
74 74 resizable: false,
75 75 modal: true,
76 76 title: "Rename Notebook",
77 77 closeText: "",
78 78 close: function(event, ui) {$(this).dialog('destroy').remove();},
79 79 buttons : {
80 80 "OK": function () {
81 81 var new_name = $(this).find('input').attr('value');
82 82 if (!IPython.notebook.test_notebook_name(new_name)) {
83 83 $(this).find('h3').html(
84 84 "Invalid notebook name. Notebook names must "+
85 85 "have 1 or more characters and can contain any characters " +
86 "except / and \\. Please enter a new notebook name:"
86 "except :/\\. Please enter a new notebook name:"
87 87 );
88 88 } else {
89 89 IPython.notebook.set_notebook_name(new_name);
90 90 IPython.notebook.save_notebook();
91 91 $(this).dialog('close');
92 92 }
93 93 },
94 94 "Cancel": function () {
95 95 $(this).dialog('close');
96 96 }
97 97 }
98 98 });
99 99 }
100 100
101 101
102 102 SaveWidget.prototype.update_notebook_name = function () {
103 103 var nbname = IPython.notebook.get_notebook_name();
104 104 this.element.find('span#notebook_name').html(nbname);
105 105 };
106 106
107 107
108 108 SaveWidget.prototype.update_document_title = function () {
109 109 var nbname = IPython.notebook.get_notebook_name();
110 110 document.title = nbname;
111 111 };
112 112
113 113
114 114 SaveWidget.prototype.update_url = function () {
115 115 var notebook_id = IPython.notebook.get_notebook_id();
116 116 if (notebook_id !== null) {
117 117 var new_url = $('body').data('baseProjectUrl') + notebook_id;
118 118 window.history.replaceState({}, '', new_url);
119 119 };
120 120 };
121 121
122 122
123 123 SaveWidget.prototype.set_save_status = function (msg) {
124 124 this.element.find('span#save_status').html(msg);
125 125 }
126 126
127 127
128 128 SaveWidget.prototype.set_last_saved = function () {
129 129 var d = new Date();
130 130 this.set_save_status('Last saved: '+d.format('mmm dd h:MM TT'));
131 131 };
132 132
133 133
134 134 IPython.SaveWidget = SaveWidget;
135 135
136 136 return IPython;
137 137
138 138 }(IPython));
139 139
General Comments 0
You need to be logged in to leave comments. Login now