diff --git a/core/block_svg.ts b/core/block_svg.ts index 10fa995ff..8e016efb3 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -507,6 +507,21 @@ export class BlockSvg this.updateCollapsed(); } + /** + * Traverses child blocks to see if any of them have a warning. + * + * @returns true if any child has a warning, false otherwise. + */ + private childHasWarning(): boolean { + const children = this.getChildren(false); + for (const child of children) { + if (child.getIcon(WarningIcon.TYPE) || child.childHasWarning()) { + return true; + } + } + return false; + } + /** * Makes sure that when the block is collapsed, it is rendered correctly * for that state. @@ -529,9 +544,17 @@ export class BlockSvg if (!collapsed) { this.updateDisabled(); this.removeInput(collapsedInputName); + this.setWarningText(null, BlockSvg.COLLAPSED_WARNING_ID); return; } + if (this.childHasWarning()) { + this.setWarningText( + Msg['COLLAPSED_WARNINGS_WARNING'], + BlockSvg.COLLAPSED_WARNING_ID, + ); + } + const text = this.toString(internalConstants.COLLAPSE_CHARS); const field = this.getField(collapsedFieldName); if (field) { diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index a489fb3e3..ce9036cc4 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -1840,6 +1840,62 @@ suite('Blocks', function () { }); }); + suite('Warning icons and collapsing', function () { + setup(function () { + this.workspace = Blockly.inject('blocklyDiv'); + this.parentBlock = Blockly.serialization.blocks.append( + { + 'type': 'statement_block', + 'inputs': { + 'STATEMENT': { + 'block': { + 'type': 'statement_block', + }, + }, + }, + }, + this.workspace, + ); + this.parentBlock.initSvg(); + this.parentBlock.render(); + + this.childBlock = this.parentBlock.getInputTargetBlock('STATEMENT'); + this.childBlock.initSvg(); + this.childBlock.render(); + }); + + teardown(function () { + workspaceTeardown.call(this, this.workspace); + }); + + test('Adding a warning to a child block does not affect the parent', function () { + const text = 'Warning Text'; + this.childBlock.setWarningText(text); + const icon = this.parentBlock.getIcon(Blockly.icons.WarningIcon.TYPE); + assert.isUndefined( + icon, + "Setting a child block's warning should not add a warning to the parent", + ); + }); + + test('Warnings are added and removed when collapsing a stack with warnings', function () { + const text = 'Warning Text'; + + this.childBlock.setWarningText(text); + + this.parentBlock.setCollapsed(true); + let icon = this.parentBlock.getIcon(Blockly.icons.WarningIcon.TYPE); + assert.exists(icon?.getText(), 'Expected warning icon text to be set'); + + this.parentBlock.setCollapsed(false); + icon = this.parentBlock.getIcon(Blockly.icons.WarningIcon.TYPE); + assert.isUndefined( + icon, + 'Warning should be removed from parent after expanding', + ); + }); + }); + suite('Bubbles and collapsing', function () { setup(function () { this.workspace = Blockly.inject('blocklyDiv');