##// END OF EJS Templates
Adding shift-enter support.
Brian Granger -
Show More
@@ -1,501 +1,504 b''
1 1 var IPYTHON = {};
2 2
3 3
4 4 //============================================================================
5 5 // Notebook
6 6 //============================================================================
7 7
8 8
9 9 var Notebook = function (selector) {
10 10 this.element = $(selector);
11 11 this.element.data("notebook", this);
12 12 this.next_prompt_number = 1;
13 13 this.bind_events();
14 14 }
15 15
16 16
17 17 Notebook.prototype.bind_events = function () {
18 18 var that = this;
19 19 that.element.keydown(function (event) {
20 // console.log(event);
20 console.log(event);
21 21 if (event.which == 38 && event.shiftKey) {
22 22 that.select_prev();
23 23 } else if (event.which == 40 && event.shiftKey) {
24 24 that.select_next();
25 } else if (event.which == 13 && event.shiftKey) {
26 // The focus is not quite working here.
27 that.insert_code_cell_after();
25 28 }
26 29 });
27 30 };
28 31
29 32
30 33 // Cell indexing, retrieval, etc.
31 34
32 35
33 36 Notebook.prototype.cell_elements = function () {
34 37 return this.element.children("div.cell");
35 38 }
36 39
37 40
38 41 Notebook.prototype.ncells = function (cell) {
39 42 return this.cell_elements().length;
40 43 }
41 44
42 45
43 46 // TODO: we are often calling cells as cells()[i], which we should optimize
44 47 // to cells(i) or a new method.
45 48 Notebook.prototype.cells = function () {
46 49 return this.cell_elements().toArray().map(function (e) {
47 50 return $(e).data("cell");
48 51 });
49 52 }
50 53
51 54
52 55 Notebook.prototype.find_cell_index = function (cell) {
53 56 var result = null;
54 57 this.cell_elements().filter(function (index) {
55 58 if ($(this).data("cell") === cell) {
56 59 result = index;
57 60 };
58 61 });
59 62 return result;
60 63 };
61 64
62 65
63 66 Notebook.prototype.index_or_selected = function (index) {
64 67 return index || this.selected_index() || 0;
65 68 }
66 69
67 70
68 71 Notebook.prototype.select = function (index) {
69 72 if (index !== undefined && index >= 0 && index < this.ncells()) {
70 73 if (this.selected_index() !== null) {
71 74 this.selected_cell().unselect();
72 75 };
73 76 this.cells()[index].select();
74 77 };
75 78 return this;
76 79 };
77 80
78 81
79 82 Notebook.prototype.select_next = function () {
80 83 var index = this.selected_index();
81 84 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
82 85 this.select(index+1);
83 86 };
84 87 return this;
85 88 };
86 89
87 90
88 91 Notebook.prototype.select_prev = function () {
89 92 var index = this.selected_index();
90 93 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
91 94 this.select(index-1);
92 95 };
93 96 return this;
94 97 };
95 98
96 99
97 100 Notebook.prototype.selected_index = function () {
98 101 var result = null;
99 102 this.cell_elements().filter(function (index) {
100 103 if ($(this).data("cell").selected === true) {
101 104 result = index;
102 105 };
103 106 });
104 107 return result;
105 108 };
106 109
107 110
108 111 Notebook.prototype.selected_cell = function () {
109 112 return this.cell_elements().eq(this.selected_index()).data("cell");
110 113 }
111 114
112 115
113 116 // Cell insertion, deletion and moving.
114 117
115 118
116 119 Notebook.prototype.delete_cell = function (index) {
117 120 var i = index || this.selected_index();
118 121 if (i !== null && i >= 0 && i < this.ncells()) {
119 122 this.cell_elements().eq(i).remove();
120 123 if (i === (this.ncells())) {
121 124 this.select(i-1);
122 125 } else {
123 126 this.select(i);
124 127 };
125 128 };
126 129 return this;
127 130 };
128 131
129 132
130 133 Notebook.prototype.append_cell = function (cell) {
131 134 this.element.append(cell.element);
132 135 return this;
133 136 };
134 137
135 138
136 139 Notebook.prototype.insert_cell_after = function (cell, index) {
137 140 var ncells = this.ncells();
138 141 if (ncells === 0) {
139 142 this.append_cell(cell);
140 143 return this;
141 144 };
142 145 if (index >= 0 && index < ncells) {
143 146 this.cell_elements().eq(index).after(cell.element);
144 147 };
145 148 return this
146 149 };
147 150
148 151
149 152 Notebook.prototype.insert_cell_before = function (cell, index) {
150 153 var ncells = this.ncells();
151 154 if (ncells === 0) {
152 155 this.append_cell(cell);
153 156 return this;
154 157 };
155 158 if (index > 0 && index < ncells) {
156 159 this.cell_elements().eq(index).before(cell.element);
157 160 };
158 161 return this;
159 162 };
160 163
161 164
162 165 Notebook.prototype.move_cell_up = function (index) {
163 166 var i = index || this.selected_index();
164 167 if (i !== null && i < this.ncells() && i > 0) {
165 168 var pivot = this.cell_elements().eq(i-1);
166 169 var tomove = this.cell_elements().eq(i);
167 170 if (pivot !== null && tomove !== null) {
168 171 tomove.detach();
169 172 pivot.before(tomove);
170 173 };
171 174 };
172 175 return this;
173 176 }
174 177
175 178
176 179 Notebook.prototype.move_cell_down = function (index) {
177 180 var i = index || this.selected_index();
178 181 if (i !== null && i < (this.ncells()-1) && i >= 0) {
179 182 var pivot = this.cell_elements().eq(i+1)
180 183 var tomove = this.cell_elements().eq(i)
181 184 if (pivot !== null && tomove !== null) {
182 185 tomove.detach();
183 186 pivot.after(tomove);
184 187 };
185 188 };
186 189 return this;
187 190 }
188 191
189 192
190 193 Notebook.prototype.sort_cells = function () {
191 194 var ncells = this.ncells();
192 195 var swapped;
193 196 do {
194 197 swapped = false
195 198 for (var i=1; i<ncells; i++) {
196 199 current = this.cell_elements().eq(i).data("cell");
197 200 previous = this.cell_elements().eq(i-1).data("cell");
198 201 if (previous.input_prompt_number > current.input_prompt_number) {
199 202 this.move_cell_up(i);
200 203 swapped = true;
201 204 };
202 205 };
203 206 } while (swapped);
204 207 return this;
205 208 };
206 209
207 210
208 211 Notebook.prototype.insert_code_cell_before = function (index) {
209 212 // TODO: Bounds check for i
210 213 var i = this.index_or_selected(index);
211 214 var cell = new CodeCell(this);
212 215 cell.set_input_prompt(this.next_prompt_number);
213 216 this.next_prompt_number = this.next_prompt_number + 1;
214 217 this.insert_cell_before(cell, i);
215 218 this.select(this.find_cell_index(cell));
216 219 return this;
217 220 }
218 221
219 222
220 223 Notebook.prototype.insert_code_cell_after = function (index) {
221 224 // TODO: Bounds check for i
222 225 var i = this.index_or_selected(index);
223 226 var cell = new CodeCell(this);
224 227 cell.set_input_prompt(this.next_prompt_number);
225 228 this.next_prompt_number = this.next_prompt_number + 1;
226 229 this.insert_cell_after(cell, i);
227 230 this.select(this.find_cell_index(cell));
228 231 return this;
229 232 }
230 233
231 234
232 235 Notebook.prototype.insert_text_cell_before = function (index) {
233 236 // TODO: Bounds check for i
234 237 var i = this.index_or_selected(index);
235 238 var cell = new TextCell(this);
236 239 cell.config_mathjax();
237 240 this.insert_cell_before(cell, i);
238 241 this.select(this.find_cell_index(cell));
239 242 return this;
240 243 }
241 244
242 245
243 246 Notebook.prototype.insert_text_cell_after = function (index) {
244 247 // TODO: Bounds check for i
245 248 var i = this.index_or_selected(index);
246 249 var cell = new TextCell(this);
247 250 cell.config_mathjax();
248 251 this.insert_cell_after(cell, i);
249 252 this.select(this.find_cell_index(cell));
250 253 return this;
251 254 }
252 255
253 256
254 257 Notebook.prototype.text_to_code = function (index) {
255 258 // TODO: Bounds check for i
256 259 var i = this.index_or_selected(index);
257 260 var source_element = this.cell_elements().eq(i);
258 261 var source_cell = source_element.data("cell");
259 262 if (source_cell instanceof TextCell) {
260 263 this.insert_code_cell_after(i);
261 264 var target_cell = this.cells()[i+1];
262 265 var text = source_element.find("textarea.text_cell_input").val();
263 266 target_cell.element.find("textarea.input_area").val(text);
264 267 source_element.remove();
265 268 };
266 269 };
267 270
268 271
269 272 Notebook.prototype.code_to_text = function (index) {
270 273 // TODO: Bounds check for i
271 274 var i = this.index_or_selected(index);
272 275 var source_element = this.cell_elements().eq(i);
273 276 var source_cell = source_element.data("cell");
274 277 if (source_cell instanceof CodeCell) {
275 278 this.insert_text_cell_after(i);
276 279 var target_cell = this.cells()[i+1];
277 280 var text = source_element.find("textarea.input_area").val();
278 281 target_cell.element.find("textarea.text_cell_input").val(text);
279 282 target_cell.element.find("textarea.text_cell_input").html(text);
280 283 target_cell.element.find("div.text_cell_render").html(text);
281 284
282 285 source_element.remove();
283 286 };
284 287 };
285 288
286 289
287 290 // Cell collapsing
288 291
289 292 Notebook.prototype.collapse = function (index) {
290 293 var i = this.index_or_selected(index);
291 294 this.cells()[i].collapse();
292 295 }
293 296
294 297
295 298 Notebook.prototype.expand = function (index) {
296 299 var i = this.index_or_selected(index);
297 300 this.cells()[i].expand();
298 301 }
299 302
300 303
301 304 //============================================================================
302 305 // Cell
303 306 //============================================================================
304 307
305 308
306 309 var Cell = function (notebook) {
307 310 this.notebook = notebook;
308 311 this.selected = false;
309 312 this.element;
310 313 this.create_element();
311 314 if (this.element !== undefined) {
312 315 this.element.data("cell", this);
313 316 this.bind_events();
314 317 }
315 318 };
316 319
317 320
318 321 Cell.prototype.select = function () {
319 322 this.element.addClass('ui-widget-content ui-corner-all');
320 323 this.selected = true;
321 324 this.element.find('textarea').trigger('focusin');
322 325 };
323 326
324 327
325 328 Cell.prototype.unselect = function () {
326 329 this.element.removeClass('ui-widget-content ui-corner-all');
327 330 this.selected = false;
328 331 };
329 332
330 333
331 334 Cell.prototype.bind_events = function () {
332 335 var that = this;
333 336 var nb = that.notebook
334 337 that.element.click(function (event) {
335 338 if (that.selected === false) {
336 339 nb.select(nb.find_cell_index(that));
337 340 };
338 341 });
339 342 that.element.focusin(function (event) {
340 343 if (that.selected === false) {
341 344 nb.select(nb.find_cell_index(that));
342 345 };
343 346 });
344 347 };
345 348
346 349
347 350 // Subclasses must implement create_element.
348 351 Cell.prototype.create_element = function () {};
349 352
350 353
351 354 //============================================================================
352 355 // CodeCell
353 356 //============================================================================
354 357
355 358
356 359 var CodeCell = function (notebook) {
357 360 Cell.apply(this, arguments);
358 361 this.input_prompt_number = ' ';
359 362 this.output_prompt_number = ' ';
360 363 };
361 364
362 365
363 366 CodeCell.prototype = new Cell();
364 367
365 368
366 369 CodeCell.prototype.create_element = function () {
367 370 var cell = $('<div></div>').addClass('cell code_cell')
368 371 var input = $('<div></div>').addClass('input').append(
369 372 $('<div/>').addClass('prompt input_prompt')
370 373 ).append(
371 374 $('<textarea/>').addClass('input_area').
372 375 attr('rows',1).
373 376 attr('cols',80).
374 377 attr('wrap','hard').
375 378 autoGrow()
376 379 );
377 380 var output = $('<div></div>').addClass('output').append(
378 381 $('<div/>').addClass('prompt output_prompt')
379 382 ).append(
380 383 $('<div/>').addClass('output_area')
381 384 );
382 385 output.hide();
383 386 cell.append(input).append(output);
384 387 this.element = cell;
385 388 };
386 389
387 390
388 391 CodeCell.prototype.collapse = function () {
389 392 this.element.find('div.output').hide();
390 393 };
391 394
392 395
393 396 CodeCell.prototype.expand = function () {
394 397 this.element.find('div.output').show();
395 398 };
396 399
397 400
398 401 CodeCell.prototype.set_prompt = function (number) {
399 402 this.set_input_prompt(number);
400 403 this.set_output_prompt(number);
401 404 };
402 405
403 406 CodeCell.prototype.set_input_prompt = function (number) {
404 407 var n = number || ' ';
405 408 this.input_prompt_number = n
406 409 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
407 410 };
408 411
409 412
410 413 CodeCell.prototype.set_output_prompt = function (number) {
411 414 var n = number || ' ';
412 415 this.output_prompt_number = n
413 416 this.element.find('div.output_prompt').html('Out[' + n + ']:');
414 417 };
415 418
416 419
417 420 //============================================================================
418 421 // TextCell
419 422 //============================================================================
420 423
421 424
422 425 var TextCell = function (notebook) {
423 426 Cell.apply(this, arguments);
424 427 };
425 428
426 429
427 430 TextCell.prototype = new Cell();
428 431
429 432
430 433 TextCell.prototype.create_element = function () {
431 434 var cell = $('<div></div').addClass('cell text_cell').
432 435 append(
433 436 $('<textarea>Type HTML/LaTex content here</textarea>').
434 437 addClass('text_cell_input').
435 438 attr('rows',1).
436 439 attr('cols',80).
437 440 autoGrow()
438 441 ).append(
439 442 $('<div></div>').addClass('text_cell_render')
440 443 )
441 444 this.element = cell;
442 445 };
443 446
444 447
445 448 TextCell.prototype.config_mathjax = function () {
446 449 var text_cell = this.element;
447 450 var input = text_cell.find("textarea.text_cell_input");
448 451 var output = text_cell.find("div.text_cell_render");
449 452
450 453 text_cell.click(function () {
451 454 output.hide();
452 455 input.show().trigger('focus');
453 456 }).focusout(function () {
454 457 var text = input.val();
455 458 output.html(text)
456 459 input.html(text);
457 460 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
458 461 input.hide();
459 462 output.show();
460 463 });
461 464
462 465 text_cell.trigger("focusout");
463 466 };
464 467
465 468
466 469 $(document).ready(function () {
467 470
468 471 MathJax.Hub.Config({
469 472 tex2jax: {
470 473 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
471 474 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
472 475 }
473 476 });
474 477
475 478 $("ul#main_menu").wijmenu({animation:{animated: "slide", duration: 100, easing: null}});
476 479 IPYTHON.notebook = new Notebook('div.notebook');
477 480 IPYTHON.notebook.insert_code_cell_after();
478 481
479 482 $("#move_cell").buttonset();
480 483 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
481 484 $("#move_up").button("option", "text", false);
482 485 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
483 486 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
484 487 $("#move_down").button("option", "text", false);
485 488 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
486 489
487 490 $("#insert_delete").buttonset();
488 491 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
489 492 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
490 493 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
491 494 $("#delete_cell").button("option", "text", false);
492 495 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
493 496
494 497 $("#cell_type").buttonset();
495 498 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
496 499 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
497 500
498 501 $("#sort").buttonset();
499 502 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
500 503
501 504 }); No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now