##// END OF EJS Templates
Start forwarding the messages over widget custom messages
Jonathan Frederic -
Show More
@@ -1,677 +1,644
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3 /**
4 4 *
5 5 *
6 6 * @module codecell
7 7 * @namespace codecell
8 8 * @class CodeCell
9 9 */
10 10
11 11
12 12 define([
13 13 'base/js/namespace',
14 14 'jquery',
15 15 'base/js/utils',
16 16 'base/js/keyboard',
17 17 'services/config',
18 18 'notebook/js/cell',
19 19 'notebook/js/outputarea',
20 20 'notebook/js/completer',
21 21 'notebook/js/celltoolbar',
22 22 'codemirror/lib/codemirror',
23 23 'codemirror/mode/python/python',
24 24 'notebook/js/codemirror-ipython'
25 25 ], function(IPython,
26 26 $,
27 27 utils,
28 28 keyboard,
29 29 configmod,
30 30 cell,
31 31 outputarea,
32 32 completer,
33 33 celltoolbar,
34 34 CodeMirror,
35 35 cmpython,
36 36 cmip
37 37 ) {
38 38 "use strict";
39 39
40 40 var Cell = cell.Cell;
41 41
42 42 /* local util for codemirror */
43 43 var posEq = function(a, b) {return a.line === b.line && a.ch === b.ch;};
44 44
45 45 /**
46 46 *
47 47 * function to delete until previous non blanking space character
48 48 * or first multiple of 4 tabstop.
49 49 * @private
50 50 */
51 51 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
52 52 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
53 53 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
54 54 var cur = cm.getCursor(), line = cm.getLine(cur.line);
55 55 var tabsize = cm.getOption('tabSize');
56 56 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
57 57 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
58 58 var select = cm.getRange(from,cur);
59 59 if( select.match(/^\ +$/) !== null){
60 60 cm.replaceRange("",from,cur);
61 61 } else {
62 62 cm.deleteH(-1,"char");
63 63 }
64 64 };
65 65
66 66 var keycodes = keyboard.keycodes;
67 67
68 68 var CodeCell = function (kernel, options) {
69 69 /**
70 70 * Constructor
71 71 *
72 72 * A Cell conceived to write code.
73 73 *
74 74 * Parameters:
75 75 * kernel: Kernel instance
76 76 * The kernel doesn't have to be set at creation time, in that case
77 77 * it will be null and set_kernel has to be called later.
78 78 * options: dictionary
79 79 * Dictionary of keyword arguments.
80 80 * events: $(Events) instance
81 81 * config: dictionary
82 82 * keyboard_manager: KeyboardManager instance
83 83 * notebook: Notebook instance
84 84 * tooltip: Tooltip instance
85 85 */
86 86 this.kernel = kernel || null;
87 87 this.notebook = options.notebook;
88 88 this.collapsed = false;
89 89 this.events = options.events;
90 90 this.tooltip = options.tooltip;
91 91 this.config = options.config;
92 92 this.class_config = new configmod.ConfigWithDefaults(this.config,
93 93 CodeCell.config_defaults, 'CodeCell');
94 94
95 95 // create all attributed in constructor function
96 96 // even if null for V8 VM optimisation
97 97 this.input_prompt_number = null;
98 98 this.celltoolbar = null;
99 99 this.output_area = null;
100 // Keep a stack of the 'active' output areas (where active means the
101 // output area that recieves output). When a user activates an output
102 // area, it gets pushed to the stack. Then, when the output area is
103 // deactivated, it's popped from the stack. When the stack is empty,
104 // the cell's output area is used.
105 this.active_output_areas = [];
106 var that = this;
107 Object.defineProperty(this, 'active_output_area', {
108 get: function() {
109 if (that.active_output_areas && that.active_output_areas.length > 0) {
110 return that.active_output_areas[that.active_output_areas.length-1];
111 } else {
112 return that.output_area;
113 }
114 },
115 });
116 100
117 101 this.last_msg_id = null;
118 102 this.completer = null;
119 103 this.widget_views = [];
120 104 this._widgets_live = true;
121 105
122 106 Cell.apply(this,[{
123 107 config: $.extend({}, CodeCell.options_default),
124 108 keyboard_manager: options.keyboard_manager,
125 109 events: this.events}]);
126 110
127 111 // Attributes we want to override in this subclass.
128 112 this.cell_type = "code";
129 113 this.element.focusout(
130 114 function() { that.auto_highlight(); }
131 115 );
132 116 };
133 117
134 118 CodeCell.options_default = {
135 119 cm_config : {
136 120 extraKeys: {
137 121 "Tab" : "indentMore",
138 122 "Shift-Tab" : "indentLess",
139 123 "Backspace" : "delSpaceToPrevTabStop",
140 124 "Cmd-/" : "toggleComment",
141 125 "Ctrl-/" : "toggleComment"
142 126 },
143 127 mode: 'ipython',
144 128 theme: 'ipython',
145 129 matchBrackets: true
146 130 }
147 131 };
148 132
149 133 CodeCell.config_defaults = {
150 134 highlight_modes : {
151 135 'magic_javascript' :{'reg':[/^%%javascript/]},
152 136 'magic_perl' :{'reg':[/^%%perl/]},
153 137 'magic_ruby' :{'reg':[/^%%ruby/]},
154 138 'magic_python' :{'reg':[/^%%python3?/]},
155 139 'magic_shell' :{'reg':[/^%%bash/]},
156 140 'magic_r' :{'reg':[/^%%R/]},
157 141 'magic_text/x-cython' :{'reg':[/^%%cython/]},
158 142 },
159 143 };
160 144
161 145 CodeCell.msg_cells = {};
162 146
163 147 CodeCell.prototype = Object.create(Cell.prototype);
164 148
165 /**
166 * @method push_output_area
167 */
168 CodeCell.prototype.push_output_area = function (output_area) {
169 this.active_output_areas.push(output_area);
170 };
171
172 /**
173 * @method pop_output_area
174 */
175 CodeCell.prototype.pop_output_area = function (output_area) {
176 var index = this.active_output_areas.lastIndexOf(output_area);
177 if (index > -1) {
178 this.active_output_areas.splice(index, 1);
179 }
180 };
181
182 149 /** @method create_element */
183 150 CodeCell.prototype.create_element = function () {
184 151 Cell.prototype.create_element.apply(this, arguments);
185 152
186 153 var cell = $('<div></div>').addClass('cell code_cell');
187 154 cell.attr('tabindex','2');
188 155
189 156 var input = $('<div></div>').addClass('input');
190 157 var prompt = $('<div/>').addClass('prompt input_prompt');
191 158 var inner_cell = $('<div/>').addClass('inner_cell');
192 159 this.celltoolbar = new celltoolbar.CellToolbar({
193 160 cell: this,
194 161 notebook: this.notebook});
195 162 inner_cell.append(this.celltoolbar.element);
196 163 var input_area = $('<div/>').addClass('input_area');
197 164 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
198 165 this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this));
199 166 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
200 167 inner_cell.append(input_area);
201 168 input.append(prompt).append(inner_cell);
202 169
203 170 var widget_area = $('<div/>')
204 171 .addClass('widget-area')
205 172 .hide();
206 173 this.widget_area = widget_area;
207 174 var widget_prompt = $('<div/>')
208 175 .addClass('prompt')
209 176 .appendTo(widget_area);
210 177 var widget_subarea = $('<div/>')
211 178 .addClass('widget-subarea')
212 179 .appendTo(widget_area);
213 180 this.widget_subarea = widget_subarea;
214 181 var that = this;
215 182 var widget_clear_buton = $('<button />')
216 183 .addClass('close')
217 184 .html('&times;')
218 185 .click(function() {
219 186 widget_area.slideUp('', function(){
220 187 for (var i = 0; i < that.widget_views.length; i++) {
221 188 var view = that.widget_views[i];
222 189 view.remove();
223 190
224 191 // Remove widget live events.
225 192 view.off('comm:live', that._widget_live);
226 193 view.off('comm:dead', that._widget_dead);
227 194 }
228 195 that.widget_views = [];
229 196 widget_subarea.html('');
230 197 });
231 198 })
232 199 .appendTo(widget_prompt);
233 200
234 201 var output = $('<div></div>');
235 202 cell.append(input).append(widget_area).append(output);
236 203 this.element = cell;
237 204 this.output_area = new outputarea.OutputArea({
238 205 selector: output,
239 206 prompt_area: true,
240 207 events: this.events,
241 208 keyboard_manager: this.keyboard_manager});
242 209 this.completer = new completer.Completer(this, this.events);
243 210 };
244 211
245 212 /**
246 213 * Display a widget view in the cell.
247 214 */
248 215 CodeCell.prototype.display_widget_view = function(view_promise) {
249 216
250 217 // Display a dummy element
251 218 var dummy = $('<div/>');
252 219 this.widget_subarea.append(dummy);
253 220
254 221 // Display the view.
255 222 var that = this;
256 223 return view_promise.then(function(view) {
257 224 that.widget_area.show();
258 225 dummy.replaceWith(view.$el);
259 226 that.widget_views.push(view);
260 227
261 228 // Check the live state of the view's model.
262 229 if (view.model.comm_live) {
263 230 that._widget_live(view);
264 231 } else {
265 232 that._widget_dead(view);
266 233 }
267 234
268 235 // Listen to comm live events for the view.
269 236 view.on('comm:live', that._widget_live, that);
270 237 view.on('comm:dead', that._widget_dead, that);
271 238 return view;
272 239 });
273 240 };
274 241
275 242 /**
276 243 * Handles when a widget loses it's comm connection.
277 244 * @param {WidgetView} view
278 245 */
279 246 CodeCell.prototype._widget_dead = function(view) {
280 247 if (this._widgets_live) {
281 248 this._widgets_live = false;
282 249 this.widget_area.addClass('connection-problems');
283 250 }
284 251
285 252 };
286 253
287 254 /**
288 255 * Handles when a widget is connected to a live comm.
289 256 * @param {WidgetView} view
290 257 */
291 258 CodeCell.prototype._widget_live = function(view) {
292 259 if (!this._widgets_live) {
293 260 // Check that the other widgets are live too. O(N) operation.
294 261 // Abort the function at the first dead widget found.
295 262 for (var i = 0; i < this.widget_views.length; i++) {
296 263 if (!this.widget_views[i].model.comm_live) return;
297 264 }
298 265 this._widgets_live = true;
299 266 this.widget_area.removeClass('connection-problems');
300 267 }
301 268 };
302 269
303 270 /** @method bind_events */
304 271 CodeCell.prototype.bind_events = function () {
305 272 Cell.prototype.bind_events.apply(this);
306 273 var that = this;
307 274
308 275 this.element.focusout(
309 276 function() { that.auto_highlight(); }
310 277 );
311 278 };
312 279
313 280
314 281 /**
315 282 * This method gets called in CodeMirror's onKeyDown/onKeyPress
316 283 * handlers and is used to provide custom key handling. Its return
317 284 * value is used to determine if CodeMirror should ignore the event:
318 285 * true = ignore, false = don't ignore.
319 286 * @method handle_codemirror_keyevent
320 287 */
321 288
322 289 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
323 290
324 291 var that = this;
325 292 // whatever key is pressed, first, cancel the tooltip request before
326 293 // they are sent, and remove tooltip if any, except for tab again
327 294 var tooltip_closed = null;
328 295 if (event.type === 'keydown' && event.which !== keycodes.tab ) {
329 296 tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
330 297 }
331 298
332 299 var cur = editor.getCursor();
333 300 if (event.keyCode === keycodes.enter){
334 301 this.auto_highlight();
335 302 }
336 303
337 304 if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
338 305 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
339 306 // browser and keyboard layout !
340 307 // Pressing '(' , request tooltip, don't forget to reappend it
341 308 // The second argument says to hide the tooltip if the docstring
342 309 // is actually empty
343 310 this.tooltip.pending(that, true);
344 311 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
345 312 // If tooltip is active, cancel it. The call to
346 313 // remove_and_cancel_tooltip above doesn't pass, force=true.
347 314 // Because of this it won't actually close the tooltip
348 315 // if it is in sticky mode. Thus, we have to check again if it is open
349 316 // and close it with force=true.
350 317 if (!this.tooltip._hidden) {
351 318 this.tooltip.remove_and_cancel_tooltip(true);
352 319 }
353 320 // If we closed the tooltip, don't let CM or the global handlers
354 321 // handle this event.
355 322 event.codemirrorIgnore = true;
356 323 event.preventDefault();
357 324 return true;
358 325 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
359 326 if (editor.somethingSelected() || editor.getSelections().length !== 1){
360 327 var anchor = editor.getCursor("anchor");
361 328 var head = editor.getCursor("head");
362 329 if( anchor.line !== head.line){
363 330 return false;
364 331 }
365 332 }
366 333 this.tooltip.request(that);
367 334 event.codemirrorIgnore = true;
368 335 event.preventDefault();
369 336 return true;
370 337 } else if (event.keyCode === keycodes.tab && event.type === 'keydown') {
371 338 // Tab completion.
372 339 this.tooltip.remove_and_cancel_tooltip();
373 340
374 341 // completion does not work on multicursor, it might be possible though in some cases
375 342 if (editor.somethingSelected() || editor.getSelections().length > 1) {
376 343 return false;
377 344 }
378 345 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
379 346 if (pre_cursor.trim() === "") {
380 347 // Don't autocomplete if the part of the line before the cursor
381 348 // is empty. In this case, let CodeMirror handle indentation.
382 349 return false;
383 350 } else {
384 351 event.codemirrorIgnore = true;
385 352 event.preventDefault();
386 353 this.completer.startCompletion();
387 354 return true;
388 355 }
389 356 }
390 357
391 358 // keyboard event wasn't one of those unique to code cells, let's see
392 359 // if it's one of the generic ones (i.e. check edit mode shortcuts)
393 360 return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
394 361 };
395 362
396 363 // Kernel related calls.
397 364
398 365 CodeCell.prototype.set_kernel = function (kernel) {
399 366 this.kernel = kernel;
400 367 };
401 368
402 369 /**
403 370 * Execute current code cell to the kernel
404 371 * @method execute
405 372 */
406 373 CodeCell.prototype.execute = function (stop_on_error) {
407 374 if (!this.kernel || !this.kernel.is_connected()) {
408 375 console.log("Can't execute, kernel is not connected.");
409 376 return;
410 377 }
411 378
412 this.active_output_area.clear_output(false, true);
379 this.output_area.clear_output(false, true);
413 380
414 381 if (stop_on_error === undefined) {
415 382 stop_on_error = true;
416 383 }
417 384
418 385 // Clear widget area
419 386 for (var i = 0; i < this.widget_views.length; i++) {
420 387 var view = this.widget_views[i];
421 388 view.remove();
422 389
423 390 // Remove widget live events.
424 391 view.off('comm:live', this._widget_live);
425 392 view.off('comm:dead', this._widget_dead);
426 393 }
427 394 this.widget_views = [];
428 395 this.widget_subarea.html('');
429 396 this.widget_subarea.height('');
430 397 this.widget_area.height('');
431 398 this.widget_area.hide();
432 399
433 400 this.set_input_prompt('*');
434 401 this.element.addClass("running");
435 402 if (this.last_msg_id) {
436 403 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
437 404 }
438 405 var callbacks = this.get_callbacks();
439 406
440 407 var old_msg_id = this.last_msg_id;
441 408 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true,
442 409 stop_on_error : stop_on_error});
443 410 if (old_msg_id) {
444 411 delete CodeCell.msg_cells[old_msg_id];
445 412 }
446 413 CodeCell.msg_cells[this.last_msg_id] = this;
447 414 this.render();
448 415 this.events.trigger('execute.CodeCell', {cell: this});
449 416 };
450 417
451 418 /**
452 419 * Construct the default callbacks for
453 420 * @method get_callbacks
454 421 */
455 422 CodeCell.prototype.get_callbacks = function () {
456 423 var that = this;
457 424 return {
458 425 shell : {
459 426 reply : $.proxy(this._handle_execute_reply, this),
460 427 payload : {
461 428 set_next_input : $.proxy(this._handle_set_next_input, this),
462 429 page : $.proxy(this._open_with_pager, this)
463 430 }
464 431 },
465 432 iopub : {
466 433 output : function() {
467 that.active_output_area.handle_output.apply(that.active_output_area, arguments);
434 that.output_area.handle_output.apply(that.output_area, arguments);
468 435 },
469 436 clear_output : function() {
470 that.active_output_area.handle_clear_output.apply(that.active_output_area, arguments);
437 that.output_area.handle_clear_output.apply(that.output_area, arguments);
471 438 },
472 439 },
473 440 input : $.proxy(this._handle_input_request, this)
474 441 };
475 442 };
476 443
477 444 CodeCell.prototype._open_with_pager = function (payload) {
478 445 this.events.trigger('open_with_text.Pager', payload);
479 446 };
480 447
481 448 /**
482 449 * @method _handle_execute_reply
483 450 * @private
484 451 */
485 452 CodeCell.prototype._handle_execute_reply = function (msg) {
486 453 this.set_input_prompt(msg.content.execution_count);
487 454 this.element.removeClass("running");
488 455 this.events.trigger('set_dirty.Notebook', {value: true});
489 456 };
490 457
491 458 /**
492 459 * @method _handle_set_next_input
493 460 * @private
494 461 */
495 462 CodeCell.prototype._handle_set_next_input = function (payload) {
496 463 var data = {'cell': this, 'text': payload.text, replace: payload.replace};
497 464 this.events.trigger('set_next_input.Notebook', data);
498 465 };
499 466
500 467 /**
501 468 * @method _handle_input_request
502 469 * @private
503 470 */
504 471 CodeCell.prototype._handle_input_request = function (msg) {
505 this.active_output_area.append_raw_input(msg);
472 this.output_area.append_raw_input(msg);
506 473 };
507 474
508 475
509 476 // Basic cell manipulation.
510 477
511 478 CodeCell.prototype.select = function () {
512 479 var cont = Cell.prototype.select.apply(this);
513 480 if (cont) {
514 481 this.code_mirror.refresh();
515 482 this.auto_highlight();
516 483 }
517 484 return cont;
518 485 };
519 486
520 487 CodeCell.prototype.render = function () {
521 488 var cont = Cell.prototype.render.apply(this);
522 489 // Always execute, even if we are already in the rendered state
523 490 return cont;
524 491 };
525 492
526 493 CodeCell.prototype.select_all = function () {
527 494 var start = {line: 0, ch: 0};
528 495 var nlines = this.code_mirror.lineCount();
529 496 var last_line = this.code_mirror.getLine(nlines-1);
530 497 var end = {line: nlines-1, ch: last_line.length};
531 498 this.code_mirror.setSelection(start, end);
532 499 };
533 500
534 501
535 502 CodeCell.prototype.collapse_output = function () {
536 503 this.output_area.collapse();
537 504 };
538 505
539 506
540 507 CodeCell.prototype.expand_output = function () {
541 508 this.output_area.expand();
542 509 this.output_area.unscroll_area();
543 510 };
544 511
545 512 CodeCell.prototype.scroll_output = function () {
546 513 this.output_area.expand();
547 514 this.output_area.scroll_if_long();
548 515 };
549 516
550 517 CodeCell.prototype.toggle_output = function () {
551 518 this.output_area.toggle_output();
552 519 };
553 520
554 521 CodeCell.prototype.toggle_output_scroll = function () {
555 522 this.output_area.toggle_scroll();
556 523 };
557 524
558 525
559 526 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
560 527 var ns;
561 528 if (prompt_value === undefined || prompt_value === null) {
562 529 ns = "&nbsp;";
563 530 } else {
564 531 ns = encodeURIComponent(prompt_value);
565 532 }
566 533 return 'In&nbsp;[' + ns + ']:';
567 534 };
568 535
569 536 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
570 537 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
571 538 for(var i=1; i < lines_number; i++) {
572 539 html.push(['...:']);
573 540 }
574 541 return html.join('<br/>');
575 542 };
576 543
577 544 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
578 545
579 546
580 547 CodeCell.prototype.set_input_prompt = function (number) {
581 548 var nline = 1;
582 549 if (this.code_mirror !== undefined) {
583 550 nline = this.code_mirror.lineCount();
584 551 }
585 552 this.input_prompt_number = number;
586 553 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
587 554 // This HTML call is okay because the user contents are escaped.
588 555 this.element.find('div.input_prompt').html(prompt_html);
589 556 };
590 557
591 558
592 559 CodeCell.prototype.clear_input = function () {
593 560 this.code_mirror.setValue('');
594 561 };
595 562
596 563
597 564 CodeCell.prototype.get_text = function () {
598 565 return this.code_mirror.getValue();
599 566 };
600 567
601 568
602 569 CodeCell.prototype.set_text = function (code) {
603 570 return this.code_mirror.setValue(code);
604 571 };
605 572
606 573
607 574 CodeCell.prototype.clear_output = function (wait) {
608 this.active_output_area.clear_output(wait);
575 this.output_area.clear_output(wait);
609 576 this.set_input_prompt();
610 577 };
611 578
612 579
613 580 // JSON serialization
614 581
615 582 CodeCell.prototype.fromJSON = function (data) {
616 583 Cell.prototype.fromJSON.apply(this, arguments);
617 584 if (data.cell_type === 'code') {
618 585 if (data.source !== undefined) {
619 586 this.set_text(data.source);
620 587 // make this value the starting point, so that we can only undo
621 588 // to this state, instead of a blank cell
622 589 this.code_mirror.clearHistory();
623 590 this.auto_highlight();
624 591 }
625 592 this.set_input_prompt(data.execution_count);
626 593 this.output_area.trusted = data.metadata.trusted || false;
627 594 this.output_area.fromJSON(data.outputs);
628 595 if (data.metadata.collapsed !== undefined) {
629 596 if (data.metadata.collapsed) {
630 597 this.collapse_output();
631 598 } else {
632 599 this.expand_output();
633 600 }
634 601 }
635 602 }
636 603 };
637 604
638 605
639 606 CodeCell.prototype.toJSON = function () {
640 607 var data = Cell.prototype.toJSON.apply(this);
641 608 data.source = this.get_text();
642 609 // is finite protect against undefined and '*' value
643 610 if (isFinite(this.input_prompt_number)) {
644 611 data.execution_count = this.input_prompt_number;
645 612 } else {
646 613 data.execution_count = null;
647 614 }
648 615 var outputs = this.output_area.toJSON();
649 616 data.outputs = outputs;
650 617 data.metadata.trusted = this.output_area.trusted;
651 618 data.metadata.collapsed = this.output_area.collapsed;
652 619 return data;
653 620 };
654 621
655 622 /**
656 623 * handle cell level logic when a cell is unselected
657 624 * @method unselect
658 625 * @return is the action being taken
659 626 */
660 627 CodeCell.prototype.unselect = function () {
661 628 var cont = Cell.prototype.unselect.apply(this);
662 629 if (cont) {
663 630 // When a code cell is usnelected, make sure that the corresponding
664 631 // tooltip and completer to that cell is closed.
665 632 this.tooltip.remove_and_cancel_tooltip(true);
666 633 if (this.completer !== null) {
667 634 this.completer.close();
668 635 }
669 636 }
670 637 return cont;
671 638 };
672 639
673 640 // Backwards compatability.
674 641 IPython.CodeCell = CodeCell;
675 642
676 643 return {'CodeCell': CodeCell};
677 644 });
@@ -1,61 +1,79
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "jquery",
7 7 'notebook/js/outputarea',
8 8 ], function(widget, $, outputarea) {
9 9 'use strict';
10 10
11 11 var OutputView = widget.DOMWidgetView.extend({
12 12 initialize: function (parameters) {
13 13 /**
14 14 * Public constructor
15 15 */
16 16 OutputView.__super__.initialize.apply(this, [parameters]);
17 17 this.model.on('msg:custom', this._handle_route_msg, this);
18 18 },
19 19
20 20 render: function(){
21 21 /**
22 22 * Called when view is rendered.
23 23 */
24 24 this.output_area = new outputarea.OutputArea({
25 25 selector: this.$el,
26 26 prompt_area: false,
27 27 events: this.model.widget_manager.notebook.events,
28 28 keyboard_manager: this.model.widget_manager.keyboard_manager });
29 29
30 30 // Make output area reactive.
31 31 var that = this;
32 32 this.output_area.element.on('changed', function() {
33 33 that.model.set('contents', that.output_area.element.html());
34 34 });
35 35 this.model.on('change:contents', function(){
36 36 var html = this.model.get('contents');
37 37 if (this.output_area.element.html() != html) {
38 38 this.output_area.element.html(html);
39 39 }
40 40 }, this);
41 41
42 42 // Set initial contents.
43 43 this.output_area.element.html(this.model.get('contents'));
44 44 },
45 45
46 46 _handle_route_msg: function(content) {
47 var cell = this.options.cell;
48 if (content && cell) {
47 if (content) {
48 // return {
49 // shell : {
50 // reply : $.proxy(this._handle_execute_reply, this),
51 // payload : {
52 // set_next_input : $.proxy(this._handle_set_next_input, this),
53 // page : $.proxy(this._open_with_pager, this)
54 // }
55 // },
56 // iopub : {
57 // output : function() {
58 // that.output_area.handle_output.apply(that.output_area, arguments);
59 // },
60 // clear_output : function() {
61 // that.output_area.handle_clear_output.apply(that.output_area, arguments);
62 // },
63 // },
64 // input : $.proxy(this._handle_input_request, this)
65 // };
66 // };
49 67 if (content.method == 'push') {
50 68 cell.push_output_area(this.output_area);
51 69 } else if (content.method == 'pop') {
52 70 cell.pop_output_area(this.output_area);
53 71 }
54 72 }
55 73 },
56 74 });
57 75
58 76 return {
59 77 'OutputView': OutputView,
60 78 };
61 79 });
General Comments 0
You need to be logged in to leave comments. Login now