##// END OF EJS Templates
Backport PR #5459: Fix interact animation page jump FF...
MinRK -
Show More
@@ -268,39 +268,47 b' var IPython = (function (IPython) {'
268 268 });
269 269 return json;
270 270 };
271
271
272 272 OutputArea.prototype.append_output = function (json) {
273 273 this.expand();
274
275 // validate output data types
276 json = this.validate_output(json);
277
274 278 // Clear the output if clear is queued.
275 279 var needs_height_reset = false;
276 280 if (this.clear_queued) {
277 281 this.clear_output(false);
278 282 needs_height_reset = true;
279 283 }
280
281 // validate output data types
282 json = this.validate_output(json);
283 284
284 285 if (json.output_type === 'pyout') {
285 286 this.append_pyout(json);
286 287 } else if (json.output_type === 'pyerr') {
287 288 this.append_pyerr(json);
288 } else if (json.output_type === 'display_data') {
289 this.append_display_data(json);
290 289 } else if (json.output_type === 'stream') {
291 290 this.append_stream(json);
292 291 }
293
294 this.outputs.push(json);
295
296 // Only reset the height to automatic if the height is currently
297 // fixed (done by wait=True flag on clear_output).
298 if (needs_height_reset) {
299 this.element.height('');
300 }
301 292
293 // We must release the animation fixed height in a callback since Gecko
294 // (FireFox) doesn't render the image immediately as the data is
295 // available.
302 296 var that = this;
303 setTimeout(function(){that.element.trigger('resize');}, 100);
297 var handle_appended = function ($el) {
298 // Only reset the height to automatic if the height is currently
299 // fixed (done by wait=True flag on clear_output).
300 if (needs_height_reset) {
301 that.element.height('');
302 }
303 that.element.trigger('resize');
304 };
305 if (json.output_type === 'display_data') {
306 this.append_display_data(json, handle_appended);
307 } else {
308 handle_appended();
309 }
310
311 this.outputs.push(json);
304 312 };
305 313
306 314
@@ -475,9 +483,9 b' var IPython = (function (IPython) {'
475 483 };
476 484
477 485
478 OutputArea.prototype.append_display_data = function (json) {
486 OutputArea.prototype.append_display_data = function (json, handle_inserted) {
479 487 var toinsert = this.create_output_area();
480 if (this.append_mime_type(json, toinsert)) {
488 if (this.append_mime_type(json, toinsert, handle_inserted)) {
481 489 this._safe_append(toinsert);
482 490 // If we just output latex, typeset it.
483 491 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
@@ -494,7 +502,7 b' var IPython = (function (IPython) {'
494 502 'image/jpeg' : true
495 503 };
496 504
497 OutputArea.prototype.append_mime_type = function (json, element) {
505 OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) {
498 506 for (var type_i in OutputArea.display_order) {
499 507 var type = OutputArea.display_order[type_i];
500 508 var append = OutputArea.append_map[type];
@@ -511,7 +519,14 b' var IPython = (function (IPython) {'
511 519 }
512 520 }
513 521 var md = json.metadata || {};
514 var toinsert = append.apply(this, [value, md, element]);
522 var toinsert = append.apply(this, [value, md, element, handle_inserted]);
523 // Since only the png and jpeg mime types call the inserted
524 // callback, if the mime type is something other we must call the
525 // inserted callback only when the element is actually inserted
526 // into the DOM. Use a timeout of 0 to do this.
527 if (['image/png', 'image/jpeg'].indexOf(type) < 0 && handle_inserted !== undefined) {
528 setTimeout(handle_inserted, 0);
529 }
515 530 $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]);
516 531 return toinsert;
517 532 }
@@ -611,10 +626,16 b' var IPython = (function (IPython) {'
611 626 if (width !== undefined) img.attr('width', width);
612 627 };
613 628
614 var append_png = function (png, md, element) {
629 var append_png = function (png, md, element, handle_inserted) {
615 630 var type = 'image/png';
616 631 var toinsert = this.create_output_subarea(md, "output_png", type);
617 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
632 var img = $("<img/>");
633 if (handle_inserted !== undefined) {
634 img.on('load', function(){
635 handle_inserted(img);
636 });
637 }
638 img[0].src = 'data:image/png;base64,'+ png;
618 639 set_width_height(img, md, 'image/png');
619 640 this._dblclick_to_reset_size(img);
620 641 toinsert.append(img);
@@ -623,10 +644,16 b' var IPython = (function (IPython) {'
623 644 };
624 645
625 646
626 var append_jpeg = function (jpeg, md, element) {
647 var append_jpeg = function (jpeg, md, element, handle_inserted) {
627 648 var type = 'image/jpeg';
628 649 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
629 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
650 var img = $("<img/>");
651 if (handle_inserted !== undefined) {
652 img.on('load', function(){
653 handle_inserted(img);
654 });
655 }
656 img[0].src = 'data:image/jpeg;base64,'+ jpeg;
630 657 set_width_height(img, md, 'image/jpeg');
631 658 this._dblclick_to_reset_size(img);
632 659 toinsert.append(img);
@@ -748,7 +775,10 b' var IPython = (function (IPython) {'
748 775 this.clear_queued = false;
749 776 }
750 777
751 // clear all, no need for logic
778 // Clear all
779 // Remove load event handlers from img tags because we don't want
780 // them to fire if the image is never added to the page.
781 this.element.find('img').off('load');
752 782 this.element.html("");
753 783 this.outputs = [];
754 784 this.trusted = true;
@@ -90,11 +90,7 b' class ZMQDisplayPublisher(DisplayPublisher):'
90 90
91 91 def clear_output(self, wait=False):
92 92 content = dict(wait=wait)
93
94 print('\r', file=sys.stdout, end='')
95 print('\r', file=sys.stderr, end='')
96 93 self._flush_streams()
97
98 94 self.session.send(
99 95 self.pub_socket, u'clear_output', content,
100 96 parent=self.parent_header, ident=self.topic,
@@ -197,6 +197,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
197 197 self._local_kernel = kw.get('local_kernel',
198 198 FrontendWidget._local_kernel)
199 199
200 # Whether or not a clear_output call is pending new output.
201 self._pending_clearoutput = False
202
200 203 #---------------------------------------------------------------------------
201 204 # 'ConsoleWidget' public interface
202 205 #---------------------------------------------------------------------------
@@ -339,6 +342,14 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
339 342 #---------------------------------------------------------------------------
340 343 # 'BaseFrontendMixin' abstract interface
341 344 #---------------------------------------------------------------------------
345 def _handle_clear_output(self, msg):
346 """Handle clear output messages."""
347 if not self._hidden and self._is_from_this_session(msg):
348 wait = msg['content'].get('wait', True)
349 if wait:
350 self._pending_clearoutput = True
351 else:
352 self.clear_output()
342 353
343 354 def _handle_complete_reply(self, rep):
344 355 """ Handle replies for tab completion.
@@ -520,6 +531,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
520 531 """
521 532 self.log.debug("pyout: %s", msg.get('content', ''))
522 533 if not self._hidden and self._is_from_this_session(msg):
534 self.flush_clearoutput()
523 535 text = msg['content']['data']
524 536 self._append_plain_text(text + '\n', before_prompt=True)
525 537
@@ -528,13 +540,8 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
528 540 """
529 541 self.log.debug("stream: %s", msg.get('content', ''))
530 542 if not self._hidden and self._is_from_this_session(msg):
531 # Most consoles treat tabs as being 8 space characters. Convert tabs
532 # to spaces so that output looks as expected regardless of this
533 # widget's tab width.
534 text = msg['content']['data'].expandtabs(8)
535
536 self._append_plain_text(text, before_prompt=True)
537 self._control.moveCursor(QtGui.QTextCursor.End)
543 self.flush_clearoutput()
544 self.append_stream(msg['content']['data'])
538 545
539 546 def _handle_shutdown_reply(self, msg):
540 547 """ Handle shutdown signal, only if from other console.
@@ -685,6 +692,29 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
685 692 before_prompt=True
686 693 )
687 694
695 def append_stream(self, text):
696 """Appends text to the output stream."""
697 # Most consoles treat tabs as being 8 space characters. Convert tabs
698 # to spaces so that output looks as expected regardless of this
699 # widget's tab width.
700 text = text.expandtabs(8)
701 self._append_plain_text(text, before_prompt=True)
702 self._control.moveCursor(QtGui.QTextCursor.End)
703
704 def flush_clearoutput(self):
705 """If a clearoutput is pending, execute it."""
706 if self._pending_clearoutput:
707 self._pending_clearoutput = False
708 self.clear_output()
709
710 def clear_output(self):
711 """Clears the current line of output."""
712 cursor = self._control.textCursor()
713 cursor.beginEditBlock()
714 cursor.movePosition(cursor.StartOfLine, cursor.KeepAnchor)
715 cursor.insertText('')
716 cursor.endEditBlock()
717
688 718 #---------------------------------------------------------------------------
689 719 # 'FrontendWidget' protected interface
690 720 #---------------------------------------------------------------------------
@@ -140,7 +140,6 b' class IPythonWidget(FrontendWidget):'
140 140 #---------------------------------------------------------------------------
141 141 # 'BaseFrontendMixin' abstract interface
142 142 #---------------------------------------------------------------------------
143
144 143 def _handle_complete_reply(self, rep):
145 144 """ Reimplemented to support IPython's improved completion machinery.
146 145 """
@@ -223,6 +222,7 b' class IPythonWidget(FrontendWidget):'
223 222 """
224 223 self.log.debug("pyout: %s", msg.get('content', ''))
225 224 if not self._hidden and self._is_from_this_session(msg):
225 self.flush_clearoutput()
226 226 content = msg['content']
227 227 prompt_number = content.get('execution_count', 0)
228 228 data = content['data']
@@ -250,6 +250,7 b' class IPythonWidget(FrontendWidget):'
250 250 # eventually will as this allows all frontends to monitor the display
251 251 # data. But we need to figure out how to handle this in the GUI.
252 252 if not self._hidden and self._is_from_this_session(msg):
253 self.flush_clearoutput()
253 254 source = msg['content']['source']
254 255 data = msg['content']['data']
255 256 metadata = msg['content']['metadata']
@@ -114,6 +114,7 b' class RichIPythonWidget(IPythonWidget):'
114 114 """ Overridden to handle rich data types, like SVG.
115 115 """
116 116 if not self._hidden and self._is_from_this_session(msg):
117 self.flush_clearoutput()
117 118 content = msg['content']
118 119 prompt_number = content.get('execution_count', 0)
119 120 data = content['data']
@@ -140,6 +141,7 b' class RichIPythonWidget(IPythonWidget):'
140 141 """ Overridden to handle rich data types, like SVG.
141 142 """
142 143 if not self._hidden and self._is_from_this_session(msg):
144 self.flush_clearoutput()
143 145 source = msg['content']['source']
144 146 data = msg['content']['data']
145 147 metadata = msg['content']['metadata']
@@ -43,6 +43,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
43 43 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
44 44 _executing = False
45 45 _execution_state = Unicode('')
46 _pending_clearoutput = False
46 47 kernel_timeout = Float(60, config=True,
47 48 help="""Timeout for giving up on a kernel (in seconds).
48 49
@@ -241,13 +242,22 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
241 242 self._execution_state = sub_msg["content"]["execution_state"]
242 243 elif msg_type == 'stream':
243 244 if sub_msg["content"]["name"] == "stdout":
245 if self._pending_clearoutput:
246 print("\r", file=io.stdout, end="")
247 self._pending_clearoutput = False
244 248 print(sub_msg["content"]["data"], file=io.stdout, end="")
245 249 io.stdout.flush()
246 250 elif sub_msg["content"]["name"] == "stderr" :
251 if self._pending_clearoutput:
252 print("\r", file=io.stderr, end="")
253 self._pending_clearoutput = False
247 254 print(sub_msg["content"]["data"], file=io.stderr, end="")
248 255 io.stderr.flush()
249 256
250 257 elif msg_type == 'pyout':
258 if self._pending_clearoutput:
259 print("\r", file=io.stdout, end="")
260 self._pending_clearoutput = False
251 261 self.execution_count = int(sub_msg["content"]["execution_count"])
252 262 format_dict = sub_msg["content"]["data"]
253 263 self.handle_rich_data(format_dict)
@@ -267,6 +277,12 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
267 277 if 'text/plain' in data:
268 278 print(data['text/plain'])
269 279
280 elif msg_type == 'clear_output':
281 if sub_msg["content"]["wait"]:
282 self._pending_clearoutput = True
283 else:
284 print("\r", file=io.stdout, end="")
285
270 286 _imagemime = {
271 287 'image/png': 'png',
272 288 'image/jpeg': 'jpeg',
General Comments 0
You need to be logged in to leave comments. Login now