##// END OF EJS Templates
Start the pager out collapsed.
Brian Granger -
Show More
@@ -1,398 +1,399 b''
1 1 /**
2 2 * Primary styles
3 3 *
4 4 * Author: IPython Development Team
5 5 */
6 6
7 7
8 8 body {
9 9 background-color: white;
10 10 /* This makes sure that the body covers the entire window and needs to
11 11 be in a different element than the display: box in wrapper below */
12 12 position: absolute;
13 13 left: 0px;
14 14 right: 0px;
15 15 top: 0px;
16 16 bottom: 0px;
17 17 overflow: hidden;
18 18 }
19 19
20 20 span#save_widget {
21 21 padding: 5px;
22 22 margin: 0px 0px 0px 300px;
23 23 display:inline-block;
24 24 }
25 25
26 26 span#notebook_name {
27 27 height: 1em;
28 28 line-height: 1em;
29 29 padding: 3px;
30 30 border: none;
31 31 font-size: 146.5%;
32 32 }
33 33
34 34 #menubar {
35 35 /* Initially hidden to prevent FLOUC */
36 36 display: none;
37 37 }
38 38
39 39 .ui-menubar-item .ui-button .ui-button-text {
40 40 padding: 0.4em 1.0em;
41 41 font-size: 100%;
42 42 }
43 43
44 44 .ui-menu {
45 45 -moz-box-shadow: 0px 6px 10px -1px #adadad;
46 46 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
47 47 box-shadow: 0px 6px 10px -1px #adadad;
48 48 }
49 49
50 50 .ui-menu .ui-menu-item a {
51 51 padding: 2px 1.6em;
52 52 }
53 53
54 54 .ui-menu hr {
55 55 margin: 0.3em 0;
56 56 }
57 57
58 58 #fulledit_widget {
59 59 /* Initially hidden to prevent FLOUC */
60 60 display: none;
61 61 width: 920px;
62 62 margin: 0px auto;
63 63 }
64 64
65 65 #fulledit_editor {
66 66 height: 577px;
67 67 width: 920px;
68 68 }
69 69
70 70 #fulledit_header {
71 71 width: 920px;
72 72 }
73 73
74 74 span#quick_help_area {
75 75 position: static;
76 76 padding: 5px 0px;
77 77 margin: 0px 0px 0px 0px;
78 78 }
79 79
80 80 span#kernel_status {
81 81 position: absolute;
82 82 padding: 8px 5px 5px 5px;
83 83 right: 10px;
84 84 font-weight: bold;
85 85 }
86 86
87 87
88 88 .status_idle {
89 89 color: gray;
90 90 visibility: hidden;
91 91 }
92 92
93 93 .status_busy {
94 94 color: red;
95 95 }
96 96
97 97 .status_restarting {
98 98 color: black;
99 99 }
100 100
101 101 #kernel_persist {
102 102 float: right;
103 103 }
104 104
105 105 .help_string {
106 106 float: right;
107 107 width: 170px;
108 108 padding: 0px 5px;
109 109 text-align: left;
110 110 font-size: 85%;
111 111 }
112 112
113 113 .help_string_label {
114 114 float: right;
115 115 font-size: 85%;
116 116 }
117 117
118 118 div#notebook_panel {
119 119 margin: 0px 0px 0px 0px;
120 120 padding: 0px;
121 121 }
122 122
123 123 div#notebook {
124 124 overflow-y: scroll;
125 125 overflow-x: auto;
126 126 width: 100%;
127 127 /* This spaces the cell away from the edge of the notebook area */
128 128 padding: 5px 5px 15px 5px;
129 129 margin: 0px
130 130 background-color: white;
131 131 }
132 132
133 133 div#pager_splitter {
134 134 height: 8px;
135 135 }
136 136
137 137 div#pager {
138 138 padding: 15px;
139 139 overflow: auto;
140 display: none;
140 141 }
141 142
142 143 div.cell {
143 144 width: 100%;
144 145 padding: 5px 5px 5px 0px;
145 146 /* This acts as a spacer between cells, that is outside the border */
146 147 margin: 2px 0px 2px 0px;
147 148 }
148 149
149 150 div.code_cell {
150 151 background-color: white;
151 152 }
152 153 /* any special styling for code cells that are currently running goes here */
153 154 div.code_cell.running {
154 155 }
155 156
156 157 div.prompt {
157 158 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
158 159 width: 11ex;
159 160 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
160 161 padding: 0.4em;
161 162 margin: 0px;
162 163 font-family: monospace;
163 164 text-align:right;
164 165 }
165 166
166 167 div.input {
167 168 page-break-inside: avoid;
168 169 }
169 170
170 171 /* input_area and input_prompt must match in top border and margin for alignment */
171 172 div.input_area {
172 173 color: black;
173 174 border: 1px solid #ddd;
174 175 border-radius: 3px;
175 176 background: #f7f7f7;
176 177 }
177 178
178 179 div.input_prompt {
179 180 color: navy;
180 181 border-top: 1px solid transparent;
181 182 }
182 183
183 184 div.output {
184 185 /* This is a spacer between the input and output of each cell */
185 186 margin-top: 5px;
186 187 }
187 188
188 189 div.output_prompt {
189 190 color: darkred;
190 191 }
191 192
192 193 /* This class is the outer container of all output sections. */
193 194 div.output_area {
194 195 padding: 0px;
195 196 page-break-inside: avoid;
196 197 }
197 198
198 199 /* This class is for the output subarea inside the output_area and after
199 200 the prompt div. */
200 201 div.output_subarea {
201 202 padding: 0.4em 6.1em 0.4em 0.4em;
202 203 }
203 204
204 205 /* The rest of the output_* classes are for special styling of the different
205 206 output types */
206 207
207 208 /* all text output has this class: */
208 209 div.output_text {
209 210 text-align: left;
210 211 color: black;
211 212 font-family: monospace;
212 213 }
213 214
214 215 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
215 216 div.output_stream {
216 217 padding-top: 0.0em;
217 218 padding-bottom: 0.0em;
218 219 }
219 220 div.output_stdout {
220 221 }
221 222 div.output_stderr {
222 223 background: #fdd; /* very light red background for stderr */
223 224 }
224 225
225 226 div.output_latex {
226 227 text-align: left;
227 228 color: black;
228 229 }
229 230
230 231 div.output_html {
231 232 }
232 233
233 234 div.output_png {
234 235 }
235 236
236 237 div.output_jpeg {
237 238 }
238 239
239 240 div.text_cell {
240 241 background-color: white;
241 242 padding: 5px 5px 5px 5px;
242 243 }
243 244
244 245 div.text_cell_input {
245 246 color: black;
246 247 border: 1px solid #ddd;
247 248 border-radius: 3px;
248 249 background: #f7f7f7;
249 250 }
250 251
251 252 div.text_cell_render {
252 253 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
253 254 outline: none;
254 255 resize: none;
255 256 width: inherit;
256 257 border-style: none;
257 258 padding: 5px;
258 259 color: black;
259 260 }
260 261
261 262 .CodeMirror {
262 263 line-height: 1.231; /* Changed from 1em to our global default */
263 264 }
264 265
265 266 .CodeMirror-scroll {
266 267 height: auto; /* Changed to auto to autogrow */
267 268 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
268 269 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
269 270 overflow-y: hidden;
270 271 overflow-x: auto; /* Changed from auto to remove scrollbar */
271 272 }
272 273
273 274 /* CSS font colors for translated ANSI colors. */
274 275
275 276
276 277 .ansiblack {color: black;}
277 278 .ansired {color: darkred;}
278 279 .ansigreen {color: darkgreen;}
279 280 .ansiyellow {color: brown;}
280 281 .ansiblue {color: darkblue;}
281 282 .ansipurple {color: darkviolet;}
282 283 .ansicyan {color: steelblue;}
283 284 .ansigrey {color: grey;}
284 285 .ansibold {font-weight: bold;}
285 286
286 287 .completions , .tooltip {
287 288 position: absolute;
288 289 z-index: 10;
289 290 overflow: auto;
290 291 border: 1px solid black;
291 292 }
292 293
293 294 .completions select {
294 295 background: white;
295 296 outline: none;
296 297 border: none;
297 298 padding: 0px;
298 299 margin: 0px;
299 300 font-family: monospace;
300 301 }
301 302
302 303 @-moz-keyframes fadeIn {
303 304 from {opacity:0;}
304 305 to {opacity:1;}
305 306 }
306 307
307 308 @-webkit-keyframes fadeIn {
308 309 from {opacity:0;}
309 310 to {opacity:1;}
310 311 }
311 312
312 313 @keyframes fadeIn {
313 314 from {opacity:0;}
314 315 to {opacity:1;}
315 316 }
316 317
317 318 /*"close" "expand" and "Open in pager button" of
318 319 /* the tooltip*/
319 320 .tooltip a {
320 321 float:right;
321 322 }
322 323
323 324 /*properties of tooltip after "expand"*/
324 325 .bigtooltip {
325 326 height:30%;
326 327 }
327 328
328 329 /*properties of tooltip before "expand"*/
329 330 .smalltooltip {
330 331 text-overflow: ellipsis;
331 332 overflow: hidden;
332 333 height:15%;
333 334 }
334 335
335 336 .tooltip {
336 337 /*transition when "expand"ing tooltip */
337 338 -webkit-transition-property: height;
338 339 -webkit-transition-duration: 1s;
339 340 -moz-transition-property: height;
340 341 -moz-transition-duration: 1s;
341 342 transition-property: height;
342 343 transition-duration: 1s;
343 344 max-width:700px;
344 345 border-radius: 0px 10px 10px 10px;
345 346 box-shadow: 3px 3px 5px #999;
346 347 /*fade-in animation when inserted*/
347 348 -webkit-animation: fadeIn 200ms;
348 349 -moz-animation: fadeIn 200ms;
349 350 animation: fadeIn 200ms;
350 351 vertical-align: middle;
351 352 background: #FDFDD8;
352 353 outline: none;
353 354 padding: 3px;
354 355 margin: 0px;
355 356 font-family: monospace;
356 357 min-height:50px;
357 358 }
358 359
359 360 /*fixed part of the completion*/
360 361 .completions p b {
361 362 font-weight:bold;
362 363 }
363 364
364 365 .completions p {
365 366 background: #DDF;
366 367 /*outline: none;
367 368 padding: 0px;*/
368 369 border-bottom: black solid 1px;
369 370 padding: 1px;
370 371 font-family: monospace;
371 372 }
372 373
373 374 pre.dialog {
374 375 background-color: #f7f7f7;
375 376 border: 1px solid #ddd;
376 377 border-radius: 3px;
377 378 padding: 0.4em;
378 379 padding-left: 2em;
379 380 }
380 381
381 382 p.dialog {
382 383 padding : 0.2em;
383 384 }
384 385
385 386 .shortcut_key {
386 387 display: inline-block;
387 388 width: 15ex;
388 389 text-align: right;
389 390 font-family: monospace;
390 391 }
391 392
392 393 .shortcut_descr {
393 394 }
394 395
395 396 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
396 397 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
397 398 */
398 399 pre, code, kbd, samp { white-space: pre-wrap; }
@@ -1,1187 +1,1186 b''
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.style();
30 30 this.create_elements();
31 31 this.bind_events();
32 32 this.set_tooltipontab(true);
33 33 this.set_smartcompleter(true);
34 34 this.set_timebeforetooltip(1200);
35 35 this.set_autoindent(true);
36 36 };
37 37
38 38
39 39 Notebook.prototype.style = function () {
40 40 $('div#notebook').addClass('border-box-sizing');
41 41 };
42 42
43 43
44 44 Notebook.prototype.create_elements = function () {
45 45 // We add this end_space div to the end of the notebook div to:
46 46 // i) provide a margin between the last cell and the end of the notebook
47 47 // ii) to prevent the div from scrolling up when the last cell is being
48 48 // edited, but is too low on the page, which browsers will do automatically.
49 49 var that = this;
50 50 var end_space = $('<div/>').addClass('end_space').height("30%");
51 51 end_space.dblclick(function (e) {
52 52 if (that.read_only) return;
53 53 var ncells = that.ncells();
54 54 that.insert_cell_below('code',ncells-1);
55 55 });
56 56 this.element.append(end_space);
57 57 $('div#notebook').addClass('border-box-sizing');
58 58 };
59 59
60 60
61 61 Notebook.prototype.bind_events = function () {
62 62 var that = this;
63 63 $(document).keydown(function (event) {
64 64 // console.log(event);
65 65 if (that.read_only) return true;
66 66 if (event.which === 27) {
67 67 // Intercept escape at highest level to avoid closing
68 68 // websocket connection with firefox
69 69 event.preventDefault();
70 70 }
71 71 if (event.which === 38 && !event.shiftKey) {
72 72 var cell = that.get_selected_cell();
73 73 if (cell.at_top()) {
74 74 event.preventDefault();
75 75 that.select_prev();
76 76 };
77 77 } else if (event.which === 40 && !event.shiftKey) {
78 78 var cell = that.get_selected_cell();
79 79 if (cell.at_bottom()) {
80 80 event.preventDefault();
81 81 that.select_next();
82 82 };
83 83 } else if (event.which === 13 && event.shiftKey) {
84 84 that.execute_selected_cell();
85 85 return false;
86 86 } else if (event.which === 13 && event.ctrlKey) {
87 87 that.execute_selected_cell({terminal:true});
88 88 return false;
89 89 } else if (event.which === 77 && event.ctrlKey) {
90 90 that.control_key_active = true;
91 91 return false;
92 92 } else if (event.which === 88 && that.control_key_active) {
93 93 // Cut selected cell = x
94 94 that.cut_cell();
95 95 that.control_key_active = false;
96 96 return false;
97 97 } else if (event.which === 67 && that.control_key_active) {
98 98 // Copy selected cell = c
99 99 that.copy_cell();
100 100 that.control_key_active = false;
101 101 return false;
102 102 } else if (event.which === 86 && that.control_key_active) {
103 103 // Paste selected cell = v
104 104 that.paste_cell();
105 105 that.control_key_active = false;
106 106 return false;
107 107 } else if (event.which === 68 && that.control_key_active) {
108 108 // Delete selected cell = d
109 109 that.delete_cell();
110 110 that.control_key_active = false;
111 111 return false;
112 112 } else if (event.which === 65 && that.control_key_active) {
113 113 // Insert code cell above selected = a
114 114 that.insert_cell_above('code');
115 115 that.control_key_active = false;
116 116 return false;
117 117 } else if (event.which === 66 && that.control_key_active) {
118 118 // Insert code cell below selected = b
119 119 that.insert_cell_below('code');
120 120 that.control_key_active = false;
121 121 return false;
122 122 } else if (event.which === 89 && that.control_key_active) {
123 123 // To code = y
124 124 that.to_code();
125 125 that.control_key_active = false;
126 126 return false;
127 127 } else if (event.which === 77 && that.control_key_active) {
128 128 // To markdown = m
129 129 that.to_markdown();
130 130 that.control_key_active = false;
131 131 return false;
132 132 } else if (event.which === 84 && that.control_key_active) {
133 133 // Toggle output = t
134 134 that.toggle_output();
135 135 that.control_key_active = false;
136 136 return false;
137 137 } else if (event.which === 83 && that.control_key_active) {
138 138 // Save notebook = s
139 139 IPython.save_widget.save_notebook();
140 140 that.control_key_active = false;
141 141 return false;
142 142 } else if (event.which === 74 && that.control_key_active) {
143 143 // Move cell down = j
144 144 that.move_cell_down();
145 145 that.control_key_active = false;
146 146 return false;
147 147 } else if (event.which === 75 && that.control_key_active) {
148 148 // Move cell up = k
149 149 that.move_cell_up();
150 150 that.control_key_active = false;
151 151 return false;
152 152 } else if (event.which === 80 && that.control_key_active) {
153 153 // Select previous = p
154 154 that.select_prev();
155 155 that.control_key_active = false;
156 156 return false;
157 157 } else if (event.which === 78 && that.control_key_active) {
158 158 // Select next = n
159 159 that.select_next();
160 160 that.control_key_active = false;
161 161 return false;
162 162 } else if (event.which === 76 && that.control_key_active) {
163 163 // Toggle line numbers = l
164 164 that.cell_toggle_line_numbers();
165 165 that.control_key_active = false;
166 166 return false;
167 167 } else if (event.which === 73 && that.control_key_active) {
168 168 // Interrupt kernel = i
169 169 IPython.notebook.kernel.interrupt();
170 170 that.control_key_active = false;
171 171 return false;
172 172 } else if (event.which === 190 && that.control_key_active) {
173 173 // Restart kernel = . # matches qt console
174 174 IPython.notebook.restart_kernel();
175 175 that.control_key_active = false;
176 176 return false;
177 177 } else if (event.which === 72 && that.control_key_active) {
178 178 // Show keyboard shortcuts = h
179 179 IPython.quick_help.show_keyboard_shortcuts();
180 180 that.control_key_active = false;
181 181 return false;
182 182 } else if (event.which === 69 && that.control_key_active) {
183 183 // Edit in Ace = e
184 184 IPython.fulledit_widget.toggle();
185 185 that.control_key_active = false;
186 186 return false;
187 187 } else if (that.control_key_active) {
188 188 that.control_key_active = false;
189 189 return true;
190 190 };
191 191 return true;
192 192 });
193 193
194 194 this.element.bind('collapse_pager', function () {
195 195 var app_height = $('div#main_app').height(); // content height
196 196 var splitter_height = $('div#pager_splitter').outerHeight(true);
197 197 var new_height = app_height - splitter_height;
198 198 that.element.animate({height : new_height + 'px'}, 'fast');
199 199 });
200 200
201 201 this.element.bind('expand_pager', function () {
202 202 var app_height = $('div#main_app').height(); // content height
203 203 var splitter_height = $('div#pager_splitter').outerHeight(true);
204 204 var pager_height = $('div#pager').outerHeight(true);
205 205 var new_height = app_height - pager_height - splitter_height;
206 206 that.element.animate({height : new_height + 'px'}, 'fast');
207 207 });
208 208
209 209 $(window).bind('beforeunload', function () {
210 210 // TODO: Make killing the kernel configurable.
211 211 var kill_kernel = false;
212 212 if (kill_kernel) {
213 213 that.kernel.kill();
214 214 }
215 215 if (that.dirty && ! that.read_only) {
216 216 return "You have unsaved changes that will be lost if you leave this page.";
217 217 };
218 218 // Null is the *only* return value that will make the browser not
219 219 // pop up the "don't leave" dialog.
220 220 return null;
221 221 });
222 222 };
223 223
224 224
225 225 Notebook.prototype.scroll_to_bottom = function () {
226 226 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
227 227 };
228 228
229 229
230 230 Notebook.prototype.scroll_to_top = function () {
231 231 this.element.animate({scrollTop:0}, 0);
232 232 };
233 233
234 234
235 235 // Cell indexing, retrieval, etc.
236 236
237 237 Notebook.prototype.get_cell_elements = function () {
238 238 return this.element.children("div.cell");
239 239 };
240 240
241 241
242 242 Notebook.prototype.get_cell_element = function (index) {
243 243 var result = null;
244 244 var e = this.get_cell_elements().eq(index);
245 245 if (e.length !== 0) {
246 246 result = e;
247 247 }
248 248 return result;
249 249 };
250 250
251 251
252 252 Notebook.prototype.ncells = function (cell) {
253 253 return this.get_cell_elements().length;
254 254 };
255 255
256 256
257 257 // TODO: we are often calling cells as cells()[i], which we should optimize
258 258 // to cells(i) or a new method.
259 259 Notebook.prototype.get_cells = function () {
260 260 return this.get_cell_elements().toArray().map(function (e) {
261 261 return $(e).data("cell");
262 262 });
263 263 };
264 264
265 265
266 266 Notebook.prototype.get_cell = function (index) {
267 267 var result = null;
268 268 var ce = this.get_cell_element(index);
269 269 if (ce !== null) {
270 270 result = ce.data('cell');
271 271 }
272 272 return result;
273 273 }
274 274
275 275
276 276 Notebook.prototype.get_next_cell = function (cell) {
277 277 var result = null;
278 278 var index = this.find_cell_index(cell);
279 279 if (index !== null && index < this.ncells()) {
280 280 result = this.get_cell(index+1);
281 281 }
282 282 return result;
283 283 }
284 284
285 285
286 286 Notebook.prototype.get_prev_cell = function (cell) {
287 287 var result = null;
288 288 var index = this.find_cell_index(cell);
289 289 if (index !== null && index > 1) {
290 290 result = this.get_cell(index-1);
291 291 }
292 292 return result;
293 293 }
294 294
295 295 Notebook.prototype.find_cell_index = function (cell) {
296 296 var result = null;
297 297 this.get_cell_elements().filter(function (index) {
298 298 if ($(this).data("cell") === cell) {
299 299 result = index;
300 300 };
301 301 });
302 302 return result;
303 303 };
304 304
305 305
306 306 Notebook.prototype.index_or_selected = function (index) {
307 307 var i;
308 308 if (index === undefined || index === null) {
309 309 i = this.get_selected_index();
310 310 if (i === null) {
311 311 i = 0;
312 312 }
313 313 } else {
314 314 i = index;
315 315 }
316 316 return i;
317 317 };
318 318
319 319
320 320 Notebook.prototype.get_selected_cell = function () {
321 321 var index = this.get_selected_index();
322 322 return this.get_cell(index);
323 323 };
324 324
325 325
326 326 Notebook.prototype.is_valid_cell_index = function (index) {
327 327 if (index !== null && index >= 0 && index < this.ncells()) {
328 328 return true;
329 329 } else {
330 330 return false;
331 331 };
332 332 }
333 333
334 334 Notebook.prototype.get_selected_index = function () {
335 335 var result = null;
336 336 this.get_cell_elements().filter(function (index) {
337 337 if ($(this).data("cell").selected === true) {
338 338 result = index;
339 339 };
340 340 });
341 341 return result;
342 342 };
343 343
344 344
345 345 Notebook.prototype.cell_for_msg = function (msg_id) {
346 346 var cell_id = this.msg_cell_map[msg_id];
347 347 var result = null;
348 348 this.get_cell_elements().filter(function (index) {
349 349 cell = $(this).data("cell");
350 350 if (cell.cell_id === cell_id) {
351 351 result = cell;
352 352 };
353 353 });
354 354 return result;
355 355 };
356 356
357 357
358 358 // Cell selection.
359 359
360 360 Notebook.prototype.select = function (index) {
361 361 if (index !== undefined && index >= 0 && index < this.ncells()) {
362 362 sindex = this.get_selected_index()
363 363 if (sindex !== null && index !== sindex) {
364 364 this.get_cell(sindex).unselect();
365 365 };
366 366 this.get_cell(index).select();
367 367 };
368 368 return this;
369 369 };
370 370
371 371
372 372 Notebook.prototype.select_next = function () {
373 373 var index = this.get_selected_index();
374 374 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
375 375 this.select(index+1);
376 376 };
377 377 return this;
378 378 };
379 379
380 380
381 381 Notebook.prototype.select_prev = function () {
382 382 var index = this.get_selected_index();
383 383 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
384 384 this.select(index-1);
385 385 };
386 386 return this;
387 387 };
388 388
389 389
390 390 // Cell movement
391 391
392 392 Notebook.prototype.move_cell_up = function (index) {
393 393 var i = this.index_or_selected();
394 394 if (i !== null && i < this.ncells() && i > 0) {
395 395 var pivot = this.get_cell_element(i-1);
396 396 var tomove = this.get_cell_element(i);
397 397 if (pivot !== null && tomove !== null) {
398 398 tomove.detach();
399 399 pivot.before(tomove);
400 400 this.select(i-1);
401 401 };
402 402 };
403 403 this.dirty = true;
404 404 return this;
405 405 };
406 406
407 407
408 408 Notebook.prototype.move_cell_down = function (index) {
409 409 var i = this.index_or_selected();
410 410 if (i !== null && i < (this.ncells()-1) && i >= 0) {
411 411 var pivot = this.get_cell_element(i+1);
412 412 var tomove = this.get_cell_element(i);
413 413 if (pivot !== null && tomove !== null) {
414 414 tomove.detach();
415 415 pivot.after(tomove);
416 416 this.select(i+1);
417 417 };
418 418 };
419 419 this.dirty = true;
420 420 return this;
421 421 };
422 422
423 423
424 424 Notebook.prototype.sort_cells = function () {
425 425 // This is not working right now. Calling this will actually crash
426 426 // the browser. I think there is an infinite loop in here...
427 427 var ncells = this.ncells();
428 428 var sindex = this.get_selected_index();
429 429 var swapped;
430 430 do {
431 431 swapped = false;
432 432 for (var i=1; i<ncells; i++) {
433 433 current = this.get_cell(i);
434 434 previous = this.get_cell(i-1);
435 435 if (previous.input_prompt_number > current.input_prompt_number) {
436 436 this.move_cell_up(i);
437 437 swapped = true;
438 438 };
439 439 };
440 440 } while (swapped);
441 441 this.select(sindex);
442 442 return this;
443 443 };
444 444
445 445 // Insertion, deletion.
446 446
447 447 Notebook.prototype.delete_cell = function (index) {
448 448 var i = this.index_or_selected(index);
449 449 if (this.is_valid_cell_index(i)) {
450 450 var ce = this.get_cell_element(i);
451 451 ce.remove();
452 452 if (i === (this.ncells())) {
453 453 this.select(i-1);
454 454 } else {
455 455 this.select(i);
456 456 };
457 457 this.dirty = true;
458 458 };
459 459 return this;
460 460 };
461 461
462 462
463 463 Notebook.prototype.insert_cell_below = function (type, index) {
464 464 // type = ('code','html','markdown')
465 465 // index = cell index or undefined to insert below selected
466 466 index = this.index_or_selected(index);
467 467 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
468 468 var cell = null;
469 469 if (type === 'code') {
470 470 var cell = new IPython.CodeCell(this);
471 471 cell.set_input_prompt();
472 472 } else if (type === 'markdown') {
473 473 var cell = new IPython.MarkdownCell(this);
474 474 } else if (type === 'html') {
475 475 var cell = new IPython.HTMLCell(this);
476 476 };
477 477 if (cell !== null) {
478 478 if (this.ncells() === 0) {
479 479 this.element.find('div.end_space').before(cell.element);
480 480 } else if (this.is_valid_cell_index(index)) {
481 481 this.get_cell_element(index).after(cell.element);
482 482 };
483 483 cell.render();
484 484 this.select(this.find_cell_index(cell));
485 485 this.dirty = true;
486 486 return cell;
487 487 };
488 488 };
489 489 };
490 490
491 491
492 492 Notebook.prototype.insert_cell_above = function (type, index) {
493 493 // type = ('code','html','markdown')
494 494 // index = cell index or undefined to insert above selected
495 495 index = this.index_or_selected(index);
496 496 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
497 497 var cell = null;
498 498 if (type === 'code') {
499 499 var cell = new IPython.CodeCell(this);
500 500 cell.set_input_prompt();
501 501 } else if (type === 'markdown') {
502 502 var cell = new IPython.MarkdownCell(this);
503 503 } else if (type === 'html') {
504 504 var cell = new IPython.HTMLCell(this);
505 505 };
506 506 if (cell !== null) {
507 507 if (this.ncells() === 0) {
508 508 this.element.find('div.end_space').before(cell.element);
509 509 } else if (this.is_valid_cell_index(index)) {
510 510 this.get_cell_element(index).before(cell.element);
511 511 };
512 512 cell.render();
513 513 this.select(this.find_cell_index(cell));
514 514 this.dirty = true;
515 515 return cell;
516 516 };
517 517 };
518 518 };
519 519
520 520
521 521 Notebook.prototype.to_code = function (index) {
522 522 var i = this.index_or_selected(index);
523 523 if (this.is_valid_cell_index(i)) {
524 524 var source_element = this.get_cell_element(i);
525 525 var source_cell = source_element.data("cell");
526 526 if (!(source_cell instanceof IPython.CodeCell)) {
527 527 target_cell = this.insert_cell_below('code',i);
528 528 var text = source_cell.get_text();
529 529 if (text === source_cell.placeholder) {
530 530 text = '';
531 531 }
532 532 target_cell.set_text(text);
533 533 source_element.remove();
534 534 };
535 535 this.dirty = true;
536 536 };
537 537 };
538 538
539 539
540 540 Notebook.prototype.to_markdown = function (index) {
541 541 var i = this.index_or_selected(index);
542 542 if (this.is_valid_cell_index(i)) {
543 543 var source_element = this.get_cell_element(i);
544 544 var source_cell = source_element.data("cell");
545 545 var target_cell = null;
546 546 if (!(source_cell instanceof IPython.MarkdownCell)) {
547 547 target_cell = this.insert_cell_below('markdown',i);
548 548 var text = source_cell.get_text();
549 549 if (text === source_cell.placeholder) {
550 550 text = '';
551 551 };
552 552 if (target_cell !== null) {
553 553 //if (text === "") {text = target_cell.placeholder;};
554 554 // The edit must come before the set_text.
555 555 target_cell.edit();
556 556 target_cell.set_text(text);
557 557 source_element.remove();
558 558 }
559 559 this.dirty = true;
560 560 };
561 561 };
562 562 };
563 563
564 564
565 565 Notebook.prototype.to_html = function (index) {
566 566 var i = this.index_or_selected(index);
567 567 if (this.is_valid_cell_index(i)) {
568 568 var source_element = this.get_cell_element(i);
569 569 var source_cell = source_element.data("cell");
570 570 var target_cell = null;
571 571 if (!(source_cell instanceof IPython.HTMLCell)) {
572 572 target_cell = this.insert_cell_below('html',i);
573 573 var text = source_cell.get_text();
574 574 if (text === source_cell.placeholder) {
575 575 text = '';
576 576 };
577 577 if (target_cell !== null) {
578 578 if (text === "") {text = target_cell.placeholder;};
579 579 // The edit must come before the set_text.
580 580 target_cell.edit();
581 581 target_cell.set_text(text);
582 582 source_element.remove();
583 583 }
584 584 this.dirty = true;
585 585 };
586 586 };
587 587 };
588 588
589 589
590 590 // Cut/Copy/Paste
591 591
592 592 Notebook.prototype.enable_paste = function () {
593 593 var that = this;
594 594 if (!this.paste_enabled) {
595 595 $('#paste_cell').removeClass('ui-state-disabled')
596 596 .on('click', function () {that.paste_cell();});
597 597 $('#paste_cell_above').removeClass('ui-state-disabled')
598 598 .on('click', function () {that.paste_cell_above();});
599 599 $('#paste_cell_below').removeClass('ui-state-disabled')
600 600 .on('click', function () {that.paste_cell_below();});
601 601 this.paste_enabled = true;
602 602 };
603 603 };
604 604
605 605
606 606 Notebook.prototype.disable_paste = function () {
607 607 if (this.paste_enabled) {
608 608 $('#paste_cell').addClass('ui-state-disabled').off('click');
609 609 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
610 610 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
611 611 this.paste_enabled = false;
612 612 };
613 613 };
614 614
615 615
616 616 Notebook.prototype.cut_cell = function () {
617 617 this.copy_cell();
618 618 this.delete_cell();
619 619 }
620 620
621 621 Notebook.prototype.copy_cell = function () {
622 622 var cell = this.get_selected_cell();
623 623 this.clipboard = cell.toJSON();
624 624 this.enable_paste();
625 625 };
626 626
627 627
628 628 Notebook.prototype.paste_cell = function () {
629 629 if (this.clipboard !== null && this.paste_enabled) {
630 630 var cell_data = this.clipboard;
631 631 var new_cell = this.insert_cell_above(cell_data.cell_type);
632 632 new_cell.fromJSON(cell_data);
633 633 old_cell = this.get_next_cell(new_cell);
634 634 this.delete_cell(this.find_cell_index(old_cell));
635 635 this.select(this.find_cell_index(new_cell));
636 636 };
637 637 };
638 638
639 639
640 640 Notebook.prototype.paste_cell_above = function () {
641 641 if (this.clipboard !== null && this.paste_enabled) {
642 642 var cell_data = this.clipboard;
643 643 var new_cell = this.insert_cell_above(cell_data.cell_type);
644 644 new_cell.fromJSON(cell_data);
645 645 };
646 646 };
647 647
648 648
649 649 Notebook.prototype.paste_cell_below = function () {
650 650 if (this.clipboard !== null && this.paste_enabled) {
651 651 var cell_data = this.clipboard;
652 652 var new_cell = this.insert_cell_below(cell_data.cell_type);
653 653 new_cell.fromJSON(cell_data);
654 654 };
655 655 };
656 656
657 657
658 658 // Split/merge
659 659
660 660 Notebook.prototype.split_cell = function () {
661 661 // Todo: implement spliting for other cell types.
662 662 var cell = this.get_selected_cell();
663 663 if (cell.is_splittable()) {
664 664 texta = cell.get_pre_cursor();
665 665 textb = cell.get_post_cursor();
666 666 if (cell instanceof IPython.CodeCell) {
667 667 cell.set_text(texta);
668 668 var new_cell = this.insert_cell_below('code');
669 669 new_cell.set_text(textb);
670 670 } else if (cell instanceof IPython.MarkdownCell) {
671 671 cell.set_text(texta);
672 672 cell.render();
673 673 var new_cell = this.insert_cell_below('markdown');
674 674 new_cell.edit(); // editor must be visible to call set_text
675 675 new_cell.set_text(textb);
676 676 new_cell.render();
677 677 } else if (cell instanceof IPython.HTMLCell) {
678 678 cell.set_text(texta);
679 679 cell.render();
680 680 var new_cell = this.insert_cell_below('html');
681 681 new_cell.edit(); // editor must be visible to call set_text
682 682 new_cell.set_text(textb);
683 683 new_cell.render();
684 684 };
685 685 };
686 686 };
687 687
688 688
689 689 Notebook.prototype.merge_cell_above = function () {
690 690 var index = this.get_selected_index();
691 691 var cell = this.get_cell(index);
692 692 if (index > 0) {
693 693 upper_cell = this.get_cell(index-1);
694 694 upper_text = upper_cell.get_text();
695 695 text = cell.get_text();
696 696 if (cell instanceof IPython.CodeCell) {
697 697 cell.set_text(upper_text+'\n'+text);
698 698 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
699 699 cell.edit();
700 700 cell.set_text(upper_text+'\n'+text);
701 701 cell.render();
702 702 };
703 703 this.delete_cell(index-1);
704 704 this.select(this.find_cell_index(cell));
705 705 };
706 706 };
707 707
708 708
709 709 Notebook.prototype.merge_cell_below = function () {
710 710 var index = this.get_selected_index();
711 711 var cell = this.get_cell(index);
712 712 if (index < this.ncells()-1) {
713 713 lower_cell = this.get_cell(index+1);
714 714 lower_text = lower_cell.get_text();
715 715 text = cell.get_text();
716 716 if (cell instanceof IPython.CodeCell) {
717 717 cell.set_text(text+'\n'+lower_text);
718 718 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
719 719 cell.edit();
720 720 cell.set_text(text+'\n'+lower_text);
721 721 cell.render();
722 722 };
723 723 this.delete_cell(index+1);
724 724 this.select(this.find_cell_index(cell));
725 725 };
726 726 };
727 727
728 728 // Cell collapsing and output clearing
729 729
730 730 Notebook.prototype.collapse = function (index) {
731 731 var i = this.index_or_selected(index);
732 732 this.get_cell(i).collapse();
733 733 this.dirty = true;
734 734 };
735 735
736 736
737 737 Notebook.prototype.expand = function (index) {
738 738 var i = this.index_or_selected(index);
739 739 this.get_cell(i).expand();
740 740 this.dirty = true;
741 741 };
742 742
743 743
744 744 Notebook.prototype.toggle_output = function (index) {
745 745 var i = this.index_or_selected(index);
746 746 this.get_cell(i).toggle_output();
747 747 this.dirty = true;
748 748 };
749 749
750 750
751 751 Notebook.prototype.set_timebeforetooltip = function (time) {
752 752 this.time_before_tooltip = time;
753 753 };
754 754
755 755 Notebook.prototype.set_tooltipontab = function (state) {
756 756 this.tooltip_on_tab = state;
757 757 };
758 758
759 759 Notebook.prototype.set_smartcompleter = function (state) {
760 760 this.smart_completer = state;
761 761 };
762 762
763 763 Notebook.prototype.set_autoindent = function (state) {
764 764 var cells = this.get_cells();
765 765 len = cells.length;
766 766 for (var i=0; i<len; i++) {
767 767 cells[i].set_autoindent(state);
768 768 };
769 769 };
770 770
771 771
772 772 Notebook.prototype.clear_all_output = function () {
773 773 var ncells = this.ncells();
774 774 var cells = this.get_cells();
775 775 for (var i=0; i<ncells; i++) {
776 776 if (cells[i] instanceof IPython.CodeCell) {
777 777 cells[i].clear_output(true,true,true);
778 778 }
779 779 };
780 780 this.dirty = true;
781 781 };
782 782
783 783 // Other cell functions: line numbers, ...
784 784
785 785 Notebook.prototype.cell_toggle_line_numbers = function() {
786 786 this.get_selected_cell().toggle_line_numbers();
787 787 };
788 788
789 789 // Kernel related things
790 790
791 791 Notebook.prototype.start_kernel = function () {
792 792 this.kernel = new IPython.Kernel();
793 793 var notebook_id = IPython.save_widget.get_notebook_id();
794 794 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
795 795 };
796 796
797 797
798 798 Notebook.prototype.restart_kernel = function () {
799 799 var that = this;
800 800 var notebook_id = IPython.save_widget.get_notebook_id();
801 801
802 802 var dialog = $('<div/>');
803 803 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
804 804 $(document).append(dialog);
805 805 dialog.dialog({
806 806 resizable: false,
807 807 modal: true,
808 808 title: "Restart kernel or continue running?",
809 809 closeText: '',
810 810 buttons : {
811 811 "Restart": function () {
812 812 that.kernel.restart($.proxy(that.kernel_started, that));
813 813 $(this).dialog('close');
814 814 },
815 815 "Continue running": function () {
816 816 $(this).dialog('close');
817 817 }
818 818 }
819 819 });
820 820 };
821 821
822 822
823 823 Notebook.prototype.kernel_started = function () {
824 824 console.log("Kernel started: ", this.kernel.kernel_id);
825 825 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
826 826 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
827 827 };
828 828
829 829
830 830 Notebook.prototype.handle_shell_reply = function (e) {
831 831 reply = $.parseJSON(e.data);
832 832 var header = reply.header;
833 833 var content = reply.content;
834 834 var msg_type = header.msg_type;
835 835 // console.log(reply);
836 836 var cell = this.cell_for_msg(reply.parent_header.msg_id);
837 837 if (msg_type === "execute_reply") {
838 838 cell.set_input_prompt(content.execution_count);
839 839 cell.element.removeClass("running");
840 840 this.dirty = true;
841 841 } else if (msg_type === "complete_reply") {
842 842 cell.finish_completing(content.matched_text, content.matches);
843 843 } else if (msg_type === "object_info_reply"){
844 844 //console.log('back from object_info_request : ')
845 845 rep = reply.content;
846 846 if(rep.found)
847 847 {
848 848 cell.finish_tooltip(rep);
849 849 }
850 850 } else {
851 851 //console.log("unknown reply:"+msg_type);
852 852 }
853 853 // when having a rely from object_info_reply,
854 854 // no payload so no nned to handle it
855 855 if(typeof(content.payload)!='undefined') {
856 856 var payload = content.payload || [];
857 857 this.handle_payload(cell, payload);
858 858 }
859 859 };
860 860
861 861
862 862 Notebook.prototype.handle_payload = function (cell, payload) {
863 863 var l = payload.length;
864 864 for (var i=0; i<l; i++) {
865 865 if (payload[i].source === 'IPython.zmq.page.page') {
866 866 if (payload[i].text.trim() !== '') {
867 867 IPython.pager.clear();
868 868 IPython.pager.expand();
869 869 IPython.pager.append_text(payload[i].text);
870 870 }
871 871 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
872 872 var index = this.find_cell_index(cell);
873 873 var new_cell = this.insert_cell_below('code',index);
874 874 new_cell.set_text(payload[i].text);
875 875 this.dirty = true;
876 876 }
877 877 };
878 878 };
879 879
880 880
881 881 Notebook.prototype.handle_iopub_reply = function (e) {
882 882 reply = $.parseJSON(e.data);
883 883 var content = reply.content;
884 884 // console.log(reply);
885 885 var msg_type = reply.header.msg_type;
886 886 var cell = this.cell_for_msg(reply.parent_header.msg_id);
887 887 if (msg_type !== 'status' && !cell){
888 888 // message not from this notebook, but should be attached to a cell
889 889 console.log("Received IOPub message not caused by one of my cells");
890 890 console.log(reply);
891 891 return;
892 892 }
893 893 var output_types = ['stream','display_data','pyout','pyerr'];
894 894 if (output_types.indexOf(msg_type) >= 0) {
895 895 this.handle_output(cell, msg_type, content);
896 896 } else if (msg_type === 'status') {
897 897 if (content.execution_state === 'busy') {
898 898 IPython.kernel_status_widget.status_busy();
899 899 } else if (content.execution_state === 'idle') {
900 900 IPython.kernel_status_widget.status_idle();
901 901 } else if (content.execution_state === 'dead') {
902 902 this.handle_status_dead();
903 903 };
904 904 } else if (msg_type === 'clear_output') {
905 905 cell.clear_output(content.stdout, content.stderr, content.other);
906 906 };
907 907 };
908 908
909 909
910 910 Notebook.prototype.handle_status_dead = function () {
911 911 var that = this;
912 912 this.kernel.stop_channels();
913 913 var dialog = $('<div/>');
914 914 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.');
915 915 $(document).append(dialog);
916 916 dialog.dialog({
917 917 resizable: false,
918 918 modal: true,
919 919 title: "Dead kernel",
920 920 buttons : {
921 921 "Restart": function () {
922 922 that.start_kernel();
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.handle_output = function (cell, msg_type, content) {
934 934 var json = {};
935 935 json.output_type = msg_type;
936 936 if (msg_type === "stream") {
937 937 json.text = utils.fixConsole(content.data);
938 938 json.stream = content.name;
939 939 } else if (msg_type === "display_data") {
940 940 json = this.convert_mime_types(json, content.data);
941 941 } else if (msg_type === "pyout") {
942 942 json.prompt_number = content.execution_count;
943 943 json = this.convert_mime_types(json, content.data);
944 944 } else if (msg_type === "pyerr") {
945 945 json.ename = content.ename;
946 946 json.evalue = content.evalue;
947 947 var traceback = [];
948 948 for (var i=0; i<content.traceback.length; i++) {
949 949 traceback.push(utils.fixConsole(content.traceback[i]));
950 950 }
951 951 json.traceback = traceback;
952 952 };
953 953 cell.append_output(json);
954 954 this.dirty = true;
955 955 };
956 956
957 957
958 958 Notebook.prototype.convert_mime_types = function (json, data) {
959 959 if (data['text/plain'] !== undefined) {
960 960 json.text = utils.fixConsole(data['text/plain']);
961 961 };
962 962 if (data['text/html'] !== undefined) {
963 963 json.html = data['text/html'];
964 964 };
965 965 if (data['image/svg+xml'] !== undefined) {
966 966 json.svg = data['image/svg+xml'];
967 967 };
968 968 if (data['image/png'] !== undefined) {
969 969 json.png = data['image/png'];
970 970 };
971 971 if (data['image/jpeg'] !== undefined) {
972 972 json.jpeg = data['image/jpeg'];
973 973 };
974 974 if (data['text/latex'] !== undefined) {
975 975 json.latex = data['text/latex'];
976 976 };
977 977 if (data['application/json'] !== undefined) {
978 978 json.json = data['application/json'];
979 979 };
980 980 if (data['application/javascript'] !== undefined) {
981 981 json.javascript = data['application/javascript'];
982 982 }
983 983 return json;
984 984 };
985 985
986 986
987 987 Notebook.prototype.execute_selected_cell = function (options) {
988 988 // add_new: should a new cell be added if we are at the end of the nb
989 989 // terminal: execute in terminal mode, which stays in the current cell
990 990 default_options = {terminal: false, add_new: true};
991 991 $.extend(default_options, options);
992 992 var that = this;
993 993 var cell = that.get_selected_cell();
994 994 var cell_index = that.find_cell_index(cell);
995 995 if (cell instanceof IPython.CodeCell) {
996 996 cell.clear_output(true, true, true);
997 997 cell.set_input_prompt('*');
998 998 cell.element.addClass("running");
999 999 var code = cell.get_text();
1000 1000 var msg_id = that.kernel.execute(cell.get_text());
1001 1001 that.msg_cell_map[msg_id] = cell.cell_id;
1002 1002 } else if (cell instanceof IPython.HTMLCell) {
1003 1003 cell.render();
1004 1004 }
1005 1005 if (default_options.terminal) {
1006 1006 cell.select_all();
1007 1007 } else {
1008 1008 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1009 1009 that.insert_cell_below('code');
1010 1010 // If we are adding a new cell at the end, scroll down to show it.
1011 1011 that.scroll_to_bottom();
1012 1012 } else {
1013 1013 that.select(cell_index+1);
1014 1014 };
1015 1015 };
1016 1016 this.dirty = true;
1017 1017 };
1018 1018
1019 1019
1020 1020 Notebook.prototype.execute_all_cells = function () {
1021 1021 var ncells = this.ncells();
1022 1022 for (var i=0; i<ncells; i++) {
1023 1023 this.select(i);
1024 1024 this.execute_get_selected_cell({add_new:false});
1025 1025 };
1026 1026 this.scroll_to_bottom();
1027 1027 };
1028 1028
1029 1029
1030 1030 Notebook.prototype.request_tool_tip = function (cell,func) {
1031 1031 // Feel free to shorten this logic if you are better
1032 1032 // than me in regEx
1033 1033 // basicaly you shoul be able to get xxx.xxx.xxx from
1034 1034 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
1035 1035 // remove everything between matchin bracket (need to iterate)
1036 1036 matchBracket = /\([^\(\)]+\)/g;
1037 1037 oldfunc = func;
1038 1038 func = func.replace(matchBracket,"");
1039 1039 while( oldfunc != func )
1040 1040 {
1041 1041 oldfunc = func;
1042 1042 func = func.replace(matchBracket,"");
1043 1043 }
1044 1044 // remove everythin after last open bracket
1045 1045 endBracket = /\([^\(]*$/g;
1046 1046 func = func.replace(endBracket,"");
1047 1047 var re = /[a-zA-Z._]+$/g;
1048 1048 var msg_id = this.kernel.object_info_request(re.exec(func));
1049 1049 if(typeof(msg_id)!='undefined'){
1050 1050 this.msg_cell_map[msg_id] = cell.cell_id;
1051 1051 }
1052 1052 };
1053 1053
1054 1054 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
1055 1055 var msg_id = this.kernel.complete(line, cursor_pos);
1056 1056 this.msg_cell_map[msg_id] = cell.cell_id;
1057 1057 };
1058 1058
1059 1059 // Persistance and loading
1060 1060
1061 1061
1062 1062 Notebook.prototype.fromJSON = function (data) {
1063 1063 var ncells = this.ncells();
1064 1064 var i;
1065 1065 for (i=0; i<ncells; i++) {
1066 1066 // Always delete cell 0 as they get renumbered as they are deleted.
1067 1067 this.delete_cell(0);
1068 1068 };
1069 1069 // Save the metadata
1070 1070 this.metadata = data.metadata;
1071 1071 // Only handle 1 worksheet for now.
1072 1072 var worksheet = data.worksheets[0];
1073 1073 if (worksheet !== undefined) {
1074 1074 var new_cells = worksheet.cells;
1075 1075 ncells = new_cells.length;
1076 1076 var cell_data = null;
1077 1077 var new_cell = null;
1078 1078 for (i=0; i<ncells; i++) {
1079 1079 cell_data = new_cells[i];
1080 1080 new_cell = this.insert_cell_below(cell_data.cell_type);
1081 1081 new_cell.fromJSON(cell_data);
1082 1082 };
1083 1083 };
1084 1084 };
1085 1085
1086 1086
1087 1087 Notebook.prototype.toJSON = function () {
1088 1088 var cells = this.get_cells();
1089 1089 var ncells = cells.length;
1090 1090 cell_array = new Array(ncells);
1091 1091 for (var i=0; i<ncells; i++) {
1092 1092 cell_array[i] = cells[i].toJSON();
1093 1093 };
1094 1094 data = {
1095 1095 // Only handle 1 worksheet for now.
1096 1096 worksheets : [{cells:cell_array}],
1097 1097 metadata : this.metadata
1098 1098 };
1099 1099 return data;
1100 1100 };
1101 1101
1102 1102 Notebook.prototype.save_notebook = function () {
1103 1103 if (IPython.save_widget.test_notebook_name()) {
1104 1104 var notebook_id = IPython.save_widget.get_notebook_id();
1105 1105 var nbname = IPython.save_widget.get_notebook_name();
1106 1106 // We may want to move the name/id/nbformat logic inside toJSON?
1107 1107 var data = this.toJSON();
1108 1108 data.metadata.name = nbname;
1109 1109 data.nbformat = 2;
1110 1110 // We do the call with settings so we can set cache to false.
1111 1111 var settings = {
1112 1112 processData : false,
1113 1113 cache : false,
1114 1114 type : "PUT",
1115 1115 data : JSON.stringify(data),
1116 1116 headers : {'Content-Type': 'application/json'},
1117 1117 success : $.proxy(this.notebook_saved,this),
1118 1118 error : $.proxy(this.notebook_save_failed,this)
1119 1119 };
1120 1120 IPython.save_widget.status_saving();
1121 1121 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
1122 1122 $.ajax(url, settings);
1123 1123 };
1124 1124 };
1125 1125
1126 1126
1127 1127 Notebook.prototype.notebook_saved = function (data, status, xhr) {
1128 1128 this.dirty = false;
1129 1129 IPython.save_widget.notebook_saved();
1130 1130 IPython.save_widget.status_last_saved();
1131 1131 };
1132 1132
1133 1133
1134 1134 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
1135 1135 IPython.save_widget.status_save_failed();
1136 1136 };
1137 1137
1138 1138
1139 1139 Notebook.prototype.load_notebook = function (callback) {
1140 1140 var that = this;
1141 1141 var notebook_id = IPython.save_widget.get_notebook_id();
1142 1142 // We do the call with settings so we can set cache to false.
1143 1143 var settings = {
1144 1144 processData : false,
1145 1145 cache : false,
1146 1146 type : "GET",
1147 1147 dataType : "json",
1148 1148 success : function (data, status, xhr) {
1149 1149 that.notebook_loaded(data, status, xhr);
1150 1150 if (callback !== undefined) {
1151 1151 callback();
1152 1152 };
1153 1153 }
1154 1154 };
1155 1155 IPython.save_widget.status_loading();
1156 1156 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
1157 1157 $.ajax(url, settings);
1158 1158 };
1159 1159
1160 1160
1161 1161 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
1162 var allowed = xhr.getResponseHeader('Allow');
1163 1162 this.fromJSON(data);
1164 1163 if (this.ncells() === 0) {
1165 1164 this.insert_cell_below('code');
1166 1165 };
1167 1166 IPython.save_widget.status_last_saved();
1168 1167 IPython.save_widget.set_notebook_name(data.metadata.name);
1169 1168 this.dirty = false;
1170 1169 if (! this.read_only) {
1171 1170 this.start_kernel();
1172 1171 }
1173 1172 // fromJSON always selects the last cell inserted. We need to wait
1174 1173 // until that is done before scrolling to the top.
1175 1174 setTimeout(function () {
1176 1175 IPython.notebook.select(0);
1177 1176 IPython.notebook.scroll_to_top();
1178 1177 }, 50);
1179 1178 };
1180 1179
1181 1180 IPython.Notebook = Notebook;
1182 1181
1183 1182
1184 1183 return IPython;
1185 1184
1186 1185 }(IPython));
1187 1186
@@ -1,124 +1,123 b''
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 // On document ready
10 10 //============================================================================
11 11
12 12
13 13 $(document).ready(function () {
14 14 if (window.MathJax){
15 15 // MathJax loaded
16 16 MathJax.Hub.Config({
17 17 tex2jax: {
18 18 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
19 19 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
20 20 },
21 21 displayAlign: 'left', // Change this to 'center' to center equations.
22 22 "HTML-CSS": {
23 23 styles: {'.MathJax_Display': {"margin": 0}}
24 24 }
25 25 });
26 26 }else if (window.mathjax_url != ""){
27 27 // Don't have MathJax, but should. Show dialog.
28 28 var dialog = $('<div></div>')
29 29 .append(
30 30 $("<p></p>").addClass('dialog').html(
31 31 "Math/LaTeX rendering will be disabled."
32 32 )
33 33 ).append(
34 34 $("<p></p>").addClass('dialog').html(
35 35 "If you have administrative access to the notebook server and" +
36 36 " a working internet connection, you can install a local copy" +
37 37 " of MathJax for offline use with the following command on the server" +
38 38 " at a Python or IPython prompt:"
39 39 )
40 40 ).append(
41 41 $("<pre></pre>").addClass('dialog').html(
42 42 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
43 43 )
44 44 ).append(
45 45 $("<p></p>").addClass('dialog').html(
46 46 "This will try to install MathJax into the IPython source directory."
47 47 )
48 48 ).append(
49 49 $("<p></p>").addClass('dialog').html(
50 50 "If IPython is installed to a location that requires" +
51 51 " administrative privileges to write, you will need to make this call as" +
52 52 " an administrator, via 'sudo'."
53 53 )
54 54 ).append(
55 55 $("<p></p>").addClass('dialog').html(
56 56 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
57 57 )
58 58 ).append(
59 59 $("<pre></pre>").addClass('dialog').html(
60 60 "$ ipython notebook --no-mathjax"
61 61 )
62 62 ).append(
63 63 $("<p></p>").addClass('dialog').html(
64 64 "which will prevent this dialog from appearing."
65 65 )
66 66 ).dialog({
67 67 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
68 68 width: "70%",
69 69 modal: true,
70 70 })
71 71 }else{
72 72 // No MathJax, but none expected. No dialog.
73 73 }
74 74
75 75
76 76 IPython.markdown_converter = new Markdown.Converter();
77 77 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
78 78
79 79 $('div#header').addClass('border-box-sizing');
80 80 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
81 81 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
82 82
83 83 IPython.layout_manager = new IPython.LayoutManager();
84 84 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
85 85 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
86 86 IPython.quick_help = new IPython.QuickHelp('span#quick_help_area');
87 87 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
88 88 IPython.notebook = new IPython.Notebook('div#notebook');
89 89 IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
90 90 IPython.menubar = new IPython.MenuBar('#menubar')
91 91 IPython.kernel_status_widget.status_idle();
92 92 IPython.fulledit_widget = new IPython.FullEditWidget('#fulledit_widget');
93 93
94 94 IPython.layout_manager.do_resize();
95 95
96 96 // These have display: none in the css file and are made visible here to prevent FLOUC.
97 97 $('div#header').css('display','block');
98 98
99 99 if(IPython.read_only){
100 100 // hide various elements from read-only view
101 101 $('div#pager').remove();
102 102 $('div#pager_splitter').remove();
103 103 $('span#login_widget').removeClass('hidden');
104 104
105 105 // set the notebook name field as not modifiable
106 106 $('#notebook_name').attr('disabled','disabled')
107 107 }
108 108
109 109 $('div#menubar').css('display','block');
110 110 $('div#main_app').css('display','block');
111 111
112 112 // Perform these actions after the notebook has been loaded.
113 113 // We wait 100 milliseconds because the notebook scrolls to the top after a load
114 114 // is completed and we need to wait for that to mostly finish.
115 115 IPython.notebook.load_notebook(function () {
116 116 setTimeout(function () {
117 117 IPython.save_widget.update_url();
118 118 IPython.layout_manager.do_resize();
119 IPython.pager.collapse();
120 119 },100);
121 120 });
122 121
123 122 });
124 123
@@ -1,102 +1,102 b''
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 // Pager
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var utils = IPython.utils;
15 15
16 16 var Pager = function (pager_selector, pager_splitter_selector) {
17 17 this.pager_element = $(pager_selector);
18 18 this.pager_splitter_element = $(pager_splitter_selector);
19 this.expanded = true;
19 this.expanded = false;
20 20 this.percentage_height = 0.40;
21 21 this.style();
22 22 this.bind_events();
23 23 };
24 24
25 25
26 26 Pager.prototype.style = function () {
27 27 this.pager_splitter_element.addClass('border-box-sizing ui-widget ui-state-default');
28 28 this.pager_element.addClass('border-box-sizing ui-widget');
29 29 this.pager_splitter_element.attr('title', 'Click to Show/Hide pager area');
30 30 };
31 31
32 32
33 33 Pager.prototype.bind_events = function () {
34 34 var that = this;
35 35
36 36 this.pager_element.bind('collapse_pager', function () {
37 37 that.pager_element.hide('fast');
38 38 });
39 39
40 40 this.pager_element.bind('expand_pager', function () {
41 41 that.pager_element.show('fast');
42 42 });
43 43
44 44 this.pager_splitter_element.hover(
45 45 function () {
46 46 that.pager_splitter_element.addClass('ui-state-hover');
47 47 },
48 48 function () {
49 49 that.pager_splitter_element.removeClass('ui-state-hover');
50 50 }
51 51 );
52 52
53 53 this.pager_splitter_element.click(function () {
54 54 that.toggle();
55 55 });
56 56
57 57 };
58 58
59 59
60 60 Pager.prototype.collapse = function () {
61 61 if (this.expanded === true) {
62 62 this.pager_element.add($('div#notebook')).trigger('collapse_pager');
63 63 this.expanded = false;
64 64 };
65 65 };
66 66
67 67
68 68 Pager.prototype.expand = function () {
69 69 if (this.expanded !== true) {
70 70 this.pager_element.add($('div#notebook')).trigger('expand_pager');
71 71 this.expanded = true;
72 72 };
73 73 };
74 74
75 75
76 76 Pager.prototype.toggle = function () {
77 77 if (this.expanded === true) {
78 78 this.collapse();
79 79 } else {
80 80 this.expand();
81 81 };
82 82 };
83 83
84 84
85 85 Pager.prototype.clear = function (text) {
86 86 this.pager_element.empty();
87 87 };
88 88
89 89
90 90 Pager.prototype.append_text = function (text) {
91 91 var toinsert = $("<div/>").addClass("output_area output_stream");
92 92 toinsert.append($('<pre/>').html(utils.fixConsole(text)));
93 93 this.pager_element.append(toinsert);
94 94 };
95 95
96 96
97 97 IPython.Pager = Pager;
98 98
99 99 return IPython;
100 100
101 101 }(IPython));
102 102
General Comments 0
You need to be logged in to leave comments. Login now