##// END OF EJS Templates
Improving the scrolling model.
Brian E. Granger -
Show More
@@ -1,251 +1,248 b''
1 1 /**
2 2 * HTML5 ✰ Boilerplate
3 3 *
4 4 * style.css contains a reset, font normalization and some base styles.
5 5 *
6 6 * Credit is left where credit is due.
7 7 * Much inspiration was taken from these projects:
8 8 * - yui.yahooapis.com/2.8.1/build/base/base.css
9 9 * - camendesign.com/design/
10 10 * - praegnanz.de/weblog/htmlcssjs-kickstart
11 11 */
12 12
13 13
14 14 /**
15 15 * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
16 16 * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark
17 17 * html5doctor.com/html-5-reset-stylesheet/
18 18 */
19 19
20 20 html, body, div, span, object, iframe,
21 21 h1, h2, h3, h4, h5, h6, p, blockquote, pre,
22 22 abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
23 23 small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
24 24 fieldset, form, label, legend,
25 25 table, caption, tbody, tfoot, thead, tr, th, td,
26 26 article, aside, canvas, details, figcaption, figure,
27 27 footer, header, hgroup, menu, nav, section, summary,
28 28 time, mark, audio, video {
29 29 margin: 0;
30 30 padding: 0;
31 31 border: 0;
32 32 /* font-size: 100%;*/
33 33 font: inherit;
34 34 vertical-align: baseline;
35 35 }
36 36
37 37 article, aside, details, figcaption, figure,
38 38 footer, header, hgroup, menu, nav, section {
39 39 display: block;
40 40 }
41 41
42 42 blockquote, q { quotes: none; }
43 43
44 44 blockquote:before, blockquote:after,
45 45 q:before, q:after { content: ""; content: none; }
46 46
47 47 ins { background-color: #ff9; color: #000; text-decoration: none; }
48 48
49 49 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
50 50
51 51 del { text-decoration: line-through; }
52 52
53 53 abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
54 54
55 55 table { border-collapse: collapse; border-spacing: 0; }
56 56
57 57 hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
58 58
59 59 input, select { vertical-align: middle; }
60 60
61 61 body {
62 62 background-color: white;
63 63 /* This won't propagate to all children so we also set it below */
64 font-size: 12pt;
64 font-size: 10pt;
65 65 /* This makes sure that the body covers the entire window and needs to
66 66 be in a different element than the display: box in wrapper below */
67 67 position: absolute;
68 68 left: 0px;
69 69 right: 0px;
70 70 top: 0px;
71 71 bottom: 0px;
72 72 overflow: hidden;
73 73 }
74 74
75 75
76 76 span#ipython_notebook h1 {
77 77 font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
78 78 font-size: 22pt;
79 79 height: 35px;
80 80 padding: 5px;
81 81 margin: 0px;
82 82
83 83 }
84 84
85 div#tools {
86 font-size: 11pt;
87 }
88
89 85 span#kernel_status {
90 86 position: absolute;
91 87 top: 12%;
92 88 right: 10px;
93 89 font-weight: bold;
94 90 }
95 91
96 92 .status_idle {
97 93 color: gray;
98 94 }
99 95
100 96 .status_busy {
101 97 color: red;
102 98 }
103 99
104 100 .status_restarting {
105 101 color: black;
106 102 }
107 103
108 104 div#notebook_app {
109 105 width: 100%;
110 106 position: relative;
111 107 }
112 108
113 109 div#left_panel {
114 110 overflow-y: auto;
115 111 top: 0px;
116 112 left: 0px;
117 113 margin: 0px;
118 114 padding: 0px;
119 115 position: absolute;
120 116 }
121 117
122 118 div#left_panel_splitter {
123 119 width: 8px;
124 120 top: 0px;
125 121 left: 202px;
126 122 margin: 0px;
127 123 padding: 0px;
128 124 position: absolute;
129 125 }
130 126
131 127 div#notebook_panel {
132 128 /* The L margin will be set in the Javascript code*/
133 129 margin: 0px 0px 0px 0px;
134 130 padding: 0px;
135 131 }
136 132
137 133 div#notebook {
138 134 overflow-y: scroll;
139 135 overflow-x: auto;
140 136 width: 100%;
141 padding: 0px 15px 15px 15px;
137 padding: 0px 15px 0px 15px;
142 138 margin: 0px
143 139 background-color: white;
144 font-size: 12pt;
140 font-size: 10pt;
145 141 }
146 142
147 143 div#pager_splitter {
148 144 height: 8px;
149 145 }
150 146
151 147 div#pager {
148 padding: 15px;
152 149 overflow: auto;
153 150 }
154 151
155 152 .monospace-font {
156 153 font-family: monospace;
157 font-size: 12pt;
154 font-size: 10pt;
158 155 }
159 156
160 157 div.cell {
161 158 width: 100%;
162 159 padding: 5px;
163 160 /* This acts as a spacer between cells, that is outside the border */
164 161 margin: 15px 0px 15px 0px;
165 162 }
166 163
167 164 div.code_cell {
168 165 background-color: white;
169 166 }
170 167
171 168 div.prompt {
172 169 width: 90px;
173 170 padding: 0px;
174 171 margin: 0px;
175 172 }
176 173
177 174 div.input_prompt {
178 175 color: navy;
179 176 }
180 177
181 178 div.output {
182 179 /* This is a spacer between the input and output of each cell */
183 180 margin-top: 15px;
184 181 }
185 182
186 183 div.output_prompt {
187 184 color: darkred;
188 185 }
189 186
190 187 div.output_area {
191 188 text-align: left;
192 189 color: black;
193 190 }
194 191
195 192 div.output_latex {
196 193 /* Slightly bigger than the rest of the notebook */
197 font-size: 13pt;
194 font-size: 11pt;
198 195 }
199 196
200 197 div.output_png {
201 198 }
202 199
203 200 div.text_cell {
204 201 background-color: white;
205 202 }
206 203
207 204 textarea.text_cell_input {
208 205 /* Slightly bigger than the rest of the notebook */
209 font-size: 13pt;
206 font-size: 11pt;
210 207 outline: none;
211 208 resize: none;
212 209 width: inherit;
213 210 border-style: none;
214 211 padding: 0px;
215 212 margin: 0px;
216 213 color: black;
217 214 }
218 215
219 216 div.text_cell_render {
220 217 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
221 218 /* Slightly bigger than the rest of the notebook */
222 font-size: 13pt;
219 font-size: 11pt;
223 220 outline: none;
224 221 resize: none;
225 222 width: inherit;
226 223 border-style: none;
227 224 padding: 5px;
228 225 color: black;
229 226 }
230 227
231 228 div.text_cell_render em {font-style: italic;}
232 229 div.text_cell_render strong {font-weight: bold;}
233 230 div.text_cell_render u {text-decoration: underline;}
234 231 div.text_cell_render :link { text-decoration: underline }
235 232 div.text_cell_render :visited { text-decoration: underline }
236 233 div.text_cell_render h1 {font-size: 2.0em; margin: .67em 0; font-weight: bold;}
237 234 div.text_cell_render h2 {font-size: 1.5em; margin: .75em 0; font-weight: bold;}
238 235 div.text_cell_render h3 {font-size: 1.17em; margin: .83em 0; font-weight: bold;}
239 236 div.text_cell_render h4 {margin: 1.12em 0; font-weight: bold;}
240 237 div.text_cell_render h5 {font-size: .83em; margin: 1.5em 0; font-weight: bold;}
241 238 div.text_cell_render h6 {font-size: .75em; margin: 1.67em 0; font-weight: bold;}
242 239 div.text_cell_render ul {list-style:disc; margin-left: 40px;}
243 240 div.text_cell_render ul ul {list-style:square; margin-left: 40px;}
244 241 div.text_cell_render ul ul ul {list-style:circle; margin-left: 40px;}
245 242 div.text_cell_render ol {list-style:upper-roman; margin-left: 40px;}
246 243 div.text_cell_render ol ol {list-style:upper-alpha;}
247 244 div.text_cell_render ol ol ol {list-style:decimal;}
248 245 div.text_cell_render ol ol ol ol {list-style:lower-alpha;}
249 246 div.text_cell_render ol ol ol ol ol {list-style:lower-roman;}
250 247
251 248
@@ -1,571 +1,591 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.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 this.create_elements();
22 23 this.bind_events();
23 24 this.start_kernel();
24 25 };
25 26
26 27
27 28 Notebook.prototype.style = function () {
28 29 $('div#notebook').addClass('border-box-sizing');
29 30 };
30 31
31 32
33 Notebook.prototype.create_elements = function () {
34 // We add this end_space div to the end of the notebook div to:
35 // i) provide a margin between the last cell and the end of the notebook
36 // ii) to prevent the div from scrolling up when the last cell is being
37 // edited, but is too low on the page, which browsers will do automatically.
38 this.element.append($('<div class="end_space"></div>').height(50));
39 $('div#notebook').addClass('border-box-sizing');
40 };
41
42
32 43 Notebook.prototype.bind_events = function () {
33 44 var that = this;
34 45 $(document).keydown(function (event) {
35 46 // console.log(event);
36 47 if (event.which === 38) {
37 48 var cell = that.selected_cell();
38 49 if (cell.at_top()) {
39 50 event.preventDefault();
40 51 that.select_prev();
41 52 };
42 53 } else if (event.which === 40) {
43 54 var cell = that.selected_cell();
44 55 if (cell.at_bottom()) {
45 56 event.preventDefault();
46 57 that.select_next();
47 58 };
48 59 } else if (event.which === 13 && event.shiftKey) {
49 60 // The focus is not quite working here.
50 61 var cell = that.selected_cell();
51 62 var cell_index = that.find_cell_index(cell);
52 63 // TODO: the logic here needs to be moved into appropriate
53 64 // methods of Notebook.
54 65 if (cell instanceof IPython.CodeCell) {
55 66 event.preventDefault();
56 67 cell.clear_output();
57 68 var code = cell.get_code();
58 69 if (that.notebook_load_re.test(code)) {
59 70 var code_parts = code.split(' ');
60 71 if (code_parts.length === 3) {
61 72 that.load_notebook(code_parts[2]);
62 73 };
63 74 } else if (that.notebook_save_re.test(code)) {
64 75 var code_parts = code.split(' ');
65 76 if (code_parts.length === 3) {
66 77 that.save_notebook(code_parts[2]);
67 78 } else {
68 79 that.save_notebook()
69 80 };
70 81 } else {
71 82 var msg_id = that.kernel.execute(cell.get_code());
72 83 that.msg_cell_map[msg_id] = cell.cell_id;
73 84 };
74 85 } else if (cell instanceof IPython.TextCell) {
75 86 event.preventDefault();
76 87 cell.render();
77 88 }
78 89 if (cell_index === (that.ncells()-1)) {
79 90 that.insert_code_cell_after();
91 // If we are adding a new cell at the end, scroll down to show it.
92 that.scroll_to_bottom();
80 93 } else {
81 94 that.select(cell_index+1);
82 95 };
83 96 };
84 97 });
85 98
86 99 this.element.bind('collapse_pager', function () {
87 100 var app_height = $('div#notebook_app').height(); // content height
88 101 var splitter_height = $('div#pager_splitter').outerHeight(true);
89 102 var new_height = app_height - splitter_height;
90 103 that.element.animate({height : new_height + 'px'}, 'fast');
91 104 });
92 105
93 106 this.element.bind('expand_pager', function () {
94 107 var app_height = $('div#notebook_app').height(); // content height
95 108 var splitter_height = $('div#pager_splitter').outerHeight(true);
96 109 var pager_height = $('div#pager').outerHeight(true);
97 110 var new_height = app_height - pager_height - splitter_height;
98 111 that.element.animate({height : new_height + 'px'}, 'fast');
99 112 });
100 113
101 114 this.element.bind('collapse_left_panel', function () {
102 115 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
103 116 var new_margin = splitter_width;
104 117 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
105 118 });
106 119
107 120 this.element.bind('expand_left_panel', function () {
108 121 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
109 122 var left_panel_width = IPython.left_panel.width;
110 123 var new_margin = splitter_width + left_panel_width;
111 124 console.log('expand', splitter_width, left_panel_width, new_margin);
112 125 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
113 126 });
114 127 };
115 128
116 129
130 Notebook.prototype.scroll_to_bottom = function () {
131 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 'slow');
132 };
133
117 134 // Cell indexing, retrieval, etc.
118 135
119 136
120 137 Notebook.prototype.cell_elements = function () {
121 138 return this.element.children("div.cell");
122 139 }
123 140
124 141
125 142 Notebook.prototype.ncells = function (cell) {
126 143 return this.cell_elements().length;
127 144 }
128 145
129 146
130 147 // TODO: we are often calling cells as cells()[i], which we should optimize
131 148 // to cells(i) or a new method.
132 149 Notebook.prototype.cells = function () {
133 150 return this.cell_elements().toArray().map(function (e) {
134 151 return $(e).data("cell");
135 152 });
136 153 }
137 154
138 155
139 156 Notebook.prototype.find_cell_index = function (cell) {
140 157 var result = null;
141 158 this.cell_elements().filter(function (index) {
142 159 if ($(this).data("cell") === cell) {
143 160 result = index;
144 161 };
145 162 });
146 163 return result;
147 164 };
148 165
149 166
150 167 Notebook.prototype.index_or_selected = function (index) {
151 168 return index || this.selected_index() || 0;
152 169 }
153 170
154 171
155 172 Notebook.prototype.select = function (index) {
156 173 if (index !== undefined && index >= 0 && index < this.ncells()) {
157 174 if (this.selected_index() !== null) {
158 175 this.selected_cell().unselect();
159 176 };
160 177 this.cells()[index].select();
178 if (index === (this.ncells()-1)) {
179 this.scroll_to_bottom();
180 };
161 181 };
162 182 return this;
163 183 };
164 184
165 185
166 186 Notebook.prototype.select_next = function () {
167 187 var index = this.selected_index();
168 188 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
169 189 this.select(index+1);
170 190 };
171 191 return this;
172 192 };
173 193
174 194
175 195 Notebook.prototype.select_prev = function () {
176 196 var index = this.selected_index();
177 197 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
178 198 this.select(index-1);
179 199 };
180 200 return this;
181 201 };
182 202
183 203
184 204 Notebook.prototype.selected_index = function () {
185 205 var result = null;
186 206 this.cell_elements().filter(function (index) {
187 207 if ($(this).data("cell").selected === true) {
188 208 result = index;
189 209 };
190 210 });
191 211 return result;
192 212 };
193 213
194 214
195 215 Notebook.prototype.cell_for_msg = function (msg_id) {
196 216 var cell_id = this.msg_cell_map[msg_id];
197 217 var result = null;
198 218 this.cell_elements().filter(function (index) {
199 219 cell = $(this).data("cell");
200 220 if (cell.cell_id === cell_id) {
201 221 result = cell;
202 222 };
203 223 });
204 224 return result;
205 225 };
206 226
207 227
208 228 Notebook.prototype.selected_cell = function () {
209 229 return this.cell_elements().eq(this.selected_index()).data("cell");
210 230 }
211 231
212 232
213 233 // Cell insertion, deletion and moving.
214 234
215 235
216 236 Notebook.prototype.delete_cell = function (index) {
217 237 var i = index || this.selected_index();
218 238 if (i !== null && i >= 0 && i < this.ncells()) {
219 239 this.cell_elements().eq(i).remove();
220 240 if (i === (this.ncells())) {
221 241 this.select(i-1);
222 242 } else {
223 243 this.select(i);
224 244 };
225 245 };
226 246 return this;
227 247 };
228 248
229 249
230 250 Notebook.prototype.append_cell = function (cell) {
231 this.element.append(cell.element);
251 this.element.find('div.end_space').before(cell.element);
232 252 return this;
233 253 };
234 254
235 255
236 256 Notebook.prototype.insert_cell_after = function (cell, index) {
237 257 var ncells = this.ncells();
238 258 if (ncells === 0) {
239 259 this.append_cell(cell);
240 260 return this;
241 261 };
242 262 if (index >= 0 && index < ncells) {
243 263 this.cell_elements().eq(index).after(cell.element);
244 264 };
245 265 return this
246 266 };
247 267
248 268
249 269 Notebook.prototype.insert_cell_before = function (cell, index) {
250 270 var ncells = this.ncells();
251 271 if (ncells === 0) {
252 272 this.append_cell(cell);
253 273 return this;
254 274 };
255 275 if (index >= 0 && index < ncells) {
256 276 this.cell_elements().eq(index).before(cell.element);
257 277 };
258 278 return this;
259 279 };
260 280
261 281
262 282 Notebook.prototype.move_cell_up = function (index) {
263 283 var i = index || this.selected_index();
264 284 if (i !== null && i < this.ncells() && i > 0) {
265 285 var pivot = this.cell_elements().eq(i-1);
266 286 var tomove = this.cell_elements().eq(i);
267 287 if (pivot !== null && tomove !== null) {
268 288 tomove.detach();
269 289 pivot.before(tomove);
270 290 this.select(i-1);
271 291 };
272 292 };
273 293 return this;
274 294 }
275 295
276 296
277 297 Notebook.prototype.move_cell_down = function (index) {
278 298 var i = index || this.selected_index();
279 299 if (i !== null && i < (this.ncells()-1) && i >= 0) {
280 300 var pivot = this.cell_elements().eq(i+1)
281 301 var tomove = this.cell_elements().eq(i)
282 302 if (pivot !== null && tomove !== null) {
283 303 tomove.detach();
284 304 pivot.after(tomove);
285 305 this.select(i+1);
286 306 };
287 307 };
288 308 return this;
289 309 }
290 310
291 311
292 312 Notebook.prototype.sort_cells = function () {
293 313 var ncells = this.ncells();
294 314 var sindex = this.selected_index();
295 315 var swapped;
296 316 do {
297 317 swapped = false
298 318 for (var i=1; i<ncells; i++) {
299 319 current = this.cell_elements().eq(i).data("cell");
300 320 previous = this.cell_elements().eq(i-1).data("cell");
301 321 if (previous.input_prompt_number > current.input_prompt_number) {
302 322 this.move_cell_up(i);
303 323 swapped = true;
304 324 };
305 325 };
306 326 } while (swapped);
307 327 this.select(sindex);
308 328 return this;
309 329 };
310 330
311 331
312 332 Notebook.prototype.insert_code_cell_before = function (index) {
313 333 // TODO: Bounds check for i
314 334 var i = this.index_or_selected(index);
315 335 var cell = new IPython.CodeCell(this);
316 336 cell.set_input_prompt(this.next_prompt_number);
317 337 this.next_prompt_number = this.next_prompt_number + 1;
318 338 this.insert_cell_before(cell, i);
319 339 this.select(this.find_cell_index(cell));
320 340 return this;
321 341 }
322 342
323 343
324 344 Notebook.prototype.insert_code_cell_after = function (index) {
325 345 // TODO: Bounds check for i
326 346 var i = this.index_or_selected(index);
327 347 var cell = new IPython.CodeCell(this);
328 348 cell.set_input_prompt(this.next_prompt_number);
329 349 this.next_prompt_number = this.next_prompt_number + 1;
330 350 this.insert_cell_after(cell, i);
331 351 this.select(this.find_cell_index(cell));
332 352 return this;
333 353 }
334 354
335 355
336 356 Notebook.prototype.insert_text_cell_before = function (index) {
337 357 // TODO: Bounds check for i
338 358 var i = this.index_or_selected(index);
339 359 var cell = new IPython.TextCell(this);
340 360 cell.config_mathjax();
341 361 this.insert_cell_before(cell, i);
342 362 this.select(this.find_cell_index(cell));
343 363 return this;
344 364 }
345 365
346 366
347 367 Notebook.prototype.insert_text_cell_after = function (index) {
348 368 // TODO: Bounds check for i
349 369 var i = this.index_or_selected(index);
350 370 var cell = new IPython.TextCell(this);
351 371 cell.config_mathjax();
352 372 this.insert_cell_after(cell, i);
353 373 this.select(this.find_cell_index(cell));
354 374 return this;
355 375 }
356 376
357 377
358 378 Notebook.prototype.text_to_code = function (index) {
359 379 // TODO: Bounds check for i
360 380 var i = this.index_or_selected(index);
361 381 var source_element = this.cell_elements().eq(i);
362 382 var source_cell = source_element.data("cell");
363 383 if (source_cell instanceof IPython.TextCell) {
364 384 this.insert_code_cell_after(i);
365 385 var target_cell = this.cells()[i+1];
366 386 target_cell.set_code(source_cell.get_text());
367 387 source_element.remove();
368 388 };
369 389 };
370 390
371 391
372 392 Notebook.prototype.code_to_text = function (index) {
373 393 // TODO: Bounds check for i
374 394 var i = this.index_or_selected(index);
375 395 var source_element = this.cell_elements().eq(i);
376 396 var source_cell = source_element.data("cell");
377 397 if (source_cell instanceof IPython.CodeCell) {
378 398 this.insert_text_cell_after(i);
379 399 var target_cell = this.cells()[i+1];
380 400 var text = source_cell.get_code();
381 401 if (text === "") {text = target_cell.placeholder;};
382 402 target_cell.set_text(text);
383 403 source_element.remove();
384 404 target_cell.edit();
385 405 };
386 406 };
387 407
388 408
389 409 // Cell collapsing
390 410
391 411 Notebook.prototype.collapse = function (index) {
392 412 var i = this.index_or_selected(index);
393 413 this.cells()[i].collapse();
394 414 };
395 415
396 416
397 417 Notebook.prototype.expand = function (index) {
398 418 var i = this.index_or_selected(index);
399 419 this.cells()[i].expand();
400 420 };
401 421
402 422
403 423 // Kernel related things
404 424
405 425 Notebook.prototype.start_kernel = function () {
406 426 this.kernel = new IPython.Kernel();
407 427 this.kernel.start_kernel($.proxy(this.kernel_started, this));
408 428 };
409 429
410 430
411 431 Notebook.prototype.handle_shell_reply = function (e) {
412 432 reply = $.parseJSON(e.data);
413 433 var header = reply.header;
414 434 var content = reply.content;
415 435 var msg_type = header.msg_type;
416 436 console.log(reply);
417 437 var cell = this.cell_for_msg(reply.parent_header.msg_id);
418 438 if (msg_type === "execute_reply") {
419 439 cell.set_input_prompt(content.execution_count);
420 440 };
421 441 var payload = content.payload || [];
422 442 this.handle_payload(content.payload);
423 443 };
424 444
425 445
426 446 Notebook.prototype.handle_payload = function (payload) {
427 447 var l = payload.length;
428 448 if (l > 0) {
429 449 IPython.pager.clear();
430 450 IPython.pager.expand();
431 451 };
432 452 for (var i=0; i<l; i++) {
433 453 IPython.pager.append_text(payload[i].text);
434 454 };
435 455 };
436 456
437 457
438 458 Notebook.prototype.handle_iopub_reply = function (e) {
439 459 reply = $.parseJSON(e.data);
440 460 var content = reply.content;
441 461 // console.log(reply);
442 462 var msg_type = reply.header.msg_type;
443 463 var cell = this.cell_for_msg(reply.parent_header.msg_id);
444 464 if (msg_type === "stream") {
445 465 cell.expand();
446 466 cell.append_stream(content.data + "\n");
447 467 } else if (msg_type === "display_data") {
448 468 cell.expand();
449 469 cell.append_display_data(content.data);
450 470 } else if (msg_type === "pyout") {
451 471 cell.expand();
452 472 cell.append_pyout(content.data, content.execution_count)
453 473 } else if (msg_type === "pyerr") {
454 474 cell.expand();
455 475 cell.append_pyerr(content.ename, content.evalue, content.traceback);
456 476 } else if (msg_type === "status") {
457 477 if (content.execution_state === "busy") {
458 478 this.kernel.status_busy();
459 479 } else if (content.execution_state === "idle") {
460 480 this.kernel.status_idle();
461 481 };
462 482 }
463 483 };
464 484
465 485
466 486 Notebook.prototype.kernel_started = function () {
467 487 console.log("Kernel started: ", this.kernel.kernel_id);
468 488 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
469 489 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
470 490 };
471 491
472 492
473 493 // Persistance and loading
474 494
475 495
476 496 Notebook.prototype.fromJSON = function (data) {
477 497 var ncells = this.ncells();
478 498 for (var i=0; i<ncells; i++) {
479 499 // Always delete cell 0 as they get renumbered as they are deleted.
480 500 this.delete_cell(0);
481 501 };
482 502 var new_cells = data.cells;
483 503 ncells = new_cells.length;
484 504 var cell_data = null;
485 505 for (var i=0; i<ncells; i++) {
486 506 cell_data = new_cells[i];
487 507 if (cell_data.cell_type == 'code') {
488 508 this.insert_code_cell_after();
489 509 this.selected_cell().fromJSON(cell_data);
490 510 } else if (cell_data.cell_type === 'text') {
491 511 this.insert_text_cell_after();
492 512 this.selected_cell().fromJSON(cell_data);
493 513 };
494 514 };
495 515 };
496 516
497 517
498 518 Notebook.prototype.toJSON = function () {
499 519 var cells = this.cells();
500 520 var ncells = cells.length;
501 521 cell_array = new Array(ncells);
502 522 for (var i=0; i<ncells; i++) {
503 523 cell_array[i] = cells[i].toJSON();
504 524 };
505 525 json = {
506 526 cells : cell_array
507 527 };
508 528 return json
509 529 };
510 530
511 531
512 532 Notebook.prototype.test_filename = function (filename) {
513 533 if (this.notebook_filename_re.test(filename)) {
514 534 return true;
515 535 } else {
516 536 var bad_filename = $('<div/>');
517 537 bad_filename.html(
518 538 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
519 539 );
520 540 bad_filename.dialog({title: 'Invalid filename', modal: true});
521 541 return false;
522 542 };
523 543 };
524 544
525 545 Notebook.prototype.save_notebook = function (filename) {
526 546 this.filename = filename || this.filename || '';
527 547 if (this.filename === '') {
528 548 var no_filename = $('<div/>');
529 549 no_filename.html(
530 550 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
531 551 );
532 552 no_filename.dialog({title: 'Missing filename', modal: true});
533 553 return;
534 554 }
535 555 if (!this.test_filename(this.filename)) {return;}
536 556 var thedata = this.toJSON();
537 557 var settings = {
538 558 processData : false,
539 559 cache : false,
540 560 type : "PUT",
541 561 data : JSON.stringify(thedata),
542 562 success : function (data, status, xhr) {console.log(data);}
543 563 };
544 564 $.ajax("/notebooks/" + this.filename, settings);
545 565 };
546 566
547 567
548 568 Notebook.prototype.load_notebook = function (filename) {
549 569 if (!this.test_filename(filename)) {return;}
550 570 var that = this;
551 571 // We do the call with settings so we can set cache to false.
552 572 var settings = {
553 573 processData : false,
554 574 cache : false,
555 575 type : "GET",
556 576 dataType : "json",
557 577 success : function (data, status, xhr) {
558 578 that.fromJSON(data);
559 579 that.filename = filename;
560 580 that.kernel.restart();
561 581 }
562 582 };
563 583 $.ajax("/notebooks/" + filename, settings);
564 584 }
565 585
566 586 IPython.Notebook = Notebook;
567 587
568 588 return IPython;
569 589
570 590 }(IPython));
571 591
General Comments 0
You need to be logged in to leave comments. Login now