##// END OF EJS Templates
Basic exception display in the notebook is working.
Brian Granger -
Show More
@@ -1,1014 +1,1028 b''
1 var IPYTHON = {};
1 var IPYTHON = {};
2
2
3
3
4 //============================================================================
4 //============================================================================
5 // Utilities
5 // Utilities
6 //============================================================================
6 //============================================================================
7
7
8
8
9 var uuid = function () {
9 var uuid = function () {
10 // http://www.ietf.org/rfc/rfc4122.txt
10 // http://www.ietf.org/rfc/rfc4122.txt
11 var s = [];
11 var s = [];
12 var hexDigits = "0123456789ABCDEF";
12 var hexDigits = "0123456789ABCDEF";
13 for (var i = 0; i < 32; i++) {
13 for (var i = 0; i < 32; i++) {
14 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
14 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
15 }
15 }
16 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
16 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
17 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
17 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
18
18
19 var uuid = s.join("");
19 var uuid = s.join("");
20 return uuid;
20 return uuid;
21 };
21 };
22
22
23
23
24 //Fix raw text to parse correctly in crazy XML
24 //Fix raw text to parse correctly in crazy XML
25 function xmlencode(string) {
25 function xmlencode(string) {
26 return string.replace(/\&/g,'&'+'amp;')
26 return string.replace(/\&/g,'&'+'amp;')
27 .replace(/</g,'&'+'lt;')
27 .replace(/</g,'&'+'lt;')
28 .replace(/>/g,'&'+'gt;')
28 .replace(/>/g,'&'+'gt;')
29 .replace(/\'/g,'&'+'apos;')
29 .replace(/\'/g,'&'+'apos;')
30 .replace(/\"/g,'&'+'quot;')
30 .replace(/\"/g,'&'+'quot;')
31 .replace(/`/g,'&'+'#96;')
31 .replace(/`/g,'&'+'#96;')
32 }
32 }
33
33
34 //Map from terminal commands to CSS classes
34 //Map from terminal commands to CSS classes
35 attrib = {
35 attrib = {
36 "30":"cblack", "31":"cred",
36 "30":"cblack", "31":"cred",
37 "32":"cgreen", "33":"cyellow",
37 "32":"cgreen", "33":"cyellow",
38 "34":"cblue", "36":"ccyan",
38 "34":"cblue", "36":"ccyan",
39 "37":"cwhite", "01":"cbold"}
39 "37":"cwhite", "01":"cbold"}
40
40
41 //Fixes escaped console commands, IE colors. Turns them into HTML
41 //Fixes escaped console commands, IE colors. Turns them into HTML
42 function fixConsole(txt) {
42 function fixConsole(txt) {
43 txt = xmlencode(txt)
43 txt = xmlencode(txt)
44 var re = /\033\[([\d;]*?)m/
44 var re = /\033\[([\d;]*?)m/
45 var opened = false
45 var opened = false
46 var cmds = []
46 var cmds = []
47 var opener = ""
47 var opener = ""
48 var closer = ""
48 var closer = ""
49
49
50 while (re.test(txt)) {
50 while (re.test(txt)) {
51 var cmds = txt.match(re)[1].split(";")
51 var cmds = txt.match(re)[1].split(";")
52 closer = opened?"</span>":""
52 closer = opened?"</span>":""
53 opened = cmds.length > 1 || cmds[0] != 0
53 opened = cmds.length > 1 || cmds[0] != 0
54 var rep = []
54 var rep = []
55 for (var i in cmds)
55 for (var i in cmds)
56 if (typeof(attrib[cmds[i]]) != "undefined")
56 if (typeof(attrib[cmds[i]]) != "undefined")
57 rep.push(attrib[cmds[i]])
57 rep.push(attrib[cmds[i]])
58 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":""
58 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":""
59 txt = txt.replace(re, closer + opener)
59 txt = txt.replace(re, closer + opener)
60 }
60 }
61 if (opened) txt += "</span>"
61 if (opened) txt += "</span>"
62 return txt.trim()
62 return txt.trim()
63 }
63 }
64
64
65
65
66 //============================================================================
66 //============================================================================
67 // Notebook
67 // Notebook
68 //============================================================================
68 //============================================================================
69
69
70
70
71 var Notebook = function (selector) {
71 var Notebook = function (selector) {
72 this.element = $(selector);
72 this.element = $(selector);
73 this.element.scroll();
73 this.element.scroll();
74 this.element.data("notebook", this);
74 this.element.data("notebook", this);
75 this.next_prompt_number = 1;
75 this.next_prompt_number = 1;
76 this.kernel = null;
76 this.kernel = null;
77 this.msg_cell_map = {};
77 this.msg_cell_map = {};
78 this.filename = null;
78 this.filename = null;
79 this.notebook_load_re = /%notebook load/
79 this.notebook_load_re = /%notebook load/
80 this.notebook_save_re = /%notebook save/
80 this.notebook_save_re = /%notebook save/
81 this.notebook_filename_re = /(\w)+.ipynb/
81 this.notebook_filename_re = /(\w)+.ipynb/
82 this.bind_events();
82 this.bind_events();
83 this.start_kernel();
83 this.start_kernel();
84 };
84 };
85
85
86
86
87 Notebook.prototype.bind_events = function () {
87 Notebook.prototype.bind_events = function () {
88 var that = this;
88 var that = this;
89 $(document).keydown(function (event) {
89 $(document).keydown(function (event) {
90 // console.log(event);
90 // console.log(event);
91 if (event.which == 38 && event.shiftKey) {
91 if (event.which == 38 && event.shiftKey) {
92 event.preventDefault();
92 event.preventDefault();
93 that.select_prev();
93 that.select_prev();
94 } else if (event.which == 40 && event.shiftKey) {
94 } else if (event.which == 40 && event.shiftKey) {
95 event.preventDefault();
95 event.preventDefault();
96 that.select_next();
96 that.select_next();
97 } else if (event.which == 13 && event.shiftKey) {
97 } else if (event.which == 13 && event.shiftKey) {
98 // The focus is not quite working here.
98 // The focus is not quite working here.
99 var cell = that.selected_cell();
99 var cell = that.selected_cell();
100 var cell_index = that.find_cell_index(cell);
100 var cell_index = that.find_cell_index(cell);
101 // TODO: the logic here needs to be moved into appropriate
101 // TODO: the logic here needs to be moved into appropriate
102 // methods of Notebook.
102 // methods of Notebook.
103 if (cell instanceof CodeCell) {
103 if (cell instanceof CodeCell) {
104 event.preventDefault();
104 event.preventDefault();
105 cell.clear_output();
105 cell.clear_output();
106 var code = cell.get_code();
106 var code = cell.get_code();
107 if (that.notebook_load_re.test(code)) {
107 if (that.notebook_load_re.test(code)) {
108 var code_parts = code.split(' ');
108 var code_parts = code.split(' ');
109 if (code_parts.length === 3) {
109 if (code_parts.length === 3) {
110 that.load_notebook(code_parts[2]);
110 that.load_notebook(code_parts[2]);
111 };
111 };
112 } else if (that.notebook_save_re.test(code)) {
112 } else if (that.notebook_save_re.test(code)) {
113 var code_parts = code.split(' ');
113 var code_parts = code.split(' ');
114 if (code_parts.length === 3) {
114 if (code_parts.length === 3) {
115 that.save_notebook(code_parts[2]);
115 that.save_notebook(code_parts[2]);
116 } else {
116 } else {
117 that.save_notebook()
117 that.save_notebook()
118 };
118 };
119 } else {
119 } else {
120 var msg_id = that.kernel.execute(cell.get_code());
120 var msg_id = that.kernel.execute(cell.get_code());
121 that.msg_cell_map[msg_id] = cell.cell_id;
121 that.msg_cell_map[msg_id] = cell.cell_id;
122 };
122 };
123 if (cell_index === (that.ncells()-1)) {
123 if (cell_index === (that.ncells()-1)) {
124 that.insert_code_cell_after();
124 that.insert_code_cell_after();
125 } else {
125 } else {
126 that.select(cell_index+1);
126 that.select(cell_index+1);
127 };
127 };
128 }
128 }
129 } else if (event.which == 9) {
129 } else if (event.which == 9) {
130 event.preventDefault();
130 event.preventDefault();
131 var cell = that.selected_cell();
131 var cell = that.selected_cell();
132 if (cell instanceof CodeCell) {
132 if (cell instanceof CodeCell) {
133 var ta = cell.element.find("textarea.input_textarea");
133 var ta = cell.element.find("textarea.input_textarea");
134 ta.val(ta.val() + " ");
134 ta.val(ta.val() + " ");
135 };
135 };
136 };
136 };
137 });
137 });
138 };
138 };
139
139
140
140
141 // Cell indexing, retrieval, etc.
141 // Cell indexing, retrieval, etc.
142
142
143
143
144 Notebook.prototype.cell_elements = function () {
144 Notebook.prototype.cell_elements = function () {
145 return this.element.children("div.cell");
145 return this.element.children("div.cell");
146 }
146 }
147
147
148
148
149 Notebook.prototype.ncells = function (cell) {
149 Notebook.prototype.ncells = function (cell) {
150 return this.cell_elements().length;
150 return this.cell_elements().length;
151 }
151 }
152
152
153
153
154 // TODO: we are often calling cells as cells()[i], which we should optimize
154 // TODO: we are often calling cells as cells()[i], which we should optimize
155 // to cells(i) or a new method.
155 // to cells(i) or a new method.
156 Notebook.prototype.cells = function () {
156 Notebook.prototype.cells = function () {
157 return this.cell_elements().toArray().map(function (e) {
157 return this.cell_elements().toArray().map(function (e) {
158 return $(e).data("cell");
158 return $(e).data("cell");
159 });
159 });
160 }
160 }
161
161
162
162
163 Notebook.prototype.find_cell_index = function (cell) {
163 Notebook.prototype.find_cell_index = function (cell) {
164 var result = null;
164 var result = null;
165 this.cell_elements().filter(function (index) {
165 this.cell_elements().filter(function (index) {
166 if ($(this).data("cell") === cell) {
166 if ($(this).data("cell") === cell) {
167 result = index;
167 result = index;
168 };
168 };
169 });
169 });
170 return result;
170 return result;
171 };
171 };
172
172
173
173
174 Notebook.prototype.index_or_selected = function (index) {
174 Notebook.prototype.index_or_selected = function (index) {
175 return index || this.selected_index() || 0;
175 return index || this.selected_index() || 0;
176 }
176 }
177
177
178
178
179 Notebook.prototype.select = function (index) {
179 Notebook.prototype.select = function (index) {
180 if (index !== undefined && index >= 0 && index < this.ncells()) {
180 if (index !== undefined && index >= 0 && index < this.ncells()) {
181 if (this.selected_index() !== null) {
181 if (this.selected_index() !== null) {
182 this.selected_cell().unselect();
182 this.selected_cell().unselect();
183 };
183 };
184 this.cells()[index].select();
184 this.cells()[index].select();
185 };
185 };
186 return this;
186 return this;
187 };
187 };
188
188
189
189
190 Notebook.prototype.select_next = function () {
190 Notebook.prototype.select_next = function () {
191 var index = this.selected_index();
191 var index = this.selected_index();
192 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
192 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
193 this.select(index+1);
193 this.select(index+1);
194 };
194 };
195 return this;
195 return this;
196 };
196 };
197
197
198
198
199 Notebook.prototype.select_prev = function () {
199 Notebook.prototype.select_prev = function () {
200 var index = this.selected_index();
200 var index = this.selected_index();
201 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
201 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
202 this.select(index-1);
202 this.select(index-1);
203 };
203 };
204 return this;
204 return this;
205 };
205 };
206
206
207
207
208 Notebook.prototype.selected_index = function () {
208 Notebook.prototype.selected_index = function () {
209 var result = null;
209 var result = null;
210 this.cell_elements().filter(function (index) {
210 this.cell_elements().filter(function (index) {
211 if ($(this).data("cell").selected === true) {
211 if ($(this).data("cell").selected === true) {
212 result = index;
212 result = index;
213 };
213 };
214 });
214 });
215 return result;
215 return result;
216 };
216 };
217
217
218
218
219 Notebook.prototype.cell_for_msg = function (msg_id) {
219 Notebook.prototype.cell_for_msg = function (msg_id) {
220 var cell_id = this.msg_cell_map[msg_id];
220 var cell_id = this.msg_cell_map[msg_id];
221 var result = null;
221 var result = null;
222 this.cell_elements().filter(function (index) {
222 this.cell_elements().filter(function (index) {
223 cell = $(this).data("cell");
223 cell = $(this).data("cell");
224 if (cell.cell_id === cell_id) {
224 if (cell.cell_id === cell_id) {
225 result = cell;
225 result = cell;
226 };
226 };
227 });
227 });
228 return result;
228 return result;
229 };
229 };
230
230
231
231
232 Notebook.prototype.selected_cell = function () {
232 Notebook.prototype.selected_cell = function () {
233 return this.cell_elements().eq(this.selected_index()).data("cell");
233 return this.cell_elements().eq(this.selected_index()).data("cell");
234 }
234 }
235
235
236
236
237 // Cell insertion, deletion and moving.
237 // Cell insertion, deletion and moving.
238
238
239
239
240 Notebook.prototype.delete_cell = function (index) {
240 Notebook.prototype.delete_cell = function (index) {
241 var i = index || this.selected_index();
241 var i = index || this.selected_index();
242 if (i !== null && i >= 0 && i < this.ncells()) {
242 if (i !== null && i >= 0 && i < this.ncells()) {
243 this.cell_elements().eq(i).remove();
243 this.cell_elements().eq(i).remove();
244 if (i === (this.ncells())) {
244 if (i === (this.ncells())) {
245 this.select(i-1);
245 this.select(i-1);
246 } else {
246 } else {
247 this.select(i);
247 this.select(i);
248 };
248 };
249 };
249 };
250 return this;
250 return this;
251 };
251 };
252
252
253
253
254 Notebook.prototype.append_cell = function (cell) {
254 Notebook.prototype.append_cell = function (cell) {
255 this.element.append(cell.element);
255 this.element.append(cell.element);
256 return this;
256 return this;
257 };
257 };
258
258
259
259
260 Notebook.prototype.insert_cell_after = function (cell, index) {
260 Notebook.prototype.insert_cell_after = function (cell, index) {
261 var ncells = this.ncells();
261 var ncells = this.ncells();
262 if (ncells === 0) {
262 if (ncells === 0) {
263 this.append_cell(cell);
263 this.append_cell(cell);
264 return this;
264 return this;
265 };
265 };
266 if (index >= 0 && index < ncells) {
266 if (index >= 0 && index < ncells) {
267 this.cell_elements().eq(index).after(cell.element);
267 this.cell_elements().eq(index).after(cell.element);
268 };
268 };
269 return this
269 return this
270 };
270 };
271
271
272
272
273 Notebook.prototype.insert_cell_before = function (cell, index) {
273 Notebook.prototype.insert_cell_before = function (cell, index) {
274 var ncells = this.ncells();
274 var ncells = this.ncells();
275 if (ncells === 0) {
275 if (ncells === 0) {
276 this.append_cell(cell);
276 this.append_cell(cell);
277 return this;
277 return this;
278 };
278 };
279 if (index >= 0 && index < ncells) {
279 if (index >= 0 && index < ncells) {
280 this.cell_elements().eq(index).before(cell.element);
280 this.cell_elements().eq(index).before(cell.element);
281 };
281 };
282 return this;
282 return this;
283 };
283 };
284
284
285
285
286 Notebook.prototype.move_cell_up = function (index) {
286 Notebook.prototype.move_cell_up = function (index) {
287 var i = index || this.selected_index();
287 var i = index || this.selected_index();
288 if (i !== null && i < this.ncells() && i > 0) {
288 if (i !== null && i < this.ncells() && i > 0) {
289 var pivot = this.cell_elements().eq(i-1);
289 var pivot = this.cell_elements().eq(i-1);
290 var tomove = this.cell_elements().eq(i);
290 var tomove = this.cell_elements().eq(i);
291 if (pivot !== null && tomove !== null) {
291 if (pivot !== null && tomove !== null) {
292 tomove.detach();
292 tomove.detach();
293 pivot.before(tomove);
293 pivot.before(tomove);
294 this.select(i-1);
294 this.select(i-1);
295 };
295 };
296 };
296 };
297 return this;
297 return this;
298 }
298 }
299
299
300
300
301 Notebook.prototype.move_cell_down = function (index) {
301 Notebook.prototype.move_cell_down = function (index) {
302 var i = index || this.selected_index();
302 var i = index || this.selected_index();
303 if (i !== null && i < (this.ncells()-1) && i >= 0) {
303 if (i !== null && i < (this.ncells()-1) && i >= 0) {
304 var pivot = this.cell_elements().eq(i+1)
304 var pivot = this.cell_elements().eq(i+1)
305 var tomove = this.cell_elements().eq(i)
305 var tomove = this.cell_elements().eq(i)
306 if (pivot !== null && tomove !== null) {
306 if (pivot !== null && tomove !== null) {
307 tomove.detach();
307 tomove.detach();
308 pivot.after(tomove);
308 pivot.after(tomove);
309 this.select(i+1);
309 this.select(i+1);
310 };
310 };
311 };
311 };
312 return this;
312 return this;
313 }
313 }
314
314
315
315
316 Notebook.prototype.sort_cells = function () {
316 Notebook.prototype.sort_cells = function () {
317 var ncells = this.ncells();
317 var ncells = this.ncells();
318 var sindex = this.selected_index();
318 var sindex = this.selected_index();
319 var swapped;
319 var swapped;
320 do {
320 do {
321 swapped = false
321 swapped = false
322 for (var i=1; i<ncells; i++) {
322 for (var i=1; i<ncells; i++) {
323 current = this.cell_elements().eq(i).data("cell");
323 current = this.cell_elements().eq(i).data("cell");
324 previous = this.cell_elements().eq(i-1).data("cell");
324 previous = this.cell_elements().eq(i-1).data("cell");
325 if (previous.input_prompt_number > current.input_prompt_number) {
325 if (previous.input_prompt_number > current.input_prompt_number) {
326 this.move_cell_up(i);
326 this.move_cell_up(i);
327 swapped = true;
327 swapped = true;
328 };
328 };
329 };
329 };
330 } while (swapped);
330 } while (swapped);
331 this.select(sindex);
331 this.select(sindex);
332 return this;
332 return this;
333 };
333 };
334
334
335
335
336 Notebook.prototype.insert_code_cell_before = function (index) {
336 Notebook.prototype.insert_code_cell_before = function (index) {
337 // TODO: Bounds check for i
337 // TODO: Bounds check for i
338 var i = this.index_or_selected(index);
338 var i = this.index_or_selected(index);
339 var cell = new CodeCell(this);
339 var cell = new CodeCell(this);
340 cell.set_input_prompt(this.next_prompt_number);
340 cell.set_input_prompt(this.next_prompt_number);
341 this.next_prompt_number = this.next_prompt_number + 1;
341 this.next_prompt_number = this.next_prompt_number + 1;
342 this.insert_cell_before(cell, i);
342 this.insert_cell_before(cell, i);
343 this.select(this.find_cell_index(cell));
343 this.select(this.find_cell_index(cell));
344 return this;
344 return this;
345 }
345 }
346
346
347
347
348 Notebook.prototype.insert_code_cell_after = function (index) {
348 Notebook.prototype.insert_code_cell_after = function (index) {
349 // TODO: Bounds check for i
349 // TODO: Bounds check for i
350 var i = this.index_or_selected(index);
350 var i = this.index_or_selected(index);
351 var cell = new CodeCell(this);
351 var cell = new CodeCell(this);
352 cell.set_input_prompt(this.next_prompt_number);
352 cell.set_input_prompt(this.next_prompt_number);
353 this.next_prompt_number = this.next_prompt_number + 1;
353 this.next_prompt_number = this.next_prompt_number + 1;
354 this.insert_cell_after(cell, i);
354 this.insert_cell_after(cell, i);
355 this.select(this.find_cell_index(cell));
355 this.select(this.find_cell_index(cell));
356 return this;
356 return this;
357 }
357 }
358
358
359
359
360 Notebook.prototype.insert_text_cell_before = function (index) {
360 Notebook.prototype.insert_text_cell_before = function (index) {
361 // TODO: Bounds check for i
361 // TODO: Bounds check for i
362 var i = this.index_or_selected(index);
362 var i = this.index_or_selected(index);
363 var cell = new TextCell(this);
363 var cell = new TextCell(this);
364 cell.config_mathjax();
364 cell.config_mathjax();
365 this.insert_cell_before(cell, i);
365 this.insert_cell_before(cell, i);
366 this.select(this.find_cell_index(cell));
366 this.select(this.find_cell_index(cell));
367 return this;
367 return this;
368 }
368 }
369
369
370
370
371 Notebook.prototype.insert_text_cell_after = function (index) {
371 Notebook.prototype.insert_text_cell_after = function (index) {
372 // TODO: Bounds check for i
372 // TODO: Bounds check for i
373 var i = this.index_or_selected(index);
373 var i = this.index_or_selected(index);
374 var cell = new TextCell(this);
374 var cell = new TextCell(this);
375 cell.config_mathjax();
375 cell.config_mathjax();
376 this.insert_cell_after(cell, i);
376 this.insert_cell_after(cell, i);
377 this.select(this.find_cell_index(cell));
377 this.select(this.find_cell_index(cell));
378 return this;
378 return this;
379 }
379 }
380
380
381
381
382 Notebook.prototype.text_to_code = function (index) {
382 Notebook.prototype.text_to_code = function (index) {
383 // TODO: Bounds check for i
383 // TODO: Bounds check for i
384 var i = this.index_or_selected(index);
384 var i = this.index_or_selected(index);
385 var source_element = this.cell_elements().eq(i);
385 var source_element = this.cell_elements().eq(i);
386 var source_cell = source_element.data("cell");
386 var source_cell = source_element.data("cell");
387 if (source_cell instanceof TextCell) {
387 if (source_cell instanceof TextCell) {
388 this.insert_code_cell_after(i);
388 this.insert_code_cell_after(i);
389 var target_cell = this.cells()[i+1];
389 var target_cell = this.cells()[i+1];
390 target_cell.set_code(source_cell.get_text());
390 target_cell.set_code(source_cell.get_text());
391 source_element.remove();
391 source_element.remove();
392 };
392 };
393 };
393 };
394
394
395
395
396 Notebook.prototype.code_to_text = function (index) {
396 Notebook.prototype.code_to_text = function (index) {
397 // TODO: Bounds check for i
397 // TODO: Bounds check for i
398 var i = this.index_or_selected(index);
398 var i = this.index_or_selected(index);
399 var source_element = this.cell_elements().eq(i);
399 var source_element = this.cell_elements().eq(i);
400 var source_cell = source_element.data("cell");
400 var source_cell = source_element.data("cell");
401 if (source_cell instanceof CodeCell) {
401 if (source_cell instanceof CodeCell) {
402 this.insert_text_cell_after(i);
402 this.insert_text_cell_after(i);
403 var target_cell = this.cells()[i+1];
403 var target_cell = this.cells()[i+1];
404 var text = source_cell.get_code();
404 var text = source_cell.get_code();
405 if (text === "") {text = target_cell.placeholder;};
405 if (text === "") {text = target_cell.placeholder;};
406 target_cell.set_text(text);
406 target_cell.set_text(text);
407 source_element.remove();
407 source_element.remove();
408 };
408 };
409 };
409 };
410
410
411
411
412 // Cell collapsing
412 // Cell collapsing
413
413
414 Notebook.prototype.collapse = function (index) {
414 Notebook.prototype.collapse = function (index) {
415 var i = this.index_or_selected(index);
415 var i = this.index_or_selected(index);
416 this.cells()[i].collapse();
416 this.cells()[i].collapse();
417 };
417 };
418
418
419
419
420 Notebook.prototype.expand = function (index) {
420 Notebook.prototype.expand = function (index) {
421 var i = this.index_or_selected(index);
421 var i = this.index_or_selected(index);
422 this.cells()[i].expand();
422 this.cells()[i].expand();
423 };
423 };
424
424
425
425
426 // Kernel related things
426 // Kernel related things
427
427
428 Notebook.prototype.start_kernel = function () {
428 Notebook.prototype.start_kernel = function () {
429 this.kernel = new Kernel();
429 this.kernel = new Kernel();
430 this.kernel.start_kernel(this._kernel_started, this);
430 this.kernel.start_kernel(this._kernel_started, this);
431 };
431 };
432
432
433
433
434 Notebook.prototype._kernel_started = function () {
434 Notebook.prototype._kernel_started = function () {
435 console.log("Kernel started: ", this.kernel.kernel_id);
435 console.log("Kernel started: ", this.kernel.kernel_id);
436 var that = this;
436 var that = this;
437
437
438 this.kernel.shell_channel.onmessage = function (e) {
438 this.kernel.shell_channel.onmessage = function (e) {
439 reply = $.parseJSON(e.data);
439 reply = $.parseJSON(e.data);
440 console.log(reply);
440 console.log(reply);
441 var msg_type = reply.msg_type;
441 var msg_type = reply.msg_type;
442 var cell = that.cell_for_msg(reply.parent_header.msg_id);
442 var cell = that.cell_for_msg(reply.parent_header.msg_id);
443 if (msg_type === "execute_reply") {
443 if (msg_type === "execute_reply") {
444 cell.set_input_prompt(reply.content.execution_count);
444 cell.set_input_prompt(reply.content.execution_count);
445 };
445 };
446 };
446 };
447
447
448 this.kernel.iopub_channel.onmessage = function (e) {
448 this.kernel.iopub_channel.onmessage = function (e) {
449 reply = $.parseJSON(e.data);
449 reply = $.parseJSON(e.data);
450 var content = reply.content;
450 console.log(reply);
451 console.log(reply);
451 var msg_type = reply.msg_type;
452 var msg_type = reply.msg_type;
452 var cell = that.cell_for_msg(reply.parent_header.msg_id);
453 var cell = that.cell_for_msg(reply.parent_header.msg_id);
453 if (msg_type === "stream") {
454 if (msg_type === "stream") {
454 cell.expand();
455 cell.expand();
455 cell.append_stream(reply.content.data + "\n");
456 cell.append_stream(content.data + "\n");
456 } else if (msg_type === "display_data") {
457 } else if (msg_type === "display_data") {
457 cell.expand();
458 cell.expand();
458 cell.append_display_data(reply.content.data);
459 cell.append_display_data(content.data);
459 } else if (msg_type === "pyout") {
460 } else if (msg_type === "pyout") {
460 cell.expand();
461 cell.expand();
461 cell.append_pyout(reply.content.data, reply.content.execution_count)
462 cell.append_pyout(content.data, content.execution_count)
463 } else if (msg_type === "pyerr") {
464 cell.expand();
465 cell.append_pyerr(content.ename, content.evalue, content.traceback);
462 } else if (msg_type === "status") {
466 } else if (msg_type === "status") {
463 if (reply.content.execution_state === "busy") {
467 if (content.execution_state === "busy") {
464 that.kernel.status_busy();
468 that.kernel.status_busy();
465 } else if (reply.content.execution_state === "idle") {
469 } else if (content.execution_state === "idle") {
466 that.kernel.status_idle();
470 that.kernel.status_idle();
467 };
471 };
468 };
472 }
469 };
473 };
470 };
474 };
471
475
472
476
473 // Persistance and loading
477 // Persistance and loading
474
478
475
479
476 Notebook.prototype.fromJSON = function (data) {
480 Notebook.prototype.fromJSON = function (data) {
477 var ncells = this.ncells();
481 var ncells = this.ncells();
478 for (var i=0; i<ncells; i++) {
482 for (var i=0; i<ncells; i++) {
479 // Always delete cell 0 as they get renumbered as they are deleted.
483 // Always delete cell 0 as they get renumbered as they are deleted.
480 this.delete_cell(0);
484 this.delete_cell(0);
481 };
485 };
482 var new_cells = data.cells;
486 var new_cells = data.cells;
483 ncells = new_cells.length;
487 ncells = new_cells.length;
484 var cell_data = null;
488 var cell_data = null;
485 for (var i=0; i<ncells; i++) {
489 for (var i=0; i<ncells; i++) {
486 cell_data = new_cells[i];
490 cell_data = new_cells[i];
487 if (cell_data.cell_type == 'code') {
491 if (cell_data.cell_type == 'code') {
488 this.insert_code_cell_after();
492 this.insert_code_cell_after();
489 this.selected_cell().fromJSON(cell_data);
493 this.selected_cell().fromJSON(cell_data);
490 } else if (cell_data.cell_type === 'text') {
494 } else if (cell_data.cell_type === 'text') {
491 this.insert_text_cell_after();
495 this.insert_text_cell_after();
492 this.selected_cell().fromJSON(cell_data);
496 this.selected_cell().fromJSON(cell_data);
493 };
497 };
494 };
498 };
495 };
499 };
496
500
497
501
498 Notebook.prototype.toJSON = function () {
502 Notebook.prototype.toJSON = function () {
499 var cells = this.cells();
503 var cells = this.cells();
500 var ncells = cells.length;
504 var ncells = cells.length;
501 cell_array = new Array(ncells);
505 cell_array = new Array(ncells);
502 for (var i=0; i<ncells; i++) {
506 for (var i=0; i<ncells; i++) {
503 cell_array[i] = cells[i].toJSON();
507 cell_array[i] = cells[i].toJSON();
504 };
508 };
505 json = {
509 json = {
506 cells : cell_array
510 cells : cell_array
507 };
511 };
508 return json
512 return json
509 };
513 };
510
514
511
515
512 Notebook.prototype.test_filename = function (filename) {
516 Notebook.prototype.test_filename = function (filename) {
513 if (this.notebook_filename_re.test(filename)) {
517 if (this.notebook_filename_re.test(filename)) {
514 return true;
518 return true;
515 } else {
519 } else {
516 var bad_filename = $('<div/>');
520 var bad_filename = $('<div/>');
517 bad_filename.html(
521 bad_filename.html(
518 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
522 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
519 );
523 );
520 bad_filename.dialog({title: 'Invalid filename', modal: true});
524 bad_filename.dialog({title: 'Invalid filename', modal: true});
521 return false;
525 return false;
522 };
526 };
523 };
527 };
524
528
525 Notebook.prototype.save_notebook = function (filename) {
529 Notebook.prototype.save_notebook = function (filename) {
526 this.filename = filename || this.filename || '';
530 this.filename = filename || this.filename || '';
527 if (this.filename === '') {
531 if (this.filename === '') {
528 var no_filename = $('<div/>');
532 var no_filename = $('<div/>');
529 no_filename.html(
533 no_filename.html(
530 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
534 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
531 );
535 );
532 no_filename.dialog({title: 'Missing filename', modal: true});
536 no_filename.dialog({title: 'Missing filename', modal: true});
533 return;
537 return;
534 }
538 }
535 if (!this.test_filename(this.filename)) {return;}
539 if (!this.test_filename(this.filename)) {return;}
536 var thedata = this.toJSON();
540 var thedata = this.toJSON();
537 var settings = {
541 var settings = {
538 processData : false,
542 processData : false,
539 cache : false,
543 cache : false,
540 type : "PUT",
544 type : "PUT",
541 data : JSON.stringify(thedata),
545 data : JSON.stringify(thedata),
542 success : function (data, status, xhr) {console.log(data);}
546 success : function (data, status, xhr) {console.log(data);}
543 };
547 };
544 $.ajax("/notebooks/" + this.filename, settings);
548 $.ajax("/notebooks/" + this.filename, settings);
545 };
549 };
546
550
547
551
548 Notebook.prototype.load_notebook = function (filename) {
552 Notebook.prototype.load_notebook = function (filename) {
549 if (!this.test_filename(filename)) {return;}
553 if (!this.test_filename(filename)) {return;}
550 var that = this;
554 var that = this;
551 $.getJSON("/notebooks/" + filename,
555 $.getJSON("/notebooks/" + filename,
552 function (data, status, xhr) {
556 function (data, status, xhr) {
553 that.fromJSON(data);
557 that.fromJSON(data);
554 that.filename = filename;
558 that.filename = filename;
555 that.kernel.restart();
559 that.kernel.restart();
556 }
560 }
557 );
561 );
558 }
562 }
559
563
560
564
561 //============================================================================
565 //============================================================================
562 // Cell
566 // Cell
563 //============================================================================
567 //============================================================================
564
568
565
569
566 var Cell = function (notebook) {
570 var Cell = function (notebook) {
567 this.notebook = notebook;
571 this.notebook = notebook;
568 this.selected = false;
572 this.selected = false;
569 this.element;
573 this.element;
570 this.create_element();
574 this.create_element();
571 if (this.element !== undefined) {
575 if (this.element !== undefined) {
572 this.element.data("cell", this);
576 this.element.data("cell", this);
573 this.bind_events();
577 this.bind_events();
574 }
578 }
575 this.cell_id = uuid();
579 this.cell_id = uuid();
576 };
580 };
577
581
578
582
579 Cell.prototype.select = function () {
583 Cell.prototype.select = function () {
580 this.element.addClass('ui-widget-content ui-corner-all');
584 this.element.addClass('ui-widget-content ui-corner-all');
581 this.selected = true;
585 this.selected = true;
582 // TODO: we need t test across browsers to see if both of these are needed.
586 // TODO: we need t test across browsers to see if both of these are needed.
583 // In the meantime, there should not be any harm in having them both.
587 // In the meantime, there should not be any harm in having them both.
584 this.element.find('textarea').trigger('focusin');
588 this.element.find('textarea').trigger('focusin');
585 this.element.find('textarea').trigger('focus');
589 this.element.find('textarea').trigger('focus');
586 };
590 };
587
591
588
592
589 Cell.prototype.unselect = function () {
593 Cell.prototype.unselect = function () {
590 this.element.removeClass('ui-widget-content ui-corner-all');
594 this.element.removeClass('ui-widget-content ui-corner-all');
591 this.selected = false;
595 this.selected = false;
592 };
596 };
593
597
594
598
595 Cell.prototype.bind_events = function () {
599 Cell.prototype.bind_events = function () {
596 var that = this;
600 var that = this;
597 var nb = that.notebook
601 var nb = that.notebook
598 that.element.click(function (event) {
602 that.element.click(function (event) {
599 if (that.selected === false) {
603 if (that.selected === false) {
600 nb.select(nb.find_cell_index(that));
604 nb.select(nb.find_cell_index(that));
601 };
605 };
602 });
606 });
603 that.element.focusin(function (event) {
607 that.element.focusin(function (event) {
604 if (that.selected === false) {
608 if (that.selected === false) {
605 nb.select(nb.find_cell_index(that));
609 nb.select(nb.find_cell_index(that));
606 };
610 };
607 });
611 });
608 };
612 };
609
613
610
614
611 // Subclasses must implement create_element.
615 // Subclasses must implement create_element.
612 Cell.prototype.create_element = function () {};
616 Cell.prototype.create_element = function () {};
613
617
614
618
615 //============================================================================
619 //============================================================================
616 // CodeCell
620 // CodeCell
617 //============================================================================
621 //============================================================================
618
622
619
623
620 var CodeCell = function (notebook) {
624 var CodeCell = function (notebook) {
621 Cell.apply(this, arguments);
625 Cell.apply(this, arguments);
622 this.input_prompt_number = ' ';
626 this.input_prompt_number = ' ';
623 };
627 };
624
628
625
629
626 CodeCell.prototype = new Cell();
630 CodeCell.prototype = new Cell();
627
631
628
632
629 CodeCell.prototype.create_element = function () {
633 CodeCell.prototype.create_element = function () {
630 var cell = $('<div></div>').addClass('cell code_cell');
634 var cell = $('<div></div>').addClass('cell code_cell');
631 var input = $('<div></div>').addClass('input');
635 var input = $('<div></div>').addClass('input');
632 input.append($('<div/>').addClass('prompt input_prompt'));
636 input.append($('<div/>').addClass('prompt input_prompt'));
633 var input_textarea = $('<textarea/>').addClass('input_textarea').attr('rows',1).attr('wrap','hard').autogrow();
637 var input_textarea = $('<textarea/>').addClass('input_textarea').attr('rows',1).attr('wrap','hard').autogrow();
634 input.append($('<div/>').addClass('input_area').append(input_textarea));
638 input.append($('<div/>').addClass('input_area').append(input_textarea));
635 var output = $('<div></div>').addClass('output');
639 var output = $('<div></div>').addClass('output');
636 cell.append(input).append(output);
640 cell.append(input).append(output);
637 this.element = cell;
641 this.element = cell;
638 this.collapse()
642 this.collapse()
639 };
643 };
640
644
641
645
642 CodeCell.prototype.append_pyout = function (data, n) {
646 CodeCell.prototype.append_pyout = function (data, n) {
643 var toinsert = $("<div/>").addClass("output_area output_pyout");
647 var toinsert = $("<div/>").addClass("output_area output_pyout");
644 toinsert.append($('<div/>').
648 toinsert.append($('<div/>').
645 addClass('prompt output_prompt').
649 addClass('prompt output_prompt').
646 html('Out[' + n + ']:')
650 html('Out[' + n + ']:')
647 );
651 );
648 this.append_display_data(data, toinsert);
652 this.append_display_data(data, toinsert);
649 toinsert.children().last().addClass("box_flex1");
653 toinsert.children().last().addClass("box_flex1");
650 this.element.find("div.output").append(toinsert);
654 this.element.find("div.output").append(toinsert);
651 // If we just output latex, typeset it.
655 // If we just output latex, typeset it.
652 if (data["text/latex"] !== undefined) {
656 if (data["text/latex"] !== undefined) {
653 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
657 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
654 };
658 };
655 };
659 };
656
660
661 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
662 var s = '';
663 var len = tb.length;
664 for (var i=0; i<len; i++) {
665 s = s + tb[i] + '\n';
666 }
667 s = s + '\n';
668 this.append_stream(s);
669 };
670
657
671
658 CodeCell.prototype.append_display_data = function (data, element) {
672 CodeCell.prototype.append_display_data = function (data, element) {
659 if (data["text/latex"] !== undefined) {
673 if (data["text/latex"] !== undefined) {
660 this.append_latex(data["text/latex"], element);
674 this.append_latex(data["text/latex"], element);
661 // If it is undefined, then we just appended to div.output, which
675 // If it is undefined, then we just appended to div.output, which
662 // makes the latex visible and we can typeset it. The typesetting
676 // makes the latex visible and we can typeset it. The typesetting
663 // has to be done after the latex is on the page.
677 // has to be done after the latex is on the page.
664 if (element === undefined) {
678 if (element === undefined) {
665 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
679 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
666 };
680 };
667 } else if (data["image/svg+xml"] !== undefined) {
681 } else if (data["image/svg+xml"] !== undefined) {
668 this.append_svg(data["image/svg+xml"], element);
682 this.append_svg(data["image/svg+xml"], element);
669 } else if (data["text/plain"] !== undefined) {
683 } else if (data["text/plain"] !== undefined) {
670 this.append_stream(data["text/plain"], element);
684 this.append_stream(data["text/plain"], element);
671 };
685 };
672 return element;
686 return element;
673 };
687 };
674
688
675
689
676 CodeCell.prototype.append_stream = function (data, element) {
690 CodeCell.prototype.append_stream = function (data, element) {
677 element = element || this.element.find("div.output");
691 element = element || this.element.find("div.output");
678 var toinsert = $("<div/>").addClass("output_area output_stream");
692 var toinsert = $("<div/>").addClass("output_area output_stream");
679 toinsert.append($("<pre/>").html(fixConsole(data)));
693 toinsert.append($("<pre/>").html(fixConsole(data)));
680 element.append(toinsert);
694 element.append(toinsert);
681 return element;
695 return element;
682 };
696 };
683
697
684
698
685 CodeCell.prototype.append_svg = function (svg, element) {
699 CodeCell.prototype.append_svg = function (svg, element) {
686 element = element || this.element.find("div.output");
700 element = element || this.element.find("div.output");
687 var toinsert = $("<div/>").addClass("output_area output_svg");
701 var toinsert = $("<div/>").addClass("output_area output_svg");
688 toinsert.append(svg);
702 toinsert.append(svg);
689 element.append(toinsert);
703 element.append(toinsert);
690 return element;
704 return element;
691 };
705 };
692
706
693
707
694 CodeCell.prototype.append_latex = function (latex, element) {
708 CodeCell.prototype.append_latex = function (latex, element) {
695 // This method cannot do the typesetting because the latex first has to
709 // This method cannot do the typesetting because the latex first has to
696 // be on the page.
710 // be on the page.
697 element = element || this.element.find("div.output");
711 element = element || this.element.find("div.output");
698 var toinsert = $("<div/>").addClass("output_area output_latex");
712 var toinsert = $("<div/>").addClass("output_area output_latex");
699 toinsert.append(latex);
713 toinsert.append(latex);
700 element.append(toinsert);
714 element.append(toinsert);
701 return element;
715 return element;
702 }
716 }
703
717
704
718
705 CodeCell.prototype.clear_output = function () {
719 CodeCell.prototype.clear_output = function () {
706 this.element.find("div.output").html("");
720 this.element.find("div.output").html("");
707 };
721 };
708
722
709
723
710 CodeCell.prototype.collapse = function () {
724 CodeCell.prototype.collapse = function () {
711 this.element.find('div.output').hide();
725 this.element.find('div.output').hide();
712 };
726 };
713
727
714
728
715 CodeCell.prototype.expand = function () {
729 CodeCell.prototype.expand = function () {
716 this.element.find('div.output').show();
730 this.element.find('div.output').show();
717 };
731 };
718
732
719
733
720 CodeCell.prototype.set_input_prompt = function (number) {
734 CodeCell.prototype.set_input_prompt = function (number) {
721 var n = number || ' ';
735 var n = number || ' ';
722 this.input_prompt_number = n
736 this.input_prompt_number = n
723 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
737 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
724 };
738 };
725
739
726
740
727 CodeCell.prototype.get_code = function () {
741 CodeCell.prototype.get_code = function () {
728 return this.element.find("textarea.input_textarea").val();
742 return this.element.find("textarea.input_textarea").val();
729 };
743 };
730
744
731
745
732 CodeCell.prototype.set_code = function (code) {
746 CodeCell.prototype.set_code = function (code) {
733 return this.element.find("textarea.input_textarea").val(code);
747 return this.element.find("textarea.input_textarea").val(code);
734 };
748 };
735
749
736
750
737 CodeCell.prototype.fromJSON = function (data) {
751 CodeCell.prototype.fromJSON = function (data) {
738 if (data.cell_type === 'code') {
752 if (data.cell_type === 'code') {
739 this.set_code(data.code);
753 this.set_code(data.code);
740 this.set_input_prompt(data.prompt_number);
754 this.set_input_prompt(data.prompt_number);
741 };
755 };
742 };
756 };
743
757
744
758
745 CodeCell.prototype.toJSON = function () {
759 CodeCell.prototype.toJSON = function () {
746 return {
760 return {
747 code : this.get_code(),
761 code : this.get_code(),
748 cell_type : 'code',
762 cell_type : 'code',
749 prompt_number : this.input_prompt_number
763 prompt_number : this.input_prompt_number
750 };
764 };
751 };
765 };
752
766
753 //============================================================================
767 //============================================================================
754 // TextCell
768 // TextCell
755 //============================================================================
769 //============================================================================
756
770
757
771
758 var TextCell = function (notebook) {
772 var TextCell = function (notebook) {
759 Cell.apply(this, arguments);
773 Cell.apply(this, arguments);
760 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
774 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
761 };
775 };
762
776
763
777
764 TextCell.prototype = new Cell();
778 TextCell.prototype = new Cell();
765
779
766
780
767 TextCell.prototype.create_element = function () {
781 TextCell.prototype.create_element = function () {
768 var cell = $("<div>").addClass('cell text_cell').
782 var cell = $("<div>").addClass('cell text_cell').
769 append(
783 append(
770 $("<textarea>" + this.placeholder + "</textarea>").
784 $("<textarea>" + this.placeholder + "</textarea>").
771 addClass('text_cell_input').
785 addClass('text_cell_input').
772 attr('rows',1).
786 attr('rows',1).
773 attr('cols',80).
787 attr('cols',80).
774 autogrow()
788 autogrow()
775 ).append(
789 ).append(
776 $('<div></div>').addClass('text_cell_render')
790 $('<div></div>').addClass('text_cell_render')
777 )
791 )
778 this.element = cell;
792 this.element = cell;
779 };
793 };
780
794
781
795
782 TextCell.prototype.select = function () {
796 TextCell.prototype.select = function () {
783 this.edit();
797 this.edit();
784 Cell.prototype.select.apply(this);
798 Cell.prototype.select.apply(this);
785 };
799 };
786
800
787
801
788 TextCell.prototype.edit = function () {
802 TextCell.prototype.edit = function () {
789 var text_cell = this.element;
803 var text_cell = this.element;
790 var input = text_cell.find("textarea.text_cell_input");
804 var input = text_cell.find("textarea.text_cell_input");
791 var output = text_cell.find("div.text_cell_render");
805 var output = text_cell.find("div.text_cell_render");
792 output.hide();
806 output.hide();
793 input.show().trigger('focus');
807 input.show().trigger('focus');
794 };
808 };
795
809
796
810
797 TextCell.prototype.render = function () {
811 TextCell.prototype.render = function () {
798 var text_cell = this.element;
812 var text_cell = this.element;
799 var input = text_cell.find("textarea.text_cell_input");
813 var input = text_cell.find("textarea.text_cell_input");
800 var output = text_cell.find("div.text_cell_render");
814 var output = text_cell.find("div.text_cell_render");
801 var text = input.val();
815 var text = input.val();
802 if (text === "") {
816 if (text === "") {
803 text = this.placeholder;
817 text = this.placeholder;
804 input.val(text);
818 input.val(text);
805 };
819 };
806 output.html(text)
820 output.html(text)
807 input.html(text);
821 input.html(text);
808 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
822 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
809 input.hide();
823 input.hide();
810 output.show();
824 output.show();
811 };
825 };
812
826
813
827
814 TextCell.prototype.config_mathjax = function () {
828 TextCell.prototype.config_mathjax = function () {
815 var text_cell = this.element;
829 var text_cell = this.element;
816 var that = this;
830 var that = this;
817 text_cell.click(function () {
831 text_cell.click(function () {
818 that.edit();
832 that.edit();
819 }).focusout(function () {
833 }).focusout(function () {
820 that.render();
834 that.render();
821 });
835 });
822
836
823 text_cell.trigger("focusout");
837 text_cell.trigger("focusout");
824 };
838 };
825
839
826
840
827 TextCell.prototype.get_text = function() {
841 TextCell.prototype.get_text = function() {
828 return this.element.find("textarea.text_cell_input").val();
842 return this.element.find("textarea.text_cell_input").val();
829 };
843 };
830
844
831
845
832 TextCell.prototype.set_text = function(text) {
846 TextCell.prototype.set_text = function(text) {
833 this.element.find("textarea.text_cell_input").val(text);
847 this.element.find("textarea.text_cell_input").val(text);
834 this.element.find("textarea.text_cell_input").html(text);
848 this.element.find("textarea.text_cell_input").html(text);
835 this.element.find("div.text_cell_render").html(text);
849 this.element.find("div.text_cell_render").html(text);
836 };
850 };
837
851
838
852
839 TextCell.prototype.fromJSON = function (data) {
853 TextCell.prototype.fromJSON = function (data) {
840 if (data.cell_type === 'text') {
854 if (data.cell_type === 'text') {
841 this.set_text(data.text);
855 this.set_text(data.text);
842 };
856 };
843 }
857 }
844
858
845
859
846 TextCell.prototype.toJSON = function () {
860 TextCell.prototype.toJSON = function () {
847 return {
861 return {
848 cell_type : 'text',
862 cell_type : 'text',
849 text : this.get_text(),
863 text : this.get_text(),
850 };
864 };
851 };
865 };
852
866
853 //============================================================================
867 //============================================================================
854 // On document ready
868 // On document ready
855 //============================================================================
869 //============================================================================
856
870
857
871
858 var Kernel = function () {
872 var Kernel = function () {
859 this.kernel_id = null;
873 this.kernel_id = null;
860 this.base_url = "/kernels";
874 this.base_url = "/kernels";
861 this.kernel_url = null;
875 this.kernel_url = null;
862 };
876 };
863
877
864
878
865 Kernel.prototype.get_msg = function (msg_type, content) {
879 Kernel.prototype.get_msg = function (msg_type, content) {
866 var msg = {
880 var msg = {
867 header : {
881 header : {
868 msg_id : uuid(),
882 msg_id : uuid(),
869 username : "bgranger",
883 username : "bgranger",
870 session: this.session_id
884 session: this.session_id
871 },
885 },
872 msg_type : msg_type,
886 msg_type : msg_type,
873 content : content,
887 content : content,
874 parent_header : {}
888 parent_header : {}
875 };
889 };
876 return msg;
890 return msg;
877 }
891 }
878
892
879 Kernel.prototype.start_kernel = function (callback, context) {
893 Kernel.prototype.start_kernel = function (callback, context) {
880 var that = this;
894 var that = this;
881 $.post(this.base_url,
895 $.post(this.base_url,
882 function (kernel_id) {
896 function (kernel_id) {
883 that._handle_start_kernel(kernel_id, callback, context);
897 that._handle_start_kernel(kernel_id, callback, context);
884 },
898 },
885 'json'
899 'json'
886 );
900 );
887 };
901 };
888
902
889
903
890 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
904 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
891 this.kernel_id = kernel_id;
905 this.kernel_id = kernel_id;
892 this.kernel_url = this.base_url + "/" + this.kernel_id;
906 this.kernel_url = this.base_url + "/" + this.kernel_id;
893 this._start_channels();
907 this._start_channels();
894 callback.call(context);
908 callback.call(context);
895 };
909 };
896
910
897
911
898 Kernel.prototype._start_channels = function () {
912 Kernel.prototype._start_channels = function () {
899 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
913 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
900 this.shell_channel = new WebSocket(ws_url + "/shell");
914 this.shell_channel = new WebSocket(ws_url + "/shell");
901 this.iopub_channel = new WebSocket(ws_url + "/iopub");
915 this.iopub_channel = new WebSocket(ws_url + "/iopub");
902 }
916 }
903
917
904
918
905 Kernel.prototype.execute = function (code) {
919 Kernel.prototype.execute = function (code) {
906 var content = {
920 var content = {
907 code : code,
921 code : code,
908 silent : false,
922 silent : false,
909 user_variables : [],
923 user_variables : [],
910 user_expressions : {}
924 user_expressions : {}
911 };
925 };
912 var msg = this.get_msg("execute_request", content);
926 var msg = this.get_msg("execute_request", content);
913 this.shell_channel.send(JSON.stringify(msg));
927 this.shell_channel.send(JSON.stringify(msg));
914 return msg.header.msg_id;
928 return msg.header.msg_id;
915 }
929 }
916
930
917
931
918 Kernel.prototype.interrupt = function () {
932 Kernel.prototype.interrupt = function () {
919 $.post(this.kernel_url + "/interrupt");
933 $.post(this.kernel_url + "/interrupt");
920 };
934 };
921
935
922
936
923 Kernel.prototype.restart = function () {
937 Kernel.prototype.restart = function () {
924 this.status_restarting();
938 this.status_restarting();
925 url = this.kernel_url + "/restart"
939 url = this.kernel_url + "/restart"
926 var that = this;
940 var that = this;
927 $.post(url, function (kernel_id) {
941 $.post(url, function (kernel_id) {
928 console.log("Kernel restarted: " + kernel_id);
942 console.log("Kernel restarted: " + kernel_id);
929 that.kernel_id = kernel_id;
943 that.kernel_id = kernel_id;
930 that.kernel_url = that.base_url + "/" + that.kernel_id;
944 that.kernel_url = that.base_url + "/" + that.kernel_id;
931 that.status_idle();
945 that.status_idle();
932 }, 'json');
946 }, 'json');
933 };
947 };
934
948
935
949
936 Kernel.prototype.status_busy = function () {
950 Kernel.prototype.status_busy = function () {
937 $("#kernel_status").removeClass("status_idle");
951 $("#kernel_status").removeClass("status_idle");
938 $("#kernel_status").removeClass("status_restarting");
952 $("#kernel_status").removeClass("status_restarting");
939 $("#kernel_status").addClass("status_busy");
953 $("#kernel_status").addClass("status_busy");
940 $("#kernel_status").text("Busy");
954 $("#kernel_status").text("Busy");
941 };
955 };
942
956
943
957
944 Kernel.prototype.status_idle = function () {
958 Kernel.prototype.status_idle = function () {
945 $("#kernel_status").removeClass("status_busy");
959 $("#kernel_status").removeClass("status_busy");
946 $("#kernel_status").removeClass("status_restarting");
960 $("#kernel_status").removeClass("status_restarting");
947 $("#kernel_status").addClass("status_idle");
961 $("#kernel_status").addClass("status_idle");
948 $("#kernel_status").text("Idle");
962 $("#kernel_status").text("Idle");
949 };
963 };
950
964
951 Kernel.prototype.status_restarting = function () {
965 Kernel.prototype.status_restarting = function () {
952 $("#kernel_status").removeClass("status_busy");
966 $("#kernel_status").removeClass("status_busy");
953 $("#kernel_status").removeClass("status_idle");
967 $("#kernel_status").removeClass("status_idle");
954 $("#kernel_status").addClass("status_restarting");
968 $("#kernel_status").addClass("status_restarting");
955 $("#kernel_status").text("Restarting");
969 $("#kernel_status").text("Restarting");
956 };
970 };
957
971
958 //============================================================================
972 //============================================================================
959 // On document ready
973 // On document ready
960 //============================================================================
974 //============================================================================
961
975
962
976
963 $(document).ready(function () {
977 $(document).ready(function () {
964
978
965 MathJax.Hub.Config({
979 MathJax.Hub.Config({
966 tex2jax: {
980 tex2jax: {
967 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
981 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
968 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
982 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
969 },
983 },
970 displayAlign: 'left', // Change this to 'center' to center equations.
984 displayAlign: 'left', // Change this to 'center' to center equations.
971 "HTML-CSS": {
985 "HTML-CSS": {
972 styles: {'.MathJax_Display': {"margin": 0}}
986 styles: {'.MathJax_Display': {"margin": 0}}
973 }
987 }
974 });
988 });
975
989
976 IPYTHON.notebook = new Notebook('div.notebook');
990 IPYTHON.notebook = new Notebook('div.notebook');
977 IPYTHON.notebook.insert_code_cell_after();
991 IPYTHON.notebook.insert_code_cell_after();
978
992
979 $("#menu_tabs").tabs();
993 $("#menu_tabs").tabs();
980
994
981 $("#help_toolbar").buttonset();
995 $("#help_toolbar").buttonset();
982
996
983 $("#kernel_toolbar").buttonset();
997 $("#kernel_toolbar").buttonset();
984 $("#interrupt_kernel").click(function () {IPYTHON.notebook.kernel.interrupt();});
998 $("#interrupt_kernel").click(function () {IPYTHON.notebook.kernel.interrupt();});
985 $("#restart_kernel").click(function () {IPYTHON.notebook.kernel.restart();});
999 $("#restart_kernel").click(function () {IPYTHON.notebook.kernel.restart();});
986 $("#kernel_status").addClass("status_idle");
1000 $("#kernel_status").addClass("status_idle");
987
1001
988 $("#move_cell").buttonset();
1002 $("#move_cell").buttonset();
989 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
1003 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
990 $("#move_up").button("option", "text", false);
1004 $("#move_up").button("option", "text", false);
991 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
1005 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
992 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
1006 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
993 $("#move_down").button("option", "text", false);
1007 $("#move_down").button("option", "text", false);
994 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
1008 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
995
1009
996 $("#insert_delete").buttonset();
1010 $("#insert_delete").buttonset();
997 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
1011 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
998 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
1012 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
999 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
1013 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
1000 $("#delete_cell").button("option", "text", false);
1014 $("#delete_cell").button("option", "text", false);
1001 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
1015 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
1002
1016
1003 $("#cell_type").buttonset();
1017 $("#cell_type").buttonset();
1004 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
1018 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
1005 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
1019 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
1006
1020
1007 $("#sort").buttonset();
1021 $("#sort").buttonset();
1008 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
1022 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
1009
1023
1010 $("#toggle").buttonset();
1024 $("#toggle").buttonset();
1011 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
1025 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
1012 $("#expand").click(function () {IPYTHON.notebook.expand();});
1026 $("#expand").click(function () {IPYTHON.notebook.expand();});
1013
1027
1014 }); No newline at end of file
1028 });
General Comments 0
You need to be logged in to leave comments. Login now