diff --git a/HISTORY.md b/HISTORY.md index 68fc14e5..cfd53967 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -50,6 +50,7 @@ ### 2022-05-017 * blocks: added experimental private isChangeableTo(type) method +* blocks, threads: tweaked programmatic blocks-changing ### 2022-05-06 * threads: include currently dragged sprites in the MY OTHER SPRITES/CLONES lists diff --git a/snap.html b/snap.html index 14f354ea..eb514ffd 100755 --- a/snap.html +++ b/snap.html @@ -17,7 +17,7 @@ - + diff --git a/src/blocks.js b/src/blocks.js index 50d453a2..0ac0c9d2 100644 --- a/src/blocks.js +++ b/src/blocks.js @@ -3577,28 +3577,19 @@ BlockMorph.prototype.isChangeableTo = function (type) { // a block is considered "changeable" if // ------------------------------------- // * it's a command & the target type isn't also a command & doesn't have a - // next block & its parent also isn't a syntax element (block or C-shaped - // slot), except it can be a ring. + // next block & is unattached (e.g. the only expression inside a context). // - // * it's a reporter or a predicate & the target type is a command & its - // parent is not a block, except it can be a ring. + // * it's a reporter or a predicate & the target type is a command & is + // unattached (e.g. the only expression inside a function context). // // * it's a reporter or a predicate & the target type is also a reporter or // a predicate the type can always be changed var typ = this.type(); if (typ === type) {return true; } - if (typ === 'command') { - if (this.nextBlock()) {return false; } - if (this.parent instanceof RingMorph) {return true; } - return !(this.parent instanceof SyntaxElementMorph); + if (typ === 'command' || type === 'command') { + return this.isUnattached(); } - // typ is 'reporter' or 'predicate' - if (type === 'command') { - if (this.parent instanceof RingMorph) {return true; } - return !(this.parent instanceof BlockMorph); - } - // type is 'reporter' or 'predicate' return true; }; @@ -3608,6 +3599,13 @@ BlockMorph.prototype.type = function () { : (this.isPredicate ? 'predicate' : 'reporter'); }; +BlockMorph.prototype.isUnattached = function () { + // private + return ((this.nextBlock && !this.nextBlock()) || !this.nextBlock) && + !(this.parent instanceof SyntaxElementMorph) && + !(this.parent instanceof ScriptsMorph) +}; + BlockMorph.prototype.isInheritedVariable = function (shadowedOnly) { // private - only for variable getter template inside the palette if (this.isTemplate && diff --git a/src/threads.js b/src/threads.js index 6a26bedc..e1df3c62 100644 --- a/src/threads.js +++ b/src/threads.js @@ -65,7 +65,7 @@ StagePickerMorph, CustomBlockDefinition*/ /*jshint esversion: 11, bitwise: false, evil: true*/ -modules.threads = '2022-May-06'; +modules.threads = '2022-May-17'; var ThreadManager; var Process; @@ -5687,9 +5687,6 @@ Process.prototype.doSetBlockAttribute = function (attribute, block, val) { 'other'; break; case 'type': - if (isInUse()) { - throw new Error('cannot change this\nfor a block that is in use'); - } this.assertType(val, ['number', 'text']); if (this.reportTypeOf(val) === 'text') { type = val; @@ -5697,7 +5694,14 @@ Process.prototype.doSetBlockAttribute = function (attribute, block, val) { type = types[val - 1] || ''; } if (!types.includes(type)) {return;} - def.type = type; + + if (rcvr.allBlockInstances(def).every(block => + block.isChangeableTo(type)) + ) { + def.type = type; + } else { + throw new Error('cannot change this\nfor a block that is in use'); + } break; case 'scope': if (isInUse()) {