##// END OF EJS Templates
Work on the notebook's code cell....
Brian Granger -
Show More
@@ -1,266 +1,269 b''
1 1 /**
2 2 * HTML5 ✰ Boilerplate
3 3 *
4 4 * style.css contains a reset, font normalization and some base styles.
5 5 *
6 6 * Credit is left where credit is due.
7 7 * Much inspiration was taken from these projects:
8 8 * - yui.yahooapis.com/2.8.1/build/base/base.css
9 9 * - camendesign.com/design/
10 10 * - praegnanz.de/weblog/htmlcssjs-kickstart
11 11 */
12 12
13 13
14 14 /**
15 15 * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
16 16 * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark
17 17 * html5doctor.com/html-5-reset-stylesheet/
18 18 */
19 19
20 20 html, body, div, span, object, iframe,
21 21 h1, h2, h3, h4, h5, h6, p, blockquote, pre,
22 22 abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
23 23 small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
24 24 fieldset, form, label, legend,
25 25 table, caption, tbody, tfoot, thead, tr, th, td,
26 26 article, aside, canvas, details, figcaption, figure,
27 27 footer, header, hgroup, menu, nav, section, summary,
28 28 time, mark, audio, video {
29 29 margin: 0;
30 30 padding: 0;
31 31 border: 0;
32 32 font-size: 100%;
33 33 font: inherit;
34 34 vertical-align: baseline;
35 35 }
36 36
37 37 article, aside, details, figcaption, figure,
38 38 footer, header, hgroup, menu, nav, section {
39 39 display: block;
40 40 }
41 41
42 42 blockquote, q { quotes: none; }
43 43
44 44 blockquote:before, blockquote:after,
45 45 q:before, q:after { content: ""; content: none; }
46 46
47 47 ins { background-color: #ff9; color: #000; text-decoration: none; }
48 48
49 49 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
50 50
51 51 del { text-decoration: line-through; }
52 52
53 53 abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
54 54
55 55 table { border-collapse: collapse; border-spacing: 0; }
56 56
57 57 hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
58 58
59 59 input, select { vertical-align: middle; }
60 60
61 61 /* Normalize monospace sizing:
62 62 en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */
63 63 pre, code, kbd, samp { font-family: monospace, sans-serif; }
64 64
65 65
66 66
67 67 body {
68 68 background-color: white;
69 69 font-size: 11pt;
70 70
71 71 /* This makes sure that the body covers the entire window and needs to
72 72 be in a different element than the display: box in wrapper below */
73 73 position: absolute;
74 74 left: 0px;
75 75 right: 0px;
76 76 top: 0px;
77 77 bottom: 0px;
78 78 }
79 79
80 80 div#wrapper {
81 81 display: box;
82 82 box-orient: vertical;
83 83
84 84 display: -webkit-box;
85 85 -webkit-box-orient: vertical;
86 86
87 87 display: -moz-box;
88 88 -moz-box-orient: vertical;
89 89
90 90 /* This is needed to make sure the wrapper fills the body */
91 91 width: 100%;
92 92 height: 100%;
93 93
94 94 box-sizing: border-box;
95 95 -moz-box-sizing: border-box;
96 96 -webkit-box-sizing: border-box;
97 97 }
98 98
99 99 span#ipython_notebook h1 {
100 100 font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
101 101 font-size: 26pt;
102 102 padding: 10px;
103 103 margin: 10px;
104 104 }
105 105
106 106 div#tools {
107 107 font-size: 10pt;
108 108 }
109 109
110 110 span#kernel_status {
111 111 position: absolute;
112 112 top: 12%;
113 113 right: 10px;
114 114 font-weight: bold;
115 115 }
116 116
117 117 .status_idle {
118 118 color: gray;
119 119 }
120 120
121 121 .status_busy {
122 122 color: red;
123 123 }
124 124
125 125 .status_restarting {
126 126 color: black;
127 127 }
128 128
129 129 div.notebook {
130 130 /* This is a trick from Google Docs. We set the height artificially low
131 131 and set overflow-y: auto to force scrolling of this dev when needed,
132 132 but prevent the browser window from scrolling. Crazy hack */
133 133 height: 15px;
134 134 overflow-y: auto;
135 135 overflow-x: hidden;
136 136 padding: 5px;
137 137 /* padding-top: 5px;*/
138 138 /* padding-bottom: 5px;*/
139 139 background-color: white;
140 140
141 141 /* Allow the notebook div to take up the rest of the vertical space */
142 142 box-flex: 1;
143 143 -webkit-box-flex: 1;
144 144 -moz-box-flex: 1;
145 145
146 146 box-sizing: border-box;
147 147 -moz-box-sizing: border-box;
148 148 -webkit-box-sizing: border-box;
149 149 }
150 150
151 151 div.cell {
152 152 width: 100%;
153 153 padding: 5px;
154 154 position: relative;
155 155 display: table;
156 156 box-sizing: border-box;
157 157 -moz-box-sizing: border-box;
158 158 -webkit-box-sizing: border-box;
159 159 }
160 160
161 161 div.code_cell {
162 162 background-color: white;
163 163 }
164 164
165 165 div.prompt {
166 166 vertical-align: top;
167 167 display: table-cell;
168 168 width: 80px;
169 169 padding: 0px;
170 170 margin: 0px;
171 171 font-family: Monaco, Consolas, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace;
172 172 font-weight: normal;
173 173 font-style: normal;
174 174 }
175 175
176 176 div.input {
177 177 display: box;
178 178 box-orient: horizontal;
179 179
180 180 display: -webkit-box;
181 181 -webkit-box-orient: horizontal;
182 182
183 183 display: -moz-box;
184 184 -moz-box-orient: horizontal;
185 185 }
186 186
187 187 div.input_prompt {
188 188 color: blue;
189 189 }
190 190
191 textarea.input_area {
191 div.input_area {
192 box-flex: 1;
193 -webkit-box-flex: 1;
194 -moz-box-flex: 1;
195 box-sizing: border-box;
196 -moz-box-sizing: border-box;
197 -webkit-box-sizing: border-box;
198 }
199
200 textarea.input_textarea {
201 width: 100%;
192 202 text-align: left;
193 203 font-family: Monaco, Consolas, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace;
194 204 font-size: inherit;
195 205 border-style: none;
196 206 display: table-cell;
197 207 padding: 0px;
198 208 margin: 0px;
199 209 overflow: auto;
200 210 outline: none;
201 211 resize: none;
202
203 box-flex: 1;
204 -webkit-box-flex: 1;
205 -moz-box-flex: 1;
206 box-sizing: border-box;
207 -moz-box-sizing: border-box;
208 -webkit-box-sizing: border-box;
209 212 }
210 213
211 214 div.output {
212 215 display: box;
213 216 box-orient: horizontal;
214 217
215 218 display: -webkit-box;
216 219 -webkit-box-orient: horizontal;
217 220
218 221 display: -moz-box;
219 222 -moz-box-orient: horizontal;
220 223 }
221 224
222 225 div.output_prompt {
223 226 color: red;
224 227 }
225 228
226 229 div.output_area {
227 230 text-align: left;
228 231 font-family: Monaco, Consolas, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace;
229 232 display: table-cell;
230 233 }
231 234
232 235 div.text_cell {
233 236 background-color: white;
234 237 }
235 238
236 239 textarea.text_cell_input {
237 240 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
238 241 font-size: 12pt;
239 242 outline: none;
240 243 resize: none;
241 244 width: inherit;
242 245 border-style: none;
243 246 padding: 0px;
244 247 margin: 0px;
245 248 color: black;
246 249 }
247 250
248 251 div.text_cell_render {
249 252 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
250 253 font-size: 12pt;
251 254 outline: none;
252 255 resize: none;
253 256 width: inherit;
254 257 border-style: none;
255 258 padding: 5px;
256 259 color: black;
257 260 }
258 261
259 262 div.text_cell_render em {
260 263 font-style: italic;
261 264 }
262 265
263 266 div.text_cell_render strong {
264 267 font-weight: bold;
265 268 }
266 269
@@ -1,874 +1,874 b''
1 1 var IPYTHON = {};
2 2
3 3
4 4
5 5 // $.get("/notebooks/number2.nb",function (data, status, xhr) {console.log(data);});
6 6 //
7 7 // settings = {
8 8 // processData : false,
9 9 // cache : false,
10 10 // type : "DELETE",
11 11 // success : function (data, status, xhr) {console.log(data);}
12 12 // }
13 13 // $.ajax("/notebooks/number2.nb",settings)
14 14 //
15 15 // settings = {
16 16 // processData : false,
17 17 // cache : false,
18 18 // type : "PUT",
19 19 // success : function (data, status, xhr) {console.log(data);}
20 20 // }
21 21 // $.ajax("/notebooks/number2.nb",settings)
22 22
23 23
24 24 //============================================================================
25 25 // Utilities
26 26 //============================================================================
27 27
28 28
29 29 var uuid = function () {
30 30 // http://www.ietf.org/rfc/rfc4122.txt
31 31 var s = [];
32 32 var hexDigits = "0123456789ABCDEF";
33 33 for (var i = 0; i < 32; i++) {
34 34 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
35 35 }
36 36 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
37 37 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
38 38
39 39 var uuid = s.join("");
40 40 return uuid;
41 41 };
42 42
43 43
44 44 //Fix raw text to parse correctly in crazy XML
45 45 function xmlencode(string) {
46 46 return string.replace(/\&/g,'&'+'amp;')
47 47 .replace(/</g,'&'+'lt;')
48 48 .replace(/>/g,'&'+'gt;')
49 49 .replace(/\'/g,'&'+'apos;')
50 50 .replace(/\"/g,'&'+'quot;')
51 51 .replace(/`/g,'&'+'#96;')
52 52 }
53 53
54 54 //Map from terminal commands to CSS classes
55 55 attrib = {
56 56 "30":"cblack", "31":"cred",
57 57 "32":"cgreen", "33":"cyellow",
58 58 "34":"cblue", "36":"ccyan",
59 59 "37":"cwhite", "01":"cbold"}
60 60
61 61 //Fixes escaped console commands, IE colors. Turns them into HTML
62 62 function fixConsole(txt) {
63 63 txt = xmlencode(txt)
64 64 var re = /\033\[([\d;]*?)m/
65 65 var opened = false
66 66 var cmds = []
67 67 var opener = ""
68 68 var closer = ""
69 69
70 70 while (re.test(txt)) {
71 71 var cmds = txt.match(re)[1].split(";")
72 72 closer = opened?"</span>":""
73 73 opened = cmds.length > 1 || cmds[0] != 0
74 74 var rep = []
75 75 for (var i in cmds)
76 76 if (typeof(attrib[cmds[i]]) != "undefined")
77 77 rep.push(attrib[cmds[i]])
78 78 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":""
79 79 txt = txt.replace(re, closer + opener)
80 80 }
81 81 if (opened) txt += "</span>"
82 82 return txt.trim()
83 83 }
84 84
85 85 //============================================================================
86 86 // Notebook
87 87 //============================================================================
88 88
89 89
90 90 var Notebook = function (selector) {
91 91 this.element = $(selector);
92 92 this.element.scroll();
93 93 this.element.data("notebook", this);
94 94 this.next_prompt_number = 1;
95 95 this.kernel = null;
96 96 this.msg_cell_map = {};
97 97 this.bind_events();
98 98 this.start_kernel();
99 99 };
100 100
101 101
102 102 Notebook.prototype.bind_events = function () {
103 103 var that = this;
104 104 $(document).keydown(function (event) {
105 105 // console.log(event);
106 106 if (event.which == 38 && event.shiftKey) {
107 107 event.preventDefault();
108 108 that.select_prev();
109 109 } else if (event.which == 40 && event.shiftKey) {
110 110 event.preventDefault();
111 111 that.select_next();
112 112 } else if (event.which == 13 && event.shiftKey) {
113 113 // The focus is not quite working here.
114 114 var cell = that.selected_cell();
115 115 var cell_index = that.find_cell_index(cell);
116 116 if (cell instanceof CodeCell) {
117 117 event.preventDefault();
118 118 cell.clear_output();
119 119 cell.hide_output_prompt();
120 120 var msg_id = that.kernel.execute(cell.get_code());
121 121 that.msg_cell_map[msg_id] = cell.cell_id;
122 122 if (cell_index === (that.ncells()-1)) {
123 123 that.insert_code_cell_after();
124 124 } else {
125 125 that.select(cell_index+1);
126 126 };
127 127 }
128 128 } else if (event.which == 9) {
129 129 event.preventDefault();
130 130 var cell = that.selected_cell();
131 131 if (cell instanceof CodeCell) {
132 132 var ta = cell.element.find("textarea.input_area");
133 133 ta.val(ta.val() + " ");
134 134 };
135 135 };
136 136 });
137 137 };
138 138
139 139
140 140 // Cell indexing, retrieval, etc.
141 141
142 142
143 143 Notebook.prototype.cell_elements = function () {
144 144 return this.element.children("div.cell");
145 145 }
146 146
147 147
148 148 Notebook.prototype.ncells = function (cell) {
149 149 return this.cell_elements().length;
150 150 }
151 151
152 152
153 153 // TODO: we are often calling cells as cells()[i], which we should optimize
154 154 // to cells(i) or a new method.
155 155 Notebook.prototype.cells = function () {
156 156 return this.cell_elements().toArray().map(function (e) {
157 157 return $(e).data("cell");
158 158 });
159 159 }
160 160
161 161
162 162 Notebook.prototype.find_cell_index = function (cell) {
163 163 var result = null;
164 164 this.cell_elements().filter(function (index) {
165 165 if ($(this).data("cell") === cell) {
166 166 result = index;
167 167 };
168 168 });
169 169 return result;
170 170 };
171 171
172 172
173 173 Notebook.prototype.index_or_selected = function (index) {
174 174 return index || this.selected_index() || 0;
175 175 }
176 176
177 177
178 178 Notebook.prototype.select = function (index) {
179 179 if (index !== undefined && index >= 0 && index < this.ncells()) {
180 180 if (this.selected_index() !== null) {
181 181 this.selected_cell().unselect();
182 182 };
183 183 this.cells()[index].select();
184 184 };
185 185 return this;
186 186 };
187 187
188 188
189 189 Notebook.prototype.select_next = function () {
190 190 var index = this.selected_index();
191 191 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
192 192 this.select(index+1);
193 193 };
194 194 return this;
195 195 };
196 196
197 197
198 198 Notebook.prototype.select_prev = function () {
199 199 var index = this.selected_index();
200 200 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
201 201 this.select(index-1);
202 202 };
203 203 return this;
204 204 };
205 205
206 206
207 207 Notebook.prototype.selected_index = function () {
208 208 var result = null;
209 209 this.cell_elements().filter(function (index) {
210 210 if ($(this).data("cell").selected === true) {
211 211 result = index;
212 212 };
213 213 });
214 214 return result;
215 215 };
216 216
217 217
218 218 Notebook.prototype.cell_for_msg = function (msg_id) {
219 219 var cell_id = this.msg_cell_map[msg_id];
220 220 var result = null;
221 221 this.cell_elements().filter(function (index) {
222 222 cell = $(this).data("cell");
223 223 if (cell.cell_id === cell_id) {
224 224 result = cell;
225 225 };
226 226 });
227 227 return result;
228 228 };
229 229
230 230
231 231 Notebook.prototype.selected_cell = function () {
232 232 return this.cell_elements().eq(this.selected_index()).data("cell");
233 233 }
234 234
235 235
236 236 // Cell insertion, deletion and moving.
237 237
238 238
239 239 Notebook.prototype.delete_cell = function (index) {
240 240 var i = index || this.selected_index();
241 241 if (i !== null && i >= 0 && i < this.ncells()) {
242 242 this.cell_elements().eq(i).remove();
243 243 if (i === (this.ncells())) {
244 244 this.select(i-1);
245 245 } else {
246 246 this.select(i);
247 247 };
248 248 };
249 249 return this;
250 250 };
251 251
252 252
253 253 Notebook.prototype.append_cell = function (cell) {
254 254 this.element.append(cell.element);
255 255 return this;
256 256 };
257 257
258 258
259 259 Notebook.prototype.insert_cell_after = function (cell, index) {
260 260 var ncells = this.ncells();
261 261 if (ncells === 0) {
262 262 this.append_cell(cell);
263 263 return this;
264 264 };
265 265 if (index >= 0 && index < ncells) {
266 266 this.cell_elements().eq(index).after(cell.element);
267 267 };
268 268 return this
269 269 };
270 270
271 271
272 272 Notebook.prototype.insert_cell_before = function (cell, index) {
273 273 var ncells = this.ncells();
274 274 if (ncells === 0) {
275 275 this.append_cell(cell);
276 276 return this;
277 277 };
278 278 if (index >= 0 && index < ncells) {
279 279 this.cell_elements().eq(index).before(cell.element);
280 280 };
281 281 return this;
282 282 };
283 283
284 284
285 285 Notebook.prototype.move_cell_up = function (index) {
286 286 var i = index || this.selected_index();
287 287 if (i !== null && i < this.ncells() && i > 0) {
288 288 var pivot = this.cell_elements().eq(i-1);
289 289 var tomove = this.cell_elements().eq(i);
290 290 if (pivot !== null && tomove !== null) {
291 291 tomove.detach();
292 292 pivot.before(tomove);
293 293 this.select(i-1);
294 294 };
295 295 };
296 296 return this;
297 297 }
298 298
299 299
300 300 Notebook.prototype.move_cell_down = function (index) {
301 301 var i = index || this.selected_index();
302 302 if (i !== null && i < (this.ncells()-1) && i >= 0) {
303 303 var pivot = this.cell_elements().eq(i+1)
304 304 var tomove = this.cell_elements().eq(i)
305 305 if (pivot !== null && tomove !== null) {
306 306 tomove.detach();
307 307 pivot.after(tomove);
308 308 this.select(i+1);
309 309 };
310 310 };
311 311 return this;
312 312 }
313 313
314 314
315 315 Notebook.prototype.sort_cells = function () {
316 316 var ncells = this.ncells();
317 317 var sindex = this.selected_index();
318 318 var swapped;
319 319 do {
320 320 swapped = false
321 321 for (var i=1; i<ncells; i++) {
322 322 current = this.cell_elements().eq(i).data("cell");
323 323 previous = this.cell_elements().eq(i-1).data("cell");
324 324 if (previous.input_prompt_number > current.input_prompt_number) {
325 325 this.move_cell_up(i);
326 326 swapped = true;
327 327 };
328 328 };
329 329 } while (swapped);
330 330 this.select(sindex);
331 331 return this;
332 332 };
333 333
334 334
335 335 Notebook.prototype.insert_code_cell_before = function (index) {
336 336 // TODO: Bounds check for i
337 337 var i = this.index_or_selected(index);
338 338 var cell = new CodeCell(this);
339 339 cell.set_input_prompt(this.next_prompt_number);
340 340 this.next_prompt_number = this.next_prompt_number + 1;
341 341 this.insert_cell_before(cell, i);
342 342 this.select(this.find_cell_index(cell));
343 343 return this;
344 344 }
345 345
346 346
347 347 Notebook.prototype.insert_code_cell_after = function (index) {
348 348 // TODO: Bounds check for i
349 349 var i = this.index_or_selected(index);
350 350 var cell = new CodeCell(this);
351 351 cell.set_input_prompt(this.next_prompt_number);
352 352 this.next_prompt_number = this.next_prompt_number + 1;
353 353 this.insert_cell_after(cell, i);
354 354 this.select(this.find_cell_index(cell));
355 355 return this;
356 356 }
357 357
358 358
359 359 Notebook.prototype.insert_text_cell_before = function (index) {
360 360 // TODO: Bounds check for i
361 361 var i = this.index_or_selected(index);
362 362 var cell = new TextCell(this);
363 363 cell.config_mathjax();
364 364 this.insert_cell_before(cell, i);
365 365 this.select(this.find_cell_index(cell));
366 366 return this;
367 367 }
368 368
369 369
370 370 Notebook.prototype.insert_text_cell_after = function (index) {
371 371 // TODO: Bounds check for i
372 372 var i = this.index_or_selected(index);
373 373 var cell = new TextCell(this);
374 374 cell.config_mathjax();
375 375 this.insert_cell_after(cell, i);
376 376 this.select(this.find_cell_index(cell));
377 377 return this;
378 378 }
379 379
380 380
381 381 Notebook.prototype.text_to_code = function (index) {
382 382 // TODO: Bounds check for i
383 383 var i = this.index_or_selected(index);
384 384 var source_element = this.cell_elements().eq(i);
385 385 var source_cell = source_element.data("cell");
386 386 if (source_cell instanceof TextCell) {
387 387 this.insert_code_cell_after(i);
388 388 var target_cell = this.cells()[i+1];
389 389 var text = source_element.find("textarea.text_cell_input").val();
390 390 target_cell.element.find("textarea.input_area").val(text);
391 391 source_element.remove();
392 392 };
393 393 };
394 394
395 395
396 396 Notebook.prototype.code_to_text = function (index) {
397 397 // TODO: Bounds check for i
398 398 var i = this.index_or_selected(index);
399 399 var source_element = this.cell_elements().eq(i);
400 400 var source_cell = source_element.data("cell");
401 401 if (source_cell instanceof CodeCell) {
402 402 this.insert_text_cell_after(i);
403 403 var target_cell = this.cells()[i+1];
404 404 var text = source_element.find("textarea.input_area").val();
405 405 if (text === "") {text = target_cell.placeholder;};
406 406 target_cell.element.find("textarea.text_cell_input").val(text);
407 407 target_cell.element.find("textarea.text_cell_input").html(text);
408 408 target_cell.element.find("div.text_cell_render").html(text);
409 409
410 410 source_element.remove();
411 411 };
412 412 };
413 413
414 414
415 415 // Cell collapsing
416 416
417 417 Notebook.prototype.collapse = function (index) {
418 418 var i = this.index_or_selected(index);
419 419 this.cells()[i].collapse();
420 420 };
421 421
422 422
423 423 Notebook.prototype.expand = function (index) {
424 424 var i = this.index_or_selected(index);
425 425 this.cells()[i].expand();
426 426 };
427 427
428 428
429 429 // Kernel related things
430 430
431 431 Notebook.prototype.start_kernel = function () {
432 432 this.kernel = new Kernel();
433 433 this.kernel.start_kernel(this._kernel_started, this);
434 434 };
435 435
436 436
437 437 Notebook.prototype._kernel_started = function () {
438 438 console.log("Kernel started: ", this.kernel.kernel_id);
439 439 var that = this;
440 440
441 441 this.kernel.shell_channel.onmessage = function (e) {
442 442 reply = $.parseJSON(e.data);
443 443 console.log(reply);
444 444 var msg_type = reply.msg_type;
445 445 var cell = that.cell_for_msg(reply.parent_header.msg_id);
446 446 if (msg_type === "execute_reply") {
447 447 cell.set_prompt(reply.content.execution_count);
448 448 };
449 449 };
450 450
451 451 this.kernel.iopub_channel.onmessage = function (e) {
452 452 reply = $.parseJSON(e.data);
453 453 console.log(reply);
454 454 var msg_type = reply.msg_type;
455 455 var cell = that.cell_for_msg(reply.parent_header.msg_id);
456 456 if (msg_type === "stream") {
457 457 cell.expand();
458 458 cell.append_stream(reply.content.data + "\n");
459 459 } else if (msg_type === "pyout" || msg_type === "display_data") {
460 460 cell.show_output_prompt();
461 461 cell.expand();
462 462 cell.append_display_data(reply.content.data);
463 463 } else if (msg_type === "status") {
464 464 if (reply.content.execution_state === "busy") {
465 465 that.kernel.status_busy();
466 466 } else if (reply.content.execution_state === "idle") {
467 467 that.kernel.status_idle();
468 468 };
469 469 };
470 470 };
471 471 };
472 472
473 473
474 474 Notebook.prototype._handle_execute_reply = function (reply, cell) {
475 475 cell.set_prompt(reply.content.execution_count);
476 476 };
477 477
478 478
479 479 //============================================================================
480 480 // Cell
481 481 //============================================================================
482 482
483 483
484 484 var Cell = function (notebook) {
485 485 this.notebook = notebook;
486 486 this.selected = false;
487 487 this.element;
488 488 this.create_element();
489 489 if (this.element !== undefined) {
490 490 this.element.data("cell", this);
491 491 this.bind_events();
492 492 }
493 493 this.cell_id = uuid();
494 494 };
495 495
496 496
497 497 Cell.prototype.select = function () {
498 498 this.element.addClass('ui-widget-content ui-corner-all');
499 499 this.selected = true;
500 500 // TODO: we need t test across browsers to see if both of these are needed.
501 501 // In the meantime, there should not be any harm in having them both.
502 502 this.element.find('textarea').trigger('focusin');
503 503 this.element.find('textarea').trigger('focus');
504 504 };
505 505
506 506
507 507 Cell.prototype.unselect = function () {
508 508 this.element.removeClass('ui-widget-content ui-corner-all');
509 509 this.selected = false;
510 510 };
511 511
512 512
513 513 Cell.prototype.bind_events = function () {
514 514 var that = this;
515 515 var nb = that.notebook
516 516 that.element.click(function (event) {
517 517 if (that.selected === false) {
518 518 nb.select(nb.find_cell_index(that));
519 519 };
520 520 });
521 521 that.element.focusin(function (event) {
522 522 if (that.selected === false) {
523 523 nb.select(nb.find_cell_index(that));
524 524 };
525 525 });
526 526 };
527 527
528 528
529 529 // Subclasses must implement create_element.
530 530 Cell.prototype.create_element = function () {};
531 531
532 532
533 533 //============================================================================
534 534 // CodeCell
535 535 //============================================================================
536 536
537 537
538 538 var CodeCell = function (notebook) {
539 539 Cell.apply(this, arguments);
540 540 this.input_prompt_number = ' ';
541 541 this.output_prompt_number = ' ';
542 542 };
543 543
544 544
545 545 CodeCell.prototype = new Cell();
546 546
547 547
548 548 CodeCell.prototype.create_element = function () {
549 var cell = $('<div></div>').addClass('cell code_cell')
550 var input = $('<div></div>').addClass('input').append(
551 $('<div/>').addClass('prompt input_prompt')
552 ).append(
553 $('<textarea/>').addClass('input_area').
554 attr('rows',1).
555 attr('cols',80).
556 attr('wrap','hard').
557 autoGrow()
558 );
559 var output = $('<div></div>').addClass('output').append(
560 $('<div/>').addClass('prompt output_prompt')
561 ).append(
562 $('<div/>').addClass('output_area')
563 );
549 var cell = $('<div></div>').addClass('cell code_cell');
550 var input = $('<div></div>').addClass('input');
551 input.append($('<div/>').addClass('prompt input_prompt'));
552 var input_textarea = $('<textarea/>').addClass('input_textarea').attr('rows',1).attr('wrap','hard').autoGrow();
553 input.append($('<div/>').addClass('input_area').append(input_textarea));
554 var output = $('<div></div>').addClass('output');
555 output.append($('<div/>').addClass('prompt output_prompt'));
556 output.append($('<div/>').addClass('output_area'));
564 557 cell.append(input).append(output);
565 558 this.element = cell;
566 559 this.collapse()
567 560 };
568 561
569 562
570 563 CodeCell.prototype.append_stream = function (data) {
571 564 var data_list = data.split("\n");
572 565 console.log(data_list);
573 566 if (data_list.length > 0) {
574 567 for (var i=0; i<data_list.length; i++) {
575 568 console.log(i, data_list[i]);
576 569 var toinsert = fixConsole(data_list[i]);
577 570 this.element.find("div.output_area").append($("<p>").append(toinsert));
578 571 };
579 572 }
580 573 };
581 574
582 575
583 576 CodeCell.prototype.append_display_data = function (data) {
584 577 if (data["image/svg+xml"] !== undefined) {
585 578 this.append_svg(data["image/svg+xml"]);
586 579 } else if (data["text/plain"] !== undefined) {
587 580 console.log(data["text/plain"]);
588 581 this.append_stream(data["text/plain"]);
589 582 };
590 583 };
591 584
592 585 CodeCell.prototype.append_svg = function (svg) {
593 586 this.element.find("div.output_area").append(svg);
594 587 };
595 588
596 589
597 590 CodeCell.prototype.clear_output = function () {
598 591 this.element.find("div.output_area").html("");
599 592 };
600 593
601 594
602 595 CodeCell.prototype.collapse = function () {
603 596 this.element.find('div.output').hide();
604 597 };
605 598
606 599
607 600 CodeCell.prototype.expand = function () {
608 601 this.element.find('div.output').show();
609 602 };
610 603
611 604
612 605 CodeCell.prototype.set_prompt = function (number) {
613 606 this.set_input_prompt(number);
614 607 this.set_output_prompt(number);
615 608 };
616 609
617 610 CodeCell.prototype.set_input_prompt = function (number) {
618 611 var n = number || ' ';
619 612 this.input_prompt_number = n
620 613 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
621 614 };
622 615
623 616
624 617 CodeCell.prototype.set_output_prompt = function (number) {
625 618 var n = number || ' ';
626 619 this.output_prompt_number = n
627 620 this.element.find('div.output_prompt').html('Out[' + n + ']:');
628 621 };
629 622
630 623 CodeCell.prototype.hide_output_prompt = function () {
631 624 this.element.find('div.output_prompt').hide();
632 625 };
633 626
634 627 CodeCell.prototype.show_output_prompt = function () {
635 628 this.element.find('div.output_prompt').show();
636 629 };
637 630
638
639 631 CodeCell.prototype.get_code = function () {
640 632 return this.element.find("textarea.input_area").val();
641 633 };
642 634
635
636 CodeCell.prototype.toJSON = function () {
637 return {
638 code : this.get_code(),
639 cell_type : 'code',
640 prompt_number : this.input_prompt_number
641 };
642 };
643 643 //============================================================================
644 644 // TextCell
645 645 //============================================================================
646 646
647 647
648 648 var TextCell = function (notebook) {
649 649 Cell.apply(this, arguments);
650 650 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
651 651 };
652 652
653 653
654 654 TextCell.prototype = new Cell();
655 655
656 656
657 657 TextCell.prototype.create_element = function () {
658 658 var cell = $("<div>").addClass('cell text_cell').
659 659 append(
660 660 $("<textarea>" + this.placeholder + "</textarea>").
661 661 addClass('text_cell_input').
662 662 attr('rows',1).
663 663 attr('cols',80).
664 664 autoGrow()
665 665 ).append(
666 666 $('<div></div>').addClass('text_cell_render')
667 667 )
668 668 this.element = cell;
669 669 };
670 670
671 671
672 672 TextCell.prototype.select = function () {
673 673 this.edit();
674 674 Cell.prototype.select.apply(this);
675 675 };
676 676
677 677
678 678 TextCell.prototype.edit = function () {
679 679 var text_cell = this.element;
680 680 var input = text_cell.find("textarea.text_cell_input");
681 681 var output = text_cell.find("div.text_cell_render");
682 682 output.hide();
683 683 input.show().trigger('focus');
684 684 };
685 685
686 686
687 687 TextCell.prototype.render = function () {
688 688 var text_cell = this.element;
689 689 var input = text_cell.find("textarea.text_cell_input");
690 690 var output = text_cell.find("div.text_cell_render");
691 691 var text = input.val();
692 692 if (text === "") {
693 693 text = this.placeholder;
694 694 input.val(text);
695 695 };
696 696 output.html(text)
697 697 input.html(text);
698 698 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
699 699 input.hide();
700 700 output.show();
701 701 };
702 702
703 703
704 704 TextCell.prototype.config_mathjax = function () {
705 705 var text_cell = this.element;
706 706 var that = this;
707 707 text_cell.click(function () {
708 708 that.edit();
709 709 }).focusout(function () {
710 710 that.render();
711 711 });
712 712
713 713 text_cell.trigger("focusout");
714 714 };
715 715
716 716
717 717 //============================================================================
718 718 // On document ready
719 719 //============================================================================
720 720
721 721
722 722 var Kernel = function () {
723 723 this.kernel_id = null;
724 724 this.base_url = "/kernels";
725 725 this.kernel_url = null;
726 726 };
727 727
728 728
729 729 Kernel.prototype.get_msg = function (msg_type, content) {
730 730 var msg = {
731 731 header : {
732 732 msg_id : uuid(),
733 733 username : "bgranger",
734 734 session: this.session_id
735 735 },
736 736 msg_type : msg_type,
737 737 content : content,
738 738 parent_header : {}
739 739 };
740 740 return msg;
741 741 }
742 742
743 743 Kernel.prototype.start_kernel = function (callback, context) {
744 744 var that = this;
745 745 $.post(this.base_url,
746 746 function (kernel_id) {
747 747 that._handle_start_kernel(kernel_id, callback, context);
748 748 },
749 749 'json'
750 750 );
751 751 };
752 752
753 753
754 754 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
755 755 this.kernel_id = kernel_id;
756 756 this.kernel_url = this.base_url + "/" + this.kernel_id;
757 757 this._start_channels();
758 758 callback.call(context);
759 759 };
760 760
761 761
762 762 Kernel.prototype._start_channels = function () {
763 763 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
764 764 this.shell_channel = new WebSocket(ws_url + "/shell");
765 765 this.iopub_channel = new WebSocket(ws_url + "/iopub");
766 766 }
767 767
768 768
769 769 Kernel.prototype.execute = function (code) {
770 770 var content = {
771 771 code : code,
772 772 silent : false,
773 773 user_variables : [],
774 774 user_expressions : {}
775 775 };
776 776 var msg = this.get_msg("execute_request", content);
777 777 this.shell_channel.send(JSON.stringify(msg));
778 778 return msg.header.msg_id;
779 779 }
780 780
781 781
782 782 Kernel.prototype.interrupt = function () {
783 783 $.post(this.kernel_url + "/interrupt");
784 784 };
785 785
786 786
787 787 Kernel.prototype.restart = function () {
788 788 this.status_restarting();
789 789 url = this.kernel_url + "/restart"
790 790 var that = this;
791 791 $.post(url, function (kernel_id) {
792 792 console.log("Kernel restarted: " + kernel_id);
793 793 that.kernel_id = kernel_id;
794 794 that.kernel_url = that.base_url + "/" + that.kernel_id;
795 795 that.status_idle();
796 796 }, 'json');
797 797 };
798 798
799 799
800 800 Kernel.prototype.status_busy = function () {
801 801 $("#kernel_status").removeClass("status_idle");
802 802 $("#kernel_status").removeClass("status_restarting");
803 803 $("#kernel_status").addClass("status_busy");
804 804 $("#kernel_status").text("Busy");
805 805 };
806 806
807 807
808 808 Kernel.prototype.status_idle = function () {
809 809 $("#kernel_status").removeClass("status_busy");
810 810 $("#kernel_status").removeClass("status_restarting");
811 811 $("#kernel_status").addClass("status_idle");
812 812 $("#kernel_status").text("Idle");
813 813 };
814 814
815 815 Kernel.prototype.status_restarting = function () {
816 816 $("#kernel_status").removeClass("status_busy");
817 817 $("#kernel_status").removeClass("status_idle");
818 818 $("#kernel_status").addClass("status_restarting");
819 819 $("#kernel_status").text("Restarting");
820 820 };
821 821
822 822 //============================================================================
823 823 // On document ready
824 824 //============================================================================
825 825
826 826
827 827 $(document).ready(function () {
828 828
829 829 MathJax.Hub.Config({
830 830 tex2jax: {
831 831 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
832 832 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
833 833 }
834 834 });
835 835
836 836 IPYTHON.notebook = new Notebook('div.notebook');
837 837 IPYTHON.notebook.insert_code_cell_after();
838 838
839 839 $("#menu_tabs").tabs();
840 840
841 841 $("#help_toolbar").buttonset();
842 842
843 843 $("#kernel_toolbar").buttonset();
844 844 $("#interrupt_kernel").click(function () {IPYTHON.notebook.kernel.interrupt();});
845 845 $("#restart_kernel").click(function () {IPYTHON.notebook.kernel.restart();});
846 846 $("#kernel_status").addClass("status_idle");
847 847
848 848 $("#move_cell").buttonset();
849 849 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
850 850 $("#move_up").button("option", "text", false);
851 851 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
852 852 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
853 853 $("#move_down").button("option", "text", false);
854 854 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
855 855
856 856 $("#insert_delete").buttonset();
857 857 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
858 858 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
859 859 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
860 860 $("#delete_cell").button("option", "text", false);
861 861 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
862 862
863 863 $("#cell_type").buttonset();
864 864 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
865 865 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
866 866
867 867 $("#sort").buttonset();
868 868 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
869 869
870 870 $("#toggle").buttonset();
871 871 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
872 872 $("#expand").click(function () {IPYTHON.notebook.expand();});
873 873
874 874 }); No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now