##// 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 return json;
269 return json;
270 };
270 };
271
271
272 OutputArea.prototype.append_output = function (json) {
272 OutputArea.prototype.append_output = function (json) {
273 this.expand();
273 this.expand();
274
275 // validate output data types
276 json = this.validate_output(json);
277
274 // Clear the output if clear is queued.
278 // Clear the output if clear is queued.
275 var needs_height_reset = false;
279 var needs_height_reset = false;
276 if (this.clear_queued) {
280 if (this.clear_queued) {
277 this.clear_output(false);
281 this.clear_output(false);
278 needs_height_reset = true;
282 needs_height_reset = true;
279 }
283 }
280
281 // validate output data types
282 json = this.validate_output(json);
283
284
284 if (json.output_type === 'pyout') {
285 if (json.output_type === 'pyout') {
285 this.append_pyout(json);
286 this.append_pyout(json);
286 } else if (json.output_type === 'pyerr') {
287 } else if (json.output_type === 'pyerr') {
287 this.append_pyerr(json);
288 this.append_pyerr(json);
288 } else if (json.output_type === 'display_data') {
289 this.append_display_data(json);
290 } else if (json.output_type === 'stream') {
289 } else if (json.output_type === 'stream') {
291 this.append_stream(json);
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 var that = this;
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 var toinsert = this.create_output_area();
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 this._safe_append(toinsert);
489 this._safe_append(toinsert);
482 // If we just output latex, typeset it.
490 // If we just output latex, typeset it.
483 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
491 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
@@ -494,7 +502,7 b' var IPython = (function (IPython) {'
494 'image/jpeg' : true
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 for (var type_i in OutputArea.display_order) {
506 for (var type_i in OutputArea.display_order) {
499 var type = OutputArea.display_order[type_i];
507 var type = OutputArea.display_order[type_i];
500 var append = OutputArea.append_map[type];
508 var append = OutputArea.append_map[type];
@@ -511,7 +519,14 b' var IPython = (function (IPython) {'
511 }
519 }
512 }
520 }
513 var md = json.metadata || {};
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 $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]);
530 $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]);
516 return toinsert;
531 return toinsert;
517 }
532 }
@@ -611,10 +626,16 b' var IPython = (function (IPython) {'
611 if (width !== undefined) img.attr('width', width);
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 var type = 'image/png';
630 var type = 'image/png';
616 var toinsert = this.create_output_subarea(md, "output_png", type);
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 set_width_height(img, md, 'image/png');
639 set_width_height(img, md, 'image/png');
619 this._dblclick_to_reset_size(img);
640 this._dblclick_to_reset_size(img);
620 toinsert.append(img);
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 var type = 'image/jpeg';
648 var type = 'image/jpeg';
628 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
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 set_width_height(img, md, 'image/jpeg');
657 set_width_height(img, md, 'image/jpeg');
631 this._dblclick_to_reset_size(img);
658 this._dblclick_to_reset_size(img);
632 toinsert.append(img);
659 toinsert.append(img);
@@ -748,7 +775,10 b' var IPython = (function (IPython) {'
748 this.clear_queued = false;
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 this.element.html("");
782 this.element.html("");
753 this.outputs = [];
783 this.outputs = [];
754 this.trusted = true;
784 this.trusted = true;
@@ -90,11 +90,7 b' class ZMQDisplayPublisher(DisplayPublisher):'
90
90
91 def clear_output(self, wait=False):
91 def clear_output(self, wait=False):
92 content = dict(wait=wait)
92 content = dict(wait=wait)
93
94 print('\r', file=sys.stdout, end='')
95 print('\r', file=sys.stderr, end='')
96 self._flush_streams()
93 self._flush_streams()
97
98 self.session.send(
94 self.session.send(
99 self.pub_socket, u'clear_output', content,
95 self.pub_socket, u'clear_output', content,
100 parent=self.parent_header, ident=self.topic,
96 parent=self.parent_header, ident=self.topic,
@@ -197,6 +197,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
197 self._local_kernel = kw.get('local_kernel',
197 self._local_kernel = kw.get('local_kernel',
198 FrontendWidget._local_kernel)
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 # 'ConsoleWidget' public interface
204 # 'ConsoleWidget' public interface
202 #---------------------------------------------------------------------------
205 #---------------------------------------------------------------------------
@@ -339,6 +342,14 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
339 #---------------------------------------------------------------------------
342 #---------------------------------------------------------------------------
340 # 'BaseFrontendMixin' abstract interface
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 def _handle_complete_reply(self, rep):
354 def _handle_complete_reply(self, rep):
344 """ Handle replies for tab completion.
355 """ Handle replies for tab completion.
@@ -520,6 +531,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
520 """
531 """
521 self.log.debug("pyout: %s", msg.get('content', ''))
532 self.log.debug("pyout: %s", msg.get('content', ''))
522 if not self._hidden and self._is_from_this_session(msg):
533 if not self._hidden and self._is_from_this_session(msg):
534 self.flush_clearoutput()
523 text = msg['content']['data']
535 text = msg['content']['data']
524 self._append_plain_text(text + '\n', before_prompt=True)
536 self._append_plain_text(text + '\n', before_prompt=True)
525
537
@@ -528,13 +540,8 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
528 """
540 """
529 self.log.debug("stream: %s", msg.get('content', ''))
541 self.log.debug("stream: %s", msg.get('content', ''))
530 if not self._hidden and self._is_from_this_session(msg):
542 if not self._hidden and self._is_from_this_session(msg):
531 # Most consoles treat tabs as being 8 space characters. Convert tabs
543 self.flush_clearoutput()
532 # to spaces so that output looks as expected regardless of this
544 self.append_stream(msg['content']['data'])
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)
538
545
539 def _handle_shutdown_reply(self, msg):
546 def _handle_shutdown_reply(self, msg):
540 """ Handle shutdown signal, only if from other console.
547 """ Handle shutdown signal, only if from other console.
@@ -685,6 +692,29 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
685 before_prompt=True
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 # 'FrontendWidget' protected interface
719 # 'FrontendWidget' protected interface
690 #---------------------------------------------------------------------------
720 #---------------------------------------------------------------------------
@@ -140,7 +140,6 b' class IPythonWidget(FrontendWidget):'
140 #---------------------------------------------------------------------------
140 #---------------------------------------------------------------------------
141 # 'BaseFrontendMixin' abstract interface
141 # 'BaseFrontendMixin' abstract interface
142 #---------------------------------------------------------------------------
142 #---------------------------------------------------------------------------
143
144 def _handle_complete_reply(self, rep):
143 def _handle_complete_reply(self, rep):
145 """ Reimplemented to support IPython's improved completion machinery.
144 """ Reimplemented to support IPython's improved completion machinery.
146 """
145 """
@@ -223,6 +222,7 b' class IPythonWidget(FrontendWidget):'
223 """
222 """
224 self.log.debug("pyout: %s", msg.get('content', ''))
223 self.log.debug("pyout: %s", msg.get('content', ''))
225 if not self._hidden and self._is_from_this_session(msg):
224 if not self._hidden and self._is_from_this_session(msg):
225 self.flush_clearoutput()
226 content = msg['content']
226 content = msg['content']
227 prompt_number = content.get('execution_count', 0)
227 prompt_number = content.get('execution_count', 0)
228 data = content['data']
228 data = content['data']
@@ -250,6 +250,7 b' class IPythonWidget(FrontendWidget):'
250 # eventually will as this allows all frontends to monitor the display
250 # eventually will as this allows all frontends to monitor the display
251 # data. But we need to figure out how to handle this in the GUI.
251 # data. But we need to figure out how to handle this in the GUI.
252 if not self._hidden and self._is_from_this_session(msg):
252 if not self._hidden and self._is_from_this_session(msg):
253 self.flush_clearoutput()
253 source = msg['content']['source']
254 source = msg['content']['source']
254 data = msg['content']['data']
255 data = msg['content']['data']
255 metadata = msg['content']['metadata']
256 metadata = msg['content']['metadata']
@@ -114,6 +114,7 b' class RichIPythonWidget(IPythonWidget):'
114 """ Overridden to handle rich data types, like SVG.
114 """ Overridden to handle rich data types, like SVG.
115 """
115 """
116 if not self._hidden and self._is_from_this_session(msg):
116 if not self._hidden and self._is_from_this_session(msg):
117 self.flush_clearoutput()
117 content = msg['content']
118 content = msg['content']
118 prompt_number = content.get('execution_count', 0)
119 prompt_number = content.get('execution_count', 0)
119 data = content['data']
120 data = content['data']
@@ -140,6 +141,7 b' class RichIPythonWidget(IPythonWidget):'
140 """ Overridden to handle rich data types, like SVG.
141 """ Overridden to handle rich data types, like SVG.
141 """
142 """
142 if not self._hidden and self._is_from_this_session(msg):
143 if not self._hidden and self._is_from_this_session(msg):
144 self.flush_clearoutput()
143 source = msg['content']['source']
145 source = msg['content']['source']
144 data = msg['content']['data']
146 data = msg['content']['data']
145 metadata = msg['content']['metadata']
147 metadata = msg['content']['metadata']
@@ -43,6 +43,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
43 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
43 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
44 _executing = False
44 _executing = False
45 _execution_state = Unicode('')
45 _execution_state = Unicode('')
46 _pending_clearoutput = False
46 kernel_timeout = Float(60, config=True,
47 kernel_timeout = Float(60, config=True,
47 help="""Timeout for giving up on a kernel (in seconds).
48 help="""Timeout for giving up on a kernel (in seconds).
48
49
@@ -241,13 +242,22 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
241 self._execution_state = sub_msg["content"]["execution_state"]
242 self._execution_state = sub_msg["content"]["execution_state"]
242 elif msg_type == 'stream':
243 elif msg_type == 'stream':
243 if sub_msg["content"]["name"] == "stdout":
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 print(sub_msg["content"]["data"], file=io.stdout, end="")
248 print(sub_msg["content"]["data"], file=io.stdout, end="")
245 io.stdout.flush()
249 io.stdout.flush()
246 elif sub_msg["content"]["name"] == "stderr" :
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 print(sub_msg["content"]["data"], file=io.stderr, end="")
254 print(sub_msg["content"]["data"], file=io.stderr, end="")
248 io.stderr.flush()
255 io.stderr.flush()
249
256
250 elif msg_type == 'pyout':
257 elif msg_type == 'pyout':
258 if self._pending_clearoutput:
259 print("\r", file=io.stdout, end="")
260 self._pending_clearoutput = False
251 self.execution_count = int(sub_msg["content"]["execution_count"])
261 self.execution_count = int(sub_msg["content"]["execution_count"])
252 format_dict = sub_msg["content"]["data"]
262 format_dict = sub_msg["content"]["data"]
253 self.handle_rich_data(format_dict)
263 self.handle_rich_data(format_dict)
@@ -267,6 +277,12 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
267 if 'text/plain' in data:
277 if 'text/plain' in data:
268 print(data['text/plain'])
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 _imagemime = {
286 _imagemime = {
271 'image/png': 'png',
287 'image/png': 'png',
272 'image/jpeg': 'jpeg',
288 'image/jpeg': 'jpeg',
General Comments 0
You need to be logged in to leave comments. Login now