##// END OF EJS Templates
More accuract height calculations for the pager collapse/expand.
Brian E. Granger -
Show More
@@ -1,557 +1,556
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.msg_cell_map = {};
17 17 this.filename = null;
18 18 this.notebook_load_re = /%notebook load/
19 19 this.notebook_save_re = /%notebook save/
20 20 this.notebook_filename_re = /(\w)+.ipynb/
21 21 this.style();
22 22 this.bind_events();
23 23 this.start_kernel();
24 24 };
25 25
26 26
27 27 Notebook.prototype.style = function () {
28 28 };
29 29
30 30
31 31 Notebook.prototype.bind_events = function () {
32 32 var that = this;
33 33 $(document).keydown(function (event) {
34 34 // console.log(event);
35 35 if (event.which === 38) {
36 36 var cell = that.selected_cell();
37 37 if (cell.at_top()) {
38 38 event.preventDefault();
39 39 that.select_prev();
40 40 };
41 41 } else if (event.which === 40) {
42 42 var cell = that.selected_cell();
43 43 if (cell.at_bottom()) {
44 44 event.preventDefault();
45 45 that.select_next();
46 46 };
47 47 } else if (event.which === 13 && event.shiftKey) {
48 48 // The focus is not quite working here.
49 49 var cell = that.selected_cell();
50 50 var cell_index = that.find_cell_index(cell);
51 51 // TODO: the logic here needs to be moved into appropriate
52 52 // methods of Notebook.
53 53 if (cell instanceof IPython.CodeCell) {
54 54 event.preventDefault();
55 55 cell.clear_output();
56 56 var code = cell.get_code();
57 57 if (that.notebook_load_re.test(code)) {
58 58 var code_parts = code.split(' ');
59 59 if (code_parts.length === 3) {
60 60 that.load_notebook(code_parts[2]);
61 61 };
62 62 } else if (that.notebook_save_re.test(code)) {
63 63 var code_parts = code.split(' ');
64 64 if (code_parts.length === 3) {
65 65 that.save_notebook(code_parts[2]);
66 66 } else {
67 67 that.save_notebook()
68 68 };
69 69 } else {
70 70 var msg_id = that.kernel.execute(cell.get_code());
71 71 that.msg_cell_map[msg_id] = cell.cell_id;
72 72 };
73 73 } else if (cell instanceof IPython.TextCell) {
74 74 event.preventDefault();
75 75 cell.render();
76 76 }
77 77 if (cell_index === (that.ncells()-1)) {
78 78 that.insert_code_cell_after();
79 79 } else {
80 80 that.select(cell_index+1);
81 81 };
82 82 };
83 83 });
84 84
85 85 this.element.bind('collapse_pager', function () {
86 var that_height = that.element.outerHeight(true);
87 var pager_height = $('div#pager').outerHeight(true);
88 var new_height = that_height + pager_height;
89 console.log('collapse', that_height, pager_height, new_height);
86 var app_height = $('div#notebook_app').height(); // content height
87 var splitter_height = $('div#pager_splitter').outerHeight(true);
88 var new_height = app_height - splitter_height;
90 89 that.element.animate({height : new_height + 'px'}, 'fast');
91 90 });
92 91
93 92 this.element.bind('expand_pager', function () {
94 var that_height = that.element.outerHeight(true);
93 var app_height = $('div#notebook_app').height(); // content height
94 var splitter_height = $('div#pager_splitter').outerHeight(true);
95 95 var pager_height = $('div#pager').outerHeight(true);
96 var new_height = that_height - pager_height;
97 console.log('expand', that_height, pager_height, new_height);
96 var new_height = app_height - pager_height - splitter_height;
98 97 that.element.animate({height : new_height + 'px'}, 'fast');
99 98 });
100 99 };
101 100
102 101
103 102 // Cell indexing, retrieval, etc.
104 103
105 104
106 105 Notebook.prototype.cell_elements = function () {
107 106 return this.element.children("div.cell");
108 107 }
109 108
110 109
111 110 Notebook.prototype.ncells = function (cell) {
112 111 return this.cell_elements().length;
113 112 }
114 113
115 114
116 115 // TODO: we are often calling cells as cells()[i], which we should optimize
117 116 // to cells(i) or a new method.
118 117 Notebook.prototype.cells = function () {
119 118 return this.cell_elements().toArray().map(function (e) {
120 119 return $(e).data("cell");
121 120 });
122 121 }
123 122
124 123
125 124 Notebook.prototype.find_cell_index = function (cell) {
126 125 var result = null;
127 126 this.cell_elements().filter(function (index) {
128 127 if ($(this).data("cell") === cell) {
129 128 result = index;
130 129 };
131 130 });
132 131 return result;
133 132 };
134 133
135 134
136 135 Notebook.prototype.index_or_selected = function (index) {
137 136 return index || this.selected_index() || 0;
138 137 }
139 138
140 139
141 140 Notebook.prototype.select = function (index) {
142 141 if (index !== undefined && index >= 0 && index < this.ncells()) {
143 142 if (this.selected_index() !== null) {
144 143 this.selected_cell().unselect();
145 144 };
146 145 this.cells()[index].select();
147 146 };
148 147 return this;
149 148 };
150 149
151 150
152 151 Notebook.prototype.select_next = function () {
153 152 var index = this.selected_index();
154 153 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
155 154 this.select(index+1);
156 155 };
157 156 return this;
158 157 };
159 158
160 159
161 160 Notebook.prototype.select_prev = function () {
162 161 var index = this.selected_index();
163 162 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
164 163 this.select(index-1);
165 164 };
166 165 return this;
167 166 };
168 167
169 168
170 169 Notebook.prototype.selected_index = function () {
171 170 var result = null;
172 171 this.cell_elements().filter(function (index) {
173 172 if ($(this).data("cell").selected === true) {
174 173 result = index;
175 174 };
176 175 });
177 176 return result;
178 177 };
179 178
180 179
181 180 Notebook.prototype.cell_for_msg = function (msg_id) {
182 181 var cell_id = this.msg_cell_map[msg_id];
183 182 var result = null;
184 183 this.cell_elements().filter(function (index) {
185 184 cell = $(this).data("cell");
186 185 if (cell.cell_id === cell_id) {
187 186 result = cell;
188 187 };
189 188 });
190 189 return result;
191 190 };
192 191
193 192
194 193 Notebook.prototype.selected_cell = function () {
195 194 return this.cell_elements().eq(this.selected_index()).data("cell");
196 195 }
197 196
198 197
199 198 // Cell insertion, deletion and moving.
200 199
201 200
202 201 Notebook.prototype.delete_cell = function (index) {
203 202 var i = index || this.selected_index();
204 203 if (i !== null && i >= 0 && i < this.ncells()) {
205 204 this.cell_elements().eq(i).remove();
206 205 if (i === (this.ncells())) {
207 206 this.select(i-1);
208 207 } else {
209 208 this.select(i);
210 209 };
211 210 };
212 211 return this;
213 212 };
214 213
215 214
216 215 Notebook.prototype.append_cell = function (cell) {
217 216 this.element.append(cell.element);
218 217 return this;
219 218 };
220 219
221 220
222 221 Notebook.prototype.insert_cell_after = function (cell, index) {
223 222 var ncells = this.ncells();
224 223 if (ncells === 0) {
225 224 this.append_cell(cell);
226 225 return this;
227 226 };
228 227 if (index >= 0 && index < ncells) {
229 228 this.cell_elements().eq(index).after(cell.element);
230 229 };
231 230 return this
232 231 };
233 232
234 233
235 234 Notebook.prototype.insert_cell_before = function (cell, index) {
236 235 var ncells = this.ncells();
237 236 if (ncells === 0) {
238 237 this.append_cell(cell);
239 238 return this;
240 239 };
241 240 if (index >= 0 && index < ncells) {
242 241 this.cell_elements().eq(index).before(cell.element);
243 242 };
244 243 return this;
245 244 };
246 245
247 246
248 247 Notebook.prototype.move_cell_up = function (index) {
249 248 var i = index || this.selected_index();
250 249 if (i !== null && i < this.ncells() && i > 0) {
251 250 var pivot = this.cell_elements().eq(i-1);
252 251 var tomove = this.cell_elements().eq(i);
253 252 if (pivot !== null && tomove !== null) {
254 253 tomove.detach();
255 254 pivot.before(tomove);
256 255 this.select(i-1);
257 256 };
258 257 };
259 258 return this;
260 259 }
261 260
262 261
263 262 Notebook.prototype.move_cell_down = function (index) {
264 263 var i = index || this.selected_index();
265 264 if (i !== null && i < (this.ncells()-1) && i >= 0) {
266 265 var pivot = this.cell_elements().eq(i+1)
267 266 var tomove = this.cell_elements().eq(i)
268 267 if (pivot !== null && tomove !== null) {
269 268 tomove.detach();
270 269 pivot.after(tomove);
271 270 this.select(i+1);
272 271 };
273 272 };
274 273 return this;
275 274 }
276 275
277 276
278 277 Notebook.prototype.sort_cells = function () {
279 278 var ncells = this.ncells();
280 279 var sindex = this.selected_index();
281 280 var swapped;
282 281 do {
283 282 swapped = false
284 283 for (var i=1; i<ncells; i++) {
285 284 current = this.cell_elements().eq(i).data("cell");
286 285 previous = this.cell_elements().eq(i-1).data("cell");
287 286 if (previous.input_prompt_number > current.input_prompt_number) {
288 287 this.move_cell_up(i);
289 288 swapped = true;
290 289 };
291 290 };
292 291 } while (swapped);
293 292 this.select(sindex);
294 293 return this;
295 294 };
296 295
297 296
298 297 Notebook.prototype.insert_code_cell_before = function (index) {
299 298 // TODO: Bounds check for i
300 299 var i = this.index_or_selected(index);
301 300 var cell = new IPython.CodeCell(this);
302 301 cell.set_input_prompt(this.next_prompt_number);
303 302 this.next_prompt_number = this.next_prompt_number + 1;
304 303 this.insert_cell_before(cell, i);
305 304 this.select(this.find_cell_index(cell));
306 305 return this;
307 306 }
308 307
309 308
310 309 Notebook.prototype.insert_code_cell_after = function (index) {
311 310 // TODO: Bounds check for i
312 311 var i = this.index_or_selected(index);
313 312 var cell = new IPython.CodeCell(this);
314 313 cell.set_input_prompt(this.next_prompt_number);
315 314 this.next_prompt_number = this.next_prompt_number + 1;
316 315 this.insert_cell_after(cell, i);
317 316 this.select(this.find_cell_index(cell));
318 317 return this;
319 318 }
320 319
321 320
322 321 Notebook.prototype.insert_text_cell_before = function (index) {
323 322 // TODO: Bounds check for i
324 323 var i = this.index_or_selected(index);
325 324 var cell = new IPython.TextCell(this);
326 325 cell.config_mathjax();
327 326 this.insert_cell_before(cell, i);
328 327 this.select(this.find_cell_index(cell));
329 328 return this;
330 329 }
331 330
332 331
333 332 Notebook.prototype.insert_text_cell_after = function (index) {
334 333 // TODO: Bounds check for i
335 334 var i = this.index_or_selected(index);
336 335 var cell = new IPython.TextCell(this);
337 336 cell.config_mathjax();
338 337 this.insert_cell_after(cell, i);
339 338 this.select(this.find_cell_index(cell));
340 339 return this;
341 340 }
342 341
343 342
344 343 Notebook.prototype.text_to_code = function (index) {
345 344 // TODO: Bounds check for i
346 345 var i = this.index_or_selected(index);
347 346 var source_element = this.cell_elements().eq(i);
348 347 var source_cell = source_element.data("cell");
349 348 if (source_cell instanceof IPython.TextCell) {
350 349 this.insert_code_cell_after(i);
351 350 var target_cell = this.cells()[i+1];
352 351 target_cell.set_code(source_cell.get_text());
353 352 source_element.remove();
354 353 };
355 354 };
356 355
357 356
358 357 Notebook.prototype.code_to_text = function (index) {
359 358 // TODO: Bounds check for i
360 359 var i = this.index_or_selected(index);
361 360 var source_element = this.cell_elements().eq(i);
362 361 var source_cell = source_element.data("cell");
363 362 if (source_cell instanceof IPython.CodeCell) {
364 363 this.insert_text_cell_after(i);
365 364 var target_cell = this.cells()[i+1];
366 365 var text = source_cell.get_code();
367 366 if (text === "") {text = target_cell.placeholder;};
368 367 target_cell.set_text(text);
369 368 source_element.remove();
370 369 target_cell.edit();
371 370 };
372 371 };
373 372
374 373
375 374 // Cell collapsing
376 375
377 376 Notebook.prototype.collapse = function (index) {
378 377 var i = this.index_or_selected(index);
379 378 this.cells()[i].collapse();
380 379 };
381 380
382 381
383 382 Notebook.prototype.expand = function (index) {
384 383 var i = this.index_or_selected(index);
385 384 this.cells()[i].expand();
386 385 };
387 386
388 387
389 388 // Kernel related things
390 389
391 390 Notebook.prototype.start_kernel = function () {
392 391 this.kernel = new IPython.Kernel();
393 392 this.kernel.start_kernel($.proxy(this.kernel_started, this));
394 393 };
395 394
396 395
397 396 Notebook.prototype.handle_shell_reply = function (e) {
398 397 reply = $.parseJSON(e.data);
399 398 var header = reply.header;
400 399 var content = reply.content;
401 400 var msg_type = header.msg_type;
402 401 console.log(reply);
403 402 var cell = this.cell_for_msg(reply.parent_header.msg_id);
404 403 if (msg_type === "execute_reply") {
405 404 cell.set_input_prompt(content.execution_count);
406 405 };
407 406 var payload = content.payload || [];
408 407 this.handle_payload(content.payload);
409 408 };
410 409
411 410
412 411 Notebook.prototype.handle_payload = function (payload) {
413 412 var l = payload.length;
414 413 if (l > 0) {
415 414 IPython.pager.clear();
416 415 IPython.pager.expand();
417 416 };
418 417 for (var i=0; i<l; i++) {
419 418 IPython.pager.append_text(payload[i].text);
420 419 };
421 420 };
422 421
423 422
424 423 Notebook.prototype.handle_iopub_reply = function (e) {
425 424 reply = $.parseJSON(e.data);
426 425 var content = reply.content;
427 426 // console.log(reply);
428 427 var msg_type = reply.header.msg_type;
429 428 var cell = this.cell_for_msg(reply.parent_header.msg_id);
430 429 if (msg_type === "stream") {
431 430 cell.expand();
432 431 cell.append_stream(content.data + "\n");
433 432 } else if (msg_type === "display_data") {
434 433 cell.expand();
435 434 cell.append_display_data(content.data);
436 435 } else if (msg_type === "pyout") {
437 436 cell.expand();
438 437 cell.append_pyout(content.data, content.execution_count)
439 438 } else if (msg_type === "pyerr") {
440 439 cell.expand();
441 440 cell.append_pyerr(content.ename, content.evalue, content.traceback);
442 441 } else if (msg_type === "status") {
443 442 if (content.execution_state === "busy") {
444 443 this.kernel.status_busy();
445 444 } else if (content.execution_state === "idle") {
446 445 this.kernel.status_idle();
447 446 };
448 447 }
449 448 };
450 449
451 450
452 451 Notebook.prototype.kernel_started = function () {
453 452 console.log("Kernel started: ", this.kernel.kernel_id);
454 453 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
455 454 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
456 455 };
457 456
458 457
459 458 // Persistance and loading
460 459
461 460
462 461 Notebook.prototype.fromJSON = function (data) {
463 462 var ncells = this.ncells();
464 463 for (var i=0; i<ncells; i++) {
465 464 // Always delete cell 0 as they get renumbered as they are deleted.
466 465 this.delete_cell(0);
467 466 };
468 467 var new_cells = data.cells;
469 468 ncells = new_cells.length;
470 469 var cell_data = null;
471 470 for (var i=0; i<ncells; i++) {
472 471 cell_data = new_cells[i];
473 472 if (cell_data.cell_type == 'code') {
474 473 this.insert_code_cell_after();
475 474 this.selected_cell().fromJSON(cell_data);
476 475 } else if (cell_data.cell_type === 'text') {
477 476 this.insert_text_cell_after();
478 477 this.selected_cell().fromJSON(cell_data);
479 478 };
480 479 };
481 480 };
482 481
483 482
484 483 Notebook.prototype.toJSON = function () {
485 484 var cells = this.cells();
486 485 var ncells = cells.length;
487 486 cell_array = new Array(ncells);
488 487 for (var i=0; i<ncells; i++) {
489 488 cell_array[i] = cells[i].toJSON();
490 489 };
491 490 json = {
492 491 cells : cell_array
493 492 };
494 493 return json
495 494 };
496 495
497 496
498 497 Notebook.prototype.test_filename = function (filename) {
499 498 if (this.notebook_filename_re.test(filename)) {
500 499 return true;
501 500 } else {
502 501 var bad_filename = $('<div/>');
503 502 bad_filename.html(
504 503 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
505 504 );
506 505 bad_filename.dialog({title: 'Invalid filename', modal: true});
507 506 return false;
508 507 };
509 508 };
510 509
511 510 Notebook.prototype.save_notebook = function (filename) {
512 511 this.filename = filename || this.filename || '';
513 512 if (this.filename === '') {
514 513 var no_filename = $('<div/>');
515 514 no_filename.html(
516 515 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
517 516 );
518 517 no_filename.dialog({title: 'Missing filename', modal: true});
519 518 return;
520 519 }
521 520 if (!this.test_filename(this.filename)) {return;}
522 521 var thedata = this.toJSON();
523 522 var settings = {
524 523 processData : false,
525 524 cache : false,
526 525 type : "PUT",
527 526 data : JSON.stringify(thedata),
528 527 success : function (data, status, xhr) {console.log(data);}
529 528 };
530 529 $.ajax("/notebooks/" + this.filename, settings);
531 530 };
532 531
533 532
534 533 Notebook.prototype.load_notebook = function (filename) {
535 534 if (!this.test_filename(filename)) {return;}
536 535 var that = this;
537 536 // We do the call with settings so we can set cache to false.
538 537 var settings = {
539 538 processData : false,
540 539 cache : false,
541 540 type : "GET",
542 541 dataType : "json",
543 542 success : function (data, status, xhr) {
544 543 that.fromJSON(data);
545 544 that.filename = filename;
546 545 that.kernel.restart();
547 546 }
548 547 };
549 548 $.ajax("/notebooks/" + filename, settings);
550 549 }
551 550
552 551 IPython.Notebook = Notebook;
553 552
554 553 return IPython;
555 554
556 555 }(IPython));
557 556
@@ -1,101 +1,105
1 1
2 2 //============================================================================
3 3 // On document ready
4 4 //============================================================================
5 5
6 6
7 7 $(document).ready(function () {
8 8
9 9
10 10 $('div#notebook_app').addClass('border-box-sizing ui-widget ui-widget-content');
11 11 $('div#left_panel').addClass('border-box-sizing ui-widget');
12 12 $('div#left_panel_splitter').addClass('border-box-sizing ui-widget ui-state-default');
13 13 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
14 14 $('div#notebook').addClass('border-box-sizing');
15 15
16 16 $('div#left_panel_splitter').click(function () {
17 17 $('div#left_panel').toggle('fast');
18 18 });
19 19
20 20 $('div#left_panel_splitter').hover(
21 21 function () {
22 22 $('div#left_panel_splitter').addClass('ui-state-hover');
23 23 },
24 24 function () {
25 25 $('div#left_panel_splitter').removeClass('ui-state-hover');
26 26 }
27 27 );
28 28
29 29 MathJax.Hub.Config({
30 30 tex2jax: {
31 31 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
32 32 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
33 33 },
34 34 displayAlign: 'left', // Change this to 'center' to center equations.
35 35 "HTML-CSS": {
36 36 styles: {'.MathJax_Display': {"margin": 0}}
37 37 }
38 38 });
39 39
40 40 var do_resize = function () {
41 41 var win = $(window);
42 42 var w = win.width();
43 43 var h = win.height();
44 44 var header_height = $('div#header').outerHeight(true);
45 var app_height = h - header_height - 2;
45 var app_height = h - header_height - 2; // content height
46 46 var pager_height = $('div#pager').outerHeight(true);
47 47 var pager_splitter_height = $('div#pager_splitter').outerHeight(true);
48 $('div#notebook_app').height(app_height + 2);
48 $('div#notebook_app').height(app_height + 2); // content+padding+border height
49 49 $('div#left_panel').height(app_height);
50 50 $('div#left_panel_splitter').height(app_height);
51 51 $('div#notebook_panel').height(app_height);
52 if (IPython.pager.expanded) {
52 53 $('div#notebook').height(app_height-pager_height-pager_splitter_height);
54 } else {
55 $('div#notebook').height(app_height-pager_splitter_height);
56 }
53 57 console.log('resize: ', app_height);
54 58 };
55 59
56 60 $(window).resize(do_resize);
57 61
58 62 IPython.notebook = new IPython.Notebook('div#notebook');
59 63 IPython.notebook.insert_code_cell_after();
60 64
61 65 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
62 66
63 67 do_resize();
64 68
65 69 // $("#menu_tabs").tabs();
66 70
67 71 // $("#help_toolbar").buttonset();
68 72
69 73 // $("#kernel_toolbar").buttonset();
70 74 // $("#interrupt_kernel").click(function () {IPython.notebook.kernel.interrupt();});
71 75 // $("#restart_kernel").click(function () {IPython.notebook.kernel.restart();});
72 76 // $("#kernel_status").addClass("status_idle");
73 77
74 78 // $("#move_cell").buttonset();
75 79 // $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
76 80 // $("#move_up").button("option", "text", false);
77 81 // $("#move_up").click(function () {IPython.notebook.move_cell_up();});
78 82 // $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
79 83 // $("#move_down").button("option", "text", false);
80 84 // $("#move_down").click(function () {IPython.notebook.move_cell_down();});
81 85
82 86 // $("#insert_delete").buttonset();
83 87 // $("#insert_cell_before").click(function () {IPython.notebook.insert_code_cell_before();});
84 88 // $("#insert_cell_after").click(function () {IPython.notebook.insert_code_cell_after();});
85 89 // $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
86 90 // $("#delete_cell").button("option", "text", false);
87 91 // $("#delete_cell").click(function () {IPython.notebook.delete_cell();});
88 92
89 93 // $("#cell_type").buttonset();
90 94 // $("#to_code").click(function () {IPython.notebook.text_to_code();});
91 95 // $("#to_text").click(function () {IPython.notebook.code_to_text();});
92 96
93 97 // $("#sort").buttonset();
94 98 // $("#sort_cells").click(function () {IPython.notebook.sort_cells();});
95 99
96 100 // $("#toggle").buttonset();
97 101 // $("#collapse").click(function () {IPython.notebook.collapse();});
98 102 // $("#expand").click(function () {IPython.notebook.expand();});
99 103
100 104 });
101 105
General Comments 0
You need to be logged in to leave comments. Login now