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