From 4c3d90d91a93875c9da7d9e24b4811cddaadf7c3 Mon Sep 17 00:00:00 2001 From: adroitwhiz <adroitwhiz@protonmail.com> Date: Sun, 17 May 2020 01:23:42 -0400 Subject: [PATCH 1/2] Don't move shadow blocks into the top level --- src/engine/blocks.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 189a595be..ed174b4c0 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -728,7 +728,12 @@ class Blocks { // Is this block a top-level block? if (typeof e.newParent === 'undefined') { - this._addScript(e.id); + // When you plug a block into a shadowed input, Blockly will move the shadow block into the top level before + // deleting it. Because we don't delete shadows here, instead keeping them on our blocks, the corresponding + // "delete" event will be ignored and the shadow would otherwise be added into the top level. + // TODO: Blockly inputs' connections keep their own copies of shadow blocks stashed away too. + // We should probably use those instead of duplicating the shadow-saving behavior. + if (!this._blocks[e.id].shadow) this._addScript(e.id); } else { // Remove script, if one exists. this._deleteScript(e.id); From da1f627185f341748078563c313b7f1222dd4cd2 Mon Sep 17 00:00:00 2001 From: adroitwhiz <adroitwhiz@protonmail.com> Date: Sun, 17 May 2020 02:00:17 -0400 Subject: [PATCH 2/2] Add "dropping blocks in shadowed inputs" unit test --- test/unit/engine_blocks.js | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/test/unit/engine_blocks.js b/test/unit/engine_blocks.js index 7fdaafc73..101fbc14b 100644 --- a/test/unit/engine_blocks.js +++ b/test/unit/engine_blocks.js @@ -599,6 +599,98 @@ test('delete inputs', t => { t.end(); }); +test('drop block into shadowed input', t => { + const b = new Blocks(new Runtime()); + b.createBlock({ + id: 'foo', + opcode: 'motion_movesteps', + inputs: { + STEPS: { + name: 'STEPS', + block: 'shadow', + shadow: 'shadow' + } + }, + topLevel: true + }); + b.createBlock({ + id: 'shadow', + opcode: 'math_number', + inputs: {}, + fields: { + NUM: { + name: 'NUM', + value: '25' + } + }, + shadow: true, + topLevel: false + }); + + b.createBlock({ + id: 'reporter', + opcode: 'looks_size', + inputs: {}, + fields: {}, + topLevel: true + }); + + // Mimic the series of events emitted by Blockly when you move a block into a shadowed input + + // 1. Move the shadow block to the top level + b.moveBlock({ + id: 'shadow', + oldParent: 'foo', + newParent: undefined + }); + + // 2: Delete the shadow block + b.deleteBlock('shadow'); + + // 3: Move the new block into the input + b.moveBlock({ + id: 'reporter', + newParent: 'foo' + }); + + t.equals(b._scripts.indexOf('shadow'), -1, 'replaced shadow blocks should not be moved to the top level'); + t.equals(b._scripts.length, 1); + + // Now mimic the series of events when you move the block out of the shadowed input + + // 1. Move the block back out of the shadowed input + b.moveBlock({ + id: 'reporter', + oldParent: 'foo', + newParent: undefined + }); + + // 2. Re-create the shadow block + b.createBlock({ + id: 'shadow', + opcode: 'math_number', + inputs: {}, + fields: { + NUM: { + name: 'NUM', + value: '25' + } + }, + shadow: true, + topLevel: false + }); + + // 3. Move the shadow block into the input + b.moveBlock({ + id: 'shadow', + newParent: 'foo' + }); + + t.equals(b._scripts.indexOf('shadow'), -1, 're-created shadow blocks should not be moved to the top level'); + t.equals(b._scripts.length, 2); + t.end(); +}); + test('updateAssetName function updates name in sound field', t => { const b = new Blocks(new Runtime()); b.createBlock({