diff --git a/HISTORY.md b/HISTORY.md index 6640e725..e8eb62df 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -14,6 +14,9 @@ * **Translation Updates:** * Russian, thanks, Pavel! +### 2020-10-22 +* fixed UNDO/REDO for "extracted" (single) command blocks + ### 2020-10-21 * gui: wait until all costumes have loaded before auto-triggering the green-flag event * gui, objects, store: wait until all sounds have loaded before auto-triggering the green-flag event diff --git a/snap.html b/snap.html index 7581c769..5830fc51 100755 --- a/snap.html +++ b/snap.html @@ -8,7 +8,7 @@ - + diff --git a/src/blocks.js b/src/blocks.js index 61868c3d..5098c9ac 100644 --- a/src/blocks.js +++ b/src/blocks.js @@ -158,7 +158,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2020-October-21'; +modules.blocks = '2020-October-22'; var SyntaxElementMorph; var BlockMorph; @@ -4751,6 +4751,10 @@ BlockMorph.prototype.reactToDropOf = function (droppedMorph) { BlockMorph.prototype.situation = function () { // answer a dictionary specifying where I am right now, so // I can slide back to it if I'm dropped somewhere else + // NOTE: We can also add more key-value pairs to the situation + // dictionary to support non-standard modes of user-interaction, + // such as extracting single commands from within a stack + // see recordDrop() and userExtractJustThis() if (!(this.parent instanceof TemplateSlotMorph)) { var scripts = this.parentThatIsA(ScriptsMorph); if (scripts) { @@ -5326,6 +5330,7 @@ CommandBlockMorph.prototype.userExtractJustThis = function () { parent = this.parentThatIsA(SyntaxElementMorph), cslot = this.parentThatIsA(CSlotMorph, RingReporterSlotMorph); + situation.action = "extract"; // record how this block was retrieved this.topBlock().fullChanged(); if (this.parent) { pb = this.parent.parentThatIsA(CommandBlockMorph); @@ -5363,6 +5368,51 @@ CommandBlockMorph.prototype.userExtractJustThis = function () { this.parent.grabOrigin = situation; }; +CommandBlockMorph.prototype.extract = function () { + // extract just this one block, reattach next block to the previous one, + var scripts = this.parentThatIsA(ScriptsMorph), + ide = this.parentThatIsA(IDE_Morph), + cs = this.parentThatIsA(CommandSlotMorph, RingReporterSlotMorph), + pb, + nb = this.nextBlock(), + above, + parent = this.parentThatIsA(SyntaxElementMorph), + cslot = this.parentThatIsA(CSlotMorph, RingReporterSlotMorph); + + this.topBlock().fullChanged(); + if (this.parent) { + pb = this.parent.parentThatIsA(CommandBlockMorph); + } + if (pb && (pb.nextBlock() === this)) { + above = pb; + } else if (cs && (cs.nestedBlock() === this)) { + above = cs; + this.prepareToBeGrabbed(); // restore ring reporter slot, if any + } + if (ide) { + // also stop all active processes hatted by this block + ide.removeBlock(this, true); // just this block + } else { + this.destroy(true); // just this block + } + if (nb) { + if (above instanceof CommandSlotMorph || + above instanceof RingReporterSlotMorph + ) { + above.nestedBlock(nb); + } else if (above instanceof CommandBlockMorph) { + above.nextBlock(nb); + } else { + scripts.add(nb); + } + } else if (cslot) { + cslot.fixLayout(); + } + if (parent) { + parent.reactToGrabOf(this); // fix highlight + } +}; + // CommandBlockMorph drawing: CommandBlockMorph.prototype.outlinePath = function(ctx, inset) { @@ -7379,6 +7429,9 @@ ScriptsMorph.prototype.redrop = function () { this.updateToolbar(); } else { this.isAnimating = true; + if (this.dropRecord.action === 'extract') { + this.dropRecord.lastDroppedBlock.extract(); + } this.dropRecord.lastDroppedBlock.slideBackTo( this.dropRecord.situation, null, @@ -7544,7 +7597,10 @@ ScriptsMorph.prototype.recordDrop = function (lastGrabOrigin) { lastNextBlock: this.lastNextBlock, lastWrapParent: this.lastWrapParent, lastOrigin: lastGrabOrigin, - action: null, + + // for special gestures, e.g. deleting or extracting single commands: + action: lastGrabOrigin ? lastGrabOrigin.action || null : null, + situation: null, lastRecord: this.dropRecord, nextRecord: null