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