From 697f7a2365c52d1bafd590aa6ae65bb488b6da38 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Fri, 4 Dec 2020 12:36:42 -0800 Subject: [PATCH] Move where a non editable bubble is created (#4495) --- core/bubble.js | 54 +++++++++++++++++++++++++++++++++++++++++ core/comment.js | 13 +++++----- core/warning.js | 64 ++++++++----------------------------------------- 3 files changed, 70 insertions(+), 61 deletions(-) diff --git a/core/bubble.js b/core/bubble.js index 4fcda64e7..0cfd785e7 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -878,3 +878,57 @@ Blockly.Bubble.prototype.getRelativeToSurfaceXY = function() { Blockly.Bubble.prototype.setAutoLayout = function(enable) { this.autoLayout_ = enable; }; + +/** + * Create the text for a non editable bubble. + * @param {string} text The text to display. + * @return {!SVGTextElement} The top-level node of the text. + * @package + */ +Blockly.Bubble.textToDom = function(text) { + var paragraph = Blockly.utils.dom.createSvgElement( + Blockly.utils.Svg.TEXT, + { + 'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents', + 'y': Blockly.Bubble.BORDER_WIDTH + }, + null); + var lines = text.split('\n'); + for (var i = 0; i < lines.length; i++) { + var tspanElement = Blockly.utils.dom.createSvgElement( + Blockly.utils.Svg.TSPAN, + {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); + var textNode = document.createTextNode(lines[i]); + tspanElement.appendChild(textNode); + } + return paragraph; +}; + +/** + * Creates a bubble that can not be edited. + * @param {!SVGTextElement} paragraphElement The text element for the non editable bubble. + * @param {!Blockly.BlockSvg} block The block that the bubble is attached to. + * @param {!Blockly.utils.Coordinate} iconXY The coordinate of the icon. + * @return {!Blockly.Bubble} The non editable bubble. + * @package + */ +Blockly.Bubble.createNonEditableBubble = function(paragraphElement, block, iconXY) { + var bubble = new Blockly.Bubble( + /** @type {!Blockly.WorkspaceSvg} */ (block.workspace), + paragraphElement, block.pathObject.svgPath, + /** @type {!Blockly.utils.Coordinate} */ (iconXY), null, null); + // Expose this bubble's block's ID on its top-level SVG group. + bubble.setSvgId(block.id); + if (block.RTL) { + // Right-align the paragraph. + // This cannot be done until the bubble is rendered on screen. + var maxWidth = paragraphElement.getBBox().width; + for (var i = 0, textElement; + (textElement = paragraphElement.childNodes[i]); i++) { + + textElement.setAttribute('text-anchor', 'end'); + textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); + } + } + return bubble; +}; diff --git a/core/comment.js b/core/comment.js index a6288b4d0..59b2ac22c 100644 --- a/core/comment.js +++ b/core/comment.js @@ -251,7 +251,6 @@ Blockly.Comment.prototype.setVisible = function(visible) { */ Blockly.Comment.prototype.createBubble_ = function() { if (!this.block_.isEditable() || Blockly.utils.userAgent.IE) { - // Steal the code from warnings to make an uneditable text bubble. // MSIE does not support foreignobject; textareas are impossible. // https://docs.microsoft.com/en-us/openspecs/ie_standards/ms-svg/56e6e04c-7c8c-44dd-8100-bd745ee42034 // Always treat comments in IE as uneditable. @@ -284,7 +283,11 @@ Blockly.Comment.prototype.createEditableBubble_ = function() { */ Blockly.Comment.prototype.createNonEditableBubble_ = function() { // TODO (#2917): It would be great if the comment could support line breaks. - Blockly.Warning.prototype.createBubble.call(this); + this.paragraphElement_ = Blockly.Bubble.textToDom(this.block_.getCommentText()); + this.bubble_ = Blockly.Bubble.createNonEditableBubble( + this.paragraphElement_, /** @type {!Blockly.BlockSvg} */ (this.block_), + /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_)); + this.applyColour(); }; /** @@ -293,11 +296,6 @@ Blockly.Comment.prototype.createNonEditableBubble_ = function() { * @suppress {checkTypes} Suppress `this` type mismatch. */ Blockly.Comment.prototype.disposeBubble_ = function() { - if (this.paragraphElement_) { - // We're using the warning UI so we have to let it dispose. - Blockly.Warning.prototype.disposeBubble.call(this); - return; - } if (this.onMouseUpWrapper_) { Blockly.unbindEvent_(this.onMouseUpWrapper_); this.onMouseUpWrapper_ = null; @@ -318,6 +316,7 @@ Blockly.Comment.prototype.disposeBubble_ = function() { this.bubble_ = null; this.textarea_ = null; this.foreignObject_ = null; + this.paragraphElement_ = null; }; /** diff --git a/core/warning.js b/core/warning.js index 8a70fcbe9..07b3738fc 100644 --- a/core/warning.js +++ b/core/warning.js @@ -74,31 +74,6 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { group); }; -/** - * Create the text for the warning's bubble. - * @param {string} text The text to display. - * @return {!SVGTextElement} The top-level node of the text. - * @private - */ -Blockly.Warning.textToDom_ = function(text) { - var paragraph = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TEXT, - { - 'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents', - 'y': Blockly.Bubble.BORDER_WIDTH - }, - null); - var lines = text.split('\n'); - for (var i = 0; i < lines.length; i++) { - var tspanElement = Blockly.utils.dom.createSvgElement( - Blockly.utils.Svg.TSPAN, - {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); - var textNode = document.createTextNode(lines[i]); - tspanElement.appendChild(textNode); - } - return paragraph; -}; - /** * Show or hide the warning bubble. * @param {boolean} visible True if the bubble should be visible. @@ -110,50 +85,31 @@ Blockly.Warning.prototype.setVisible = function(visible) { Blockly.Events.fire( new Blockly.Events.BubbleOpen(this.block_, visible, 'warning')); if (visible) { - this.createBubble(); + this.createBubble_(); } else { - this.disposeBubble(); + this.disposeBubble_(); } }; /** * Show the bubble. - * @package + * @private */ -Blockly.Warning.prototype.createBubble = function() { - // TODO (#2943): This is package because comments steal this UI for - // non-editable comments, but really this should be private. - this.paragraphElement_ = Blockly.Warning.textToDom_(this.getText()); - this.bubble_ = new Blockly.Bubble( - /** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace), - this.paragraphElement_, this.block_.pathObject.svgPath, - /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_), null, null); - // Expose this warning's block's ID on its top-level SVG group. - this.bubble_.setSvgId(this.block_.id); - if (this.block_.RTL) { - // Right-align the paragraph. - // This cannot be done until the bubble is rendered on screen. - var maxWidth = this.paragraphElement_.getBBox().width; - for (var i = 0, textElement; - (textElement = this.paragraphElement_.childNodes[i]); i++) { - - textElement.setAttribute('text-anchor', 'end'); - textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); - } - } +Blockly.Warning.prototype.createBubble_ = function() { + this.paragraphElement_ = Blockly.Bubble.textToDom(this.getText()); + this.bubble_ = Blockly.Bubble.createNonEditableBubble( + this.paragraphElement_, /** @type {!Blockly.BlockSvg} */ (this.block_), + /** @type {!Blockly.utils.Coordinate} */ (this.iconXY_)); this.applyColour(); }; /** * Dispose of the bubble and references to it. - * @package + * @private */ -Blockly.Warning.prototype.disposeBubble = function() { - // TODO (#2943): This is package because comments steal this UI for - // non-editable comments, but really this should be private. +Blockly.Warning.prototype.disposeBubble_ = function() { this.bubble_.dispose(); this.bubble_ = null; - this.body_ = null; this.paragraphElement_ = null; };