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