##// END OF EJS Templates
Major refactoring of saving, notification....
Brian Granger -
Show More
@@ -0,0 +1,31
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // Events
10 //============================================================================
11
12 // Give us an object to bind all events to. This object should be created
13 // before all other objects so it exists when others register event handlers.
14 // To trigger an event handler:
15 // $([IPython.events]).trigger('event.Namespace);
16 // To handle it:
17 // $([IPython.events]).on('event.Namespace',function () {});
18
19 var IPython = (function (IPython) {
20
21 var utils = IPython.utils;
22
23 var Events = function () {};
24
25 IPython.Events = Events;
26 IPython.events = new Events();
27
28 return IPython;
29
30 }(IPython));
31
@@ -0,0 +1,102
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // Notification widget
10 //============================================================================
11
12 var IPython = (function (IPython) {
13
14 var utils = IPython.utils;
15
16
17 var NotificationWidget = function (selector) {
18 this.selector = selector;
19 this.timeout = null;
20 this.busy = false;
21 if (this.selector !== undefined) {
22 this.element = $(selector);
23 this.style();
24 this.bind_events();
25 }
26 };
27
28
29 NotificationWidget.prototype.style = function () {
30 this.element.addClass('ui-widget ui-widget-content ui-corner-all');
31 this.element.addClass('border-box-sizing');
32 };
33
34
35 NotificationWidget.prototype.bind_events = function () {
36 var that = this;
37 // Kernel events
38 $([IPython.events]).on('status_idle.Kernel',function () {
39 IPython.save_widget.update_document_title();
40 if (that.get_message() === 'Kernel busy') {
41 that.element.fadeOut(100, function () {
42 that.element.html('');
43 });
44 };
45 });
46 $([IPython.events]).on('status_busy.Kernel',function () {
47 window.document.title='(Busy) '+window.document.title;
48 that.set_message("Kernel busy");
49 });
50 $([IPython.events]).on('status_restarting.Kernel',function () {
51 that.set_message("Restarting kernel",500);
52 });
53 $([IPython.events]).on('status_interrupting.Kernel',function () {
54 that.set_message("Interrupting kernel",500);
55 });
56 // Notebook events
57 $([IPython.events]).on('notebook_loading.Notebook', function () {
58 that.set_message("Loading notebook",500);
59 });
60 $([IPython.events]).on('notebook_loaded.Notebook', function () {
61 that.set_message("Notebook loaded",500);
62 });
63 $([IPython.events]).on('notebook_saving.Notebook', function () {
64 that.set_message("Saving notebook",500);
65 });
66 $([IPython.events]).on('notebook_saved.Notebook', function () {
67 that.set_message("Notebook saved",500);
68 });
69 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
70 that.set_message("Notebook save failed",500);
71 });
72 };
73
74
75 NotificationWidget.prototype.set_message = function (msg, timeout) {
76 var that = this;
77 this.element.html(msg);
78 this.element.fadeIn(100);
79 if (this.timeout !== null) {
80 clearTimeout(this.timeout);
81 this.timeout = null;
82 };
83 if (timeout !== undefined) {
84 this.timeout = setTimeout(function () {
85 that.element.fadeOut(100, function () {that.element.html('');});
86 that.timeout = null;
87 }, timeout)
88 };
89 };
90
91
92 NotificationWidget.prototype.get_message = function () {
93 return this.element.html();
94 };
95
96
97 IPython.NotificationWidget = NotificationWidget;
98
99 return IPython;
100
101 }(IPython));
102
@@ -1,393 +1,381
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 padding: 5px;
21 padding: 5px;
22 margin: 0px 0px 0px 300px;
22 margin: 0px 0px 0px 300px;
23 display:inline-block;
23 display:inline-block;
24 }
24 }
25
25
26 span#notebook_name {
26 span#notebook_name {
27 height: 1em;
27 height: 1em;
28 line-height: 1em;
28 line-height: 1em;
29 padding: 3px;
29 padding: 3px;
30 border: none;
30 border: none;
31 font-size: 146.5%;
31 font-size: 146.5%;
32 }
32 }
33
33
34 #menubar {
34 #menubar {
35 /* Initially hidden to prevent FLOUC */
35 /* Initially hidden to prevent FLOUC */
36 display: none;
36 display: none;
37 }
37 }
38
38
39 .ui-menubar-item .ui-button .ui-button-text {
39 .ui-menubar-item .ui-button .ui-button-text {
40 padding: 0.4em 1.0em;
40 padding: 0.4em 1.0em;
41 font-size: 100%;
41 font-size: 100%;
42 }
42 }
43
43
44 .ui-menu {
44 .ui-menu {
45 -moz-box-shadow: 0px 6px 10px -1px #adadad;
45 -moz-box-shadow: 0px 6px 10px -1px #adadad;
46 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
46 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
47 box-shadow: 0px 6px 10px -1px #adadad;
47 box-shadow: 0px 6px 10px -1px #adadad;
48 }
48 }
49
49
50 .ui-menu .ui-menu-item a {
50 .ui-menu .ui-menu-item a {
51 padding: 2px 1.6em;
51 padding: 2px 1.6em;
52 }
52 }
53
53
54 .ui-menu hr {
54 .ui-menu hr {
55 margin: 0.3em 0;
55 margin: 0.3em 0;
56 }
56 }
57
57
58 #menubar_container {
59 position: relative;
60 }
61
62 #notification {
63 position: absolute;
64 right: 3px;
65 top: 3px;
66 height: 25px;
67 padding: 3px 6px;
68 z-index: 10;
69 }
70
58 #toolbar {
71 #toolbar {
59 /* Initially hidden to prevent FLOUC */
72 /* Initially hidden to prevent FLOUC */
60 display: none;
73 display: none;
61 padding: 3px 15px;
74 padding: 3px 15px;
62 }
75 }
63
76
64 #cell_type {
77 #cell_type {
65 font-size: 85%;
78 font-size: 85%;
66 }
79 }
67
80
68 span#quick_help_area {
81 span#quick_help_area {
69 position: static;
82 position: static;
70 padding: 5px 0px;
83 padding: 5px 0px;
71 margin: 0px 0px 0px 0px;
84 margin: 0px 0px 0px 0px;
72 }
85 }
73
86
74 span#kernel_status {
75 position: absolute;
76 padding: 8px 5px 5px 5px;
77 right: 10px;
78 font-weight: bold;
79 }
80
81
82 .status_idle {
83 color: gray;
84 visibility: hidden;
85 }
86
87 .status_busy {
88 color: red;
89 }
90
91 .status_restarting {
92 color: black;
93 }
94
95 #kernel_persist {
96 float: right;
97 }
98
99 .help_string {
87 .help_string {
100 float: right;
88 float: right;
101 width: 170px;
89 width: 170px;
102 padding: 0px 5px;
90 padding: 0px 5px;
103 text-align: left;
91 text-align: left;
104 font-size: 85%;
92 font-size: 85%;
105 }
93 }
106
94
107 .help_string_label {
95 .help_string_label {
108 float: right;
96 float: right;
109 font-size: 85%;
97 font-size: 85%;
110 }
98 }
111
99
112 div#notebook_panel {
100 div#notebook_panel {
113 margin: 0px 0px 0px 0px;
101 margin: 0px 0px 0px 0px;
114 padding: 0px;
102 padding: 0px;
115 }
103 }
116
104
117 div#notebook {
105 div#notebook {
118 overflow-y: scroll;
106 overflow-y: scroll;
119 overflow-x: auto;
107 overflow-x: auto;
120 width: 100%;
108 width: 100%;
121 /* This spaces the cell away from the edge of the notebook area */
109 /* This spaces the cell away from the edge of the notebook area */
122 padding: 5px 5px 15px 5px;
110 padding: 5px 5px 15px 5px;
123 margin: 0px
111 margin: 0px
124 background-color: white;
112 background-color: white;
125 }
113 }
126
114
127 div#pager_splitter {
115 div#pager_splitter {
128 height: 8px;
116 height: 8px;
129 }
117 }
130
118
131 div#pager {
119 div#pager {
132 padding: 15px;
120 padding: 15px;
133 overflow: auto;
121 overflow: auto;
134 display: none;
122 display: none;
135 }
123 }
136
124
137 div.cell {
125 div.cell {
138 width: 100%;
126 width: 100%;
139 padding: 5px 5px 5px 0px;
127 padding: 5px 5px 5px 0px;
140 /* This acts as a spacer between cells, that is outside the border */
128 /* This acts as a spacer between cells, that is outside the border */
141 margin: 2px 0px 2px 0px;
129 margin: 2px 0px 2px 0px;
142 }
130 }
143
131
144 div.code_cell {
132 div.code_cell {
145 background-color: white;
133 background-color: white;
146 }
134 }
147 /* any special styling for code cells that are currently running goes here */
135 /* any special styling for code cells that are currently running goes here */
148 div.code_cell.running {
136 div.code_cell.running {
149 }
137 }
150
138
151 div.prompt {
139 div.prompt {
152 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
140 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
153 width: 11ex;
141 width: 11ex;
154 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
142 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
155 padding: 0.4em;
143 padding: 0.4em;
156 margin: 0px;
144 margin: 0px;
157 font-family: monospace;
145 font-family: monospace;
158 text-align:right;
146 text-align:right;
159 }
147 }
160
148
161 div.input {
149 div.input {
162 page-break-inside: avoid;
150 page-break-inside: avoid;
163 }
151 }
164
152
165 /* input_area and input_prompt must match in top border and margin for alignment */
153 /* input_area and input_prompt must match in top border and margin for alignment */
166 div.input_area {
154 div.input_area {
167 color: black;
155 color: black;
168 border: 1px solid #ddd;
156 border: 1px solid #ddd;
169 border-radius: 3px;
157 border-radius: 3px;
170 background: #f7f7f7;
158 background: #f7f7f7;
171 }
159 }
172
160
173 div.input_prompt {
161 div.input_prompt {
174 color: navy;
162 color: navy;
175 border-top: 1px solid transparent;
163 border-top: 1px solid transparent;
176 }
164 }
177
165
178 div.output {
166 div.output {
179 /* This is a spacer between the input and output of each cell */
167 /* This is a spacer between the input and output of each cell */
180 margin-top: 5px;
168 margin-top: 5px;
181 }
169 }
182
170
183 div.output_prompt {
171 div.output_prompt {
184 color: darkred;
172 color: darkred;
185 }
173 }
186
174
187 /* This class is the outer container of all output sections. */
175 /* This class is the outer container of all output sections. */
188 div.output_area {
176 div.output_area {
189 padding: 0px;
177 padding: 0px;
190 page-break-inside: avoid;
178 page-break-inside: avoid;
191 }
179 }
192
180
193 /* This class is for the output subarea inside the output_area and after
181 /* This class is for the output subarea inside the output_area and after
194 the prompt div. */
182 the prompt div. */
195 div.output_subarea {
183 div.output_subarea {
196 padding: 0.4em 6.1em 0.4em 0.4em;
184 padding: 0.4em 6.1em 0.4em 0.4em;
197 }
185 }
198
186
199 /* The rest of the output_* classes are for special styling of the different
187 /* The rest of the output_* classes are for special styling of the different
200 output types */
188 output types */
201
189
202 /* all text output has this class: */
190 /* all text output has this class: */
203 div.output_text {
191 div.output_text {
204 text-align: left;
192 text-align: left;
205 color: black;
193 color: black;
206 font-family: monospace;
194 font-family: monospace;
207 }
195 }
208
196
209 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
197 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
210 div.output_stream {
198 div.output_stream {
211 padding-top: 0.0em;
199 padding-top: 0.0em;
212 padding-bottom: 0.0em;
200 padding-bottom: 0.0em;
213 }
201 }
214 div.output_stdout {
202 div.output_stdout {
215 }
203 }
216 div.output_stderr {
204 div.output_stderr {
217 background: #fdd; /* very light red background for stderr */
205 background: #fdd; /* very light red background for stderr */
218 }
206 }
219
207
220 div.output_latex {
208 div.output_latex {
221 text-align: left;
209 text-align: left;
222 color: black;
210 color: black;
223 }
211 }
224
212
225 div.output_html {
213 div.output_html {
226 }
214 }
227
215
228 div.output_png {
216 div.output_png {
229 }
217 }
230
218
231 div.output_jpeg {
219 div.output_jpeg {
232 }
220 }
233
221
234 div.text_cell {
222 div.text_cell {
235 background-color: white;
223 background-color: white;
236 padding: 5px 5px 5px 5px;
224 padding: 5px 5px 5px 5px;
237 }
225 }
238
226
239 div.text_cell_input {
227 div.text_cell_input {
240 color: black;
228 color: black;
241 border: 1px solid #ddd;
229 border: 1px solid #ddd;
242 border-radius: 3px;
230 border-radius: 3px;
243 background: #f7f7f7;
231 background: #f7f7f7;
244 }
232 }
245
233
246 div.text_cell_render {
234 div.text_cell_render {
247 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
235 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
248 outline: none;
236 outline: none;
249 resize: none;
237 resize: none;
250 width: inherit;
238 width: inherit;
251 border-style: none;
239 border-style: none;
252 padding: 5px;
240 padding: 5px;
253 color: black;
241 color: black;
254 }
242 }
255
243
256 .CodeMirror {
244 .CodeMirror {
257 line-height: 1.231; /* Changed from 1em to our global default */
245 line-height: 1.231; /* Changed from 1em to our global default */
258 }
246 }
259
247
260 .CodeMirror-scroll {
248 .CodeMirror-scroll {
261 height: auto; /* Changed to auto to autogrow */
249 height: auto; /* Changed to auto to autogrow */
262 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
250 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
263 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
251 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
264 overflow-y: hidden;
252 overflow-y: hidden;
265 overflow-x: auto; /* Changed from auto to remove scrollbar */
253 overflow-x: auto; /* Changed from auto to remove scrollbar */
266 }
254 }
267
255
268 /* CSS font colors for translated ANSI colors. */
256 /* CSS font colors for translated ANSI colors. */
269
257
270
258
271 .ansiblack {color: black;}
259 .ansiblack {color: black;}
272 .ansired {color: darkred;}
260 .ansired {color: darkred;}
273 .ansigreen {color: darkgreen;}
261 .ansigreen {color: darkgreen;}
274 .ansiyellow {color: brown;}
262 .ansiyellow {color: brown;}
275 .ansiblue {color: darkblue;}
263 .ansiblue {color: darkblue;}
276 .ansipurple {color: darkviolet;}
264 .ansipurple {color: darkviolet;}
277 .ansicyan {color: steelblue;}
265 .ansicyan {color: steelblue;}
278 .ansigrey {color: grey;}
266 .ansigrey {color: grey;}
279 .ansibold {font-weight: bold;}
267 .ansibold {font-weight: bold;}
280
268
281 .completions , .tooltip {
269 .completions , .tooltip {
282 position: absolute;
270 position: absolute;
283 z-index: 10;
271 z-index: 10;
284 overflow: auto;
272 overflow: auto;
285 border: 1px solid black;
273 border: 1px solid black;
286 }
274 }
287
275
288 .completions select {
276 .completions select {
289 background: white;
277 background: white;
290 outline: none;
278 outline: none;
291 border: none;
279 border: none;
292 padding: 0px;
280 padding: 0px;
293 margin: 0px;
281 margin: 0px;
294 font-family: monospace;
282 font-family: monospace;
295 }
283 }
296
284
297 @-moz-keyframes fadeIn {
285 @-moz-keyframes fadeIn {
298 from {opacity:0;}
286 from {opacity:0;}
299 to {opacity:1;}
287 to {opacity:1;}
300 }
288 }
301
289
302 @-webkit-keyframes fadeIn {
290 @-webkit-keyframes fadeIn {
303 from {opacity:0;}
291 from {opacity:0;}
304 to {opacity:1;}
292 to {opacity:1;}
305 }
293 }
306
294
307 @keyframes fadeIn {
295 @keyframes fadeIn {
308 from {opacity:0;}
296 from {opacity:0;}
309 to {opacity:1;}
297 to {opacity:1;}
310 }
298 }
311
299
312 /*"close" "expand" and "Open in pager button" of
300 /*"close" "expand" and "Open in pager button" of
313 /* the tooltip*/
301 /* the tooltip*/
314 .tooltip a {
302 .tooltip a {
315 float:right;
303 float:right;
316 }
304 }
317
305
318 /*properties of tooltip after "expand"*/
306 /*properties of tooltip after "expand"*/
319 .bigtooltip {
307 .bigtooltip {
320 height:30%;
308 height:30%;
321 }
309 }
322
310
323 /*properties of tooltip before "expand"*/
311 /*properties of tooltip before "expand"*/
324 .smalltooltip {
312 .smalltooltip {
325 text-overflow: ellipsis;
313 text-overflow: ellipsis;
326 overflow: hidden;
314 overflow: hidden;
327 height:15%;
315 height:15%;
328 }
316 }
329
317
330 .tooltip {
318 .tooltip {
331 /*transition when "expand"ing tooltip */
319 /*transition when "expand"ing tooltip */
332 -webkit-transition-property: height;
320 -webkit-transition-property: height;
333 -webkit-transition-duration: 1s;
321 -webkit-transition-duration: 1s;
334 -moz-transition-property: height;
322 -moz-transition-property: height;
335 -moz-transition-duration: 1s;
323 -moz-transition-duration: 1s;
336 transition-property: height;
324 transition-property: height;
337 transition-duration: 1s;
325 transition-duration: 1s;
338 max-width:700px;
326 max-width:700px;
339 border-radius: 0px 10px 10px 10px;
327 border-radius: 0px 10px 10px 10px;
340 box-shadow: 3px 3px 5px #999;
328 box-shadow: 3px 3px 5px #999;
341 /*fade-in animation when inserted*/
329 /*fade-in animation when inserted*/
342 -webkit-animation: fadeIn 200ms;
330 -webkit-animation: fadeIn 200ms;
343 -moz-animation: fadeIn 200ms;
331 -moz-animation: fadeIn 200ms;
344 animation: fadeIn 200ms;
332 animation: fadeIn 200ms;
345 vertical-align: middle;
333 vertical-align: middle;
346 background: #FDFDD8;
334 background: #FDFDD8;
347 outline: none;
335 outline: none;
348 padding: 3px;
336 padding: 3px;
349 margin: 0px;
337 margin: 0px;
350 font-family: monospace;
338 font-family: monospace;
351 min-height:50px;
339 min-height:50px;
352 }
340 }
353
341
354 /*fixed part of the completion*/
342 /*fixed part of the completion*/
355 .completions p b {
343 .completions p b {
356 font-weight:bold;
344 font-weight:bold;
357 }
345 }
358
346
359 .completions p {
347 .completions p {
360 background: #DDF;
348 background: #DDF;
361 /*outline: none;
349 /*outline: none;
362 padding: 0px;*/
350 padding: 0px;*/
363 border-bottom: black solid 1px;
351 border-bottom: black solid 1px;
364 padding: 1px;
352 padding: 1px;
365 font-family: monospace;
353 font-family: monospace;
366 }
354 }
367
355
368 pre.dialog {
356 pre.dialog {
369 background-color: #f7f7f7;
357 background-color: #f7f7f7;
370 border: 1px solid #ddd;
358 border: 1px solid #ddd;
371 border-radius: 3px;
359 border-radius: 3px;
372 padding: 0.4em;
360 padding: 0.4em;
373 padding-left: 2em;
361 padding-left: 2em;
374 }
362 }
375
363
376 p.dialog {
364 p.dialog {
377 padding : 0.2em;
365 padding : 0.2em;
378 }
366 }
379
367
380 .shortcut_key {
368 .shortcut_key {
381 display: inline-block;
369 display: inline-block;
382 width: 15ex;
370 width: 15ex;
383 text-align: right;
371 text-align: right;
384 font-family: monospace;
372 font-family: monospace;
385 }
373 }
386
374
387 .shortcut_descr {
375 .shortcut_descr {
388 }
376 }
389
377
390 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
378 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
391 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
379 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
392 */
380 */
393 pre, code, kbd, samp { white-space: pre-wrap; }
381 pre, code, kbd, samp { white-space: pre-wrap; }
@@ -1,235 +1,235
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 // Kernel
9 // Kernel
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 Kernel = function () {
16 var Kernel = function () {
17 this.kernel_id = null;
17 this.kernel_id = null;
18 this.shell_channel = null;
18 this.shell_channel = null;
19 this.iopub_channel = null;
19 this.iopub_channel = null;
20 this.base_url = $('body').data('baseKernelUrl') + "kernels";
20 this.base_url = $('body').data('baseKernelUrl') + "kernels";
21 this.running = false;
21 this.running = false;
22 this.username = "username";
22 this.username = "username";
23 this.session_id = utils.uuid();
23 this.session_id = utils.uuid();
24
24
25 if (typeof(WebSocket) !== 'undefined') {
25 if (typeof(WebSocket) !== 'undefined') {
26 this.WebSocket = WebSocket;
26 this.WebSocket = WebSocket;
27 } else if (typeof(MozWebSocket) !== 'undefined') {
27 } else if (typeof(MozWebSocket) !== 'undefined') {
28 this.WebSocket = MozWebSocket;
28 this.WebSocket = MozWebSocket;
29 } else {
29 } else {
30 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox ≥ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
30 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox ≥ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
31 };
31 };
32 };
32 };
33
33
34
34
35 Kernel.prototype.get_msg = function (msg_type, content) {
35 Kernel.prototype.get_msg = function (msg_type, content) {
36 var msg = {
36 var msg = {
37 header : {
37 header : {
38 msg_id : utils.uuid(),
38 msg_id : utils.uuid(),
39 username : this.username,
39 username : this.username,
40 session : this.session_id,
40 session : this.session_id,
41 msg_type : msg_type
41 msg_type : msg_type
42 },
42 },
43 content : content,
43 content : content,
44 parent_header : {}
44 parent_header : {}
45 };
45 };
46 return msg;
46 return msg;
47 };
47 };
48
48
49 Kernel.prototype.start = function (notebook_id, callback) {
49 Kernel.prototype.start = function (notebook_id, callback) {
50 var that = this;
50 var that = this;
51 if (!this.running) {
51 if (!this.running) {
52 var qs = $.param({notebook:notebook_id});
52 var qs = $.param({notebook:notebook_id});
53 var url = this.base_url + '?' + qs;
53 var url = this.base_url + '?' + qs;
54 $.post(url,
54 $.post(url,
55 function (kernel_id) {
55 function (kernel_id) {
56 that._handle_start_kernel(kernel_id, callback);
56 that._handle_start_kernel(kernel_id, callback);
57 },
57 },
58 'json'
58 'json'
59 );
59 );
60 };
60 };
61 };
61 };
62
62
63
63
64 Kernel.prototype.restart = function (callback) {
64 Kernel.prototype.restart = function (callback) {
65 IPython.kernel_status_widget.status_restarting();
65 $([IPython.events]).trigger('status_restarting.Kernel');
66 var url = this.kernel_url + "/restart";
66 var url = this.kernel_url + "/restart";
67 var that = this;
67 var that = this;
68 if (this.running) {
68 if (this.running) {
69 this.stop_channels();
69 this.stop_channels();
70 $.post(url,
70 $.post(url,
71 function (kernel_id) {
71 function (kernel_id) {
72 that._handle_start_kernel(kernel_id, callback);
72 that._handle_start_kernel(kernel_id, callback);
73 },
73 },
74 'json'
74 'json'
75 );
75 );
76 };
76 };
77 };
77 };
78
78
79
79
80 Kernel.prototype._handle_start_kernel = function (json, callback) {
80 Kernel.prototype._handle_start_kernel = function (json, callback) {
81 this.running = true;
81 this.running = true;
82 this.kernel_id = json.kernel_id;
82 this.kernel_id = json.kernel_id;
83 this.ws_url = json.ws_url;
83 this.ws_url = json.ws_url;
84 this.kernel_url = this.base_url + "/" + this.kernel_id;
84 this.kernel_url = this.base_url + "/" + this.kernel_id;
85 this.start_channels();
85 this.start_channels();
86 callback();
86 callback();
87 IPython.kernel_status_widget.status_idle();
88 };
87 };
89
88
90 Kernel.prototype._websocket_closed = function(ws_url, early){
89 Kernel.prototype._websocket_closed = function(ws_url, early){
91 var msg;
90 var msg;
92 var parent_item = $('body');
91 var parent_item = $('body');
93 if (early) {
92 if (early) {
94 msg = "Websocket connection to " + ws_url + " could not be established.<br/>" +
93 msg = "Websocket connection to " + ws_url + " could not be established." +
95 " You will NOT be able to run code.<br/>" +
94 " You will NOT be able to run code." +
96 " Your browser may not be compatible with the websocket version in the server," +
95 " Your browser may not be compatible with the websocket version in the server," +
97 " or if the url does not look right, there could be an error in the" +
96 " or if the url does not look right, there could be an error in the" +
98 " server's configuration.";
97 " server's configuration.";
99 } else {
98 } else {
100 msg = "Websocket connection closed unexpectedly.<br/>" +
99 msg = "Websocket connection closed unexpectedly." +
101 " The kernel will no longer be responsive.";
100 " The kernel will no longer be responsive.";
102 }
101 }
103 var dialog = $('<div/>');
102 var dialog = $('<div/>');
104 dialog.html(msg);
103 dialog.html(msg);
105 parent_item.append(dialog);
104 parent_item.append(dialog);
106 dialog.dialog({
105 dialog.dialog({
107 resizable: false,
106 resizable: false,
108 modal: true,
107 modal: true,
109 title: "Websocket closed",
108 title: "Websocket closed",
110 buttons : {
109 buttons : {
111 "Okay": function () {
110 "Okay": function () {
112 $(this).dialog('close');
111 $(this).dialog('close');
113 }
112 }
114 }
113 }
115 });
114 });
116
115
117 };
116 };
118
117
119 Kernel.prototype.start_channels = function () {
118 Kernel.prototype.start_channels = function () {
120 var that = this;
119 var that = this;
121 this.stop_channels();
120 this.stop_channels();
122 var ws_url = this.ws_url + this.kernel_url;
121 var ws_url = this.ws_url + this.kernel_url;
123 console.log("Starting WS:", ws_url);
122 console.log("Starting WS:", ws_url);
124 this.shell_channel = new this.WebSocket(ws_url + "/shell");
123 this.shell_channel = new this.WebSocket(ws_url + "/shell");
125 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
124 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
126 send_cookie = function(){
125 send_cookie = function(){
127 this.send(document.cookie);
126 this.send(document.cookie);
128 };
127 };
129 var already_called_onclose = false; // only alert once
128 var already_called_onclose = false; // only alert once
130 ws_closed_early = function(evt){
129 ws_closed_early = function(evt){
131 if (already_called_onclose){
130 if (already_called_onclose){
132 return;
131 return;
133 }
132 }
134 already_called_onclose = true;
133 already_called_onclose = true;
135 if ( ! evt.wasClean ){
134 if ( ! evt.wasClean ){
136 that._websocket_closed(ws_url, true);
135 that._websocket_closed(ws_url, true);
137 }
136 }
138 };
137 };
139 ws_closed_late = function(evt){
138 ws_closed_late = function(evt){
140 if (already_called_onclose){
139 if (already_called_onclose){
141 return;
140 return;
142 }
141 }
143 already_called_onclose = true;
142 already_called_onclose = true;
144 if ( ! evt.wasClean ){
143 if ( ! evt.wasClean ){
145 that._websocket_closed(ws_url, false);
144 that._websocket_closed(ws_url, false);
146 }
145 }
147 };
146 };
148 this.shell_channel.onopen = send_cookie;
147 this.shell_channel.onopen = send_cookie;
149 this.shell_channel.onclose = ws_closed_early;
148 this.shell_channel.onclose = ws_closed_early;
150 this.iopub_channel.onopen = send_cookie;
149 this.iopub_channel.onopen = send_cookie;
151 this.iopub_channel.onclose = ws_closed_early;
150 this.iopub_channel.onclose = ws_closed_early;
152 // switch from early-close to late-close message after 1s
151 // switch from early-close to late-close message after 1s
153 setTimeout(function(){
152 setTimeout(function(){
154 that.shell_channel.onclose = ws_closed_late;
153 that.shell_channel.onclose = ws_closed_late;
155 that.iopub_channel.onclose = ws_closed_late;
154 that.iopub_channel.onclose = ws_closed_late;
156 }, 1000);
155 }, 1000);
157 };
156 };
158
157
159
158
160 Kernel.prototype.stop_channels = function () {
159 Kernel.prototype.stop_channels = function () {
161 if (this.shell_channel !== null) {
160 if (this.shell_channel !== null) {
162 this.shell_channel.onclose = function (evt) {};
161 this.shell_channel.onclose = function (evt) {};
163 this.shell_channel.close();
162 this.shell_channel.close();
164 this.shell_channel = null;
163 this.shell_channel = null;
165 };
164 };
166 if (this.iopub_channel !== null) {
165 if (this.iopub_channel !== null) {
167 this.iopub_channel.onclose = function (evt) {};
166 this.iopub_channel.onclose = function (evt) {};
168 this.iopub_channel.close();
167 this.iopub_channel.close();
169 this.iopub_channel = null;
168 this.iopub_channel = null;
170 };
169 };
171 };
170 };
172
171
173 Kernel.prototype.object_info_request = function (objname) {
172 Kernel.prototype.object_info_request = function (objname) {
174 if(typeof(objname)!=null && objname!=null)
173 if(typeof(objname)!=null && objname!=null)
175 {
174 {
176 var content = {
175 var content = {
177 oname : objname.toString(),
176 oname : objname.toString(),
178 };
177 };
179 var msg = this.get_msg("object_info_request", content);
178 var msg = this.get_msg("object_info_request", content);
180 this.shell_channel.send(JSON.stringify(msg));
179 this.shell_channel.send(JSON.stringify(msg));
181 return msg.header.msg_id;
180 return msg.header.msg_id;
182 }
181 }
183 return;
182 return;
184 }
183 }
185
184
186 Kernel.prototype.execute = function (code) {
185 Kernel.prototype.execute = function (code) {
187 var content = {
186 var content = {
188 code : code,
187 code : code,
189 silent : false,
188 silent : false,
190 user_variables : [],
189 user_variables : [],
191 user_expressions : {},
190 user_expressions : {},
192 allow_stdin : false
191 allow_stdin : false
193 };
192 };
194 var msg = this.get_msg("execute_request", content);
193 var msg = this.get_msg("execute_request", content);
195 this.shell_channel.send(JSON.stringify(msg));
194 this.shell_channel.send(JSON.stringify(msg));
196 return msg.header.msg_id;
195 return msg.header.msg_id;
197 };
196 };
198
197
199
198
200 Kernel.prototype.complete = function (line, cursor_pos) {
199 Kernel.prototype.complete = function (line, cursor_pos) {
201 var content = {
200 var content = {
202 text : '',
201 text : '',
203 line : line,
202 line : line,
204 cursor_pos : cursor_pos
203 cursor_pos : cursor_pos
205 };
204 };
206 var msg = this.get_msg("complete_request", content);
205 var msg = this.get_msg("complete_request", content);
207 this.shell_channel.send(JSON.stringify(msg));
206 this.shell_channel.send(JSON.stringify(msg));
208 return msg.header.msg_id;
207 return msg.header.msg_id;
209 };
208 };
210
209
211
210
212 Kernel.prototype.interrupt = function () {
211 Kernel.prototype.interrupt = function () {
213 if (this.running) {
212 if (this.running) {
213 $([IPython.events]).trigger('status_interrupting.Kernel');
214 $.post(this.kernel_url + "/interrupt");
214 $.post(this.kernel_url + "/interrupt");
215 };
215 };
216 };
216 };
217
217
218
218
219 Kernel.prototype.kill = function () {
219 Kernel.prototype.kill = function () {
220 if (this.running) {
220 if (this.running) {
221 this.running = false;
221 this.running = false;
222 var settings = {
222 var settings = {
223 cache : false,
223 cache : false,
224 type : "DELETE"
224 type : "DELETE"
225 };
225 };
226 $.ajax(this.kernel_url, settings);
226 $.ajax(this.kernel_url, settings);
227 };
227 };
228 };
228 };
229
229
230 IPython.Kernel = Kernel;
230 IPython.Kernel = Kernel;
231
231
232 return IPython;
232 return IPython;
233
233
234 }(IPython));
234 }(IPython));
235
235
@@ -1,177 +1,177
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 // MenuBar
9 // MenuBar
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 var MenuBar = function (selector) {
14 var MenuBar = function (selector) {
15 this.selector = selector;
15 this.selector = selector;
16 if (this.selector !== undefined) {
16 if (this.selector !== undefined) {
17 this.element = $(selector);
17 this.element = $(selector);
18 this.style();
18 this.style();
19 this.bind_events();
19 this.bind_events();
20 }
20 }
21 };
21 };
22
22
23
23
24 MenuBar.prototype.style = function () {
24 MenuBar.prototype.style = function () {
25 $('ul#menus').menubar({
25 $('ul#menus').menubar({
26 select : function (event, ui) {
26 select : function (event, ui) {
27 // The selected cell loses focus when the menu is entered, so we
27 // The selected cell loses focus when the menu is entered, so we
28 // re-select it upon selection.
28 // re-select it upon selection.
29 var i = IPython.notebook.get_selected_index();
29 var i = IPython.notebook.get_selected_index();
30 IPython.notebook.select(i);
30 IPython.notebook.select(i);
31 }
31 }
32 });
32 });
33 };
33 };
34
34
35
35
36 MenuBar.prototype.bind_events = function () {
36 MenuBar.prototype.bind_events = function () {
37 // File
37 // File
38 this.element.find('#new_notebook').click(function () {
38 this.element.find('#new_notebook').click(function () {
39 window.open($('body').data('baseProjectUrl')+'new');
39 window.open($('body').data('baseProjectUrl')+'new');
40 });
40 });
41 this.element.find('#open_notebook').click(function () {
41 this.element.find('#open_notebook').click(function () {
42 window.open($('body').data('baseProjectUrl'));
42 window.open($('body').data('baseProjectUrl'));
43 });
43 });
44 this.element.find('#rename_notebook').click(function () {
44 this.element.find('#rename_notebook').click(function () {
45 IPython.save_widget.rename_notebook();
45 IPython.save_widget.rename_notebook();
46 });
46 });
47 this.element.find('#copy_notebook').click(function () {
47 this.element.find('#copy_notebook').click(function () {
48 var notebook_id = IPython.save_widget.get_notebook_id();
48 var notebook_id = IPython.notebook.get_notebook_id();
49 var url = $('body').data('baseProjectUrl') + notebook_id + '/copy';
49 var url = $('body').data('baseProjectUrl') + notebook_id + '/copy';
50 window.open(url,'_newtab');
50 window.open(url,'_newtab');
51 });
51 });
52 this.element.find('#save_notebook').click(function () {
52 this.element.find('#save_notebook').click(function () {
53 IPython.save_widget.save_notebook();
53 IPython.notebook.save_notebook();
54 });
54 });
55 this.element.find('#download_ipynb').click(function () {
55 this.element.find('#download_ipynb').click(function () {
56 var notebook_id = IPython.save_widget.get_notebook_id();
56 var notebook_id = IPython.notebook.get_notebook_id();
57 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
57 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
58 notebook_id + '?format=json';
58 notebook_id + '?format=json';
59 window.open(url,'_newtab');
59 window.open(url,'_newtab');
60 });
60 });
61 this.element.find('#download_py').click(function () {
61 this.element.find('#download_py').click(function () {
62 var notebook_id = IPython.save_widget.get_notebook_id();
62 var notebook_id = IPython.notebook.get_notebook_id();
63 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
63 var url = $('body').data('baseProjectUrl') + 'notebooks/' +
64 notebook_id + '?format=py';
64 notebook_id + '?format=py';
65 window.open(url,'_newtab');
65 window.open(url,'_newtab');
66 });
66 });
67 this.element.find('button#print_notebook').click(function () {
67 this.element.find('button#print_notebook').click(function () {
68 IPython.print_widget.print_notebook();
68 IPython.print_widget.print_notebook();
69 });
69 });
70 // Edit
70 // Edit
71 this.element.find('#cut_cell').click(function () {
71 this.element.find('#cut_cell').click(function () {
72 IPython.notebook.cut_cell();
72 IPython.notebook.cut_cell();
73 });
73 });
74 this.element.find('#copy_cell').click(function () {
74 this.element.find('#copy_cell').click(function () {
75 IPython.notebook.copy_cell();
75 IPython.notebook.copy_cell();
76 });
76 });
77 this.element.find('#delete_cell').click(function () {
77 this.element.find('#delete_cell').click(function () {
78 IPython.notebook.delete_cell();
78 IPython.notebook.delete_cell();
79 });
79 });
80 this.element.find('#split_cell').click(function () {
80 this.element.find('#split_cell').click(function () {
81 IPython.notebook.split_cell();
81 IPython.notebook.split_cell();
82 });
82 });
83 this.element.find('#merge_cell_above').click(function () {
83 this.element.find('#merge_cell_above').click(function () {
84 IPython.notebook.merge_cell_above();
84 IPython.notebook.merge_cell_above();
85 });
85 });
86 this.element.find('#merge_cell_below').click(function () {
86 this.element.find('#merge_cell_below').click(function () {
87 IPython.notebook.merge_cell_below();
87 IPython.notebook.merge_cell_below();
88 });
88 });
89 this.element.find('#move_cell_up').click(function () {
89 this.element.find('#move_cell_up').click(function () {
90 IPython.notebook.move_cell_up();
90 IPython.notebook.move_cell_up();
91 });
91 });
92 this.element.find('#move_cell_down').click(function () {
92 this.element.find('#move_cell_down').click(function () {
93 IPython.notebook.move_cell_down();
93 IPython.notebook.move_cell_down();
94 });
94 });
95 this.element.find('#select_previous').click(function () {
95 this.element.find('#select_previous').click(function () {
96 IPython.notebook.select_prev();
96 IPython.notebook.select_prev();
97 });
97 });
98 this.element.find('#select_next').click(function () {
98 this.element.find('#select_next').click(function () {
99 IPython.notebook.select_next();
99 IPython.notebook.select_next();
100 });
100 });
101 // View
101 // View
102 this.element.find('#toggle_header').click(function () {
102 this.element.find('#toggle_header').click(function () {
103 $('div#header').toggle();
103 $('div#header').toggle();
104 IPython.layout_manager.do_resize();
104 IPython.layout_manager.do_resize();
105 });
105 });
106 this.element.find('#toggle_toolbar').click(function () {
106 this.element.find('#toggle_toolbar').click(function () {
107 IPython.toolbar.toggle();
107 IPython.toolbar.toggle();
108 });
108 });
109 // Insert
109 // Insert
110 this.element.find('#insert_cell_above').click(function () {
110 this.element.find('#insert_cell_above').click(function () {
111 IPython.notebook.insert_cell_above('code');
111 IPython.notebook.insert_cell_above('code');
112 });
112 });
113 this.element.find('#insert_cell_below').click(function () {
113 this.element.find('#insert_cell_below').click(function () {
114 IPython.notebook.insert_cell_below('code');
114 IPython.notebook.insert_cell_below('code');
115 });
115 });
116 // Cell
116 // Cell
117 this.element.find('#run_cell').click(function () {
117 this.element.find('#run_cell').click(function () {
118 IPython.notebook.execute_selected_cell();
118 IPython.notebook.execute_selected_cell();
119 });
119 });
120 this.element.find('#run_cell_in_place').click(function () {
120 this.element.find('#run_cell_in_place').click(function () {
121 IPython.notebook.execute_selected_cell({terminal:true});
121 IPython.notebook.execute_selected_cell({terminal:true});
122 });
122 });
123 this.element.find('#run_all_cells').click(function () {
123 this.element.find('#run_all_cells').click(function () {
124 IPython.notebook.execute_all_cells();
124 IPython.notebook.execute_all_cells();
125 });
125 });
126 this.element.find('#to_code').click(function () {
126 this.element.find('#to_code').click(function () {
127 IPython.notebook.to_code();
127 IPython.notebook.to_code();
128 });
128 });
129 this.element.find('#to_markdown').click(function () {
129 this.element.find('#to_markdown').click(function () {
130 IPython.notebook.to_markdown();
130 IPython.notebook.to_markdown();
131 });
131 });
132 this.element.find('#to_plaintext').click(function () {
132 this.element.find('#to_plaintext').click(function () {
133 IPython.notebook.to_plaintext();
133 IPython.notebook.to_plaintext();
134 });
134 });
135 this.element.find('#to_heading1').click(function () {
135 this.element.find('#to_heading1').click(function () {
136 IPython.notebook.to_heading(undefined, 1);
136 IPython.notebook.to_heading(undefined, 1);
137 });
137 });
138 this.element.find('#to_heading2').click(function () {
138 this.element.find('#to_heading2').click(function () {
139 IPython.notebook.to_heading(undefined, 2);
139 IPython.notebook.to_heading(undefined, 2);
140 });
140 });
141 this.element.find('#to_heading3').click(function () {
141 this.element.find('#to_heading3').click(function () {
142 IPython.notebook.to_heading(undefined, 3);
142 IPython.notebook.to_heading(undefined, 3);
143 });
143 });
144 this.element.find('#to_heading4').click(function () {
144 this.element.find('#to_heading4').click(function () {
145 IPython.notebook.to_heading(undefined, 4);
145 IPython.notebook.to_heading(undefined, 4);
146 });
146 });
147 this.element.find('#to_heading5').click(function () {
147 this.element.find('#to_heading5').click(function () {
148 IPython.notebook.to_heading(undefined, 5);
148 IPython.notebook.to_heading(undefined, 5);
149 });
149 });
150 this.element.find('#to_heading6').click(function () {
150 this.element.find('#to_heading6').click(function () {
151 IPython.notebook.to_heading(undefined, 6);
151 IPython.notebook.to_heading(undefined, 6);
152 });
152 });
153 this.element.find('#toggle_output').click(function () {
153 this.element.find('#toggle_output').click(function () {
154 IPython.notebook.toggle_output();
154 IPython.notebook.toggle_output();
155 });
155 });
156 this.element.find('#clear_all_output').click(function () {
156 this.element.find('#clear_all_output').click(function () {
157 IPython.notebook.clear_all_output();
157 IPython.notebook.clear_all_output();
158 });
158 });
159 // Kernel
159 // Kernel
160 this.element.find('#int_kernel').click(function () {
160 this.element.find('#int_kernel').click(function () {
161 IPython.notebook.kernel.interrupt();
161 IPython.notebook.kernel.interrupt();
162 });
162 });
163 this.element.find('#restart_kernel').click(function () {
163 this.element.find('#restart_kernel').click(function () {
164 IPython.notebook.restart_kernel();
164 IPython.notebook.restart_kernel();
165 });
165 });
166 // Help
166 // Help
167 this.element.find('#keyboard_shortcuts').click(function () {
167 this.element.find('#keyboard_shortcuts').click(function () {
168 IPython.quick_help.show_keyboard_shortcuts();
168 IPython.quick_help.show_keyboard_shortcuts();
169 });
169 });
170 };
170 };
171
171
172
172
173 IPython.MenuBar = MenuBar;
173 IPython.MenuBar = MenuBar;
174
174
175 return IPython;
175 return IPython;
176
176
177 }(IPython));
177 }(IPython));
@@ -1,1265 +1,1292
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.clipboard = null;
23 this.clipboard = null;
24 this.paste_enabled = false;
24 this.paste_enabled = false;
25 this.dirty = false;
25 this.dirty = false;
26 this.msg_cell_map = {};
26 this.msg_cell_map = {};
27 this.metadata = {};
27 this.metadata = {};
28 this.control_key_active = false;
28 this.control_key_active = false;
29 this.notebook_id = null;
30 this.notebook_name = null;
31 this.notebook_name_blacklist_re = /[\/\\]/;
29 this.style();
32 this.style();
30 this.create_elements();
33 this.create_elements();
31 this.bind_events();
34 this.bind_events();
32 this.set_tooltipontab(true);
35 this.set_tooltipontab(true);
33 this.set_smartcompleter(true);
36 this.set_smartcompleter(true);
34 this.set_timebeforetooltip(1200);
37 this.set_timebeforetooltip(1200);
35 };
38 };
36
39
37
40
38 Notebook.prototype.style = function () {
41 Notebook.prototype.style = function () {
39 $('div#notebook').addClass('border-box-sizing');
42 $('div#notebook').addClass('border-box-sizing');
40 };
43 };
41
44
42
45
43 Notebook.prototype.create_elements = function () {
46 Notebook.prototype.create_elements = function () {
44 // We add this end_space div to the end of the notebook div to:
47 // We add this end_space div to the end of the notebook div to:
45 // i) provide a margin between the last cell and the end of the notebook
48 // i) provide a margin between the last cell and the end of the notebook
46 // ii) to prevent the div from scrolling up when the last cell is being
49 // ii) to prevent the div from scrolling up when the last cell is being
47 // edited, but is too low on the page, which browsers will do automatically.
50 // edited, but is too low on the page, which browsers will do automatically.
48 var that = this;
51 var that = this;
49 var end_space = $('<div/>').addClass('end_space').height("30%");
52 var end_space = $('<div/>').addClass('end_space').height("30%");
50 end_space.dblclick(function (e) {
53 end_space.dblclick(function (e) {
51 if (that.read_only) return;
54 if (that.read_only) return;
52 var ncells = that.ncells();
55 var ncells = that.ncells();
53 that.insert_cell_below('code',ncells-1);
56 that.insert_cell_below('code',ncells-1);
54 });
57 });
55 this.element.append(end_space);
58 this.element.append(end_space);
56 $('div#notebook').addClass('border-box-sizing');
59 $('div#notebook').addClass('border-box-sizing');
57 };
60 };
58
61
59
62
60 Notebook.prototype.bind_events = function () {
63 Notebook.prototype.bind_events = function () {
61 var that = this;
64 var that = this;
62 $(document).keydown(function (event) {
65 $(document).keydown(function (event) {
63 // console.log(event);
66 // console.log(event);
64 if (that.read_only) return true;
67 if (that.read_only) return true;
65
68
66 // Save (CTRL+S) or (AppleKey+S)
69 // Save (CTRL+S) or (AppleKey+S)
67 //metaKey = applekey on mac
70 //metaKey = applekey on mac
68 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
71 if ((event.ctrlKey || event.metaKey) && event.keyCode==83) {
69 IPython.save_widget.save_notebook();
72 that.save_notebook();
70 event.preventDefault();
73 event.preventDefault();
71 return false;
74 return false;
72 } else if (event.which === 27) {
75 } else if (event.which === 27) {
73 // Intercept escape at highest level to avoid closing
76 // Intercept escape at highest level to avoid closing
74 // websocket connection with firefox
77 // websocket connection with firefox
75 event.preventDefault();
78 event.preventDefault();
76 }
79 }
77 if (event.which === 38 && !event.shiftKey) {
80 if (event.which === 38 && !event.shiftKey) {
78 var cell = that.get_selected_cell();
81 var cell = that.get_selected_cell();
79 if (cell.at_top()) {
82 if (cell.at_top()) {
80 event.preventDefault();
83 event.preventDefault();
81 that.select_prev();
84 that.select_prev();
82 };
85 };
83 } else if (event.which === 40 && !event.shiftKey) {
86 } else if (event.which === 40 && !event.shiftKey) {
84 var cell = that.get_selected_cell();
87 var cell = that.get_selected_cell();
85 if (cell.at_bottom()) {
88 if (cell.at_bottom()) {
86 event.preventDefault();
89 event.preventDefault();
87 that.select_next();
90 that.select_next();
88 };
91 };
89 } else if (event.which === 13 && event.shiftKey) {
92 } else if (event.which === 13 && event.shiftKey) {
90 that.execute_selected_cell();
93 that.execute_selected_cell();
91 return false;
94 return false;
92 } else if (event.which === 13 && event.ctrlKey) {
95 } else if (event.which === 13 && event.ctrlKey) {
93 that.execute_selected_cell({terminal:true});
96 that.execute_selected_cell({terminal:true});
94 return false;
97 return false;
95 } else if (event.which === 77 && event.ctrlKey) {
98 } else if (event.which === 77 && event.ctrlKey) {
96 that.control_key_active = true;
99 that.control_key_active = true;
97 return false;
100 return false;
98 } else if (event.which === 88 && that.control_key_active) {
101 } else if (event.which === 88 && that.control_key_active) {
99 // Cut selected cell = x
102 // Cut selected cell = x
100 that.cut_cell();
103 that.cut_cell();
101 that.control_key_active = false;
104 that.control_key_active = false;
102 return false;
105 return false;
103 } else if (event.which === 67 && that.control_key_active) {
106 } else if (event.which === 67 && that.control_key_active) {
104 // Copy selected cell = c
107 // Copy selected cell = c
105 that.copy_cell();
108 that.copy_cell();
106 that.control_key_active = false;
109 that.control_key_active = false;
107 return false;
110 return false;
108 } else if (event.which === 86 && that.control_key_active) {
111 } else if (event.which === 86 && that.control_key_active) {
109 // Paste selected cell = v
112 // Paste selected cell = v
110 that.paste_cell();
113 that.paste_cell();
111 that.control_key_active = false;
114 that.control_key_active = false;
112 return false;
115 return false;
113 } else if (event.which === 68 && that.control_key_active) {
116 } else if (event.which === 68 && that.control_key_active) {
114 // Delete selected cell = d
117 // Delete selected cell = d
115 that.delete_cell();
118 that.delete_cell();
116 that.control_key_active = false;
119 that.control_key_active = false;
117 return false;
120 return false;
118 } else if (event.which === 65 && that.control_key_active) {
121 } else if (event.which === 65 && that.control_key_active) {
119 // Insert code cell above selected = a
122 // Insert code cell above selected = a
120 that.insert_cell_above('code');
123 that.insert_cell_above('code');
121 that.control_key_active = false;
124 that.control_key_active = false;
122 return false;
125 return false;
123 } else if (event.which === 66 && that.control_key_active) {
126 } else if (event.which === 66 && that.control_key_active) {
124 // Insert code cell below selected = b
127 // Insert code cell below selected = b
125 that.insert_cell_below('code');
128 that.insert_cell_below('code');
126 that.control_key_active = false;
129 that.control_key_active = false;
127 return false;
130 return false;
128 } else if (event.which === 89 && that.control_key_active) {
131 } else if (event.which === 89 && that.control_key_active) {
129 // To code = y
132 // To code = y
130 that.to_code();
133 that.to_code();
131 that.control_key_active = false;
134 that.control_key_active = false;
132 return false;
135 return false;
133 } else if (event.which === 77 && that.control_key_active) {
136 } else if (event.which === 77 && that.control_key_active) {
134 // To markdown = m
137 // To markdown = m
135 that.to_markdown();
138 that.to_markdown();
136 that.control_key_active = false;
139 that.control_key_active = false;
137 return false;
140 return false;
138 } else if (event.which === 84 && that.control_key_active) {
141 } else if (event.which === 84 && that.control_key_active) {
139 // To Plaintext = t
142 // To Plaintext = t
140 that.to_plaintext();
143 that.to_plaintext();
141 that.control_key_active = false;
144 that.control_key_active = false;
142 return false;
145 return false;
143 } else if (event.which === 49 && that.control_key_active) {
146 } else if (event.which === 49 && that.control_key_active) {
144 // To Heading 1 = 1
147 // To Heading 1 = 1
145 that.to_heading(undefined, 1);
148 that.to_heading(undefined, 1);
146 that.control_key_active = false;
149 that.control_key_active = false;
147 return false;
150 return false;
148 } else if (event.which === 50 && that.control_key_active) {
151 } else if (event.which === 50 && that.control_key_active) {
149 // To Heading 2 = 2
152 // To Heading 2 = 2
150 that.to_heading(undefined, 2);
153 that.to_heading(undefined, 2);
151 that.control_key_active = false;
154 that.control_key_active = false;
152 return false;
155 return false;
153 } else if (event.which === 51 && that.control_key_active) {
156 } else if (event.which === 51 && that.control_key_active) {
154 // To Heading 3 = 3
157 // To Heading 3 = 3
155 that.to_heading(undefined, 3);
158 that.to_heading(undefined, 3);
156 that.control_key_active = false;
159 that.control_key_active = false;
157 return false;
160 return false;
158 } else if (event.which === 52 && that.control_key_active) {
161 } else if (event.which === 52 && that.control_key_active) {
159 // To Heading 4 = 4
162 // To Heading 4 = 4
160 that.to_heading(undefined, 4);
163 that.to_heading(undefined, 4);
161 that.control_key_active = false;
164 that.control_key_active = false;
162 return false;
165 return false;
163 } else if (event.which === 53 && that.control_key_active) {
166 } else if (event.which === 53 && that.control_key_active) {
164 // To Heading 5 = 5
167 // To Heading 5 = 5
165 that.to_heading(undefined, 5);
168 that.to_heading(undefined, 5);
166 that.control_key_active = false;
169 that.control_key_active = false;
167 return false;
170 return false;
168 } else if (event.which === 54 && that.control_key_active) {
171 } else if (event.which === 54 && that.control_key_active) {
169 // To Heading 6 = 6
172 // To Heading 6 = 6
170 that.to_heading(undefined, 6);
173 that.to_heading(undefined, 6);
171 that.control_key_active = false;
174 that.control_key_active = false;
172 return false;
175 return false;
173 } else if (event.which === 79 && that.control_key_active) {
176 } else if (event.which === 79 && that.control_key_active) {
174 // Toggle output = o
177 // Toggle output = o
175 that.toggle_output();
178 that.toggle_output();
176 that.control_key_active = false;
179 that.control_key_active = false;
177 return false;
180 return false;
178 } else if (event.which === 83 && that.control_key_active) {
181 } else if (event.which === 83 && that.control_key_active) {
179 // Save notebook = s
182 // Save notebook = s
180 IPython.save_widget.save_notebook();
183 that.save_notebook();
181 that.control_key_active = false;
184 that.control_key_active = false;
182 return false;
185 return false;
183 } else if (event.which === 74 && that.control_key_active) {
186 } else if (event.which === 74 && that.control_key_active) {
184 // Move cell down = j
187 // Move cell down = j
185 that.move_cell_down();
188 that.move_cell_down();
186 that.control_key_active = false;
189 that.control_key_active = false;
187 return false;
190 return false;
188 } else if (event.which === 75 && that.control_key_active) {
191 } else if (event.which === 75 && that.control_key_active) {
189 // Move cell up = k
192 // Move cell up = k
190 that.move_cell_up();
193 that.move_cell_up();
191 that.control_key_active = false;
194 that.control_key_active = false;
192 return false;
195 return false;
193 } else if (event.which === 80 && that.control_key_active) {
196 } else if (event.which === 80 && that.control_key_active) {
194 // Select previous = p
197 // Select previous = p
195 that.select_prev();
198 that.select_prev();
196 that.control_key_active = false;
199 that.control_key_active = false;
197 return false;
200 return false;
198 } else if (event.which === 78 && that.control_key_active) {
201 } else if (event.which === 78 && that.control_key_active) {
199 // Select next = n
202 // Select next = n
200 that.select_next();
203 that.select_next();
201 that.control_key_active = false;
204 that.control_key_active = false;
202 return false;
205 return false;
203 } else if (event.which === 76 && that.control_key_active) {
206 } else if (event.which === 76 && that.control_key_active) {
204 // Toggle line numbers = l
207 // Toggle line numbers = l
205 that.cell_toggle_line_numbers();
208 that.cell_toggle_line_numbers();
206 that.control_key_active = false;
209 that.control_key_active = false;
207 return false;
210 return false;
208 } else if (event.which === 73 && that.control_key_active) {
211 } else if (event.which === 73 && that.control_key_active) {
209 // Interrupt kernel = i
212 // Interrupt kernel = i
210 IPython.notebook.kernel.interrupt();
213 that.kernel.interrupt();
211 that.control_key_active = false;
214 that.control_key_active = false;
212 return false;
215 return false;
213 } else if (event.which === 190 && that.control_key_active) {
216 } else if (event.which === 190 && that.control_key_active) {
214 // Restart kernel = . # matches qt console
217 // Restart kernel = . # matches qt console
215 IPython.notebook.restart_kernel();
218 that.restart_kernel();
216 that.control_key_active = false;
219 that.control_key_active = false;
217 return false;
220 return false;
218 } else if (event.which === 72 && that.control_key_active) {
221 } else if (event.which === 72 && that.control_key_active) {
219 // Show keyboard shortcuts = h
222 // Show keyboard shortcuts = h
220 IPython.quick_help.show_keyboard_shortcuts();
223 IPython.quick_help.show_keyboard_shortcuts();
221 that.control_key_active = false;
224 that.control_key_active = false;
222 return false;
225 return false;
223 } else if (that.control_key_active) {
226 } else if (that.control_key_active) {
224 that.control_key_active = false;
227 that.control_key_active = false;
225 return true;
228 return true;
226 };
229 };
227 return true;
230 return true;
228 });
231 });
229
232
230 this.element.bind('collapse_pager', function () {
233 this.element.bind('collapse_pager', function () {
231 var app_height = $('div#main_app').height(); // content height
234 var app_height = $('div#main_app').height(); // content height
232 var splitter_height = $('div#pager_splitter').outerHeight(true);
235 var splitter_height = $('div#pager_splitter').outerHeight(true);
233 var new_height = app_height - splitter_height;
236 var new_height = app_height - splitter_height;
234 that.element.animate({height : new_height + 'px'}, 'fast');
237 that.element.animate({height : new_height + 'px'}, 'fast');
235 });
238 });
236
239
237 this.element.bind('expand_pager', function () {
240 this.element.bind('expand_pager', function () {
238 var app_height = $('div#main_app').height(); // content height
241 var app_height = $('div#main_app').height(); // content height
239 var splitter_height = $('div#pager_splitter').outerHeight(true);
242 var splitter_height = $('div#pager_splitter').outerHeight(true);
240 var pager_height = $('div#pager').outerHeight(true);
243 var pager_height = $('div#pager').outerHeight(true);
241 var new_height = app_height - pager_height - splitter_height;
244 var new_height = app_height - pager_height - splitter_height;
242 that.element.animate({height : new_height + 'px'}, 'fast');
245 that.element.animate({height : new_height + 'px'}, 'fast');
243 });
246 });
244
247
245 $(window).bind('beforeunload', function () {
248 $(window).bind('beforeunload', function () {
246 // TODO: Make killing the kernel configurable.
249 // TODO: Make killing the kernel configurable.
247 var kill_kernel = false;
250 var kill_kernel = false;
248 if (kill_kernel) {
251 if (kill_kernel) {
249 that.kernel.kill();
252 that.kernel.kill();
250 }
253 }
251 if (that.dirty && ! that.read_only) {
254 if (that.dirty && ! that.read_only) {
252 return "You have unsaved changes that will be lost if you leave this page.";
255 return "You have unsaved changes that will be lost if you leave this page.";
253 };
256 };
254 // Null is the *only* return value that will make the browser not
257 // Null is the *only* return value that will make the browser not
255 // pop up the "don't leave" dialog.
258 // pop up the "don't leave" dialog.
256 return null;
259 return null;
257 });
260 });
258 };
261 };
259
262
260
263
261 Notebook.prototype.scroll_to_bottom = function () {
264 Notebook.prototype.scroll_to_bottom = function () {
262 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
265 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
263 };
266 };
264
267
265
268
266 Notebook.prototype.scroll_to_top = function () {
269 Notebook.prototype.scroll_to_top = function () {
267 this.element.animate({scrollTop:0}, 0);
270 this.element.animate({scrollTop:0}, 0);
268 };
271 };
269
272
270
273
271 // Cell indexing, retrieval, etc.
274 // Cell indexing, retrieval, etc.
272
275
273 Notebook.prototype.get_cell_elements = function () {
276 Notebook.prototype.get_cell_elements = function () {
274 return this.element.children("div.cell");
277 return this.element.children("div.cell");
275 };
278 };
276
279
277
280
278 Notebook.prototype.get_cell_element = function (index) {
281 Notebook.prototype.get_cell_element = function (index) {
279 var result = null;
282 var result = null;
280 var e = this.get_cell_elements().eq(index);
283 var e = this.get_cell_elements().eq(index);
281 if (e.length !== 0) {
284 if (e.length !== 0) {
282 result = e;
285 result = e;
283 }
286 }
284 return result;
287 return result;
285 };
288 };
286
289
287
290
288 Notebook.prototype.ncells = function (cell) {
291 Notebook.prototype.ncells = function (cell) {
289 return this.get_cell_elements().length;
292 return this.get_cell_elements().length;
290 };
293 };
291
294
292
295
293 // TODO: we are often calling cells as cells()[i], which we should optimize
296 // TODO: we are often calling cells as cells()[i], which we should optimize
294 // to cells(i) or a new method.
297 // to cells(i) or a new method.
295 Notebook.prototype.get_cells = function () {
298 Notebook.prototype.get_cells = function () {
296 return this.get_cell_elements().toArray().map(function (e) {
299 return this.get_cell_elements().toArray().map(function (e) {
297 return $(e).data("cell");
300 return $(e).data("cell");
298 });
301 });
299 };
302 };
300
303
301
304
302 Notebook.prototype.get_cell = function (index) {
305 Notebook.prototype.get_cell = function (index) {
303 var result = null;
306 var result = null;
304 var ce = this.get_cell_element(index);
307 var ce = this.get_cell_element(index);
305 if (ce !== null) {
308 if (ce !== null) {
306 result = ce.data('cell');
309 result = ce.data('cell');
307 }
310 }
308 return result;
311 return result;
309 }
312 }
310
313
311
314
312 Notebook.prototype.get_next_cell = function (cell) {
315 Notebook.prototype.get_next_cell = function (cell) {
313 var result = null;
316 var result = null;
314 var index = this.find_cell_index(cell);
317 var index = this.find_cell_index(cell);
315 if (index !== null && index < this.ncells()) {
318 if (index !== null && index < this.ncells()) {
316 result = this.get_cell(index+1);
319 result = this.get_cell(index+1);
317 }
320 }
318 return result;
321 return result;
319 }
322 }
320
323
321
324
322 Notebook.prototype.get_prev_cell = function (cell) {
325 Notebook.prototype.get_prev_cell = function (cell) {
323 var result = null;
326 var result = null;
324 var index = this.find_cell_index(cell);
327 var index = this.find_cell_index(cell);
325 if (index !== null && index > 1) {
328 if (index !== null && index > 1) {
326 result = this.get_cell(index-1);
329 result = this.get_cell(index-1);
327 }
330 }
328 return result;
331 return result;
329 }
332 }
330
333
331 Notebook.prototype.find_cell_index = function (cell) {
334 Notebook.prototype.find_cell_index = function (cell) {
332 var result = null;
335 var result = null;
333 this.get_cell_elements().filter(function (index) {
336 this.get_cell_elements().filter(function (index) {
334 if ($(this).data("cell") === cell) {
337 if ($(this).data("cell") === cell) {
335 result = index;
338 result = index;
336 };
339 };
337 });
340 });
338 return result;
341 return result;
339 };
342 };
340
343
341
344
342 Notebook.prototype.index_or_selected = function (index) {
345 Notebook.prototype.index_or_selected = function (index) {
343 var i;
346 var i;
344 if (index === undefined || index === null) {
347 if (index === undefined || index === null) {
345 i = this.get_selected_index();
348 i = this.get_selected_index();
346 if (i === null) {
349 if (i === null) {
347 i = 0;
350 i = 0;
348 }
351 }
349 } else {
352 } else {
350 i = index;
353 i = index;
351 }
354 }
352 return i;
355 return i;
353 };
356 };
354
357
355
358
356 Notebook.prototype.get_selected_cell = function () {
359 Notebook.prototype.get_selected_cell = function () {
357 var index = this.get_selected_index();
360 var index = this.get_selected_index();
358 return this.get_cell(index);
361 return this.get_cell(index);
359 };
362 };
360
363
361
364
362 Notebook.prototype.is_valid_cell_index = function (index) {
365 Notebook.prototype.is_valid_cell_index = function (index) {
363 if (index !== null && index >= 0 && index < this.ncells()) {
366 if (index !== null && index >= 0 && index < this.ncells()) {
364 return true;
367 return true;
365 } else {
368 } else {
366 return false;
369 return false;
367 };
370 };
368 }
371 }
369
372
370 Notebook.prototype.get_selected_index = function () {
373 Notebook.prototype.get_selected_index = function () {
371 var result = null;
374 var result = null;
372 this.get_cell_elements().filter(function (index) {
375 this.get_cell_elements().filter(function (index) {
373 if ($(this).data("cell").selected === true) {
376 if ($(this).data("cell").selected === true) {
374 result = index;
377 result = index;
375 };
378 };
376 });
379 });
377 return result;
380 return result;
378 };
381 };
379
382
380
383
381 Notebook.prototype.cell_for_msg = function (msg_id) {
384 Notebook.prototype.cell_for_msg = function (msg_id) {
382 var cell_id = this.msg_cell_map[msg_id];
385 var cell_id = this.msg_cell_map[msg_id];
383 var result = null;
386 var result = null;
384 this.get_cell_elements().filter(function (index) {
387 this.get_cell_elements().filter(function (index) {
385 cell = $(this).data("cell");
388 cell = $(this).data("cell");
386 if (cell.cell_id === cell_id) {
389 if (cell.cell_id === cell_id) {
387 result = cell;
390 result = cell;
388 };
391 };
389 });
392 });
390 return result;
393 return result;
391 };
394 };
392
395
393
396
394 // Cell selection.
397 // Cell selection.
395
398
396 Notebook.prototype.select = function (index) {
399 Notebook.prototype.select = function (index) {
397 if (index !== undefined && index >= 0 && index < this.ncells()) {
400 if (index !== undefined && index >= 0 && index < this.ncells()) {
398 sindex = this.get_selected_index()
401 sindex = this.get_selected_index()
399 if (sindex !== null && index !== sindex) {
402 if (sindex !== null && index !== sindex) {
400 this.get_cell(sindex).unselect();
403 this.get_cell(sindex).unselect();
401 };
404 };
402 var cell = this.get_cell(index)
405 var cell = this.get_cell(index)
403 cell.select();
406 cell.select();
404 if (cell.cell_type === 'heading') {
407 if (cell.cell_type === 'heading') {
405 IPython.toolbar.set_cell_type(cell.cell_type+cell.level);
408 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
409 {'cell_type':cell.cell_type,level:cell.level}
410 );
406 } else {
411 } else {
407 IPython.toolbar.set_cell_type(cell.cell_type)
412 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
408 }
413 {'cell_type':cell.cell_type}
414 );
415 };
409 };
416 };
410 return this;
417 return this;
411 };
418 };
412
419
413
420
414 Notebook.prototype.select_next = function () {
421 Notebook.prototype.select_next = function () {
415 var index = this.get_selected_index();
422 var index = this.get_selected_index();
416 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
423 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
417 this.select(index+1);
424 this.select(index+1);
418 };
425 };
419 return this;
426 return this;
420 };
427 };
421
428
422
429
423 Notebook.prototype.select_prev = function () {
430 Notebook.prototype.select_prev = function () {
424 var index = this.get_selected_index();
431 var index = this.get_selected_index();
425 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
432 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
426 this.select(index-1);
433 this.select(index-1);
427 };
434 };
428 return this;
435 return this;
429 };
436 };
430
437
431
438
432 // Cell movement
439 // Cell movement
433
440
434 Notebook.prototype.move_cell_up = function (index) {
441 Notebook.prototype.move_cell_up = function (index) {
435 var i = this.index_or_selected();
442 var i = this.index_or_selected();
436 if (i !== null && i < this.ncells() && i > 0) {
443 if (i !== null && i < this.ncells() && i > 0) {
437 var pivot = this.get_cell_element(i-1);
444 var pivot = this.get_cell_element(i-1);
438 var tomove = this.get_cell_element(i);
445 var tomove = this.get_cell_element(i);
439 if (pivot !== null && tomove !== null) {
446 if (pivot !== null && tomove !== null) {
440 tomove.detach();
447 tomove.detach();
441 pivot.before(tomove);
448 pivot.before(tomove);
442 this.select(i-1);
449 this.select(i-1);
443 };
450 };
444 };
451 };
445 this.dirty = true;
452 this.dirty = true;
446 return this;
453 return this;
447 };
454 };
448
455
449
456
450 Notebook.prototype.move_cell_down = function (index) {
457 Notebook.prototype.move_cell_down = function (index) {
451 var i = this.index_or_selected();
458 var i = this.index_or_selected();
452 if (i !== null && i < (this.ncells()-1) && i >= 0) {
459 if (i !== null && i < (this.ncells()-1) && i >= 0) {
453 var pivot = this.get_cell_element(i+1);
460 var pivot = this.get_cell_element(i+1);
454 var tomove = this.get_cell_element(i);
461 var tomove = this.get_cell_element(i);
455 if (pivot !== null && tomove !== null) {
462 if (pivot !== null && tomove !== null) {
456 tomove.detach();
463 tomove.detach();
457 pivot.after(tomove);
464 pivot.after(tomove);
458 this.select(i+1);
465 this.select(i+1);
459 };
466 };
460 };
467 };
461 this.dirty = true;
468 this.dirty = true;
462 return this;
469 return this;
463 };
470 };
464
471
465
472
466 Notebook.prototype.sort_cells = function () {
473 Notebook.prototype.sort_cells = function () {
467 // This is not working right now. Calling this will actually crash
474 // This is not working right now. Calling this will actually crash
468 // the browser. I think there is an infinite loop in here...
475 // the browser. I think there is an infinite loop in here...
469 var ncells = this.ncells();
476 var ncells = this.ncells();
470 var sindex = this.get_selected_index();
477 var sindex = this.get_selected_index();
471 var swapped;
478 var swapped;
472 do {
479 do {
473 swapped = false;
480 swapped = false;
474 for (var i=1; i<ncells; i++) {
481 for (var i=1; i<ncells; i++) {
475 current = this.get_cell(i);
482 current = this.get_cell(i);
476 previous = this.get_cell(i-1);
483 previous = this.get_cell(i-1);
477 if (previous.input_prompt_number > current.input_prompt_number) {
484 if (previous.input_prompt_number > current.input_prompt_number) {
478 this.move_cell_up(i);
485 this.move_cell_up(i);
479 swapped = true;
486 swapped = true;
480 };
487 };
481 };
488 };
482 } while (swapped);
489 } while (swapped);
483 this.select(sindex);
490 this.select(sindex);
484 return this;
491 return this;
485 };
492 };
486
493
487 // Insertion, deletion.
494 // Insertion, deletion.
488
495
489 Notebook.prototype.delete_cell = function (index) {
496 Notebook.prototype.delete_cell = function (index) {
490 var i = this.index_or_selected(index);
497 var i = this.index_or_selected(index);
491 if (this.is_valid_cell_index(i)) {
498 if (this.is_valid_cell_index(i)) {
492 var ce = this.get_cell_element(i);
499 var ce = this.get_cell_element(i);
493 ce.remove();
500 ce.remove();
494 if (i === (this.ncells())) {
501 if (i === (this.ncells())) {
495 this.select(i-1);
502 this.select(i-1);
496 } else {
503 } else {
497 this.select(i);
504 this.select(i);
498 };
505 };
499 this.dirty = true;
506 this.dirty = true;
500 };
507 };
501 return this;
508 return this;
502 };
509 };
503
510
504
511
505 Notebook.prototype.insert_cell_below = function (type, index) {
512 Notebook.prototype.insert_cell_below = function (type, index) {
506 // type = ('code','html','markdown')
513 // type = ('code','html','markdown')
507 // index = cell index or undefined to insert below selected
514 // index = cell index or undefined to insert below selected
508 index = this.index_or_selected(index);
515 index = this.index_or_selected(index);
509 var cell = null;
516 var cell = null;
510 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
517 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
511 if (type === 'code') {
518 if (type === 'code') {
512 cell = new IPython.CodeCell(this);
519 cell = new IPython.CodeCell(this);
513 cell.set_input_prompt();
520 cell.set_input_prompt();
514 } else if (type === 'markdown') {
521 } else if (type === 'markdown') {
515 cell = new IPython.MarkdownCell(this);
522 cell = new IPython.MarkdownCell(this);
516 } else if (type === 'html') {
523 } else if (type === 'html') {
517 cell = new IPython.HTMLCell(this);
524 cell = new IPython.HTMLCell(this);
518 } else if (type === 'plaintext') {
525 } else if (type === 'plaintext') {
519 cell = new IPython.PlaintextCell(this);
526 cell = new IPython.PlaintextCell(this);
520 } else if (type === 'heading') {
527 } else if (type === 'heading') {
521 cell = new IPython.HeadingCell(this);
528 cell = new IPython.HeadingCell(this);
522 };
529 };
523 if (cell !== null) {
530 if (cell !== null) {
524 if (this.ncells() === 0) {
531 if (this.ncells() === 0) {
525 this.element.find('div.end_space').before(cell.element);
532 this.element.find('div.end_space').before(cell.element);
526 } else if (this.is_valid_cell_index(index)) {
533 } else if (this.is_valid_cell_index(index)) {
527 this.get_cell_element(index).after(cell.element);
534 this.get_cell_element(index).after(cell.element);
528 };
535 };
529 cell.render();
536 cell.render();
530 this.select(this.find_cell_index(cell));
537 this.select(this.find_cell_index(cell));
531 this.dirty = true;
538 this.dirty = true;
532 return cell;
539 return cell;
533 };
540 };
534 };
541 };
535 return cell;
542 return cell;
536 };
543 };
537
544
538
545
539 Notebook.prototype.insert_cell_above = function (type, index) {
546 Notebook.prototype.insert_cell_above = function (type, index) {
540 // type = ('code','html','markdown')
547 // type = ('code','html','markdown')
541 // index = cell index or undefined to insert above selected
548 // index = cell index or undefined to insert above selected
542 index = this.index_or_selected(index);
549 index = this.index_or_selected(index);
543 var cell = null;
550 var cell = null;
544 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
551 if (this.ncells() === 0 || this.is_valid_cell_index(index)) {
545 if (type === 'code') {
552 if (type === 'code') {
546 cell = new IPython.CodeCell(this);
553 cell = new IPython.CodeCell(this);
547 cell.set_input_prompt();
554 cell.set_input_prompt();
548 } else if (type === 'markdown') {
555 } else if (type === 'markdown') {
549 cell = new IPython.MarkdownCell(this);
556 cell = new IPython.MarkdownCell(this);
550 } else if (type === 'html') {
557 } else if (type === 'html') {
551 cell = new IPython.HTMLCell(this);
558 cell = new IPython.HTMLCell(this);
552 } else if (type === 'plaintext') {
559 } else if (type === 'plaintext') {
553 cell = new IPython.PlaintextCell(this);
560 cell = new IPython.PlaintextCell(this);
554 } else if (type === 'heading') {
561 } else if (type === 'heading') {
555 cell = new IPython.HeadingCell(this);
562 cell = new IPython.HeadingCell(this);
556 };
563 };
557 if (cell !== null) {
564 if (cell !== null) {
558 if (this.ncells() === 0) {
565 if (this.ncells() === 0) {
559 this.element.find('div.end_space').before(cell.element);
566 this.element.find('div.end_space').before(cell.element);
560 } else if (this.is_valid_cell_index(index)) {
567 } else if (this.is_valid_cell_index(index)) {
561 this.get_cell_element(index).before(cell.element);
568 this.get_cell_element(index).before(cell.element);
562 };
569 };
563 cell.render();
570 cell.render();
564 this.select(this.find_cell_index(cell));
571 this.select(this.find_cell_index(cell));
565 this.dirty = true;
572 this.dirty = true;
566 return cell;
573 return cell;
567 };
574 };
568 };
575 };
569 return cell;
576 return cell;
570 };
577 };
571
578
572
579
573 Notebook.prototype.to_code = function (index) {
580 Notebook.prototype.to_code = function (index) {
574 var i = this.index_or_selected(index);
581 var i = this.index_or_selected(index);
575 if (this.is_valid_cell_index(i)) {
582 if (this.is_valid_cell_index(i)) {
576 var source_element = this.get_cell_element(i);
583 var source_element = this.get_cell_element(i);
577 var source_cell = source_element.data("cell");
584 var source_cell = source_element.data("cell");
578 if (!(source_cell instanceof IPython.CodeCell)) {
585 if (!(source_cell instanceof IPython.CodeCell)) {
579 target_cell = this.insert_cell_below('code',i);
586 target_cell = this.insert_cell_below('code',i);
580 var text = source_cell.get_text();
587 var text = source_cell.get_text();
581 if (text === source_cell.placeholder) {
588 if (text === source_cell.placeholder) {
582 text = '';
589 text = '';
583 }
590 }
584 target_cell.set_text(text);
591 target_cell.set_text(text);
585 source_element.remove();
592 source_element.remove();
586 this.dirty = true;
593 this.dirty = true;
587 };
594 };
588 };
595 };
589 };
596 };
590
597
591
598
592 Notebook.prototype.to_markdown = function (index) {
599 Notebook.prototype.to_markdown = function (index) {
593 var i = this.index_or_selected(index);
600 var i = this.index_or_selected(index);
594 if (this.is_valid_cell_index(i)) {
601 if (this.is_valid_cell_index(i)) {
595 var source_element = this.get_cell_element(i);
602 var source_element = this.get_cell_element(i);
596 var source_cell = source_element.data("cell");
603 var source_cell = source_element.data("cell");
597 if (!(source_cell instanceof IPython.MarkdownCell)) {
604 if (!(source_cell instanceof IPython.MarkdownCell)) {
598 target_cell = this.insert_cell_below('markdown',i);
605 target_cell = this.insert_cell_below('markdown',i);
599 var text = source_cell.get_text();
606 var text = source_cell.get_text();
600 if (text === source_cell.placeholder) {
607 if (text === source_cell.placeholder) {
601 text = '';
608 text = '';
602 };
609 };
603 // The edit must come before the set_text.
610 // The edit must come before the set_text.
604 target_cell.edit();
611 target_cell.edit();
605 target_cell.set_text(text);
612 target_cell.set_text(text);
606 source_element.remove();
613 source_element.remove();
607 this.dirty = true;
614 this.dirty = true;
608 };
615 };
609 };
616 };
610 };
617 };
611
618
612
619
613 Notebook.prototype.to_html = function (index) {
620 Notebook.prototype.to_html = function (index) {
614 var i = this.index_or_selected(index);
621 var i = this.index_or_selected(index);
615 if (this.is_valid_cell_index(i)) {
622 if (this.is_valid_cell_index(i)) {
616 var source_element = this.get_cell_element(i);
623 var source_element = this.get_cell_element(i);
617 var source_cell = source_element.data("cell");
624 var source_cell = source_element.data("cell");
618 var target_cell = null;
625 var target_cell = null;
619 if (!(source_cell instanceof IPython.HTMLCell)) {
626 if (!(source_cell instanceof IPython.HTMLCell)) {
620 target_cell = this.insert_cell_below('html',i);
627 target_cell = this.insert_cell_below('html',i);
621 var text = source_cell.get_text();
628 var text = source_cell.get_text();
622 if (text === source_cell.placeholder) {
629 if (text === source_cell.placeholder) {
623 text = '';
630 text = '';
624 };
631 };
625 // The edit must come before the set_text.
632 // The edit must come before the set_text.
626 target_cell.edit();
633 target_cell.edit();
627 target_cell.set_text(text);
634 target_cell.set_text(text);
628 source_element.remove();
635 source_element.remove();
629 this.dirty = true;
636 this.dirty = true;
630 };
637 };
631 };
638 };
632 };
639 };
633
640
634
641
635 Notebook.prototype.to_plaintext = function (index) {
642 Notebook.prototype.to_plaintext = function (index) {
636 var i = this.index_or_selected(index);
643 var i = this.index_or_selected(index);
637 if (this.is_valid_cell_index(i)) {
644 if (this.is_valid_cell_index(i)) {
638 var source_element = this.get_cell_element(i);
645 var source_element = this.get_cell_element(i);
639 var source_cell = source_element.data("cell");
646 var source_cell = source_element.data("cell");
640 var target_cell = null;
647 var target_cell = null;
641 if (!(source_cell instanceof IPython.PlaintextCell)) {
648 if (!(source_cell instanceof IPython.PlaintextCell)) {
642 target_cell = this.insert_cell_below('plaintext',i);
649 target_cell = this.insert_cell_below('plaintext',i);
643 var text = source_cell.get_text();
650 var text = source_cell.get_text();
644 if (text === source_cell.placeholder) {
651 if (text === source_cell.placeholder) {
645 text = '';
652 text = '';
646 };
653 };
647 // The edit must come before the set_text.
654 // The edit must come before the set_text.
648 target_cell.edit();
655 target_cell.edit();
649 target_cell.set_text(text);
656 target_cell.set_text(text);
650 source_element.remove();
657 source_element.remove();
651 this.dirty = true;
658 this.dirty = true;
652 };
659 };
653 };
660 };
654 };
661 };
655
662
656
663
657 Notebook.prototype.to_heading = function (index, level) {
664 Notebook.prototype.to_heading = function (index, level) {
658 level = level || 1;
665 level = level || 1;
659 var i = this.index_or_selected(index);
666 var i = this.index_or_selected(index);
660 if (this.is_valid_cell_index(i)) {
667 if (this.is_valid_cell_index(i)) {
661 var source_element = this.get_cell_element(i);
668 var source_element = this.get_cell_element(i);
662 var source_cell = source_element.data("cell");
669 var source_cell = source_element.data("cell");
663 var target_cell = null;
670 var target_cell = null;
664 if (source_cell instanceof IPython.HeadingCell) {
671 if (source_cell instanceof IPython.HeadingCell) {
665 source_cell.set_level(level);
672 source_cell.set_level(level);
666 } else {
673 } else {
667 target_cell = this.insert_cell_below('heading',i);
674 target_cell = this.insert_cell_below('heading',i);
668 var text = source_cell.get_text();
675 var text = source_cell.get_text();
669 if (text === source_cell.placeholder) {
676 if (text === source_cell.placeholder) {
670 text = '';
677 text = '';
671 };
678 };
672 // The edit must come before the set_text.
679 // The edit must come before the set_text.
673 target_cell.set_level(level);
680 target_cell.set_level(level);
674 target_cell.edit();
681 target_cell.edit();
675 target_cell.set_text(text);
682 target_cell.set_text(text);
676 source_element.remove();
683 source_element.remove();
677 this.dirty = true;
684 this.dirty = true;
678 };
685 };
679 IPython.toolbar.set_cell_type("heading"+level);
686 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
687 {'cell_type':'heading',level:level}
688 );
680 };
689 };
681 };
690 };
682
691
683
692
684 // Cut/Copy/Paste
693 // Cut/Copy/Paste
685
694
686 Notebook.prototype.enable_paste = function () {
695 Notebook.prototype.enable_paste = function () {
687 var that = this;
696 var that = this;
688 if (!this.paste_enabled) {
697 if (!this.paste_enabled) {
689 $('#paste_cell').removeClass('ui-state-disabled')
698 $('#paste_cell').removeClass('ui-state-disabled')
690 .on('click', function () {that.paste_cell();});
699 .on('click', function () {that.paste_cell();});
691 $('#paste_cell_above').removeClass('ui-state-disabled')
700 $('#paste_cell_above').removeClass('ui-state-disabled')
692 .on('click', function () {that.paste_cell_above();});
701 .on('click', function () {that.paste_cell_above();});
693 $('#paste_cell_below').removeClass('ui-state-disabled')
702 $('#paste_cell_below').removeClass('ui-state-disabled')
694 .on('click', function () {that.paste_cell_below();});
703 .on('click', function () {that.paste_cell_below();});
695 this.paste_enabled = true;
704 this.paste_enabled = true;
696 };
705 };
697 };
706 };
698
707
699
708
700 Notebook.prototype.disable_paste = function () {
709 Notebook.prototype.disable_paste = function () {
701 if (this.paste_enabled) {
710 if (this.paste_enabled) {
702 $('#paste_cell').addClass('ui-state-disabled').off('click');
711 $('#paste_cell').addClass('ui-state-disabled').off('click');
703 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
712 $('#paste_cell_above').addClass('ui-state-disabled').off('click');
704 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
713 $('#paste_cell_below').addClass('ui-state-disabled').off('click');
705 this.paste_enabled = false;
714 this.paste_enabled = false;
706 };
715 };
707 };
716 };
708
717
709
718
710 Notebook.prototype.cut_cell = function () {
719 Notebook.prototype.cut_cell = function () {
711 this.copy_cell();
720 this.copy_cell();
712 this.delete_cell();
721 this.delete_cell();
713 }
722 }
714
723
715 Notebook.prototype.copy_cell = function () {
724 Notebook.prototype.copy_cell = function () {
716 var cell = this.get_selected_cell();
725 var cell = this.get_selected_cell();
717 this.clipboard = cell.toJSON();
726 this.clipboard = cell.toJSON();
718 this.enable_paste();
727 this.enable_paste();
719 };
728 };
720
729
721
730
722 Notebook.prototype.paste_cell = function () {
731 Notebook.prototype.paste_cell = function () {
723 if (this.clipboard !== null && this.paste_enabled) {
732 if (this.clipboard !== null && this.paste_enabled) {
724 var cell_data = this.clipboard;
733 var cell_data = this.clipboard;
725 var new_cell = this.insert_cell_above(cell_data.cell_type);
734 var new_cell = this.insert_cell_above(cell_data.cell_type);
726 new_cell.fromJSON(cell_data);
735 new_cell.fromJSON(cell_data);
727 old_cell = this.get_next_cell(new_cell);
736 old_cell = this.get_next_cell(new_cell);
728 this.delete_cell(this.find_cell_index(old_cell));
737 this.delete_cell(this.find_cell_index(old_cell));
729 this.select(this.find_cell_index(new_cell));
738 this.select(this.find_cell_index(new_cell));
730 };
739 };
731 };
740 };
732
741
733
742
734 Notebook.prototype.paste_cell_above = function () {
743 Notebook.prototype.paste_cell_above = function () {
735 if (this.clipboard !== null && this.paste_enabled) {
744 if (this.clipboard !== null && this.paste_enabled) {
736 var cell_data = this.clipboard;
745 var cell_data = this.clipboard;
737 var new_cell = this.insert_cell_above(cell_data.cell_type);
746 var new_cell = this.insert_cell_above(cell_data.cell_type);
738 new_cell.fromJSON(cell_data);
747 new_cell.fromJSON(cell_data);
739 };
748 };
740 };
749 };
741
750
742
751
743 Notebook.prototype.paste_cell_below = function () {
752 Notebook.prototype.paste_cell_below = function () {
744 if (this.clipboard !== null && this.paste_enabled) {
753 if (this.clipboard !== null && this.paste_enabled) {
745 var cell_data = this.clipboard;
754 var cell_data = this.clipboard;
746 var new_cell = this.insert_cell_below(cell_data.cell_type);
755 var new_cell = this.insert_cell_below(cell_data.cell_type);
747 new_cell.fromJSON(cell_data);
756 new_cell.fromJSON(cell_data);
748 };
757 };
749 };
758 };
750
759
751
760
752 // Split/merge
761 // Split/merge
753
762
754 Notebook.prototype.split_cell = function () {
763 Notebook.prototype.split_cell = function () {
755 // Todo: implement spliting for other cell types.
764 // Todo: implement spliting for other cell types.
756 var cell = this.get_selected_cell();
765 var cell = this.get_selected_cell();
757 if (cell.is_splittable()) {
766 if (cell.is_splittable()) {
758 texta = cell.get_pre_cursor();
767 texta = cell.get_pre_cursor();
759 textb = cell.get_post_cursor();
768 textb = cell.get_post_cursor();
760 if (cell instanceof IPython.CodeCell) {
769 if (cell instanceof IPython.CodeCell) {
761 cell.set_text(texta);
770 cell.set_text(texta);
762 var new_cell = this.insert_cell_below('code');
771 var new_cell = this.insert_cell_below('code');
763 new_cell.set_text(textb);
772 new_cell.set_text(textb);
764 } else if (cell instanceof IPython.MarkdownCell) {
773 } else if (cell instanceof IPython.MarkdownCell) {
765 cell.set_text(texta);
774 cell.set_text(texta);
766 cell.render();
775 cell.render();
767 var new_cell = this.insert_cell_below('markdown');
776 var new_cell = this.insert_cell_below('markdown');
768 new_cell.edit(); // editor must be visible to call set_text
777 new_cell.edit(); // editor must be visible to call set_text
769 new_cell.set_text(textb);
778 new_cell.set_text(textb);
770 new_cell.render();
779 new_cell.render();
771 } else if (cell instanceof IPython.HTMLCell) {
780 } else if (cell instanceof IPython.HTMLCell) {
772 cell.set_text(texta);
781 cell.set_text(texta);
773 cell.render();
782 cell.render();
774 var new_cell = this.insert_cell_below('html');
783 var new_cell = this.insert_cell_below('html');
775 new_cell.edit(); // editor must be visible to call set_text
784 new_cell.edit(); // editor must be visible to call set_text
776 new_cell.set_text(textb);
785 new_cell.set_text(textb);
777 new_cell.render();
786 new_cell.render();
778 };
787 };
779 };
788 };
780 };
789 };
781
790
782
791
783 Notebook.prototype.merge_cell_above = function () {
792 Notebook.prototype.merge_cell_above = function () {
784 var index = this.get_selected_index();
793 var index = this.get_selected_index();
785 var cell = this.get_cell(index);
794 var cell = this.get_cell(index);
786 if (index > 0) {
795 if (index > 0) {
787 upper_cell = this.get_cell(index-1);
796 upper_cell = this.get_cell(index-1);
788 upper_text = upper_cell.get_text();
797 upper_text = upper_cell.get_text();
789 text = cell.get_text();
798 text = cell.get_text();
790 if (cell instanceof IPython.CodeCell) {
799 if (cell instanceof IPython.CodeCell) {
791 cell.set_text(upper_text+'\n'+text);
800 cell.set_text(upper_text+'\n'+text);
792 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
801 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
793 cell.edit();
802 cell.edit();
794 cell.set_text(upper_text+'\n'+text);
803 cell.set_text(upper_text+'\n'+text);
795 cell.render();
804 cell.render();
796 };
805 };
797 this.delete_cell(index-1);
806 this.delete_cell(index-1);
798 this.select(this.find_cell_index(cell));
807 this.select(this.find_cell_index(cell));
799 };
808 };
800 };
809 };
801
810
802
811
803 Notebook.prototype.merge_cell_below = function () {
812 Notebook.prototype.merge_cell_below = function () {
804 var index = this.get_selected_index();
813 var index = this.get_selected_index();
805 var cell = this.get_cell(index);
814 var cell = this.get_cell(index);
806 if (index < this.ncells()-1) {
815 if (index < this.ncells()-1) {
807 lower_cell = this.get_cell(index+1);
816 lower_cell = this.get_cell(index+1);
808 lower_text = lower_cell.get_text();
817 lower_text = lower_cell.get_text();
809 text = cell.get_text();
818 text = cell.get_text();
810 if (cell instanceof IPython.CodeCell) {
819 if (cell instanceof IPython.CodeCell) {
811 cell.set_text(text+'\n'+lower_text);
820 cell.set_text(text+'\n'+lower_text);
812 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
821 } else if (cell instanceof IPython.MarkdownCell || cell instanceof IPython.HTMLCell) {
813 cell.edit();
822 cell.edit();
814 cell.set_text(text+'\n'+lower_text);
823 cell.set_text(text+'\n'+lower_text);
815 cell.render();
824 cell.render();
816 };
825 };
817 this.delete_cell(index+1);
826 this.delete_cell(index+1);
818 this.select(this.find_cell_index(cell));
827 this.select(this.find_cell_index(cell));
819 };
828 };
820 };
829 };
821
830
822
831
823 // Cell collapsing and output clearing
832 // Cell collapsing and output clearing
824
833
825 Notebook.prototype.collapse = function (index) {
834 Notebook.prototype.collapse = function (index) {
826 var i = this.index_or_selected(index);
835 var i = this.index_or_selected(index);
827 this.get_cell(i).collapse();
836 this.get_cell(i).collapse();
828 this.dirty = true;
837 this.dirty = true;
829 };
838 };
830
839
831
840
832 Notebook.prototype.expand = function (index) {
841 Notebook.prototype.expand = function (index) {
833 var i = this.index_or_selected(index);
842 var i = this.index_or_selected(index);
834 this.get_cell(i).expand();
843 this.get_cell(i).expand();
835 this.dirty = true;
844 this.dirty = true;
836 };
845 };
837
846
838
847
839 Notebook.prototype.toggle_output = function (index) {
848 Notebook.prototype.toggle_output = function (index) {
840 var i = this.index_or_selected(index);
849 var i = this.index_or_selected(index);
841 this.get_cell(i).toggle_output();
850 this.get_cell(i).toggle_output();
842 this.dirty = true;
851 this.dirty = true;
843 };
852 };
844
853
845
854
846 Notebook.prototype.set_timebeforetooltip = function (time) {
855 Notebook.prototype.set_timebeforetooltip = function (time) {
847 this.time_before_tooltip = time;
856 this.time_before_tooltip = time;
848 };
857 };
849
858
850
859
851 Notebook.prototype.set_tooltipontab = function (state) {
860 Notebook.prototype.set_tooltipontab = function (state) {
852 this.tooltip_on_tab = state;
861 this.tooltip_on_tab = state;
853 };
862 };
854
863
855
864
856 Notebook.prototype.set_smartcompleter = function (state) {
865 Notebook.prototype.set_smartcompleter = function (state) {
857 this.smart_completer = state;
866 this.smart_completer = state;
858 };
867 };
859
868
860
869
861 Notebook.prototype.clear_all_output = function () {
870 Notebook.prototype.clear_all_output = function () {
862 var ncells = this.ncells();
871 var ncells = this.ncells();
863 var cells = this.get_cells();
872 var cells = this.get_cells();
864 for (var i=0; i<ncells; i++) {
873 for (var i=0; i<ncells; i++) {
865 if (cells[i] instanceof IPython.CodeCell) {
874 if (cells[i] instanceof IPython.CodeCell) {
866 cells[i].clear_output(true,true,true);
875 cells[i].clear_output(true,true,true);
867 }
876 }
868 };
877 };
869 this.dirty = true;
878 this.dirty = true;
870 };
879 };
871
880
872
881
873 // Other cell functions: line numbers, ...
882 // Other cell functions: line numbers, ...
874
883
875 Notebook.prototype.cell_toggle_line_numbers = function() {
884 Notebook.prototype.cell_toggle_line_numbers = function() {
876 this.get_selected_cell().toggle_line_numbers();
885 this.get_selected_cell().toggle_line_numbers();
877 };
886 };
878
887
879 // Kernel related things
888 // Kernel related things
880
889
881 Notebook.prototype.start_kernel = function () {
890 Notebook.prototype.start_kernel = function () {
882 this.kernel = new IPython.Kernel();
891 this.kernel = new IPython.Kernel();
883 var notebook_id = IPython.save_widget.get_notebook_id();
892 this.kernel.start(this.notebook_id, $.proxy(this.kernel_started, this));
884 this.kernel.start(notebook_id, $.proxy(this.kernel_started, this));
885 };
893 };
886
894
887
895
888 Notebook.prototype.restart_kernel = function () {
896 Notebook.prototype.restart_kernel = function () {
889 var that = this;
897 var that = this;
890 var notebook_id = IPython.save_widget.get_notebook_id();
891
892 var dialog = $('<div/>');
898 var dialog = $('<div/>');
893 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
899 dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
894 $(document).append(dialog);
900 $(document).append(dialog);
895 dialog.dialog({
901 dialog.dialog({
896 resizable: false,
902 resizable: false,
897 modal: true,
903 modal: true,
898 title: "Restart kernel or continue running?",
904 title: "Restart kernel or continue running?",
899 closeText: '',
905 closeText: '',
900 buttons : {
906 buttons : {
901 "Restart": function () {
907 "Restart": function () {
902 that.kernel.restart($.proxy(that.kernel_started, that));
908 that.kernel.restart($.proxy(that.kernel_started, that));
903 $(this).dialog('close');
909 $(this).dialog('close');
904 },
910 },
905 "Continue running": function () {
911 "Continue running": function () {
906 $(this).dialog('close');
912 $(this).dialog('close');
907 }
913 }
908 }
914 }
909 });
915 });
910 };
916 };
911
917
912
918
913 Notebook.prototype.kernel_started = function () {
919 Notebook.prototype.kernel_started = function () {
914 console.log("Kernel started: ", this.kernel.kernel_id);
920 console.log("Kernel started: ", this.kernel.kernel_id);
915 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
921 this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this);
916 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
922 this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this);
917 };
923 };
918
924
919
925
920 Notebook.prototype.handle_shell_reply = function (e) {
926 Notebook.prototype.handle_shell_reply = function (e) {
921 reply = $.parseJSON(e.data);
927 reply = $.parseJSON(e.data);
922 var header = reply.header;
928 var header = reply.header;
923 var content = reply.content;
929 var content = reply.content;
924 var msg_type = header.msg_type;
930 var msg_type = header.msg_type;
925 // console.log(reply);
931 // console.log(reply);
926 var cell = this.cell_for_msg(reply.parent_header.msg_id);
932 var cell = this.cell_for_msg(reply.parent_header.msg_id);
927 if (msg_type === "execute_reply") {
933 if (msg_type === "execute_reply") {
928 cell.set_input_prompt(content.execution_count);
934 cell.set_input_prompt(content.execution_count);
929 cell.element.removeClass("running");
935 cell.element.removeClass("running");
930 this.dirty = true;
936 this.dirty = true;
931 } else if (msg_type === "complete_reply") {
937 } else if (msg_type === "complete_reply") {
932 cell.finish_completing(content.matched_text, content.matches);
938 cell.finish_completing(content.matched_text, content.matches);
933 } else if (msg_type === "object_info_reply"){
939 } else if (msg_type === "object_info_reply"){
934 //console.log('back from object_info_request : ')
940 //console.log('back from object_info_request : ')
935 rep = reply.content;
941 rep = reply.content;
936 if(rep.found)
942 if(rep.found)
937 {
943 {
938 cell.finish_tooltip(rep);
944 cell.finish_tooltip(rep);
939 }
945 }
940 } else {
946 } else {
941 //console.log("unknown reply:"+msg_type);
947 //console.log("unknown reply:"+msg_type);
942 }
948 }
943 // when having a rely from object_info_reply,
949 // when having a rely from object_info_reply,
944 // no payload so no nned to handle it
950 // no payload so no nned to handle it
945 if(typeof(content.payload)!='undefined') {
951 if(typeof(content.payload)!='undefined') {
946 var payload = content.payload || [];
952 var payload = content.payload || [];
947 this.handle_payload(cell, payload);
953 this.handle_payload(cell, payload);
948 }
954 }
949 };
955 };
950
956
951
957
952 Notebook.prototype.handle_payload = function (cell, payload) {
958 Notebook.prototype.handle_payload = function (cell, payload) {
953 var l = payload.length;
959 var l = payload.length;
954 for (var i=0; i<l; i++) {
960 for (var i=0; i<l; i++) {
955 if (payload[i].source === 'IPython.zmq.page.page') {
961 if (payload[i].source === 'IPython.zmq.page.page') {
956 if (payload[i].text.trim() !== '') {
962 if (payload[i].text.trim() !== '') {
957 IPython.pager.clear();
963 IPython.pager.clear();
958 IPython.pager.expand();
964 IPython.pager.expand();
959 IPython.pager.append_text(payload[i].text);
965 IPython.pager.append_text(payload[i].text);
960 }
966 }
961 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
967 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
962 var index = this.find_cell_index(cell);
968 var index = this.find_cell_index(cell);
963 var new_cell = this.insert_cell_below('code',index);
969 var new_cell = this.insert_cell_below('code',index);
964 new_cell.set_text(payload[i].text);
970 new_cell.set_text(payload[i].text);
965 this.dirty = true;
971 this.dirty = true;
966 }
972 }
967 };
973 };
968 };
974 };
969
975
970
976
971 Notebook.prototype.handle_iopub_reply = function (e) {
977 Notebook.prototype.handle_iopub_reply = function (e) {
972 reply = $.parseJSON(e.data);
978 reply = $.parseJSON(e.data);
973 var content = reply.content;
979 var content = reply.content;
974 // console.log(reply);
980 // console.log(reply);
975 var msg_type = reply.header.msg_type;
981 var msg_type = reply.header.msg_type;
976 var cell = this.cell_for_msg(reply.parent_header.msg_id);
982 var cell = this.cell_for_msg(reply.parent_header.msg_id);
977 if (msg_type !== 'status' && !cell){
983 if (msg_type !== 'status' && !cell){
978 // message not from this notebook, but should be attached to a cell
984 // message not from this notebook, but should be attached to a cell
979 console.log("Received IOPub message not caused by one of my cells");
985 // console.log("Received IOPub message not caused by one of my cells");
980 console.log(reply);
986 // console.log(reply);
981 return;
987 return;
982 }
988 }
983 var output_types = ['stream','display_data','pyout','pyerr'];
989 var output_types = ['stream','display_data','pyout','pyerr'];
984 if (output_types.indexOf(msg_type) >= 0) {
990 if (output_types.indexOf(msg_type) >= 0) {
985 this.handle_output(cell, msg_type, content);
991 this.handle_output(cell, msg_type, content);
986 } else if (msg_type === 'status') {
992 } else if (msg_type === 'status') {
987 if (content.execution_state === 'busy') {
993 if (content.execution_state === 'busy') {
994 $([IPython.events]).trigger('status_busy.Kernel');
988 IPython.kernel_status_widget.status_busy();
995 IPython.kernel_status_widget.status_busy();
989 } else if (content.execution_state === 'idle') {
996 } else if (content.execution_state === 'idle') {
990 IPython.kernel_status_widget.status_idle();
997 $([IPython.events]).trigger('status_idle.Kernel');
991 } else if (content.execution_state === 'dead') {
998 } else if (content.execution_state === 'dead') {
992 this.handle_status_dead();
999 this.handle_status_dead();
993 };
1000 };
994 } else if (msg_type === 'clear_output') {
1001 } else if (msg_type === 'clear_output') {
995 cell.clear_output(content.stdout, content.stderr, content.other);
1002 cell.clear_output(content.stdout, content.stderr, content.other);
996 };
1003 };
997 };
1004 };
998
1005
999
1006
1000 Notebook.prototype.handle_status_dead = function () {
1007 Notebook.prototype.handle_status_dead = function () {
1001 var that = this;
1008 var that = this;
1002 this.kernel.stop_channels();
1009 this.kernel.stop_channels();
1003 var dialog = $('<div/>');
1010 var dialog = $('<div/>');
1004 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.');
1011 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.');
1005 $(document).append(dialog);
1012 $(document).append(dialog);
1006 dialog.dialog({
1013 dialog.dialog({
1007 resizable: false,
1014 resizable: false,
1008 modal: true,
1015 modal: true,
1009 title: "Dead kernel",
1016 title: "Dead kernel",
1010 buttons : {
1017 buttons : {
1011 "Restart": function () {
1018 "Restart": function () {
1012 that.start_kernel();
1019 that.start_kernel();
1013 $(this).dialog('close');
1020 $(this).dialog('close');
1014 },
1021 },
1015 "Continue running": function () {
1022 "Continue running": function () {
1016 $(this).dialog('close');
1023 $(this).dialog('close');
1017 }
1024 }
1018 }
1025 }
1019 });
1026 });
1020 };
1027 };
1021
1028
1022
1029
1023 Notebook.prototype.handle_output = function (cell, msg_type, content) {
1030 Notebook.prototype.handle_output = function (cell, msg_type, content) {
1024 var json = {};
1031 var json = {};
1025 json.output_type = msg_type;
1032 json.output_type = msg_type;
1026 if (msg_type === "stream") {
1033 if (msg_type === "stream") {
1027 json.text = content.data;
1034 json.text = content.data;
1028 json.stream = content.name;
1035 json.stream = content.name;
1029 } else if (msg_type === "display_data") {
1036 } else if (msg_type === "display_data") {
1030 json = this.convert_mime_types(json, content.data);
1037 json = this.convert_mime_types(json, content.data);
1031 } else if (msg_type === "pyout") {
1038 } else if (msg_type === "pyout") {
1032 json.prompt_number = content.execution_count;
1039 json.prompt_number = content.execution_count;
1033 json = this.convert_mime_types(json, content.data);
1040 json = this.convert_mime_types(json, content.data);
1034 } else if (msg_type === "pyerr") {
1041 } else if (msg_type === "pyerr") {
1035 json.ename = content.ename;
1042 json.ename = content.ename;
1036 json.evalue = content.evalue;
1043 json.evalue = content.evalue;
1037 json.traceback = content.traceback;
1044 json.traceback = content.traceback;
1038 };
1045 };
1039 cell.append_output(json);
1046 cell.append_output(json);
1040 this.dirty = true;
1047 this.dirty = true;
1041 };
1048 };
1042
1049
1043
1050
1044 Notebook.prototype.convert_mime_types = function (json, data) {
1051 Notebook.prototype.convert_mime_types = function (json, data) {
1045 if (data['text/plain'] !== undefined) {
1052 if (data['text/plain'] !== undefined) {
1046 json.text = data['text/plain'];
1053 json.text = data['text/plain'];
1047 };
1054 };
1048 if (data['text/html'] !== undefined) {
1055 if (data['text/html'] !== undefined) {
1049 json.html = data['text/html'];
1056 json.html = data['text/html'];
1050 };
1057 };
1051 if (data['image/svg+xml'] !== undefined) {
1058 if (data['image/svg+xml'] !== undefined) {
1052 json.svg = data['image/svg+xml'];
1059 json.svg = data['image/svg+xml'];
1053 };
1060 };
1054 if (data['image/png'] !== undefined) {
1061 if (data['image/png'] !== undefined) {
1055 json.png = data['image/png'];
1062 json.png = data['image/png'];
1056 };
1063 };
1057 if (data['image/jpeg'] !== undefined) {
1064 if (data['image/jpeg'] !== undefined) {
1058 json.jpeg = data['image/jpeg'];
1065 json.jpeg = data['image/jpeg'];
1059 };
1066 };
1060 if (data['text/latex'] !== undefined) {
1067 if (data['text/latex'] !== undefined) {
1061 json.latex = data['text/latex'];
1068 json.latex = data['text/latex'];
1062 };
1069 };
1063 if (data['application/json'] !== undefined) {
1070 if (data['application/json'] !== undefined) {
1064 json.json = data['application/json'];
1071 json.json = data['application/json'];
1065 };
1072 };
1066 if (data['application/javascript'] !== undefined) {
1073 if (data['application/javascript'] !== undefined) {
1067 json.javascript = data['application/javascript'];
1074 json.javascript = data['application/javascript'];
1068 }
1075 }
1069 return json;
1076 return json;
1070 };
1077 };
1071
1078
1072
1079
1073 Notebook.prototype.execute_selected_cell = function (options) {
1080 Notebook.prototype.execute_selected_cell = function (options) {
1074 // add_new: should a new cell be added if we are at the end of the nb
1081 // add_new: should a new cell be added if we are at the end of the nb
1075 // terminal: execute in terminal mode, which stays in the current cell
1082 // terminal: execute in terminal mode, which stays in the current cell
1076 default_options = {terminal: false, add_new: true};
1083 default_options = {terminal: false, add_new: true};
1077 $.extend(default_options, options);
1084 $.extend(default_options, options);
1078 var that = this;
1085 var that = this;
1079 var cell = that.get_selected_cell();
1086 var cell = that.get_selected_cell();
1080 var cell_index = that.find_cell_index(cell);
1087 var cell_index = that.find_cell_index(cell);
1081 if (cell instanceof IPython.CodeCell) {
1088 if (cell instanceof IPython.CodeCell) {
1082 cell.clear_output(true, true, true);
1089 cell.clear_output(true, true, true);
1083 cell.set_input_prompt('*');
1090 cell.set_input_prompt('*');
1084 cell.element.addClass("running");
1091 cell.element.addClass("running");
1085 var code = cell.get_text();
1092 var code = cell.get_text();
1086 var msg_id = that.kernel.execute(cell.get_text());
1093 var msg_id = that.kernel.execute(cell.get_text());
1087 that.msg_cell_map[msg_id] = cell.cell_id;
1094 that.msg_cell_map[msg_id] = cell.cell_id;
1088 } else if (cell instanceof IPython.HTMLCell) {
1095 } else if (cell instanceof IPython.HTMLCell) {
1089 cell.render();
1096 cell.render();
1090 }
1097 }
1091 if (default_options.terminal) {
1098 if (default_options.terminal) {
1092 cell.select_all();
1099 cell.select_all();
1093 } else {
1100 } else {
1094 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1101 if ((cell_index === (that.ncells()-1)) && default_options.add_new) {
1095 that.insert_cell_below('code');
1102 that.insert_cell_below('code');
1096 // If we are adding a new cell at the end, scroll down to show it.
1103 // If we are adding a new cell at the end, scroll down to show it.
1097 that.scroll_to_bottom();
1104 that.scroll_to_bottom();
1098 } else {
1105 } else {
1099 that.select(cell_index+1);
1106 that.select(cell_index+1);
1100 };
1107 };
1101 };
1108 };
1102 this.dirty = true;
1109 this.dirty = true;
1103 };
1110 };
1104
1111
1105
1112
1106 Notebook.prototype.execute_all_cells = function () {
1113 Notebook.prototype.execute_all_cells = function () {
1107 var ncells = this.ncells();
1114 var ncells = this.ncells();
1108 for (var i=0; i<ncells; i++) {
1115 for (var i=0; i<ncells; i++) {
1109 this.select(i);
1116 this.select(i);
1110 this.execute_selected_cell({add_new:false});
1117 this.execute_selected_cell({add_new:false});
1111 };
1118 };
1112 this.scroll_to_bottom();
1119 this.scroll_to_bottom();
1113 };
1120 };
1114
1121
1115
1122
1116 Notebook.prototype.request_tool_tip = function (cell,func) {
1123 Notebook.prototype.request_tool_tip = function (cell,func) {
1117 // Feel free to shorten this logic if you are better
1124 // Feel free to shorten this logic if you are better
1118 // than me in regEx
1125 // than me in regEx
1119 // basicaly you shoul be able to get xxx.xxx.xxx from
1126 // basicaly you shoul be able to get xxx.xxx.xxx from
1120 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
1127 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
1121 // remove everything between matchin bracket (need to iterate)
1128 // remove everything between matchin bracket (need to iterate)
1122 matchBracket = /\([^\(\)]+\)/g;
1129 matchBracket = /\([^\(\)]+\)/g;
1123 oldfunc = func;
1130 oldfunc = func;
1124 func = func.replace(matchBracket,"");
1131 func = func.replace(matchBracket,"");
1125 while( oldfunc != func )
1132 while( oldfunc != func )
1126 {
1133 {
1127 oldfunc = func;
1134 oldfunc = func;
1128 func = func.replace(matchBracket,"");
1135 func = func.replace(matchBracket,"");
1129 }
1136 }
1130 // remove everythin after last open bracket
1137 // remove everythin after last open bracket
1131 endBracket = /\([^\(]*$/g;
1138 endBracket = /\([^\(]*$/g;
1132 func = func.replace(endBracket,"");
1139 func = func.replace(endBracket,"");
1133 var re = /[a-zA-Z._]+$/g;
1140 var re = /[a-zA-Z._]+$/g;
1134 var msg_id = this.kernel.object_info_request(re.exec(func));
1141 var msg_id = this.kernel.object_info_request(re.exec(func));
1135 if(typeof(msg_id)!='undefined'){
1142 if(typeof(msg_id)!='undefined'){
1136 this.msg_cell_map[msg_id] = cell.cell_id;
1143 this.msg_cell_map[msg_id] = cell.cell_id;
1137 }
1144 }
1138 };
1145 };
1139
1146
1140 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
1147 Notebook.prototype.complete_cell = function (cell, line, cursor_pos) {
1141 var msg_id = this.kernel.complete(line, cursor_pos);
1148 var msg_id = this.kernel.complete(line, cursor_pos);
1142 this.msg_cell_map[msg_id] = cell.cell_id;
1149 this.msg_cell_map[msg_id] = cell.cell_id;
1143 };
1150 };
1144
1151
1152
1145 // Persistance and loading
1153 // Persistance and loading
1146
1154
1155 Notebook.prototype.get_notebook_id = function () {
1156 return this.notebook_id;
1157 };
1158
1159
1160 Notebook.prototype.get_notebook_name = function () {
1161 return this.notebook_name;
1162 };
1163
1164
1165 Notebook.prototype.set_notebook_name = function (name) {
1166 this.notebook_name = name;
1167 };
1168
1169
1170 Notebook.prototype.test_notebook_name = function (nbname) {
1171 nbname = nbname || '';
1172 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1173 return true;
1174 } else {
1175 return false;
1176 };
1177 };
1178
1147
1179
1148 Notebook.prototype.fromJSON = function (data) {
1180 Notebook.prototype.fromJSON = function (data) {
1149 var ncells = this.ncells();
1181 var ncells = this.ncells();
1150 var i;
1182 var i;
1151 for (i=0; i<ncells; i++) {
1183 for (i=0; i<ncells; i++) {
1152 // Always delete cell 0 as they get renumbered as they are deleted.
1184 // Always delete cell 0 as they get renumbered as they are deleted.
1153 this.delete_cell(0);
1185 this.delete_cell(0);
1154 };
1186 };
1155 // Save the metadata
1187 // Save the metadata and name.
1156 this.metadata = data.metadata;
1188 this.metadata = data.metadata;
1189 this.notebook_name = data.metadata.name;
1157 // Only handle 1 worksheet for now.
1190 // Only handle 1 worksheet for now.
1158 var worksheet = data.worksheets[0];
1191 var worksheet = data.worksheets[0];
1159 if (worksheet !== undefined) {
1192 if (worksheet !== undefined) {
1160 var new_cells = worksheet.cells;
1193 var new_cells = worksheet.cells;
1161 ncells = new_cells.length;
1194 ncells = new_cells.length;
1162 var cell_data = null;
1195 var cell_data = null;
1163 var new_cell = null;
1196 var new_cell = null;
1164 for (i=0; i<ncells; i++) {
1197 for (i=0; i<ncells; i++) {
1165 cell_data = new_cells[i];
1198 cell_data = new_cells[i];
1166 new_cell = this.insert_cell_below(cell_data.cell_type);
1199 new_cell = this.insert_cell_below(cell_data.cell_type);
1167 new_cell.fromJSON(cell_data);
1200 new_cell.fromJSON(cell_data);
1168 };
1201 };
1169 };
1202 };
1170 };
1203 };
1171
1204
1172
1205
1173 Notebook.prototype.toJSON = function () {
1206 Notebook.prototype.toJSON = function () {
1174 var cells = this.get_cells();
1207 var cells = this.get_cells();
1175 var ncells = cells.length;
1208 var ncells = cells.length;
1176 cell_array = new Array(ncells);
1209 cell_array = new Array(ncells);
1177 for (var i=0; i<ncells; i++) {
1210 for (var i=0; i<ncells; i++) {
1178 cell_array[i] = cells[i].toJSON();
1211 cell_array[i] = cells[i].toJSON();
1179 };
1212 };
1180 data = {
1213 data = {
1181 // Only handle 1 worksheet for now.
1214 // Only handle 1 worksheet for now.
1182 worksheets : [{cells:cell_array}],
1215 worksheets : [{cells:cell_array}],
1183 metadata : this.metadata
1216 metadata : this.metadata
1184 };
1217 };
1185 return data;
1218 return data;
1186 };
1219 };
1187
1220
1188 Notebook.prototype.save_notebook = function () {
1221 Notebook.prototype.save_notebook = function () {
1189 var notebook_id = IPython.save_widget.get_notebook_id();
1190 var nbname = IPython.save_widget.get_notebook_name();
1191 // We may want to move the name/id/nbformat logic inside toJSON?
1222 // We may want to move the name/id/nbformat logic inside toJSON?
1192 var data = this.toJSON();
1223 var data = this.toJSON();
1193 data.metadata.name = nbname;
1224 data.metadata.name = this.notebook_name;
1194 data.nbformat = 3;
1225 data.nbformat = 3;
1195 // We do the call with settings so we can set cache to false.
1226 // We do the call with settings so we can set cache to false.
1196 var settings = {
1227 var settings = {
1197 processData : false,
1228 processData : false,
1198 cache : false,
1229 cache : false,
1199 type : "PUT",
1230 type : "PUT",
1200 data : JSON.stringify(data),
1231 data : JSON.stringify(data),
1201 headers : {'Content-Type': 'application/json'},
1232 headers : {'Content-Type': 'application/json'},
1202 success : $.proxy(this.notebook_saved,this),
1233 success : $.proxy(this.notebook_save_success,this),
1203 error : $.proxy(this.notebook_save_failed,this)
1234 error : $.proxy(this.notebook_save_failed,this)
1204 };
1235 };
1205 IPython.save_widget.status_saving();
1236 $([IPython.events]).trigger('notebook_saving.Notebook');
1206 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
1237 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1207 $.ajax(url, settings);
1238 $.ajax(url, settings);
1208 };
1239 };
1209
1240
1210
1241
1211 Notebook.prototype.notebook_saved = function (data, status, xhr) {
1242 Notebook.prototype.notebook_save_success = function (data, status, xhr) {
1212 this.dirty = false;
1243 this.dirty = false;
1213 IPython.save_widget.notebook_saved();
1244 $([IPython.events]).trigger('notebook_saved.Notebook');
1214 IPython.save_widget.status_last_saved();
1215 };
1245 };
1216
1246
1217
1247
1218 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
1248 Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) {
1219 IPython.save_widget.status_save_failed();
1249 $([IPython.events]).trigger('notebook_save_failed.Notebook');
1220 };
1250 };
1221
1251
1222
1252
1223 Notebook.prototype.load_notebook = function () {
1253 Notebook.prototype.load_notebook = function (notebook_id) {
1224 var that = this;
1254 var that = this;
1225 var notebook_id = IPython.save_widget.get_notebook_id();
1255 this.notebook_id = notebook_id;
1226 // We do the call with settings so we can set cache to false.
1256 // We do the call with settings so we can set cache to false.
1227 var settings = {
1257 var settings = {
1228 processData : false,
1258 processData : false,
1229 cache : false,
1259 cache : false,
1230 type : "GET",
1260 type : "GET",
1231 dataType : "json",
1261 dataType : "json",
1232 success : function (data, status, xhr) {
1262 success : function (data, status, xhr) {
1233 that.notebook_loaded(data, status, xhr);
1263 that.load_notebook_success(data, status, xhr);
1234 }
1264 }
1235 };
1265 };
1236 IPython.save_widget.status_loading();
1266 $([IPython.events]).trigger('notebook_loading.Notebook');
1237 var url = $('body').data('baseProjectUrl') + 'notebooks/' + notebook_id;
1267 var url = $('body').data('baseProjectUrl') + 'notebooks/' + this.notebook_id;
1238 $.ajax(url, settings);
1268 $.ajax(url, settings);
1239 };
1269 };
1240
1270
1241
1271
1242 Notebook.prototype.notebook_loaded = function (data, status, xhr) {
1272 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1243 this.fromJSON(data);
1273 this.fromJSON(data);
1244 if (this.ncells() === 0) {
1274 if (this.ncells() === 0) {
1245 this.insert_cell_below('code');
1275 this.insert_cell_below('code');
1246 };
1276 };
1247 IPython.save_widget.status_last_saved();
1248 IPython.save_widget.set_notebook_name(data.metadata.name);
1249 this.dirty = false;
1277 this.dirty = false;
1250 if (! this.read_only) {
1278 if (! this.read_only) {
1251 this.start_kernel();
1279 this.start_kernel();
1252 }
1280 }
1253 this.select(0);
1281 this.select(0);
1254 this.scroll_to_top();
1282 this.scroll_to_top();
1255 IPython.save_widget.update_url();
1283 $([IPython.events]).trigger('notebook_loaded.Notebook');
1256 IPython.layout_manager.do_resize();
1257 };
1284 };
1258
1285
1259 IPython.Notebook = Notebook;
1286 IPython.Notebook = Notebook;
1260
1287
1261
1288
1262 return IPython;
1289 return IPython;
1263
1290
1264 }(IPython));
1291 }(IPython));
1265
1292
@@ -1,117 +1,120
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 // On document ready
9 // On document ready
10 //============================================================================
10 //============================================================================
11
11
12
12
13 $(document).ready(function () {
13 $(document).ready(function () {
14 if (window.MathJax){
14 if (window.MathJax){
15 // MathJax loaded
15 // MathJax loaded
16 MathJax.Hub.Config({
16 MathJax.Hub.Config({
17 tex2jax: {
17 tex2jax: {
18 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
18 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
19 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
19 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
20 },
20 },
21 displayAlign: 'left', // Change this to 'center' to center equations.
21 displayAlign: 'left', // Change this to 'center' to center equations.
22 "HTML-CSS": {
22 "HTML-CSS": {
23 styles: {'.MathJax_Display': {"margin": 0}}
23 styles: {'.MathJax_Display': {"margin": 0}}
24 }
24 }
25 });
25 });
26 }else if (window.mathjax_url != ""){
26 }else if (window.mathjax_url != ""){
27 // Don't have MathJax, but should. Show dialog.
27 // Don't have MathJax, but should. Show dialog.
28 var dialog = $('<div></div>')
28 var dialog = $('<div></div>')
29 .append(
29 .append(
30 $("<p></p>").addClass('dialog').html(
30 $("<p></p>").addClass('dialog').html(
31 "Math/LaTeX rendering will be disabled."
31 "Math/LaTeX rendering will be disabled."
32 )
32 )
33 ).append(
33 ).append(
34 $("<p></p>").addClass('dialog').html(
34 $("<p></p>").addClass('dialog').html(
35 "If you have administrative access to the notebook server and" +
35 "If you have administrative access to the notebook server and" +
36 " a working internet connection, you can install a local copy" +
36 " a working internet connection, you can install a local copy" +
37 " of MathJax for offline use with the following command on the server" +
37 " of MathJax for offline use with the following command on the server" +
38 " at a Python or IPython prompt:"
38 " at a Python or IPython prompt:"
39 )
39 )
40 ).append(
40 ).append(
41 $("<pre></pre>").addClass('dialog').html(
41 $("<pre></pre>").addClass('dialog').html(
42 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
42 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
43 )
43 )
44 ).append(
44 ).append(
45 $("<p></p>").addClass('dialog').html(
45 $("<p></p>").addClass('dialog').html(
46 "This will try to install MathJax into the IPython source directory."
46 "This will try to install MathJax into the IPython source directory."
47 )
47 )
48 ).append(
48 ).append(
49 $("<p></p>").addClass('dialog').html(
49 $("<p></p>").addClass('dialog').html(
50 "If IPython is installed to a location that requires" +
50 "If IPython is installed to a location that requires" +
51 " administrative privileges to write, you will need to make this call as" +
51 " administrative privileges to write, you will need to make this call as" +
52 " an administrator, via 'sudo'."
52 " an administrator, via 'sudo'."
53 )
53 )
54 ).append(
54 ).append(
55 $("<p></p>").addClass('dialog').html(
55 $("<p></p>").addClass('dialog').html(
56 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
56 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
57 )
57 )
58 ).append(
58 ).append(
59 $("<pre></pre>").addClass('dialog').html(
59 $("<pre></pre>").addClass('dialog').html(
60 "$ ipython notebook --no-mathjax"
60 "$ ipython notebook --no-mathjax"
61 )
61 )
62 ).append(
62 ).append(
63 $("<p></p>").addClass('dialog').html(
63 $("<p></p>").addClass('dialog').html(
64 "which will prevent this dialog from appearing."
64 "which will prevent this dialog from appearing."
65 )
65 )
66 ).dialog({
66 ).dialog({
67 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
67 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
68 width: "70%",
68 width: "70%",
69 modal: true,
69 modal: true,
70 })
70 })
71 }else{
71 }else{
72 // No MathJax, but none expected. No dialog.
72 // No MathJax, but none expected. No dialog.
73 }
73 }
74
74
75
75
76 IPython.markdown_converter = new Markdown.Converter();
76 IPython.markdown_converter = new Markdown.Converter();
77 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
77 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
78
78
79 $('div#header').addClass('border-box-sizing');
79 $('div#header').addClass('border-box-sizing');
80 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
80 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
81 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
81 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
82
82
83 IPython.layout_manager = new IPython.LayoutManager();
83 IPython.layout_manager = new IPython.LayoutManager();
84 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
84 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
85 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
86 IPython.quick_help = new IPython.QuickHelp('span#quick_help_area');
85 IPython.quick_help = new IPython.QuickHelp('span#quick_help_area');
87 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
86 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
88 IPython.notebook = new IPython.Notebook('div#notebook');
87 IPython.notebook = new IPython.Notebook('div#notebook');
89 IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
88 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
90 IPython.menubar = new IPython.MenuBar('#menubar')
89 IPython.menubar = new IPython.MenuBar('#menubar')
91 IPython.toolbar = new IPython.ToolBar('#toolbar')
90 IPython.toolbar = new IPython.ToolBar('#toolbar')
92 IPython.kernel_status_widget.status_idle();
91 IPython.notification_widget = new IPython.NotificationWidget('#notification')
93
92
94 IPython.layout_manager.do_resize();
93 IPython.layout_manager.do_resize();
95
94
96 // These have display: none in the css file and are made visible here to prevent FLOUC.
95 // These have display: none in the css file and are made visible here to prevent FLOUC.
97 $('div#header').css('display','block');
96 $('div#header').css('display','block');
98
97
99 if(IPython.read_only){
98 if(IPython.read_only){
100 // hide various elements from read-only view
99 // hide various elements from read-only view
101 $('div#pager').remove();
100 $('div#pager').remove();
102 $('div#pager_splitter').remove();
101 $('div#pager_splitter').remove();
103 $('span#login_widget').removeClass('hidden');
102 $('span#login_widget').removeClass('hidden');
104
103
105 // set the notebook name field as not modifiable
104 // set the notebook name field as not modifiable
106 $('#notebook_name').attr('disabled','disabled')
105 $('#notebook_name').attr('disabled','disabled')
107 }
106 }
108
107
109 $('div#menubar').css('display','block');
108 $('div#menubar').css('display','block');
110 $('div#toolbar').css('display','block');
109 $('div#toolbar').css('display','block');
111 $('div#main_app').css('display','block');
110 $('div#main_app').css('display','block');
112
111
113 IPython.layout_manager.do_resize();
112 IPython.layout_manager.do_resize();
114 IPython.notebook.load_notebook();
113 $([IPython.events]).on('notebook_loaded.Notebook', function () {
114 IPython.layout_manager.do_resize();
115 IPython.save_widget.update_url();
116 })
117 IPython.notebook.load_notebook($('body').data('notebookId'));
115
118
116 });
119 });
117
120
@@ -1,94 +1,93
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 // On document ready
9 // On document ready
10 //============================================================================
10 //============================================================================
11
11
12
12
13 $(document).ready(function () {
13 $(document).ready(function () {
14 if (window.MathJax){
14 if (window.MathJax){
15 // MathJax loaded
15 // MathJax loaded
16 MathJax.Hub.Config({
16 MathJax.Hub.Config({
17 tex2jax: {
17 tex2jax: {
18 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
18 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
19 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
19 displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
20 },
20 },
21 displayAlign: 'left', // Change this to 'center' to center equations.
21 displayAlign: 'left', // Change this to 'center' to center equations.
22 "HTML-CSS": {
22 "HTML-CSS": {
23 styles: {'.MathJax_Display': {"margin": 0}}
23 styles: {'.MathJax_Display': {"margin": 0}}
24 }
24 }
25 });
25 });
26 }else if (window.mathjax_url != ""){
26 }else if (window.mathjax_url != ""){
27 // Don't have MathJax, but should. Show dialog.
27 // Don't have MathJax, but should. Show dialog.
28 var dialog = $('<div></div>')
28 var dialog = $('<div></div>')
29 .append(
29 .append(
30 $("<p></p>").addClass('dialog').html(
30 $("<p></p>").addClass('dialog').html(
31 "Math/LaTeX rendering will be disabled."
31 "Math/LaTeX rendering will be disabled."
32 )
32 )
33 ).append(
33 ).append(
34 $("<p></p>").addClass('dialog').html(
34 $("<p></p>").addClass('dialog').html(
35 "If you have administrative access to the notebook server and" +
35 "If you have administrative access to the notebook server and" +
36 " a working internet connection, you can install a local copy" +
36 " a working internet connection, you can install a local copy" +
37 " of MathJax for offline use with the following command on the server" +
37 " of MathJax for offline use with the following command on the server" +
38 " at a Python or IPython prompt:"
38 " at a Python or IPython prompt:"
39 )
39 )
40 ).append(
40 ).append(
41 $("<pre></pre>").addClass('dialog').html(
41 $("<pre></pre>").addClass('dialog').html(
42 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
42 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
43 )
43 )
44 ).append(
44 ).append(
45 $("<p></p>").addClass('dialog').html(
45 $("<p></p>").addClass('dialog').html(
46 "This will try to install MathJax into the IPython source directory."
46 "This will try to install MathJax into the IPython source directory."
47 )
47 )
48 ).append(
48 ).append(
49 $("<p></p>").addClass('dialog').html(
49 $("<p></p>").addClass('dialog').html(
50 "If IPython is installed to a location that requires" +
50 "If IPython is installed to a location that requires" +
51 " administrative privileges to write, you will need to make this call as" +
51 " administrative privileges to write, you will need to make this call as" +
52 " an administrator, via 'sudo'."
52 " an administrator, via 'sudo'."
53 )
53 )
54 ).append(
54 ).append(
55 $("<p></p>").addClass('dialog').html(
55 $("<p></p>").addClass('dialog').html(
56 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
56 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
57 )
57 )
58 ).append(
58 ).append(
59 $("<pre></pre>").addClass('dialog').html(
59 $("<pre></pre>").addClass('dialog').html(
60 "$ ipython notebook --no-mathjax"
60 "$ ipython notebook --no-mathjax"
61 )
61 )
62 ).append(
62 ).append(
63 $("<p></p>").addClass('dialog').html(
63 $("<p></p>").addClass('dialog').html(
64 "which will prevent this dialog from appearing."
64 "which will prevent this dialog from appearing."
65 )
65 )
66 ).dialog({
66 ).dialog({
67 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
67 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
68 width: "70%",
68 width: "70%",
69 modal: true,
69 modal: true,
70 })
70 })
71 }else{
71 }else{
72 // No MathJax, but none expected. No dialog.
72 // No MathJax, but none expected. No dialog.
73 }
73 }
74
74
75 IPython.markdown_converter = new Markdown.Converter();
75 IPython.markdown_converter = new Markdown.Converter();
76 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
76 IPython.read_only = $('meta[name=read_only]').attr("content") == 'True';
77
77
78 $('div#header').addClass('border-box-sizing');
78 $('div#header').addClass('border-box-sizing');
79 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
79 $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content');
80 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
80 $('div#notebook_panel').addClass('border-box-sizing ui-widget');
81
81
82 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
83 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
82 IPython.login_widget = new IPython.LoginWidget('span#login_widget');
84 IPython.notebook = new IPython.Notebook('div#notebook');
83 IPython.notebook = new IPython.Notebook('div#notebook');
84 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
85
85
86 // These have display: none in the css file and are made visible here to prevent FLOUC.
86 // These have display: none in the css file and are made visible here to prevent FLOUC.
87 $('div#header').css('display','block');
87 $('div#header').css('display','block');
88 $('div#main_app').css('display','block');
88 $('div#main_app').css('display','block');
89
89
90 // Perform these actions after the notebook has been loaded.
90 IPython.notebook.load_notebook($('body').data('notebookId'));
91 IPython.notebook.load_notebook(function () {});
92
91
93 });
92 });
94
93
@@ -1,179 +1,139
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 // SaveWidget
9 // SaveWidget
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 SaveWidget = function (selector) {
16 var SaveWidget = function (selector) {
17 this.selector = selector;
17 this.selector = selector;
18 this.notebook_name_blacklist_re = /[\/\\]/;
19 this.last_saved_name = '';
20 if (this.selector !== undefined) {
18 if (this.selector !== undefined) {
21 this.element = $(selector);
19 this.element = $(selector);
22 this.style();
20 this.style();
23 this.bind_events();
21 this.bind_events();
24 }
22 }
25 };
23 };
26
24
27
25
28 SaveWidget.prototype.style = function () {
26 SaveWidget.prototype.style = function () {
29 this.element.find('span#save_widget').addClass('ui-widget');
27 this.element.find('span#save_widget').addClass('ui-widget');
30 this.element.find('span#notebook_name').addClass('ui-widget ui-widget-content');
28 this.element.find('span#notebook_name').addClass('ui-widget ui-widget-content');
31 this.element.find('span#save_status').addClass('ui-widget ui-widget-content')
29 this.element.find('span#save_status').addClass('ui-widget ui-widget-content')
32 .css({border: 'none', 'margin-left': '20px'});
30 .css({border: 'none', 'margin-left': '20px'});
33 };
31 };
34
32
35
33
36 SaveWidget.prototype.bind_events = function () {
34 SaveWidget.prototype.bind_events = function () {
37 var that = this;
35 var that = this;
38 this.element.find('span#notebook_name').click(function () {
36 this.element.find('span#notebook_name').click(function () {
39 that.rename_notebook();
37 that.rename_notebook();
40 });
38 });
41 this.element.find('span#notebook_name').hover(function () {
39 this.element.find('span#notebook_name').hover(function () {
42 $(this).addClass("ui-state-hover");
40 $(this).addClass("ui-state-hover");
43 }, function () {
41 }, function () {
44 $(this).removeClass("ui-state-hover");
42 $(this).removeClass("ui-state-hover");
45 });
43 });
46 };
44 $([IPython.events]).on('notebook_loaded.Notebook', function () {
47
45 that.set_last_saved();
48
46 that.update_notebook_name();
49 SaveWidget.prototype.save_notebook = function () {
47 that.update_document_title();
50 IPython.notebook.save_notebook();
48 });
49 $([IPython.events]).on('notebook_saved.Notebook', function () {
50 that.set_last_saved();
51 that.update_notebook_name();
52 that.update_document_title();
53 });
54 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
55 that.set_save_status('');
56 });
51 };
57 };
52
58
53
59
54 SaveWidget.prototype.rename_notebook = function () {
60 SaveWidget.prototype.rename_notebook = function () {
55 var that = this;
61 var that = this;
56 var dialog = $('<div/>');
62 var dialog = $('<div/>');
57 dialog.append(
63 dialog.append(
58 $('<h3/>').html('Enter a new notebook name:')
64 $('<h3/>').html('Enter a new notebook name:')
59 .css({'margin-bottom': '10px'})
65 .css({'margin-bottom': '10px'})
60 );
66 );
61 dialog.append(
67 dialog.append(
62 $('<input/>').attr('type','text').attr('size','25')
68 $('<input/>').attr('type','text').attr('size','25')
63 .addClass('ui-widget ui-widget-content')
69 .addClass('ui-widget ui-widget-content')
64 .attr('value',that.get_notebook_name())
70 .attr('value',IPython.notebook.get_notebook_name())
65 );
71 );
66 // $(document).append(dialog);
72 // $(document).append(dialog);
67 dialog.dialog({
73 dialog.dialog({
68 resizable: false,
74 resizable: false,
69 modal: true,
75 modal: true,
70 title: "Rename Notebook",
76 title: "Rename Notebook",
71 closeText: "",
77 closeText: "",
72 close: function(event, ui) {$(this).dialog('destroy').remove();},
78 close: function(event, ui) {$(this).dialog('destroy').remove();},
73 buttons : {
79 buttons : {
74 "OK": function () {
80 "OK": function () {
75 var new_name = $(this).find('input').attr('value');
81 var new_name = $(this).find('input').attr('value');
76 if (!that.test_notebook_name(new_name)) {
82 if (!IPython.notebook.test_notebook_name(new_name)) {
77 $(this).find('h3').html(
83 $(this).find('h3').html(
78 "Invalid notebook name. Notebook names must "+
84 "Invalid notebook name. Notebook names must "+
79 "have 1 or more characters and can contain any characters " +
85 "have 1 or more characters and can contain any characters " +
80 "except / and \\. Please enter a new notebook name:"
86 "except / and \\. Please enter a new notebook name:"
81 );
87 );
82 } else {
88 } else {
83 that.set_notebook_name(new_name);
89 IPython.notebook.set_notebook_name(new_name);
84 that.save_notebook();
90 IPython.notebook.save_notebook();
85 $(this).dialog('close');
91 $(this).dialog('close');
86 }
92 }
87 },
93 },
88 "Cancel": function () {
94 "Cancel": function () {
89 $(this).dialog('close');
95 $(this).dialog('close');
90 }
96 }
91 }
97 }
92 });
98 });
93 }
99 }
94
100
95 SaveWidget.prototype.notebook_saved = function () {
96 this.set_document_title();
97 this.last_saved_name = this.get_notebook_name();
98 };
99
100
101
101 SaveWidget.prototype.get_notebook_name = function () {
102 SaveWidget.prototype.update_notebook_name = function () {
102 return this.element.find('span#notebook_name').html();
103 var nbname = IPython.notebook.get_notebook_name();
103 };
104
105
106 SaveWidget.prototype.set_notebook_name = function (nbname) {
107 this.element.find('span#notebook_name').html(nbname);
104 this.element.find('span#notebook_name').html(nbname);
108 this.set_document_title();
109 this.last_saved_name = nbname;
110 };
105 };
111
106
112
107
113 SaveWidget.prototype.set_document_title = function () {
108 SaveWidget.prototype.update_document_title = function () {
114 nbname = this.get_notebook_name();
109 var nbname = IPython.notebook.get_notebook_name();
115 document.title = nbname;
110 document.title = nbname;
116 };
111 };
117
118
119 SaveWidget.prototype.get_notebook_id = function () {
120 return $('body').data('notebookId');
121 };
122
112
123
113
124 SaveWidget.prototype.update_url = function () {
114 SaveWidget.prototype.update_url = function () {
125 var notebook_id = this.get_notebook_id();
115 var notebook_id = IPython.notebook.get_notebook_id();
126 if (notebook_id !== '') {
116 if (notebook_id !== null) {
127 var new_url = $('body').data('baseProjectUrl') + notebook_id;
117 var new_url = $('body').data('baseProjectUrl') + notebook_id;
128 window.history.replaceState({}, '', new_url);
118 window.history.replaceState({}, '', new_url);
129 };
119 };
130 };
120 };
131
121
132
122
133 SaveWidget.prototype.test_notebook_name = function (nbname) {
123 SaveWidget.prototype.set_save_status = function (msg) {
134 nbname = nbname || '';
124 this.element.find('span#save_status').html(msg);
135 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
125 }
136 return true;
137 } else {
138 return false;
139 };
140 };
141
126
142
127
143 SaveWidget.prototype.set_last_saved = function () {
128 SaveWidget.prototype.set_last_saved = function () {
144 var d = new Date();
129 var d = new Date();
145 $('#save_status').html('Last saved: '+d.format('mmm dd h:MM TT'));
130 this.set_save_status('Last saved: '+d.format('mmm dd h:MM TT'));
146
147 };
148
149 SaveWidget.prototype.reset_status = function () {
150 this.element.find('span#save_status').html('');
151 };
152
153
154 SaveWidget.prototype.status_last_saved = function () {
155 this.set_last_saved();
156 };
157
158
159 SaveWidget.prototype.status_saving = function () {
160 this.element.find('span#save_status').html('Saving...');
161 };
162
163
164 SaveWidget.prototype.status_save_failed = function () {
165 this.element.find('span#save_status').html('Save failed');
166 };
167
168
169 SaveWidget.prototype.status_loading = function () {
170 this.element.find('span#save_status').html('Loading...');
171 };
131 };
172
132
173
133
174 IPython.SaveWidget = SaveWidget;
134 IPython.SaveWidget = SaveWidget;
175
135
176 return IPython;
136 return IPython;
177
137
178 }(IPython));
138 }(IPython));
179
139
@@ -1,146 +1,148
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 // ToolBar
9 // ToolBar
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 var ToolBar = function (selector) {
14 var ToolBar = function (selector) {
15 this.selector = selector;
15 this.selector = selector;
16 if (this.selector !== undefined) {
16 if (this.selector !== undefined) {
17 this.element = $(selector);
17 this.element = $(selector);
18 this.style();
18 this.style();
19 this.bind_events();
19 this.bind_events();
20 }
20 }
21 };
21 };
22
22
23
23
24 ToolBar.prototype.style = function () {
24 ToolBar.prototype.style = function () {
25 this.element.addClass('border-box-sizing');
25 this.element.addClass('border-box-sizing');
26 this.element.find('#cell_type').addClass('ui-widget ui-widget-content');
26 this.element.find('#cell_type').addClass('ui-widget ui-widget-content');
27 this.element.find('#save_b').button({
27 this.element.find('#save_b').button({
28 icons : {primary: 'ui-icon-disk'},
28 icons : {primary: 'ui-icon-disk'},
29 text : false
29 text : false
30 });
30 });
31 this.element.find('#cut_b').button({
31 this.element.find('#cut_b').button({
32 icons: {primary: 'ui-icon-scissors'},
32 icons: {primary: 'ui-icon-scissors'},
33 text : false
33 text : false
34 });
34 });
35 this.element.find('#copy_b').button({
35 this.element.find('#copy_b').button({
36 icons: {primary: 'ui-icon-copy'},
36 icons: {primary: 'ui-icon-copy'},
37 text : false
37 text : false
38 });
38 });
39 this.element.find('#paste_b').button({
39 this.element.find('#paste_b').button({
40 icons: {primary: 'ui-icon-clipboard'},
40 icons: {primary: 'ui-icon-clipboard'},
41 text : false
41 text : false
42 });
42 });
43 this.element.find('#cut_copy_paste').buttonset();
43 this.element.find('#cut_copy_paste').buttonset();
44 this.element.find('#move_up_b').button({
44 this.element.find('#move_up_b').button({
45 icons: {primary: 'ui-icon-arrowthick-1-n'},
45 icons: {primary: 'ui-icon-arrowthick-1-n'},
46 text : false
46 text : false
47 });
47 });
48 this.element.find('#move_down_b').button({
48 this.element.find('#move_down_b').button({
49 icons: {primary: 'ui-icon-arrowthick-1-s'},
49 icons: {primary: 'ui-icon-arrowthick-1-s'},
50 text : false
50 text : false
51 });
51 });
52 this.element.find('#move_up_down').buttonset();
52 this.element.find('#move_up_down').buttonset();
53 this.element.find('#insert_above_b').button({
53 this.element.find('#insert_above_b').button({
54 icons: {primary: 'ui-icon-arrowthickstop-1-n'},
54 icons: {primary: 'ui-icon-arrowthickstop-1-n'},
55 text : false
55 text : false
56 });
56 });
57 this.element.find('#insert_below_b').button({
57 this.element.find('#insert_below_b').button({
58 icons: {primary: 'ui-icon-arrowthickstop-1-s'},
58 icons: {primary: 'ui-icon-arrowthickstop-1-s'},
59 text : false
59 text : false
60 });
60 });
61 this.element.find('#insert_above_below').buttonset();
61 this.element.find('#insert_above_below').buttonset();
62 this.element.find('#run_b').button({
62 this.element.find('#run_b').button({
63 icons: {primary: 'ui-icon-play'},
63 icons: {primary: 'ui-icon-play'},
64 text : false
64 text : false
65 });
65 });
66 this.element.find('#interrupt_b').button({
66 this.element.find('#interrupt_b').button({
67 icons: {primary: 'ui-icon-stop'},
67 icons: {primary: 'ui-icon-stop'},
68 text : false
68 text : false
69 });
69 });
70 this.element.find('#run_int').buttonset();
70 this.element.find('#run_int').buttonset();
71 };
71 };
72
72
73
73
74 ToolBar.prototype.bind_events = function () {
74 ToolBar.prototype.bind_events = function () {
75 var that = this;
75 this.element.find('#save_b').click(function () {
76 this.element.find('#save_b').click(function () {
76 IPython.save_widget.save_notebook();
77 IPython.notebook.save_notebook();
77 });
78 });
78 this.element.find('#cut_b').click(function () {
79 this.element.find('#cut_b').click(function () {
79 IPython.notebook.cut_cell();
80 IPython.notebook.cut_cell();
80 });
81 });
81 this.element.find('#copy_b').click(function () {
82 this.element.find('#copy_b').click(function () {
82 IPython.notebook.copy_cell();
83 IPython.notebook.copy_cell();
83 });
84 });
84 this.element.find('#paste_b').click(function () {
85 this.element.find('#paste_b').click(function () {
85 IPython.notebook.paste_cell();
86 IPython.notebook.paste_cell();
86 });
87 });
87 this.element.find('#move_up_b').click(function () {
88 this.element.find('#move_up_b').click(function () {
88 IPython.notebook.move_cell_up();
89 IPython.notebook.move_cell_up();
89 });
90 });
90 this.element.find('#move_down_b').click(function () {
91 this.element.find('#move_down_b').click(function () {
91 IPython.notebook.move_cell_down();
92 IPython.notebook.move_cell_down();
92 });
93 });
93 this.element.find('#insert_above_b').click(function () {
94 this.element.find('#insert_above_b').click(function () {
94 IPython.notebook.insert_cell_above('code');
95 IPython.notebook.insert_cell_above('code');
95 });
96 });
96 this.element.find('#insert_below_b').click(function () {
97 this.element.find('#insert_below_b').click(function () {
97 IPython.notebook.insert_cell_below('code');
98 IPython.notebook.insert_cell_below('code');
98 });
99 });
99 this.element.find('#run_b').click(function () {
100 this.element.find('#run_b').click(function () {
100 IPython.notebook.execute_selected_cell();
101 IPython.notebook.execute_selected_cell();
101 });
102 });
102 this.element.find('#interrupt_b').click(function () {
103 this.element.find('#interrupt_b').click(function () {
103 IPython.notebook.kernel.interrupt();
104 IPython.notebook.kernel.interrupt();
104 });
105 });
105 this.element.find('#cell_type').change(function () {
106 this.element.find('#cell_type').change(function () {
106 var cell_type = $(this).val();
107 var cell_type = $(this).val();
107 if (cell_type === 'code') {
108 if (cell_type === 'code') {
108 IPython.notebook.to_code();
109 IPython.notebook.to_code();
109 } else if (cell_type === 'markdown') {
110 } else if (cell_type === 'markdown') {
110 IPython.notebook.to_markdown();
111 IPython.notebook.to_markdown();
111 } else if (cell_type === 'plaintext') {
112 } else if (cell_type === 'plaintext') {
112 IPython.notebook.to_plaintext();
113 IPython.notebook.to_plaintext();
113 } else if (cell_type === 'heading1') {
114 } else if (cell_type === 'heading1') {
114 IPython.notebook.to_heading(undefined, 1);
115 IPython.notebook.to_heading(undefined, 1);
115 } else if (cell_type === 'heading2') {
116 } else if (cell_type === 'heading2') {
116 IPython.notebook.to_heading(undefined, 2);
117 IPython.notebook.to_heading(undefined, 2);
117 } else if (cell_type === 'heading3') {
118 } else if (cell_type === 'heading3') {
118 IPython.notebook.to_heading(undefined, 3);
119 IPython.notebook.to_heading(undefined, 3);
119 } else if (cell_type === 'heading4') {
120 } else if (cell_type === 'heading4') {
120 IPython.notebook.to_heading(undefined, 4);
121 IPython.notebook.to_heading(undefined, 4);
121 } else if (cell_type === 'heading5') {
122 } else if (cell_type === 'heading5') {
122 IPython.notebook.to_heading(undefined, 5);
123 IPython.notebook.to_heading(undefined, 5);
123 } else if (cell_type === 'heading6') {
124 } else if (cell_type === 'heading6') {
124 IPython.notebook.to_heading(undefined, 6);
125 IPython.notebook.to_heading(undefined, 6);
125 };
126 };
126 });
127 });
127
128 $([IPython.events]).on('selected_cell_type_changed', function (event, data) {
128 };
129 if (data.cell_type === 'heading') {
129
130 that.element.find('#cell_type').val(data.cell_type+data.level);
130
131 } else {
131 ToolBar.prototype.set_cell_type = function (cell_type) {
132 that.element.find('#cell_type').val(data.cell_type);
132 this.element.find('#cell_type').val(cell_type);
133 }
134 });
133 };
135 };
134
136
135
137
136 ToolBar.prototype.toggle = function () {
138 ToolBar.prototype.toggle = function () {
137 this.element.toggle();
139 this.element.toggle();
138 IPython.layout_manager.do_resize();
140 IPython.layout_manager.do_resize();
139 };
141 };
140
142
141
143
142 IPython.ToolBar = ToolBar;
144 IPython.ToolBar = ToolBar;
143
145
144 return IPython;
146 return IPython;
145
147
146 }(IPython));
148 }(IPython));
@@ -1,241 +1,244
1 <!DOCTYPE HTML>
1 <!DOCTYPE HTML>
2 <html>
2 <html>
3
3
4 <head>
4 <head>
5 <meta charset="utf-8">
5 <meta charset="utf-8">
6
6
7 <title>IPython Notebook</title>
7 <title>IPython Notebook</title>
8
8
9 {% if mathjax_url %}
9 {% if mathjax_url %}
10 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
10 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
11 {% end %}
11 {% end %}
12 <script type="text/javascript">
12 <script type="text/javascript">
13 // MathJax disabled, set as null to distingish from *missing* MathJax,
13 // MathJax disabled, set as null to distingish from *missing* MathJax,
14 // where it will be undefined, and should prompt a dialog later.
14 // where it will be undefined, and should prompt a dialog later.
15 window.mathjax_url = "{{mathjax_url}}";
15 window.mathjax_url = "{{mathjax_url}}";
16 </script>
16 </script>
17
17
18 <link rel="stylesheet" href="{{ static_url("jquery/css/themes/base/jquery-ui.min.css") }}" type="text/css" />
18 <link rel="stylesheet" href="{{ static_url("jquery/css/themes/base/jquery-ui.min.css") }}" type="text/css" />
19 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
19 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
20 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
20 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
21
21
22 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
22 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
23
23
24 <link rel="stylesheet" href="{{ static_url("css/boilerplate.css") }}" type="text/css" />
24 <link rel="stylesheet" href="{{ static_url("css/boilerplate.css") }}" type="text/css" />
25 <link rel="stylesheet" href="{{ static_url("css/layout.css") }}" type="text/css" />
25 <link rel="stylesheet" href="{{ static_url("css/layout.css") }}" type="text/css" />
26 <link rel="stylesheet" href="{{ static_url("css/base.css") }}" type="text/css" />
26 <link rel="stylesheet" href="{{ static_url("css/base.css") }}" type="text/css" />
27 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
27 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
28 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
28 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
29
29
30 {% comment In the notebook, the read-only flag is used to determine %}
30 {% comment In the notebook, the read-only flag is used to determine %}
31 {% comment whether to hide the side panels and switch off input %}
31 {% comment whether to hide the side panels and switch off input %}
32 <meta name="read_only" content="{{read_only and not logged_in}}"/>
32 <meta name="read_only" content="{{read_only and not logged_in}}"/>
33
33
34 </head>
34 </head>
35
35
36 <body
36 <body
37 data-project={{project}} data-notebook-id={{notebook_id}}
37 data-project={{project}} data-notebook-id={{notebook_id}}
38 data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}
38 data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}
39 >
39 >
40
40
41 <div id="header">
41 <div id="header">
42 <span id="ipython_notebook"><h1><a href='..' alt='dashboard'><img src='{{static_url("ipynblogo.png")}}' alt='IPython Notebook'/></a></h1></span>
42 <span id="ipython_notebook"><h1><a href='..' alt='dashboard'><img src='{{static_url("ipynblogo.png")}}' alt='IPython Notebook'/></a></h1></span>
43 <span id="save_widget">
43 <span id="save_widget">
44 <span id="notebook_name"></span>
44 <span id="notebook_name"></span>
45 <span id="save_status"></span>
45 <span id="save_status"></span>
46 </span>
46 </span>
47
47
48 <span id="login_widget">
48 <span id="login_widget">
49 {% comment This is a temporary workaround to hide the logout button %}
49 {% comment This is a temporary workaround to hide the logout button %}
50 {% comment when appropriate until notebook.html is templated %}
50 {% comment when appropriate until notebook.html is templated %}
51 {% if logged_in %}
51 {% if logged_in %}
52 <button id="logout">Logout</button>
52 <button id="logout">Logout</button>
53 {% elif not logged_in and login_available %}
53 {% elif not logged_in and login_available %}
54 <button id="login">Login</button>
54 <button id="login">Login</button>
55 {% end %}
55 {% end %}
56 </span>
56 </span>
57
58 <span id="kernel_status">Idle</span>
59 </div>
57 </div>
60
58
59 <div id="menubar_container">
61 <div id="menubar">
60 <div id="menubar">
62 <ul id="menus">
61 <ul id="menus">
63 <li><a href="#">File</a>
62 <li><a href="#">File</a>
64 <ul>
63 <ul>
65 <li id="new_notebook"><a href="#">New</a></li>
64 <li id="new_notebook"><a href="#">New</a></li>
66 <li id="open_notebook"><a href="#">Open...</a></li>
65 <li id="open_notebook"><a href="#">Open...</a></li>
67 <hr/>
66 <hr/>
68 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
67 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
69 <li id="rename_notebook"><a href="#">Rename...</a></li>
68 <li id="rename_notebook"><a href="#">Rename...</a></li>
70 <li id="save_notebook"><a href="#">Save</a></li>
69 <li id="save_notebook"><a href="#">Save</a></li>
71 <hr/>
70 <hr/>
72 <li><a href="#">Download as</a>
71 <li><a href="#">Download as</a>
73 <ul>
72 <ul>
74 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
73 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
75 <li id="download_py"><a href="#">Python (.py)</a></li>
74 <li id="download_py"><a href="#">Python (.py)</a></li>
76 </ul>
75 </ul>
77 </li>
76 </li>
78 <hr/>
77 <hr/>
79 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
78 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
80 </ul>
79 </ul>
81 </li>
80 </li>
82 <li><a href="#">Edit</a>
81 <li><a href="#">Edit</a>
83 <ul>
82 <ul>
84 <li id="cut_cell"><a href="#">Cut Cell</a></li>
83 <li id="cut_cell"><a href="#">Cut Cell</a></li>
85 <li id="copy_cell"><a href="#">Copy Cell</a></li>
84 <li id="copy_cell"><a href="#">Copy Cell</a></li>
86 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
85 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
87 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
86 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
88 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
87 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
89 <li id="delete_cell"><a href="#">Delete</a></li>
88 <li id="delete_cell"><a href="#">Delete</a></li>
90 <hr/>
89 <hr/>
91 <li id="split_cell"><a href="#">Split Cell</a></li>
90 <li id="split_cell"><a href="#">Split Cell</a></li>
92 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
91 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
93 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
92 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
94 <hr/>
93 <hr/>
95 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
94 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
96 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
95 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
97 <hr/>
96 <hr/>
98 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
97 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
99 <li id="select_next"><a href="#">Select Next Cell</a></li>
98 <li id="select_next"><a href="#">Select Next Cell</a></li>
100 </ul>
99 </ul>
101 </li>
100 </li>
102 <li><a href="#">View</a>
101 <li><a href="#">View</a>
103 <ul>
102 <ul>
104 <li id="toggle_header"><a href="#">Toggle Header</a></li>
103 <li id="toggle_header"><a href="#">Toggle Header</a></li>
105 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
104 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
106 </ul>
105 </ul>
107 </li>
106 </li>
108 <li><a href="#">Insert</a>
107 <li><a href="#">Insert</a>
109 <ul>
108 <ul>
110 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
109 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
111 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
110 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
112 </ul>
111 </ul>
113 </li>
112 </li>
114 <li><a href="#">Cell</a>
113 <li><a href="#">Cell</a>
115 <ul>
114 <ul>
116 <li id="run_cell"><a href="#">Run</a></li>
115 <li id="run_cell"><a href="#">Run</a></li>
117 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
116 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
118 <li id="run_all_cells"><a href="#">Run All</a></li>
117 <li id="run_all_cells"><a href="#">Run All</a></li>
119 <hr/>
118 <hr/>
120 <li id="to_code"><a href="#">Code</a></li>
119 <li id="to_code"><a href="#">Code</a></li>
121 <li id="to_markdown"><a href="#">Markdown </a></li>
120 <li id="to_markdown"><a href="#">Markdown </a></li>
122 <li id="to_plaintext"><a href="#">Plaintext</a></li>
121 <li id="to_plaintext"><a href="#">Plaintext</a></li>
123 <li id="to_heading1"><a href="#">Heading 1</a></li>
122 <li id="to_heading1"><a href="#">Heading 1</a></li>
124 <li id="to_heading2"><a href="#">Heading 2</a></li>
123 <li id="to_heading2"><a href="#">Heading 2</a></li>
125 <li id="to_heading3"><a href="#">Heading 3</a></li>
124 <li id="to_heading3"><a href="#">Heading 3</a></li>
126 <li id="to_heading4"><a href="#">Heading 4</a></li>
125 <li id="to_heading4"><a href="#">Heading 4</a></li>
127 <li id="to_heading5"><a href="#">Heading 5</a></li>
126 <li id="to_heading5"><a href="#">Heading 5</a></li>
128 <li id="to_heading6"><a href="#">Heading 6</a></li>
127 <li id="to_heading6"><a href="#">Heading 6</a></li>
129 <hr/>
128 <hr/>
130 <li id="toggle_output"><a href="#">Toggle Output</a></li>
129 <li id="toggle_output"><a href="#">Toggle Output</a></li>
131 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
130 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
132 </ul>
131 </ul>
133 </li>
132 </li>
134 <li><a href="#">Kernel</a>
133 <li><a href="#">Kernel</a>
135 <ul>
134 <ul>
136 <li id="int_kernel"><a href="#">Interrupt</a></li>
135 <li id="int_kernel"><a href="#">Interrupt</a></li>
137 <li id="restart_kernel"><a href="#">Restart</a></li>
136 <li id="restart_kernel"><a href="#">Restart</a></li>
138 </ul>
137 </ul>
139 </li>
138 </li>
140 <li><a href="#">Help</a>
139 <li><a href="#">Help</a>
141 <ul>
140 <ul>
142 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
141 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
143 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
142 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
144 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
143 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
145 <hr/>
144 <hr/>
146 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
145 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
147 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
146 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
148 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
147 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
149 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
148 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
150 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
149 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
151 </ul>
150 </ul>
152 </li>
151 </li>
153 </ul>
152 </ul>
154
153
155 </div>
154 </div>
155 <div id="notification"></div>
156 </div>
157
156
158
157 <div id="toolbar">
159 <div id="toolbar">
158
160
159 <span>
161 <span>
160 <button id="save_b">Save</button>
162 <button id="save_b">Save</button>
161 </span>
163 </span>
162 <span id="cut_copy_paste">
164 <span id="cut_copy_paste">
163 <button id="cut_b" title="Cut Cell">Cut Cell</button>
165 <button id="cut_b" title="Cut Cell">Cut Cell</button>
164 <button id="copy_b" title="Copy Cell">Copy Cell</button>
166 <button id="copy_b" title="Copy Cell">Copy Cell</button>
165 <button id="paste_b" title="Paste Cell">Paste Cell</button>
167 <button id="paste_b" title="Paste Cell">Paste Cell</button>
166 </span>
168 </span>
167 <span id="move_up_down">
169 <span id="move_up_down">
168 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
170 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
169 <button id="move_down_b" title="Move Cell Down">Move Down</button>
171 <button id="move_down_b" title="Move Cell Down">Move Down</button>
170 </span>
172 </span>
171 <span id="insert_above_below">
173 <span id="insert_above_below">
172 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
174 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
173 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
175 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
174 </span>
176 </span>
175 <span id="run_int">
177 <span id="run_int">
176 <button id="run_b" title="Run Cell">Run Cell</button>
178 <button id="run_b" title="Run Cell">Run Cell</button>
177 <button id="interrupt_b" title="Interrupt">Interrupt</button>
179 <button id="interrupt_b" title="Interrupt">Interrupt</button>
178 </span>
180 </span>
179 <span>
181 <span>
180 <select id="cell_type">
182 <select id="cell_type">
181 <option value="code">Code</option>
183 <option value="code">Code</option>
182 <option value="markdown">Markdown</option>
184 <option value="markdown">Markdown</option>
183 <option value="plaintext">Plaintext</option>
185 <option value="plaintext">Plaintext</option>
184 <option value="heading1">Heading 1</option>
186 <option value="heading1">Heading 1</option>
185 <option value="heading2">Heading 2</option>
187 <option value="heading2">Heading 2</option>
186 <option value="heading3">Heading 3</option>
188 <option value="heading3">Heading 3</option>
187 <option value="heading4">Heading 4</option>
189 <option value="heading4">Heading 4</option>
188 <option value="heading5">Heading 5</option>
190 <option value="heading5">Heading 5</option>
189 <option value="heading6">Heading 6</option>
191 <option value="heading6">Heading 6</option>
190 </select>
192 </select>
191 </span>
193 </span>
192
194
193 </div>
195 </div>
194
196
195 <div id="main_app">
197 <div id="main_app">
196
198
197 <div id="notebook_panel">
199 <div id="notebook_panel">
198 <div id="notebook"></div>
200 <div id="notebook"></div>
199 <div id="pager_splitter"></div>
201 <div id="pager_splitter"></div>
200 <div id="pager"></div>
202 <div id="pager"></div>
201 </div>
203 </div>
202
204
203 </div>
205 </div>
204
206
205 <script src="{{ static_url("jquery/js/jquery-1.7.1.min.js") }}" type="text/javascript" charset="utf-8"></script>
207 <script src="{{ static_url("jquery/js/jquery-1.7.1.min.js") }}" type="text/javascript" charset="utf-8"></script>
206 <script src="{{ static_url("jquery/js/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
208 <script src="{{ static_url("jquery/js/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
207
209
208 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
210 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
209 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
211 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
210 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
212 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
211 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
213 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
212 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
214 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
213 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
215 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
214 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
216 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
215 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
217 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
216
218
217 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
219 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
218
220
219 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
221 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
220 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
222 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
221
223
222 <script src="{{ static_url("js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
224 <script src="{{ static_url("js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
225 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
223 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
226 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
224 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
227 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
225 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
228 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
226 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
229 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
227 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
230 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
228 <script src="{{ static_url("js/kernelstatus.js") }}" type="text/javascript" charset="utf-8"></script>
229 <script src="{{ static_url("js/layout.js") }}" type="text/javascript" charset="utf-8"></script>
231 <script src="{{ static_url("js/layout.js") }}" type="text/javascript" charset="utf-8"></script>
230 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
232 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
231 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
233 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
232 <script src="{{ static_url("js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
234 <script src="{{ static_url("js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
233 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
235 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
234 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
236 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
235 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
237 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
236 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
238 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
239 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
237 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
240 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
238
241
239 </body>
242 </body>
240
243
241 </html>
244 </html>
@@ -1,104 +1,102
1 <!DOCTYPE HTML>
1 <!DOCTYPE HTML>
2 <html>
2 <html>
3
3
4 <head>
4 <head>
5 <meta charset="utf-8">
5 <meta charset="utf-8">
6
6
7 <title>IPython Notebook</title>
7 <title>IPython Notebook</title>
8
8
9 {% if mathjax_url %}
9 {% if mathjax_url %}
10 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
10 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
11 {% end %}
11 {% end %}
12 <script type="text/javascript">
12 <script type="text/javascript">
13 // MathJax disabled, set as null to distingish from *missing* MathJax,
13 // MathJax disabled, set as null to distingish from *missing* MathJax,
14 // where it will be undefined, and should prompt a dialog later.
14 // where it will be undefined, and should prompt a dialog later.
15 window.mathjax_url = "{{mathjax_url}}";
15 window.mathjax_url = "{{mathjax_url}}";
16 </script>
16 </script>
17
17
18 <link rel="stylesheet" href="{{ static_url("jquery/css/themes/base/jquery-ui.min.css") }}" type="text/css" />
18 <link rel="stylesheet" href="{{ static_url("jquery/css/themes/base/jquery-ui.min.css") }}" type="text/css" />
19 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
19 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
20 <link rel="stylesheet" href="{{ static_url("codemirror/mode/markdown/markdown.css") }}">
21 <link rel="stylesheet" href="{{ static_url("codemirror/mode/rst/rst.css") }}">
22 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
20 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
23 <link rel="stylesheet" href="{{ static_url("codemirror/theme/default.css") }}">
24
21
25 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
22 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
26
23
27 <link rel="stylesheet" href="{{ static_url("css/boilerplate.css") }}" type="text/css" />
24 <link rel="stylesheet" href="{{ static_url("css/boilerplate.css") }}" type="text/css" />
28 <link rel="stylesheet" href="{{ static_url("css/layout.css") }}" type="text/css" />
25 <link rel="stylesheet" href="{{ static_url("css/layout.css") }}" type="text/css" />
29 <link rel="stylesheet" href="{{ static_url("css/base.css") }}" type="text/css" />
26 <link rel="stylesheet" href="{{ static_url("css/base.css") }}" type="text/css" />
30 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
27 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
31 <link rel="stylesheet" href="{{ static_url("css/printnotebook.css") }}" type="text/css" />
28 <link rel="stylesheet" href="{{ static_url("css/printnotebook.css") }}" type="text/css" />
32 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
29 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
33
30
34 {% comment In the notebook, the read-only flag is used to determine %}
31 {% comment In the notebook, the read-only flag is used to determine %}
35 {% comment whether to hide the side panels and switch off input %}
32 {% comment whether to hide the side panels and switch off input %}
36 <meta name="read_only" content="{{read_only and not logged_in}}"/>
33 <meta name="read_only" content="{{read_only and not logged_in}}"/>
37
34
38 </head>
35 </head>
39
36
40 <body
37 <body
41 data-project={{project}} data-notebook-id={{notebook_id}}
38 data-project={{project}} data-notebook-id={{notebook_id}}
42 data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}
39 data-base-project-url={{base_project_url}} data-base-kernel-url={{base_kernel_url}}
43 >
40 >
44
41
45 <div id="header">
42 <div id="header">
46 <span id="ipython_notebook"><h1><a href='..' alt='dashboard'><img src='{{static_url("ipynblogo.png") }}' alt='IPython Notebook'/></a></h1></span>
43 <span id="ipython_notebook"><h1><a href='..' alt='dashboard'><img src='{{static_url("ipynblogo.png") }}' alt='IPython Notebook'/></a></h1></span>
47 <span id="save_widget">
44 <span id="save_widget">
48 <span id="notebook_name"></span>
45 <span id="notebook_name"></span>
49 <span id="save_status"></span>
46 <span id="save_status"></span>
50 </span>
47 </span>
51
48
52 <span id="login_widget">
49 <span id="login_widget">
53 {% comment This is a temporary workaround to hide the logout button %}
50 {% comment This is a temporary workaround to hide the logout button %}
54 {% comment when appropriate until notebook.html is templated %}
51 {% comment when appropriate until notebook.html is templated %}
55 {% if logged_in %}
52 {% if logged_in %}
56 <button id="logout">Logout</button>
53 <button id="logout">Logout</button>
57 {% elif not logged_in and login_available %}
54 {% elif not logged_in and login_available %}
58 <button id="login">Login</button>
55 <button id="login">Login</button>
59 {% end %}
56 {% end %}
60 </span>
57 </span>
61
58
62 </div>
59 </div>
63
60
64
61
65 <div id="main_app">
62 <div id="main_app">
66
63
67 <div id="notebook_panel">
64 <div id="notebook_panel">
68 <div id="notebook"></div>
65 <div id="notebook"></div>
69 </div>
66 </div>
70
67
71 </div>
68 </div>
72
69
73 <script src="{{ static_url("jquery/js/jquery-1.7.1.min.js") }}" type="text/javascript" charset="utf-8"></script>
70 <script src="{{ static_url("jquery/js/jquery-1.7.1.min.js") }}" type="text/javascript" charset="utf-8"></script>
74 <script src="{{ static_url("jquery/js/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
71 <script src="{{ static_url("jquery/js/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
75
72
76 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
73 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
77 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
74 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
78 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
75 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
79 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
76 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
80 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
77 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
81 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
78 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
82 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
79 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
83 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
80 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
84
81
85 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
82 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
86
83
87 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
84 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
88 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
85 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
89
86
90 <script src="{{ static_url("js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
87 <script src="{{ static_url("js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
88 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
91 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
89 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
92 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
90 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
93 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
91 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
94 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
92 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
95 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
93 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
96 <script src="{{ static_url("js/kernelstatus.js") }}" type="text/javascript" charset="utf-8"></script>
94 <script src="{{ static_url("js/kernelstatus.js") }}" type="text/javascript" charset="utf-8"></script>
97 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
95 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
98 <script src="{{ static_url("js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
96 <script src="{{ static_url("js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
99 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
97 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
100 <script src="{{ static_url("js/printnotebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
98 <script src="{{ static_url("js/printnotebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
101
99
102 </body>
100 </body>
103
101
104 </html>
102 </html>
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now