##// END OF EJS Templates
Align colons in help dialog.
Stefan van der Walt -
Show More
@@ -1,313 +1,321
1 1
2 2 /**
3 3 * Primary styles
4 4 *
5 5 * Author: IPython Development Team
6 6 */
7 7
8 8
9 9 body {
10 10 background-color: white;
11 11 /* This makes sure that the body covers the entire window and needs to
12 12 be in a different element than the display: box in wrapper below */
13 13 position: absolute;
14 14 left: 0px;
15 15 right: 0px;
16 16 top: 0px;
17 17 bottom: 0px;
18 18 overflow: hidden;
19 19 }
20 20
21 21 span#save_widget {
22 22 position: absolute;
23 23 left: 0px;
24 24 padding: 5px 0px;
25 25 margin: 0px 0px 0px 0px;
26 26 }
27 27
28 28 input#notebook_name {
29 29 height: 1em;
30 30 line-height: 1em;
31 31 padding: 5px;
32 32 }
33 33
34 34 span#kernel_status {
35 35 position: absolute;
36 36 padding: 8px 5px 5px 5px;
37 37 right: 10px;
38 38 font-weight: bold;
39 39 }
40 40
41 41 .status_idle {
42 42 color: gray;
43 43 }
44 44
45 45 .status_busy {
46 46 color: red;
47 47 }
48 48
49 49 .status_restarting {
50 50 color: black;
51 51 }
52 52
53 53 div#left_panel {
54 54 overflow-y: auto;
55 55 top: 0px;
56 56 left: 0px;
57 57 margin: 0px;
58 58 padding: 0px;
59 59 position: absolute;
60 60 }
61 61
62 62 h3.section_header {
63 63 padding: 5px;
64 64 }
65 65
66 66 div.section_content {
67 67 padding: 5px;
68 68 }
69 69
70 70 span.section_row_buttons button {
71 71 width: 70px;
72 72 }
73 73
74 74 span.section_row_buttons a {
75 75 width: 70px;
76 76 }
77 77
78 78 .section_row {
79 79 margin: 5px 0px;
80 80 }
81 81
82 82 .section_row_buttons {
83 83 float: right;
84 84 }
85 85
86 86 #kernel_persist {
87 87 float: right;
88 88 }
89 89
90 90 .help_string {
91 91 float: right;
92 92 width: 170px;
93 93 padding: 0px 5px;
94 94 text-align: left;
95 95 font-size: 85%;
96 96 }
97 97
98 98 .help_string_label {
99 99 float: right;
100 100 font-size: 85%;
101 101 }
102 102
103 103 #autoindent_span {
104 104 float: right;
105 105 }
106 106
107 107 .checkbox_label {
108 108 font-size: 85%;
109 109 float: right;
110 110 padding: 0.3em;
111 111 }
112 112
113 113 .section_row_header {
114 114 float: left;
115 115 font-size: 85%;
116 116 padding: 0.4em 0em;
117 117 font-weight: bold;
118 118 }
119 119
120 120 span.button_label {
121 121 padding: 0.2em 1em;
122 122 font-size: 77%;
123 123 float: right;
124 124 }
125 125
126 126 /* This is needed because FF was adding a 2px margin top and bottom. */
127 127 .section_row .ui-button {
128 128 margin-top: 0px;
129 129 margin-bottom: 0px;
130 130 }
131 131
132 132 #download_format {
133 133 float: right;
134 134 font-size: 85%;
135 135 width: 62px;
136 136 margin: 1px 5px;
137 137 }
138 138
139 139 div#left_panel_splitter {
140 140 width: 8px;
141 141 top: 0px;
142 142 left: 202px;
143 143 margin: 0px;
144 144 padding: 0px;
145 145 position: absolute;
146 146 }
147 147
148 148 div#notebook_panel {
149 149 /* The L margin will be set in the Javascript code*/
150 150 margin: 0px 0px 0px 0px;
151 151 padding: 0px;
152 152 }
153 153
154 154 div#notebook {
155 155 overflow-y: scroll;
156 156 overflow-x: auto;
157 157 width: 100%;
158 158 /* This spaces the cell away from the edge of the notebook area */
159 159 padding: 15px 15px 15px 15px;
160 160 margin: 0px
161 161 background-color: white;
162 162 }
163 163
164 164 div#pager_splitter {
165 165 height: 8px;
166 166 }
167 167
168 168 div#pager {
169 169 padding: 15px;
170 170 overflow: auto;
171 171 }
172 172
173 173 div.cell {
174 174 width: 100%;
175 175 padding: 5px;
176 176 /* This acts as a spacer between cells, that is outside the border */
177 177 margin: 5px 0px 5px 0px;
178 178 }
179 179
180 180 div.code_cell {
181 181 background-color: white;
182 182 }
183 183
184 184 div.prompt {
185 185 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
186 186 width: 11ex;
187 187 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
188 188 padding: 0.4em;
189 189 margin: 0px;
190 190 font-family: monospace;
191 191 text-align:right;
192 192 }
193 193
194 194 div.input {
195 195 page-break-inside: avoid;
196 196 }
197 197
198 198 div.input_area {
199 199 color: black;
200 200 }
201 201
202 202 div.input_prompt {
203 203 color: navy;
204 204 }
205 205
206 206 div.output {
207 207 /* This is a spacer between the input and output of each cell */
208 208 margin-top: 5px;
209 209 }
210 210
211 211 div.output_prompt {
212 212 color: darkred;
213 213 }
214 214
215 215 /* This class is the outer container of all output sections. */
216 216 div.output_area {
217 217 padding: 0px;
218 218 page-break-inside: avoid;
219 219 }
220 220
221 221 /* This class is for the output subarea inside the output_area and after
222 222 the prompt div. */
223 223 div.output_subarea {
224 224 padding: 0.4em;
225 225 }
226 226
227 227 /* The rest of the output_* classes are for special styling of the different
228 228 output types */
229 229
230 230 div.output_stream {
231 231 text-align: left;
232 232 color: black;
233 233 font-family: monospace;
234 234 }
235 235
236 236 div.output_latex {
237 237 text-align: left;
238 238 color: black;
239 239 }
240 240
241 241 div.output_html {
242 242 }
243 243
244 244 div.output_png {
245 245 }
246 246
247 247 div.output_jpeg {
248 248 }
249 249
250 250 div.text_cell {
251 251 background-color: white;
252 252 }
253 253
254 254 div.text_cell_input {
255 255 color: black;
256 256 }
257 257
258 258 div.text_cell_render {
259 259 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
260 260 outline: none;
261 261 resize: none;
262 262 width: inherit;
263 263 border-style: none;
264 264 padding: 5px;
265 265 color: black;
266 266 }
267 267
268 268 .CodeMirror {
269 269 line-height: 1.231; /* Changed from 1em to our global default */
270 270 }
271 271
272 272 .CodeMirror-scroll {
273 273 height: auto; /* Changed to auto to autogrow */
274 274 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
275 275 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
276 276 overflow-y: hidden;
277 277 overflow-x: auto; /* Changed from auto to remove scrollbar */
278 278 }
279 279
280 280 /* CSS font colors for translated ANSI colors. */
281 281
282 282
283 283 .ansiblack {color: black;}
284 284 .ansired {color: darkred;}
285 285 .ansigreen {color: darkgreen;}
286 286 .ansiyellow {color: brown;}
287 287 .ansiblue {color: darkblue;}
288 288 .ansipurple {color: darkviolet;}
289 289 .ansicyan {color: steelblue;}
290 290 .ansigrey {color: grey;}
291 291 .ansibold {font-weight: bold;}
292 292
293 293 .completions {
294 294 position: absolute;
295 295 z-index: 10;
296 296 overflow: auto;
297 297 border: 1px solid black;
298 298 }
299 299
300 300 .completions select {
301 301 background: white;
302 302 outline: none;
303 303 border: none;
304 304 padding: 0px;
305 305 margin: 0px;
306 306 font-family: monospace;
307 307 }
308 308
309 309 @media print {
310 310 body { overflow: visible !important; }
311 311 .ui-widget-content { border: 0px; }
312 312 }
313 313
314 .shortcut_key {
315 display: inline-block;
316 width: 10ex;
317 text-align: right;
318 }
319
320 .shortcut_descr {
321 } No newline at end of file
@@ -1,930 +1,930
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.element = $(selector);
18 18 this.element.scroll();
19 19 this.element.data("notebook", this);
20 20 this.next_prompt_number = 1;
21 21 this.kernel = null;
22 22 this.dirty = false;
23 23 this.msg_cell_map = {};
24 24 this.metadata = {};
25 25 this.control_key_active = false;
26 26 this.style();
27 27 this.create_elements();
28 28 this.bind_events();
29 29 };
30 30
31 31
32 32 Notebook.prototype.style = function () {
33 33 $('div#notebook').addClass('border-box-sizing');
34 34 };
35 35
36 36
37 37 Notebook.prototype.create_elements = function () {
38 38 // We add this end_space div to the end of the notebook div to:
39 39 // i) provide a margin between the last cell and the end of the notebook
40 40 // ii) to prevent the div from scrolling up when the last cell is being
41 41 // edited, but is too low on the page, which browsers will do automatically.
42 42 var that = this;
43 43 var end_space = $('<div class="end_space"></div>').height(150);
44 44 end_space.dblclick(function (e) {
45 45 var ncells = that.ncells();
46 46 that.insert_code_cell_after(ncells-1);
47 47 });
48 48 this.element.append(end_space);
49 49 $('div#notebook').addClass('border-box-sizing');
50 50 };
51 51
52 52
53 53 Notebook.prototype.bind_events = function () {
54 54 var that = this;
55 55 $(document).keydown(function (event) {
56 56 // console.log(event);
57 57 if (event.which === 38) {
58 58 var cell = that.selected_cell();
59 59 if (cell.at_top()) {
60 60 event.preventDefault();
61 61 that.select_prev();
62 62 };
63 63 } else if (event.which === 40) {
64 64 var cell = that.selected_cell();
65 65 if (cell.at_bottom()) {
66 66 event.preventDefault();
67 67 that.select_next();
68 68 };
69 69 } else if (event.which === 13 && event.shiftKey) {
70 70 that.execute_selected_cell();
71 71 return false;
72 72 } else if (event.which === 13 && event.ctrlKey) {
73 73 that.execute_selected_cell({terminal:true});
74 74 return false;
75 75 } else if (event.which === 77 && event.ctrlKey) {
76 76 that.control_key_active = true;
77 77 return false;
78 78 } else if (event.which === 68 && that.control_key_active) {
79 79 // Delete selected cell = d
80 80 that.delete_cell();
81 81 that.control_key_active = false;
82 82 return false;
83 83 } else if (event.which === 65 && that.control_key_active) {
84 84 // Insert code cell after selected = a
85 85 that.insert_code_cell_after();
86 86 that.control_key_active = false;
87 87 return false;
88 88 } else if (event.which === 66 && that.control_key_active) {
89 89 // Insert code cell before selected = b
90 90 that.insert_code_cell_before();
91 91 that.control_key_active = false;
92 92 return false;
93 93 } else if (event.which === 67 && that.control_key_active) {
94 94 // To code = c
95 95 that.to_code();
96 96 that.control_key_active = false;
97 97 return false;
98 98 } else if (event.which === 77 && that.control_key_active) {
99 99 // To markdown = m
100 100 that.to_markdown();
101 101 that.control_key_active = false;
102 102 return false;
103 103 } else if (event.which === 84 && that.control_key_active) {
104 104 // Toggle output = t
105 105 that.toggle_output();
106 106 that.control_key_active = false;
107 107 return false;
108 108 } else if (event.which === 83 && that.control_key_active) {
109 109 // Save notebook = s
110 110 IPython.save_widget.save_notebook();
111 111 that.control_key_active = false;
112 112 return false;
113 113 } else if (event.which === 74 && that.control_key_active) {
114 114 // Move cell down = j
115 115 that.move_cell_down();
116 116 that.control_key_active = false;
117 117 return false;
118 118 } else if (event.which === 75 && that.control_key_active) {
119 119 // Move cell up = k
120 120 that.move_cell_up();
121 121 that.control_key_active = false;
122 122 return false;
123 123 } else if (event.which === 80 && that.control_key_active) {
124 124 // Select previous = p
125 125 that.select_prev();
126 126 that.control_key_active = false;
127 127 return false;
128 128 } else if (event.which === 78 && that.control_key_active) {
129 129 // Select next = n
130 130 that.select_next();
131 131 that.control_key_active = false;
132 132 return false;
133 133 } else if (event.which === 72 && that.control_key_active) {
134 134 // Show keyboard shortcuts = h
135 135 that.show_keyboard_shortcuts();
136 136 that.control_key_active = false;
137 137 return false;
138 138 } else if (that.control_key_active) {
139 139 that.control_key_active = false;
140 140 return true;
141 141 };
142 142 });
143 143
144 144 this.element.bind('collapse_pager', function () {
145 145 var app_height = $('div#main_app').height(); // content height
146 146 var splitter_height = $('div#pager_splitter').outerHeight(true);
147 147 var new_height = app_height - splitter_height;
148 148 that.element.animate({height : new_height + 'px'}, 'fast');
149 149 });
150 150
151 151 this.element.bind('expand_pager', function () {
152 152 var app_height = $('div#main_app').height(); // content height
153 153 var splitter_height = $('div#pager_splitter').outerHeight(true);
154 154 var pager_height = $('div#pager').outerHeight(true);
155 155 var new_height = app_height - pager_height - splitter_height;
156 156 that.element.animate({height : new_height + 'px'}, 'fast');
157 157 });
158 158
159 159 this.element.bind('collapse_left_panel', function () {
160 160 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
161 161 var new_margin = splitter_width;
162 162 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
163 163 });
164 164
165 165 this.element.bind('expand_left_panel', function () {
166 166 var splitter_width = $('div#left_panel_splitter').outerWidth(true);
167 167 var left_panel_width = IPython.left_panel.width;
168 168 var new_margin = splitter_width + left_panel_width;
169 169 $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast');
170 170 });
171 171
172 172 $(window).bind('beforeunload', function () {
173 173 var kill_kernel = $('#kill_kernel').prop('checked');
174 174 if (kill_kernel) {
175 175 that.kernel.kill();
176 176 }
177 177 if (that.dirty) {
178 178 return "You have unsaved changes that will be lost if you leave this page.";
179 179 };
180 180 });
181 181 };
182 182
183 183
184 184 Notebook.prototype.show_keyboard_shortcuts = function () {
185 185 var dialog = $('<div/>');
186 186 var shortcuts = [
187 187 {key: 'Shift-Enter', help: 'run cell'},
188 188 {key: 'Ctrl-Enter', help: 'run cell in terminal mode'},
189 189 {key: 'Ctrl-m d', help: 'delete cell'},
190 190 {key: 'Ctrl-m a', help: 'insert cell above'},
191 191 {key: 'Ctrl-m b', help: 'insert cell below'},
192 192 {key: 'Ctrl-m t', help: 'toggle output'},
193 193 {key: 'Ctrl-m s', help: 'save notebook'},
194 194 {key: 'Ctrl-m j', help: 'move cell down'},
195 195 {key: 'Ctrl-m k', help: 'move cell up'},
196 196 {key: 'Ctrl-m c', help: 'code cell'},
197 197 {key: 'Ctrl-m m', help: 'markdown cell'},
198 198 {key: 'Ctrl-m p', help: 'select previous'},
199 199 {key: 'Ctrl-m n', help: 'select next'},
200 200 {key: 'Ctrl-m h', help: 'display keyboard shortcuts'}
201 201 ];
202 202 for (var i=0; i<shortcuts.length; i++) {
203 203 dialog.append($('<div>').
204 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key+' : ')).
205 append($('<span/>').html(shortcuts[i].help))
204 append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)).
205 append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
206 206 );
207 207 };
208 208 dialog.dialog({title: 'Keyboard shortcuts'});
209 209 };
210 210
211 211
212 212 Notebook.prototype.scroll_to_bottom = function () {
213 213 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
214 214 };
215 215
216 216
217 217 Notebook.prototype.scroll_to_top = function () {
218 218 this.element.animate({scrollTop:0}, 0);
219 219 };
220 220
221 221
222 222 // Cell indexing, retrieval, etc.
223 223
224 224
225 225 Notebook.prototype.cell_elements = function () {
226 226 return this.element.children("div.cell");
227 227 }
228 228
229 229
230 230 Notebook.prototype.ncells = function (cell) {
231 231 return this.cell_elements().length;
232 232 }
233 233
234 234
235 235 // TODO: we are often calling cells as cells()[i], which we should optimize
236 236 // to cells(i) or a new method.
237 237 Notebook.prototype.cells = function () {
238 238 return this.cell_elements().toArray().map(function (e) {
239 239 return $(e).data("cell");
240 240 });
241 241 }
242 242
243 243
244 244 Notebook.prototype.find_cell_index = function (cell) {
245 245 var result = null;
246 246 this.cell_elements().filter(function (index) {
247 247 if ($(this).data("cell") === cell) {
248 248 result = index;
249 249 };
250 250 });
251 251 return result;
252 252 };
253 253
254 254
255 255 Notebook.prototype.index_or_selected = function (index) {
256 256 return index || this.selected_index() || 0;
257 257 }
258 258
259 259
260 260 Notebook.prototype.select = function (index) {
261 261 if (index !== undefined && index >= 0 && index < this.ncells()) {
262 262 if (this.selected_index() !== null) {
263 263 this.selected_cell().unselect();
264 264 };
265 265 this.cells()[index].select();
266 266 };
267 267 return this;
268 268 };
269 269
270 270
271 271 Notebook.prototype.select_next = function () {
272 272 var index = this.selected_index();
273 273 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
274 274 this.select(index+1);
275 275 };
276 276 return this;
277 277 };
278 278
279 279
280 280 Notebook.prototype.select_prev = function () {
281 281 var index = this.selected_index();
282 282 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
283 283 this.select(index-1);
284 284 };
285 285 return this;
286 286 };
287 287
288 288
289 289 Notebook.prototype.selected_index = function () {
290 290 var result = null;
291 291 this.cell_elements().filter(function (index) {
292 292 if ($(this).data("cell").selected === true) {
293 293 result = index;
294 294 };
295 295 });
296 296 return result;
297 297 };
298 298
299 299
300 300 Notebook.prototype.cell_for_msg = function (msg_id) {
301 301 var cell_id = this.msg_cell_map[msg_id];
302 302 var result = null;
303 303 this.cell_elements().filter(function (index) {
304 304 cell = $(this).data("cell");
305 305 if (cell.cell_id === cell_id) {
306 306 result = cell;
307 307 };
308 308 });
309 309 return result;
310 310 };
311 311
312 312
313 313 Notebook.prototype.selected_cell = function () {
314 314 return this.cell_elements().eq(this.selected_index()).data("cell");
315 315 }
316 316
317 317
318 318 // Cell insertion, deletion and moving.
319 319
320 320
321 321 Notebook.prototype.delete_cell = function (index) {
322 322 var i = index || this.selected_index();
323 323 if (i !== null && i >= 0 && i < this.ncells()) {
324 324 this.cell_elements().eq(i).remove();
325 325 if (i === (this.ncells())) {
326 326 this.select(i-1);
327 327 } else {
328 328 this.select(i);
329 329 };
330 330 };
331 331 this.dirty = true;
332 332 return this;
333 333 };
334 334
335 335
336 336 Notebook.prototype.append_cell = function (cell) {
337 337 this.element.find('div.end_space').before(cell.element);
338 338 this.dirty = true;
339 339 return this;
340 340 };
341 341
342 342
343 343 Notebook.prototype.insert_cell_after = function (cell, index) {
344 344 var ncells = this.ncells();
345 345 if (ncells === 0) {
346 346 this.append_cell(cell);
347 347 return this;
348 348 };
349 349 if (index >= 0 && index < ncells) {
350 350 this.cell_elements().eq(index).after(cell.element);
351 351 };
352 352 this.dirty = true;
353 353 return this
354 354 };
355 355
356 356
357 357 Notebook.prototype.insert_cell_before = function (cell, index) {
358 358 var ncells = this.ncells();
359 359 if (ncells === 0) {
360 360 this.append_cell(cell);
361 361 return this;
362 362 };
363 363 if (index >= 0 && index < ncells) {
364 364 this.cell_elements().eq(index).before(cell.element);
365 365 };
366 366 this.dirty = true;
367 367 return this;
368 368 };
369 369
370 370
371 371 Notebook.prototype.move_cell_up = function (index) {
372 372 var i = index || this.selected_index();
373 373 if (i !== null && i < this.ncells() && i > 0) {
374 374 var pivot = this.cell_elements().eq(i-1);
375 375 var tomove = this.cell_elements().eq(i);
376 376 if (pivot !== null && tomove !== null) {
377 377 tomove.detach();
378 378 pivot.before(tomove);
379 379 this.select(i-1);
380 380 };
381 381 };
382 382 this.dirty = true;
383 383 return this;
384 384 }
385 385
386 386
387 387 Notebook.prototype.move_cell_down = function (index) {
388 388 var i = index || this.selected_index();
389 389 if (i !== null && i < (this.ncells()-1) && i >= 0) {
390 390 var pivot = this.cell_elements().eq(i+1)
391 391 var tomove = this.cell_elements().eq(i)
392 392 if (pivot !== null && tomove !== null) {
393 393 tomove.detach();
394 394 pivot.after(tomove);
395 395 this.select(i+1);
396 396 };
397 397 };
398 398 this.dirty = true;
399 399 return this;
400 400 }
401 401
402 402
403 403 Notebook.prototype.sort_cells = function () {
404 404 var ncells = this.ncells();
405 405 var sindex = this.selected_index();
406 406 var swapped;
407 407 do {
408 408 swapped = false
409 409 for (var i=1; i<ncells; i++) {
410 410 current = this.cell_elements().eq(i).data("cell");
411 411 previous = this.cell_elements().eq(i-1).data("cell");
412 412 if (previous.input_prompt_number > current.input_prompt_number) {
413 413 this.move_cell_up(i);
414 414 swapped = true;
415 415 };
416 416 };
417 417 } while (swapped);
418 418 this.select(sindex);
419 419 return this;
420 420 };
421 421
422 422
423 423 Notebook.prototype.insert_code_cell_before = function (index) {
424 424 // TODO: Bounds check for i
425 425 var i = this.index_or_selected(index);
426 426 var cell = new IPython.CodeCell(this);
427 427 cell.set_input_prompt();
428 428 this.insert_cell_before(cell, i);
429 429 this.select(this.find_cell_index(cell));
430 430 return cell;
431 431 }
432 432
433 433
434 434 Notebook.prototype.insert_code_cell_after = function (index) {
435 435 // TODO: Bounds check for i
436 436 var i = this.index_or_selected(index);
437 437 var cell = new IPython.CodeCell(this);
438 438 cell.set_input_prompt();
439 439 this.insert_cell_after(cell, i);
440 440 this.select(this.find_cell_index(cell));
441 441 return cell;
442 442 }
443 443
444 444
445 445 Notebook.prototype.insert_html_cell_before = function (index) {
446 446 // TODO: Bounds check for i
447 447 var i = this.index_or_selected(index);
448 448 var cell = new IPython.HTMLCell(this);
449 449 cell.config_mathjax();
450 450 this.insert_cell_before(cell, i);
451 451 this.select(this.find_cell_index(cell));
452 452 return cell;
453 453 }
454 454
455 455
456 456 Notebook.prototype.insert_html_cell_after = function (index) {
457 457 // TODO: Bounds check for i
458 458 var i = this.index_or_selected(index);
459 459 var cell = new IPython.HTMLCell(this);
460 460 cell.config_mathjax();
461 461 this.insert_cell_after(cell, i);
462 462 this.select(this.find_cell_index(cell));
463 463 return cell;
464 464 }
465 465
466 466
467 467 Notebook.prototype.insert_markdown_cell_before = function (index) {
468 468 // TODO: Bounds check for i
469 469 var i = this.index_or_selected(index);
470 470 var cell = new IPython.MarkdownCell(this);
471 471 cell.config_mathjax();
472 472 this.insert_cell_before(cell, i);
473 473 this.select(this.find_cell_index(cell));
474 474 return cell;
475 475 }
476 476
477 477
478 478 Notebook.prototype.insert_markdown_cell_after = function (index) {
479 479 // TODO: Bounds check for i
480 480 var i = this.index_or_selected(index);
481 481 var cell = new IPython.MarkdownCell(this);
482 482 cell.config_mathjax();
483 483 this.insert_cell_after(cell, i);
484 484 this.select(this.find_cell_index(cell));
485 485 return cell;
486 486 }
487 487
488 488
489 489 Notebook.prototype.to_code = function (index) {
490 490 // TODO: Bounds check for i
491 491 var i = this.index_or_selected(index);
492 492 var source_element = this.cell_elements().eq(i);
493 493 var source_cell = source_element.data("cell");
494 494 if (source_cell instanceof IPython.HTMLCell ||
495 495 source_cell instanceof IPython.MarkdownCell) {
496 496 this.insert_code_cell_after(i);
497 497 var target_cell = this.cells()[i+1];
498 498 target_cell.set_code(source_cell.get_source());
499 499 source_element.remove();
500 500 target_cell.select();
501 501 };
502 502 this.dirty = true;
503 503 };
504 504
505 505
506 506 Notebook.prototype.to_markdown = function (index) {
507 507 // TODO: Bounds check for i
508 508 var i = this.index_or_selected(index);
509 509 var source_element = this.cell_elements().eq(i);
510 510 var source_cell = source_element.data("cell");
511 511 var target_cell = null;
512 512 if (source_cell instanceof IPython.CodeCell) {
513 513 this.insert_markdown_cell_after(i);
514 514 var target_cell = this.cells()[i+1];
515 515 var text = source_cell.get_code();
516 516 } else if (source_cell instanceof IPython.HTMLCell) {
517 517 this.insert_markdown_cell_after(i);
518 518 var target_cell = this.cells()[i+1];
519 519 var text = source_cell.get_source();
520 520 if (text === source_cell.placeholder) {
521 521 text = target_cell.placeholder;
522 522 }
523 523 }
524 524 if (target_cell !== null) {
525 525 if (text === "") {text = target_cell.placeholder;};
526 526 target_cell.set_source(text);
527 527 source_element.remove();
528 528 target_cell.edit();
529 529 }
530 530 this.dirty = true;
531 531 };
532 532
533 533
534 534 Notebook.prototype.to_html = function (index) {
535 535 // TODO: Bounds check for i
536 536 var i = this.index_or_selected(index);
537 537 var source_element = this.cell_elements().eq(i);
538 538 var source_cell = source_element.data("cell");
539 539 var target_cell = null;
540 540 if (source_cell instanceof IPython.CodeCell) {
541 541 this.insert_html_cell_after(i);
542 542 var target_cell = this.cells()[i+1];
543 543 var text = source_cell.get_code();
544 544 } else if (source_cell instanceof IPython.MarkdownCell) {
545 545 this.insert_html_cell_after(i);
546 546 var target_cell = this.cells()[i+1];
547 547 var text = source_cell.get_source();
548 548 if (text === source_cell.placeholder) {
549 549 text = target_cell.placeholder;
550 550 }
551 551 }
552 552 if (target_cell !== null) {
553 553 if (text === "") {text = target_cell.placeholder;};
554 554 target_cell.set_source(text);
555 555 source_element.remove();
556 556 target_cell.edit();
557 557 }
558 558 this.dirty = true;
559 559 };
560 560
561 561
562 562 // Cell collapsing and output clearing
563 563
564 564 Notebook.prototype.collapse = function (index) {
565 565 var i = this.index_or_selected(index);
566 566 this.cells()[i].collapse();
567 567 this.dirty = true;
568 568 };
569 569
570 570
571 571 Notebook.prototype.expand = function (index) {
572 572 var i = this.index_or_selected(index);
573 573 this.cells()[i].expand();
574 574 this.dirty = true;
575 575 };
576 576
577 577
578 578 Notebook.prototype.toggle_output = function (index) {
579 579 var i = this.index_or_selected(index);
580 580 this.cells()[i].toggle_output();
581 581 this.dirty = true;
582 582 };
583 583
584 584
585 585 Notebook.prototype.set_autoindent = function (state) {
586 586 var cells = this.cells();
587 587 len = cells.length;
588 588 for (var i=0; i<len; i++) {
589 589 cells[i].set_autoindent(state)
590 590 };
591 591 };
592 592
593 593
594 594 Notebook.prototype.clear_all_output = function () {
595 595 var ncells = this.ncells();
596 596 var cells = this.cells();
597 597 for (var i=0; i<ncells; i++) {
598 598 if (cells[i] instanceof IPython.CodeCell) {
599 599 cells[i].clear_output();
600 600 }
601 601 };
602 602 this.dirty = true;
603 603 };
604 604
605 605
606 606 // Kernel related things
607 607
608 608 Notebook.prototype.start_kernel = function () {
609 609 this.kernel = new IPython.Kernel();
610 610 var notebook_id = IPython.save_widget.get_notebook_id();
611 611 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
612 612 };
613 613
614 614
615 615 Notebook.prototype.restart_kernel = function () {
616 616 var notebook_id = IPython.save_widget.get_notebook_id();
617 617 this.kernel.restart($.proxy(this.kernel_started, this));
618 618 };
619 619
620 620
621 621 Notebook.prototype.kernel_started = function () {
622 622 console.log("Kernel started: ", this.kernel.kernel_id);
623 623 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
624 624 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
625 625 };
626 626
627 627
628 628 Notebook.prototype.handle_shell_reply = function (e) {
629 629 reply = $.parseJSON(e.data);
630 630 var header = reply.header;
631 631 var content = reply.content;
632 632 var msg_type = header.msg_type;
633 633 // console.log(reply);
634 634 var cell = this.cell_for_msg(reply.parent_header.msg_id);
635 635 if (msg_type === "execute_reply") {
636 636 cell.set_input_prompt(content.execution_count);
637 637 this.dirty = true;
638 638 } else if (msg_type === "complete_reply") {
639 639 cell.finish_completing(content.matched_text, content.matches);
640 640 };
641 641 var payload = content.payload || [];
642 642 this.handle_payload(cell, payload);
643 643 };
644 644
645 645
646 646 Notebook.prototype.handle_payload = function (cell, payload) {
647 647 var l = payload.length;
648 648 for (var i=0; i<l; i++) {
649 649 if (payload[i].source === 'IPython.zmq.page.page') {
650 650 if (payload[i].text.trim() !== '') {
651 651 IPython.pager.clear();
652 652 IPython.pager.expand();
653 653 IPython.pager.append_text(payload[i].text);
654 654 }
655 655 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
656 656 var index = this.find_cell_index(cell);
657 657 var new_cell = this.insert_code_cell_after(index);
658 658 new_cell.set_code(payload[i].text);
659 659 this.dirty = true;
660 660 }
661 661 };
662 662 };
663 663
664 664
665 665 Notebook.prototype.handle_iopub_reply = function (e) {
666 666 reply = $.parseJSON(e.data);
667 667 var content = reply.content;
668 668 // console.log(reply);
669 669 var msg_type = reply.header.msg_type;
670 670 var cell = this.cell_for_msg(reply.parent_header.msg_id);
671 671 var output_types = ['stream','display_data','pyout','pyerr'];
672 672 if (output_types.indexOf(msg_type) >= 0) {
673 673 this.handle_output(cell, msg_type, content);
674 674 } else if (msg_type === 'status') {
675 675 if (content.execution_state === 'busy') {
676 676 IPython.kernel_status_widget.status_busy();
677 677 } else if (content.execution_state === 'idle') {
678 678 IPython.kernel_status_widget.status_idle();
679 679 } else if (content.execution_state === 'dead') {
680 680 this.handle_status_dead();
681 681 };
682 682 }
683 683 };
684 684
685 685
686 686 Notebook.prototype.handle_status_dead = function () {
687 687 var that = this;
688 688 this.kernel.stop_channels();
689 689 var dialog = $('<div/>');
690 690 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.');
691 691 $(document).append(dialog);
692 692 dialog.dialog({
693 693 resizable: false,
694 694 modal: true,
695 695 title: "Dead kernel",
696 696 buttons : {
697 697 "Yes": function () {
698 698 that.start_kernel();
699 699 $(this).dialog('close');
700 700 },
701 701 "No": function () {
702 702 $(this).dialog('close');
703 703 }
704 704 }
705 705 });
706 706 };
707 707
708 708
709 709 Notebook.prototype.handle_output = function (cell, msg_type, content) {
710 710 var json = {};
711 711 json.output_type = msg_type;
712 712 if (msg_type === "stream") {
713 713 json.text = utils.fixConsole(content.data + '\n');
714 714 } else if (msg_type === "display_data") {
715 715 json = this.convert_mime_types(json, content.data);
716 716 } else if (msg_type === "pyout") {
717 717 json.prompt_number = content.execution_count;
718 718 json = this.convert_mime_types(json, content.data);
719 719 } else if (msg_type === "pyerr") {
720 720 json.ename = content.ename;
721 721 json.evalue = content.evalue;
722 722 var traceback = [];
723 723 for (var i=0; i<content.traceback.length; i++) {
724 724 traceback.push(utils.fixConsole(content.traceback[i]));
725 725 }
726 726 json.traceback = traceback;
727 727 };
728 728 cell.append_output(json);
729 729 this.dirty = true;
730 730 };
731 731
732 732
733 733 Notebook.prototype.convert_mime_types = function (json, data) {
734 734 if (data['text/plain'] !== undefined) {
735 735 json.text = utils.fixConsole(data['text/plain']);
736 736 };
737 737 if (data['text/html'] !== undefined) {
738 738 json.html = data['text/html'];
739 739 };
740 740 if (data['image/svg+xml'] !== undefined) {
741 741 json.svg = data['image/svg+xml'];
742 742 };
743 743 if (data['image/png'] !== undefined) {
744 744 json.png = data['image/png'];
745 745 };
746 746 if (data['image/jpeg'] !== undefined) {
747 747 json.jpeg = data['image/jpeg'];
748 748 };
749 749 if (data['text/latex'] !== undefined) {
750 750 json.latex = data['text/latex'];
751 751 };
752 752 if (data['application/json'] !== undefined) {
753 753 json.json = data['application/json'];
754 754 };
755 755 if (data['application/javascript'] !== undefined) {
756 756 json.javascript = data['application/javascript'];
757 757 }
758 758 return json;
759 759 };
760 760
761 761
762 762 Notebook.prototype.execute_selected_cell = function (options) {
763 763 // add_new: should a new cell be added if we are at the end of the nb
764 764 // terminal: execute in terminal mode, which stays in the current cell
765 765 default_options = {terminal: false, add_new: true}
766 766 $.extend(default_options, options)
767 767 var that = this;
768 768 var cell = that.selected_cell();
769 769 var cell_index = that.find_cell_index(cell);
770 770 if (cell instanceof IPython.CodeCell) {
771 771 cell.clear_output();
772 772 var code = cell.get_code();
773 773 var msg_id = that.kernel.execute(cell.get_code());
774 774 that.msg_cell_map[msg_id] = cell.cell_id;
775 775 } else if (cell instanceof IPython.HTMLCell) {
776 776 cell.render();
777 777 }
778 778 if (default_options.terminal) {
779 779 cell.clear_input();
780 780 } else {
781 781 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
782 782 that.insert_code_cell_after();
783 783 // If we are adding a new cell at the end, scroll down to show it.
784 784 that.scroll_to_bottom();
785 785 } else {
786 786 that.select(cell_index+1);
787 787 };
788 788 };
789 789 this.dirty = true;
790 790 };
791 791
792 792
793 793 Notebook.prototype.execute_all_cells = function () {
794 794 var ncells = this.ncells();
795 795 for (var i=0; i<ncells; i++) {
796 796 this.select(i);
797 797 this.execute_selected_cell({add_new:false});
798 798 };
799 799 this.scroll_to_bottom();
800 800 };
801 801
802 802
803 803 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
804 804 var msg_id = this.kernel.complete(line, cursor_pos);
805 805 this.msg_cell_map[msg_id] = cell.cell_id;
806 806 };
807 807
808 808 // Persistance and loading
809 809
810 810
811 811 Notebook.prototype.fromJSON = function (data) {
812 812 var ncells = this.ncells();
813 813 for (var i=0; i<ncells; i++) {
814 814 // Always delete cell 0 as they get renumbered as they are deleted.
815 815 this.delete_cell(0);
816 816 };
817 817 // Save the metadata
818 818 this.metadata = data.metadata;
819 819 // Only handle 1 worksheet for now.
820 820 var worksheet = data.worksheets[0];
821 821 if (worksheet !== undefined) {
822 822 var new_cells = worksheet.cells;
823 823 ncells = new_cells.length;
824 824 var cell_data = null;
825 825 var new_cell = null;
826 826 for (var i=0; i<ncells; i++) {
827 827 cell_data = new_cells[i];
828 828 if (cell_data.cell_type == 'code') {
829 829 new_cell = this.insert_code_cell_after();
830 830 new_cell.fromJSON(cell_data);
831 831 } else if (cell_data.cell_type === 'html') {
832 832 new_cell = this.insert_html_cell_after();
833 833 new_cell.fromJSON(cell_data);
834 834 } else if (cell_data.cell_type === 'markdown') {
835 835 new_cell = this.insert_markdown_cell_after();
836 836 new_cell.fromJSON(cell_data);
837 837 };
838 838 };
839 839 };
840 840 };
841 841
842 842
843 843 Notebook.prototype.toJSON = function () {
844 844 var cells = this.cells();
845 845 var ncells = cells.length;
846 846 cell_array = new Array(ncells);
847 847 for (var i=0; i<ncells; i++) {
848 848 cell_array[i] = cells[i].toJSON();
849 849 };
850 850 data = {
851 851 // Only handle 1 worksheet for now.
852 852 worksheets : [{cells:cell_array}],
853 853 metadata : this.metadata
854 854 }
855 855 return data
856 856 };
857 857
858 858 Notebook.prototype.save_notebook = function () {
859 859 if (IPython.save_widget.test_notebook_name()) {
860 860 var notebook_id = IPython.save_widget.get_notebook_id();
861 861 var nbname = IPython.save_widget.get_notebook_name();
862 862 // We may want to move the name/id/nbformat logic inside toJSON?
863 863 var data = this.toJSON();
864 864 data.metadata.name = nbname;
865 865 data.nbformat = 2;
866 866 // We do the call with settings so we can set cache to false.
867 867 var settings = {
868 868 processData : false,
869 869 cache : false,
870 870 type : "PUT",
871 871 data : JSON.stringify(data),
872 872 headers : {'Content-Type': 'application/json'},
873 873 success : $.proxy(this.notebook_saved,this)
874 874 };
875 875 IPython.save_widget.status_saving();
876 876 $.ajax("/notebooks/" + notebook_id, settings);
877 877 };
878 878 };
879 879
880 880
881 881 Notebook.prototype.notebook_saved = function (data, status, xhr) {
882 882 this.dirty = false;
883 883 setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500);
884 884 }
885 885
886 886
887 887 Notebook.prototype.load_notebook = function (callback) {
888 888 var that = this;
889 889 var notebook_id = IPython.save_widget.get_notebook_id();
890 890 // We do the call with settings so we can set cache to false.
891 891 var settings = {
892 892 processData : false,
893 893 cache : false,
894 894 type : "GET",
895 895 dataType : "json",
896 896 success : function (data, status, xhr) {
897 897 that.notebook_loaded(data, status, xhr);
898 898 if (callback !== undefined) {
899 899 callback();
900 900 };
901 901 }
902 902 };
903 903 IPython.save_widget.status_loading();
904 904 $.ajax("/notebooks/" + notebook_id, settings);
905 905 }
906 906
907 907
908 908 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
909 909 this.fromJSON(data);
910 910 if (this.ncells() === 0) {
911 911 this.insert_code_cell_after();
912 912 };
913 913 IPython.save_widget.status_save();
914 914 IPython.save_widget.set_notebook_name(data.metadata.name);
915 915 this.start_kernel();
916 916 this.dirty = false;
917 917 // fromJSON always selects the last cell inserted. We need to wait
918 918 // until that is done before scrolling to the top.
919 919 setTimeout(function () {
920 920 IPython.notebook.select(0);
921 921 IPython.notebook.scroll_to_top();
922 922 }, 50);
923 923 };
924 924
925 925 IPython.Notebook = Notebook;
926 926
927 927 return IPython;
928 928
929 929 }(IPython));
930 930
General Comments 0
You need to be logged in to leave comments. Login now