##// END OF EJS Templates
Cells call grow by hand when they reload from JSON.
Brian Granger -
Show More
@@ -1,1028 +1,1048 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 var content = reply.content;
451 console.log(reply);
451 console.log(reply);
452 var msg_type = reply.msg_type;
452 var msg_type = reply.msg_type;
453 var cell = that.cell_for_msg(reply.parent_header.msg_id);
453 var cell = that.cell_for_msg(reply.parent_header.msg_id);
454 if (msg_type === "stream") {
454 if (msg_type === "stream") {
455 cell.expand();
455 cell.expand();
456 cell.append_stream(content.data + "\n");
456 cell.append_stream(content.data + "\n");
457 } else if (msg_type === "display_data") {
457 } else if (msg_type === "display_data") {
458 cell.expand();
458 cell.expand();
459 cell.append_display_data(content.data);
459 cell.append_display_data(content.data);
460 } else if (msg_type === "pyout") {
460 } else if (msg_type === "pyout") {
461 cell.expand();
461 cell.expand();
462 cell.append_pyout(content.data, content.execution_count)
462 cell.append_pyout(content.data, content.execution_count)
463 } else if (msg_type === "pyerr") {
463 } else if (msg_type === "pyerr") {
464 cell.expand();
464 cell.expand();
465 cell.append_pyerr(content.ename, content.evalue, content.traceback);
465 cell.append_pyerr(content.ename, content.evalue, content.traceback);
466 } else if (msg_type === "status") {
466 } else if (msg_type === "status") {
467 if (content.execution_state === "busy") {
467 if (content.execution_state === "busy") {
468 that.kernel.status_busy();
468 that.kernel.status_busy();
469 } else if (content.execution_state === "idle") {
469 } else if (content.execution_state === "idle") {
470 that.kernel.status_idle();
470 that.kernel.status_idle();
471 };
471 };
472 }
472 }
473 };
473 };
474 };
474 };
475
475
476
476
477 // Persistance and loading
477 // Persistance and loading
478
478
479
479
480 Notebook.prototype.fromJSON = function (data) {
480 Notebook.prototype.fromJSON = function (data) {
481 var ncells = this.ncells();
481 var ncells = this.ncells();
482 for (var i=0; i<ncells; i++) {
482 for (var i=0; i<ncells; i++) {
483 // 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.
484 this.delete_cell(0);
484 this.delete_cell(0);
485 };
485 };
486 var new_cells = data.cells;
486 var new_cells = data.cells;
487 ncells = new_cells.length;
487 ncells = new_cells.length;
488 var cell_data = null;
488 var cell_data = null;
489 for (var i=0; i<ncells; i++) {
489 for (var i=0; i<ncells; i++) {
490 cell_data = new_cells[i];
490 cell_data = new_cells[i];
491 if (cell_data.cell_type == 'code') {
491 if (cell_data.cell_type == 'code') {
492 this.insert_code_cell_after();
492 this.insert_code_cell_after();
493 this.selected_cell().fromJSON(cell_data);
493 this.selected_cell().fromJSON(cell_data);
494 } else if (cell_data.cell_type === 'text') {
494 } else if (cell_data.cell_type === 'text') {
495 this.insert_text_cell_after();
495 this.insert_text_cell_after();
496 this.selected_cell().fromJSON(cell_data);
496 this.selected_cell().fromJSON(cell_data);
497 };
497 };
498 };
498 };
499 };
499 };
500
500
501
501
502 Notebook.prototype.toJSON = function () {
502 Notebook.prototype.toJSON = function () {
503 var cells = this.cells();
503 var cells = this.cells();
504 var ncells = cells.length;
504 var ncells = cells.length;
505 cell_array = new Array(ncells);
505 cell_array = new Array(ncells);
506 for (var i=0; i<ncells; i++) {
506 for (var i=0; i<ncells; i++) {
507 cell_array[i] = cells[i].toJSON();
507 cell_array[i] = cells[i].toJSON();
508 };
508 };
509 json = {
509 json = {
510 cells : cell_array
510 cells : cell_array
511 };
511 };
512 return json
512 return json
513 };
513 };
514
514
515
515
516 Notebook.prototype.test_filename = function (filename) {
516 Notebook.prototype.test_filename = function (filename) {
517 if (this.notebook_filename_re.test(filename)) {
517 if (this.notebook_filename_re.test(filename)) {
518 return true;
518 return true;
519 } else {
519 } else {
520 var bad_filename = $('<div/>');
520 var bad_filename = $('<div/>');
521 bad_filename.html(
521 bad_filename.html(
522 "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"
523 );
523 );
524 bad_filename.dialog({title: 'Invalid filename', modal: true});
524 bad_filename.dialog({title: 'Invalid filename', modal: true});
525 return false;
525 return false;
526 };
526 };
527 };
527 };
528
528
529 Notebook.prototype.save_notebook = function (filename) {
529 Notebook.prototype.save_notebook = function (filename) {
530 this.filename = filename || this.filename || '';
530 this.filename = filename || this.filename || '';
531 if (this.filename === '') {
531 if (this.filename === '') {
532 var no_filename = $('<div/>');
532 var no_filename = $('<div/>');
533 no_filename.html(
533 no_filename.html(
534 "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"
535 );
535 );
536 no_filename.dialog({title: 'Missing filename', modal: true});
536 no_filename.dialog({title: 'Missing filename', modal: true});
537 return;
537 return;
538 }
538 }
539 if (!this.test_filename(this.filename)) {return;}
539 if (!this.test_filename(this.filename)) {return;}
540 var thedata = this.toJSON();
540 var thedata = this.toJSON();
541 var settings = {
541 var settings = {
542 processData : false,
542 processData : false,
543 cache : false,
543 cache : false,
544 type : "PUT",
544 type : "PUT",
545 data : JSON.stringify(thedata),
545 data : JSON.stringify(thedata),
546 success : function (data, status, xhr) {console.log(data);}
546 success : function (data, status, xhr) {console.log(data);}
547 };
547 };
548 $.ajax("/notebooks/" + this.filename, settings);
548 $.ajax("/notebooks/" + this.filename, settings);
549 };
549 };
550
550
551
551
552 Notebook.prototype.load_notebook = function (filename) {
552 Notebook.prototype.load_notebook = function (filename) {
553 if (!this.test_filename(filename)) {return;}
553 if (!this.test_filename(filename)) {return;}
554 var that = this;
554 var that = this;
555 $.getJSON("/notebooks/" + filename,
555 $.getJSON("/notebooks/" + filename,
556 function (data, status, xhr) {
556 function (data, status, xhr) {
557 that.fromJSON(data);
557 that.fromJSON(data);
558 that.filename = filename;
558 that.filename = filename;
559 that.kernel.restart();
559 that.kernel.restart();
560 }
560 }
561 );
561 );
562 }
562 }
563
563
564
564
565 //============================================================================
565 //============================================================================
566 // Cell
566 // Cell
567 //============================================================================
567 //============================================================================
568
568
569
569
570 var Cell = function (notebook) {
570 var Cell = function (notebook) {
571 this.notebook = notebook;
571 this.notebook = notebook;
572 this.selected = false;
572 this.selected = false;
573 this.element;
573 this.element;
574 this.create_element();
574 this.create_element();
575 if (this.element !== undefined) {
575 if (this.element !== undefined) {
576 this.element.data("cell", this);
576 this.element.data("cell", this);
577 this.bind_events();
577 this.bind_events();
578 }
578 }
579 this.cell_id = uuid();
579 this.cell_id = uuid();
580 };
580 };
581
581
582
582
583 Cell.prototype.grow = function(element) {
584 // Grow the cell by hand. This is used upon reloading from JSON, when the
585 // autogrow handler is not called.
586 var dom = element.get(0);
587 var lines_count = 0;
588 // modified split rule from
589 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
590 var lines = dom.value.split(/\r|\r\n|\n/);
591 lines_count = lines.length;
592 if (lines_count >= 1) {
593 dom.rows = lines_count;
594 } else {
595 dom.rows = 1;
596 }
597 };
598
599
583 Cell.prototype.select = function () {
600 Cell.prototype.select = function () {
584 this.element.addClass('ui-widget-content ui-corner-all');
601 this.element.addClass('ui-widget-content ui-corner-all');
585 this.selected = true;
602 this.selected = true;
586 // TODO: we need t test across browsers to see if both of these are needed.
603 // TODO: we need t test across browsers to see if both of these are needed.
587 // In the meantime, there should not be any harm in having them both.
604 // In the meantime, there should not be any harm in having them both.
588 this.element.find('textarea').trigger('focusin');
605 this.element.find('textarea').trigger('focusin');
589 this.element.find('textarea').trigger('focus');
606 this.element.find('textarea').trigger('focus');
590 };
607 };
591
608
592
609
593 Cell.prototype.unselect = function () {
610 Cell.prototype.unselect = function () {
594 this.element.removeClass('ui-widget-content ui-corner-all');
611 this.element.removeClass('ui-widget-content ui-corner-all');
595 this.selected = false;
612 this.selected = false;
596 };
613 };
597
614
598
615
599 Cell.prototype.bind_events = function () {
616 Cell.prototype.bind_events = function () {
600 var that = this;
617 var that = this;
601 var nb = that.notebook
618 var nb = that.notebook
602 that.element.click(function (event) {
619 that.element.click(function (event) {
603 if (that.selected === false) {
620 if (that.selected === false) {
604 nb.select(nb.find_cell_index(that));
621 nb.select(nb.find_cell_index(that));
605 };
622 };
606 });
623 });
607 that.element.focusin(function (event) {
624 that.element.focusin(function (event) {
608 if (that.selected === false) {
625 if (that.selected === false) {
609 nb.select(nb.find_cell_index(that));
626 nb.select(nb.find_cell_index(that));
610 };
627 };
611 });
628 });
612 };
629 };
613
630
614
631
615 // Subclasses must implement create_element.
632 // Subclasses must implement create_element.
616 Cell.prototype.create_element = function () {};
633 Cell.prototype.create_element = function () {};
617
634
618
635
619 //============================================================================
636 //============================================================================
620 // CodeCell
637 // CodeCell
621 //============================================================================
638 //============================================================================
622
639
623
640
624 var CodeCell = function (notebook) {
641 var CodeCell = function (notebook) {
625 Cell.apply(this, arguments);
642 Cell.apply(this, arguments);
626 this.input_prompt_number = ' ';
643 this.input_prompt_number = ' ';
627 };
644 };
628
645
629
646
630 CodeCell.prototype = new Cell();
647 CodeCell.prototype = new Cell();
631
648
632
649
633 CodeCell.prototype.create_element = function () {
650 CodeCell.prototype.create_element = function () {
634 var cell = $('<div></div>').addClass('cell code_cell');
651 var cell = $('<div></div>').addClass('cell code_cell');
635 var input = $('<div></div>').addClass('input');
652 var input = $('<div></div>').addClass('input');
636 input.append($('<div/>').addClass('prompt input_prompt'));
653 input.append($('<div/>').addClass('prompt input_prompt'));
637 var input_textarea = $('<textarea/>').addClass('input_textarea').attr('rows',1).attr('wrap','hard').autogrow();
654 var input_textarea = $('<textarea/>').addClass('input_textarea').attr('rows',1).attr('wrap','hard').autogrow();
638 input.append($('<div/>').addClass('input_area').append(input_textarea));
655 input.append($('<div/>').addClass('input_area').append(input_textarea));
639 var output = $('<div></div>').addClass('output');
656 var output = $('<div></div>').addClass('output');
640 cell.append(input).append(output);
657 cell.append(input).append(output);
641 this.element = cell;
658 this.element = cell;
642 this.collapse()
659 this.collapse()
643 };
660 };
644
661
645
662
646 CodeCell.prototype.append_pyout = function (data, n) {
663 CodeCell.prototype.append_pyout = function (data, n) {
647 var toinsert = $("<div/>").addClass("output_area output_pyout");
664 var toinsert = $("<div/>").addClass("output_area output_pyout");
648 toinsert.append($('<div/>').
665 toinsert.append($('<div/>').
649 addClass('prompt output_prompt').
666 addClass('prompt output_prompt').
650 html('Out[' + n + ']:')
667 html('Out[' + n + ']:')
651 );
668 );
652 this.append_display_data(data, toinsert);
669 this.append_display_data(data, toinsert);
653 toinsert.children().last().addClass("box_flex1");
670 toinsert.children().last().addClass("box_flex1");
654 this.element.find("div.output").append(toinsert);
671 this.element.find("div.output").append(toinsert);
655 // If we just output latex, typeset it.
672 // If we just output latex, typeset it.
656 if (data["text/latex"] !== undefined) {
673 if (data["text/latex"] !== undefined) {
657 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
674 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
658 };
675 };
659 };
676 };
660
677
678
661 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
679 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
662 var s = '';
680 var s = '';
663 var len = tb.length;
681 var len = tb.length;
664 for (var i=0; i<len; i++) {
682 for (var i=0; i<len; i++) {
665 s = s + tb[i] + '\n';
683 s = s + tb[i] + '\n';
666 }
684 }
667 s = s + '\n';
685 s = s + '\n';
668 this.append_stream(s);
686 this.append_stream(s);
669 };
687 };
670
688
671
689
672 CodeCell.prototype.append_display_data = function (data, element) {
690 CodeCell.prototype.append_display_data = function (data, element) {
673 if (data["text/latex"] !== undefined) {
691 if (data["text/latex"] !== undefined) {
674 this.append_latex(data["text/latex"], element);
692 this.append_latex(data["text/latex"], element);
675 // If it is undefined, then we just appended to div.output, which
693 // If it is undefined, then we just appended to div.output, which
676 // makes the latex visible and we can typeset it. The typesetting
694 // makes the latex visible and we can typeset it. The typesetting
677 // has to be done after the latex is on the page.
695 // has to be done after the latex is on the page.
678 if (element === undefined) {
696 if (element === undefined) {
679 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
697 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
680 };
698 };
681 } else if (data["image/svg+xml"] !== undefined) {
699 } else if (data["image/svg+xml"] !== undefined) {
682 this.append_svg(data["image/svg+xml"], element);
700 this.append_svg(data["image/svg+xml"], element);
683 } else if (data["text/plain"] !== undefined) {
701 } else if (data["text/plain"] !== undefined) {
684 this.append_stream(data["text/plain"], element);
702 this.append_stream(data["text/plain"], element);
685 };
703 };
686 return element;
704 return element;
687 };
705 };
688
706
689
707
690 CodeCell.prototype.append_stream = function (data, element) {
708 CodeCell.prototype.append_stream = function (data, element) {
691 element = element || this.element.find("div.output");
709 element = element || this.element.find("div.output");
692 var toinsert = $("<div/>").addClass("output_area output_stream");
710 var toinsert = $("<div/>").addClass("output_area output_stream");
693 toinsert.append($("<pre/>").html(fixConsole(data)));
711 toinsert.append($("<pre/>").html(fixConsole(data)));
694 element.append(toinsert);
712 element.append(toinsert);
695 return element;
713 return element;
696 };
714 };
697
715
698
716
699 CodeCell.prototype.append_svg = function (svg, element) {
717 CodeCell.prototype.append_svg = function (svg, element) {
700 element = element || this.element.find("div.output");
718 element = element || this.element.find("div.output");
701 var toinsert = $("<div/>").addClass("output_area output_svg");
719 var toinsert = $("<div/>").addClass("output_area output_svg");
702 toinsert.append(svg);
720 toinsert.append(svg);
703 element.append(toinsert);
721 element.append(toinsert);
704 return element;
722 return element;
705 };
723 };
706
724
707
725
708 CodeCell.prototype.append_latex = function (latex, element) {
726 CodeCell.prototype.append_latex = function (latex, element) {
709 // This method cannot do the typesetting because the latex first has to
727 // This method cannot do the typesetting because the latex first has to
710 // be on the page.
728 // be on the page.
711 element = element || this.element.find("div.output");
729 element = element || this.element.find("div.output");
712 var toinsert = $("<div/>").addClass("output_area output_latex");
730 var toinsert = $("<div/>").addClass("output_area output_latex");
713 toinsert.append(latex);
731 toinsert.append(latex);
714 element.append(toinsert);
732 element.append(toinsert);
715 return element;
733 return element;
716 }
734 }
717
735
718
736
719 CodeCell.prototype.clear_output = function () {
737 CodeCell.prototype.clear_output = function () {
720 this.element.find("div.output").html("");
738 this.element.find("div.output").html("");
721 };
739 };
722
740
723
741
724 CodeCell.prototype.collapse = function () {
742 CodeCell.prototype.collapse = function () {
725 this.element.find('div.output').hide();
743 this.element.find('div.output').hide();
726 };
744 };
727
745
728
746
729 CodeCell.prototype.expand = function () {
747 CodeCell.prototype.expand = function () {
730 this.element.find('div.output').show();
748 this.element.find('div.output').show();
731 };
749 };
732
750
733
751
734 CodeCell.prototype.set_input_prompt = function (number) {
752 CodeCell.prototype.set_input_prompt = function (number) {
735 var n = number || ' ';
753 var n = number || ' ';
736 this.input_prompt_number = n
754 this.input_prompt_number = n
737 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
755 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
738 };
756 };
739
757
740
758
741 CodeCell.prototype.get_code = function () {
759 CodeCell.prototype.get_code = function () {
742 return this.element.find("textarea.input_textarea").val();
760 return this.element.find("textarea.input_textarea").val();
743 };
761 };
744
762
745
763
746 CodeCell.prototype.set_code = function (code) {
764 CodeCell.prototype.set_code = function (code) {
747 return this.element.find("textarea.input_textarea").val(code);
765 return this.element.find("textarea.input_textarea").val(code);
748 };
766 };
749
767
750
768
751 CodeCell.prototype.fromJSON = function (data) {
769 CodeCell.prototype.fromJSON = function (data) {
752 if (data.cell_type === 'code') {
770 if (data.cell_type === 'code') {
753 this.set_code(data.code);
771 this.set_code(data.code);
754 this.set_input_prompt(data.prompt_number);
772 this.set_input_prompt(data.prompt_number);
773 this.grow(this.element.find("textarea.input_textarea"));
755 };
774 };
756 };
775 };
757
776
758
777
759 CodeCell.prototype.toJSON = function () {
778 CodeCell.prototype.toJSON = function () {
760 return {
779 return {
761 code : this.get_code(),
780 code : this.get_code(),
762 cell_type : 'code',
781 cell_type : 'code',
763 prompt_number : this.input_prompt_number
782 prompt_number : this.input_prompt_number
764 };
783 };
765 };
784 };
766
785
767 //============================================================================
786 //============================================================================
768 // TextCell
787 // TextCell
769 //============================================================================
788 //============================================================================
770
789
771
790
772 var TextCell = function (notebook) {
791 var TextCell = function (notebook) {
773 Cell.apply(this, arguments);
792 Cell.apply(this, arguments);
774 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
793 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
775 };
794 };
776
795
777
796
778 TextCell.prototype = new Cell();
797 TextCell.prototype = new Cell();
779
798
780
799
781 TextCell.prototype.create_element = function () {
800 TextCell.prototype.create_element = function () {
782 var cell = $("<div>").addClass('cell text_cell').
801 var cell = $("<div>").addClass('cell text_cell').
783 append(
802 append(
784 $("<textarea>" + this.placeholder + "</textarea>").
803 $("<textarea>" + this.placeholder + "</textarea>").
785 addClass('text_cell_input').
804 addClass('text_cell_input').
786 attr('rows',1).
805 attr('rows',1).
787 attr('cols',80).
806 attr('cols',80).
788 autogrow()
807 autogrow()
789 ).append(
808 ).append(
790 $('<div></div>').addClass('text_cell_render')
809 $('<div></div>').addClass('text_cell_render')
791 )
810 )
792 this.element = cell;
811 this.element = cell;
793 };
812 };
794
813
795
814
796 TextCell.prototype.select = function () {
815 TextCell.prototype.select = function () {
797 this.edit();
816 this.edit();
798 Cell.prototype.select.apply(this);
817 Cell.prototype.select.apply(this);
799 };
818 };
800
819
801
820
802 TextCell.prototype.edit = function () {
821 TextCell.prototype.edit = function () {
803 var text_cell = this.element;
822 var text_cell = this.element;
804 var input = text_cell.find("textarea.text_cell_input");
823 var input = text_cell.find("textarea.text_cell_input");
805 var output = text_cell.find("div.text_cell_render");
824 var output = text_cell.find("div.text_cell_render");
806 output.hide();
825 output.hide();
807 input.show().trigger('focus');
826 input.show().trigger('focus');
808 };
827 };
809
828
810
829
811 TextCell.prototype.render = function () {
830 TextCell.prototype.render = function () {
812 var text_cell = this.element;
831 var text_cell = this.element;
813 var input = text_cell.find("textarea.text_cell_input");
832 var input = text_cell.find("textarea.text_cell_input");
814 var output = text_cell.find("div.text_cell_render");
833 var output = text_cell.find("div.text_cell_render");
815 var text = input.val();
834 var text = input.val();
816 if (text === "") {
835 if (text === "") {
817 text = this.placeholder;
836 text = this.placeholder;
818 input.val(text);
837 input.val(text);
819 };
838 };
820 output.html(text)
839 output.html(text)
821 input.html(text);
840 input.html(text);
822 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
841 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
823 input.hide();
842 input.hide();
824 output.show();
843 output.show();
825 };
844 };
826
845
827
846
828 TextCell.prototype.config_mathjax = function () {
847 TextCell.prototype.config_mathjax = function () {
829 var text_cell = this.element;
848 var text_cell = this.element;
830 var that = this;
849 var that = this;
831 text_cell.click(function () {
850 text_cell.click(function () {
832 that.edit();
851 that.edit();
833 }).focusout(function () {
852 }).focusout(function () {
834 that.render();
853 that.render();
835 });
854 });
836
855
837 text_cell.trigger("focusout");
856 text_cell.trigger("focusout");
838 };
857 };
839
858
840
859
841 TextCell.prototype.get_text = function() {
860 TextCell.prototype.get_text = function() {
842 return this.element.find("textarea.text_cell_input").val();
861 return this.element.find("textarea.text_cell_input").val();
843 };
862 };
844
863
845
864
846 TextCell.prototype.set_text = function(text) {
865 TextCell.prototype.set_text = function(text) {
847 this.element.find("textarea.text_cell_input").val(text);
866 this.element.find("textarea.text_cell_input").val(text);
848 this.element.find("textarea.text_cell_input").html(text);
867 this.element.find("textarea.text_cell_input").html(text);
849 this.element.find("div.text_cell_render").html(text);
868 this.element.find("div.text_cell_render").html(text);
850 };
869 };
851
870
852
871
853 TextCell.prototype.fromJSON = function (data) {
872 TextCell.prototype.fromJSON = function (data) {
854 if (data.cell_type === 'text') {
873 if (data.cell_type === 'text') {
855 this.set_text(data.text);
874 this.set_text(data.text);
875 this.grow(this.element.find("textarea.text_cell_input"));
856 };
876 };
857 }
877 }
858
878
859
879
860 TextCell.prototype.toJSON = function () {
880 TextCell.prototype.toJSON = function () {
861 return {
881 return {
862 cell_type : 'text',
882 cell_type : 'text',
863 text : this.get_text(),
883 text : this.get_text(),
864 };
884 };
865 };
885 };
866
886
867 //============================================================================
887 //============================================================================
868 // On document ready
888 // On document ready
869 //============================================================================
889 //============================================================================
870
890
871
891
872 var Kernel = function () {
892 var Kernel = function () {
873 this.kernel_id = null;
893 this.kernel_id = null;
874 this.base_url = "/kernels";
894 this.base_url = "/kernels";
875 this.kernel_url = null;
895 this.kernel_url = null;
876 };
896 };
877
897
878
898
879 Kernel.prototype.get_msg = function (msg_type, content) {
899 Kernel.prototype.get_msg = function (msg_type, content) {
880 var msg = {
900 var msg = {
881 header : {
901 header : {
882 msg_id : uuid(),
902 msg_id : uuid(),
883 username : "bgranger",
903 username : "bgranger",
884 session: this.session_id
904 session: this.session_id
885 },
905 },
886 msg_type : msg_type,
906 msg_type : msg_type,
887 content : content,
907 content : content,
888 parent_header : {}
908 parent_header : {}
889 };
909 };
890 return msg;
910 return msg;
891 }
911 }
892
912
893 Kernel.prototype.start_kernel = function (callback, context) {
913 Kernel.prototype.start_kernel = function (callback, context) {
894 var that = this;
914 var that = this;
895 $.post(this.base_url,
915 $.post(this.base_url,
896 function (kernel_id) {
916 function (kernel_id) {
897 that._handle_start_kernel(kernel_id, callback, context);
917 that._handle_start_kernel(kernel_id, callback, context);
898 },
918 },
899 'json'
919 'json'
900 );
920 );
901 };
921 };
902
922
903
923
904 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
924 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
905 this.kernel_id = kernel_id;
925 this.kernel_id = kernel_id;
906 this.kernel_url = this.base_url + "/" + this.kernel_id;
926 this.kernel_url = this.base_url + "/" + this.kernel_id;
907 this._start_channels();
927 this._start_channels();
908 callback.call(context);
928 callback.call(context);
909 };
929 };
910
930
911
931
912 Kernel.prototype._start_channels = function () {
932 Kernel.prototype._start_channels = function () {
913 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
933 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
914 this.shell_channel = new WebSocket(ws_url + "/shell");
934 this.shell_channel = new WebSocket(ws_url + "/shell");
915 this.iopub_channel = new WebSocket(ws_url + "/iopub");
935 this.iopub_channel = new WebSocket(ws_url + "/iopub");
916 }
936 }
917
937
918
938
919 Kernel.prototype.execute = function (code) {
939 Kernel.prototype.execute = function (code) {
920 var content = {
940 var content = {
921 code : code,
941 code : code,
922 silent : false,
942 silent : false,
923 user_variables : [],
943 user_variables : [],
924 user_expressions : {}
944 user_expressions : {}
925 };
945 };
926 var msg = this.get_msg("execute_request", content);
946 var msg = this.get_msg("execute_request", content);
927 this.shell_channel.send(JSON.stringify(msg));
947 this.shell_channel.send(JSON.stringify(msg));
928 return msg.header.msg_id;
948 return msg.header.msg_id;
929 }
949 }
930
950
931
951
932 Kernel.prototype.interrupt = function () {
952 Kernel.prototype.interrupt = function () {
933 $.post(this.kernel_url + "/interrupt");
953 $.post(this.kernel_url + "/interrupt");
934 };
954 };
935
955
936
956
937 Kernel.prototype.restart = function () {
957 Kernel.prototype.restart = function () {
938 this.status_restarting();
958 this.status_restarting();
939 url = this.kernel_url + "/restart"
959 url = this.kernel_url + "/restart"
940 var that = this;
960 var that = this;
941 $.post(url, function (kernel_id) {
961 $.post(url, function (kernel_id) {
942 console.log("Kernel restarted: " + kernel_id);
962 console.log("Kernel restarted: " + kernel_id);
943 that.kernel_id = kernel_id;
963 that.kernel_id = kernel_id;
944 that.kernel_url = that.base_url + "/" + that.kernel_id;
964 that.kernel_url = that.base_url + "/" + that.kernel_id;
945 that.status_idle();
965 that.status_idle();
946 }, 'json');
966 }, 'json');
947 };
967 };
948
968
949
969
950 Kernel.prototype.status_busy = function () {
970 Kernel.prototype.status_busy = function () {
951 $("#kernel_status").removeClass("status_idle");
971 $("#kernel_status").removeClass("status_idle");
952 $("#kernel_status").removeClass("status_restarting");
972 $("#kernel_status").removeClass("status_restarting");
953 $("#kernel_status").addClass("status_busy");
973 $("#kernel_status").addClass("status_busy");
954 $("#kernel_status").text("Busy");
974 $("#kernel_status").text("Busy");
955 };
975 };
956
976
957
977
958 Kernel.prototype.status_idle = function () {
978 Kernel.prototype.status_idle = function () {
959 $("#kernel_status").removeClass("status_busy");
979 $("#kernel_status").removeClass("status_busy");
960 $("#kernel_status").removeClass("status_restarting");
980 $("#kernel_status").removeClass("status_restarting");
961 $("#kernel_status").addClass("status_idle");
981 $("#kernel_status").addClass("status_idle");
962 $("#kernel_status").text("Idle");
982 $("#kernel_status").text("Idle");
963 };
983 };
964
984
965 Kernel.prototype.status_restarting = function () {
985 Kernel.prototype.status_restarting = function () {
966 $("#kernel_status").removeClass("status_busy");
986 $("#kernel_status").removeClass("status_busy");
967 $("#kernel_status").removeClass("status_idle");
987 $("#kernel_status").removeClass("status_idle");
968 $("#kernel_status").addClass("status_restarting");
988 $("#kernel_status").addClass("status_restarting");
969 $("#kernel_status").text("Restarting");
989 $("#kernel_status").text("Restarting");
970 };
990 };
971
991
972 //============================================================================
992 //============================================================================
973 // On document ready
993 // On document ready
974 //============================================================================
994 //============================================================================
975
995
976
996
977 $(document).ready(function () {
997 $(document).ready(function () {
978
998
979 MathJax.Hub.Config({
999 MathJax.Hub.Config({
980 tex2jax: {
1000 tex2jax: {
981 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
1001 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
982 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
1002 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
983 },
1003 },
984 displayAlign: 'left', // Change this to 'center' to center equations.
1004 displayAlign: 'left', // Change this to 'center' to center equations.
985 "HTML-CSS": {
1005 "HTML-CSS": {
986 styles: {'.MathJax_Display': {"margin": 0}}
1006 styles: {'.MathJax_Display': {"margin": 0}}
987 }
1007 }
988 });
1008 });
989
1009
990 IPYTHON.notebook = new Notebook('div.notebook');
1010 IPYTHON.notebook = new Notebook('div.notebook');
991 IPYTHON.notebook.insert_code_cell_after();
1011 IPYTHON.notebook.insert_code_cell_after();
992
1012
993 $("#menu_tabs").tabs();
1013 $("#menu_tabs").tabs();
994
1014
995 $("#help_toolbar").buttonset();
1015 $("#help_toolbar").buttonset();
996
1016
997 $("#kernel_toolbar").buttonset();
1017 $("#kernel_toolbar").buttonset();
998 $("#interrupt_kernel").click(function () {IPYTHON.notebook.kernel.interrupt();});
1018 $("#interrupt_kernel").click(function () {IPYTHON.notebook.kernel.interrupt();});
999 $("#restart_kernel").click(function () {IPYTHON.notebook.kernel.restart();});
1019 $("#restart_kernel").click(function () {IPYTHON.notebook.kernel.restart();});
1000 $("#kernel_status").addClass("status_idle");
1020 $("#kernel_status").addClass("status_idle");
1001
1021
1002 $("#move_cell").buttonset();
1022 $("#move_cell").buttonset();
1003 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
1023 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
1004 $("#move_up").button("option", "text", false);
1024 $("#move_up").button("option", "text", false);
1005 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
1025 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
1006 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
1026 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
1007 $("#move_down").button("option", "text", false);
1027 $("#move_down").button("option", "text", false);
1008 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
1028 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
1009
1029
1010 $("#insert_delete").buttonset();
1030 $("#insert_delete").buttonset();
1011 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
1031 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
1012 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
1032 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
1013 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
1033 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
1014 $("#delete_cell").button("option", "text", false);
1034 $("#delete_cell").button("option", "text", false);
1015 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
1035 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
1016
1036
1017 $("#cell_type").buttonset();
1037 $("#cell_type").buttonset();
1018 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
1038 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
1019 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
1039 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
1020
1040
1021 $("#sort").buttonset();
1041 $("#sort").buttonset();
1022 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
1042 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
1023
1043
1024 $("#toggle").buttonset();
1044 $("#toggle").buttonset();
1025 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
1045 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
1026 $("#expand").click(function () {IPYTHON.notebook.expand();});
1046 $("#expand").click(function () {IPYTHON.notebook.expand();});
1027
1047
1028 }); No newline at end of file
1048 });
General Comments 0
You need to be logged in to leave comments. Login now