let clones share the orginal’s scripts without shallow-copying them

upd4.1
Jens Mönig 2017-05-30 17:07:09 +02:00
rodzic cc47a6fb5a
commit eea1d08c82
6 zmienionych plików z 228 dodań i 181 usunięć

160
blocks.js
Wyświetl plik

@ -150,7 +150,7 @@ CustomCommandBlockMorph*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2017-May-12'; modules.blocks = '2017-May-30';
var SyntaxElementMorph; var SyntaxElementMorph;
var BlockMorph; var BlockMorph;
@ -570,7 +570,7 @@ SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) {
deflt = this.labelPart(this.parseSpec(this.blockSpec)[idx]); deflt = this.labelPart(this.parseSpec(this.blockSpec)[idx]);
if (this.isCustomBlock) { if (this.isCustomBlock) {
def = this.isGlobal ? this.definition def = this.isGlobal ? this.definition
: this.receiver().getMethod(this.blockSpec); : this.scriptTarget().getMethod(this.blockSpec);
if (deflt instanceof InputSlotMorph) { if (deflt instanceof InputSlotMorph) {
deflt.setChoices.apply( deflt.setChoices.apply(
deflt, deflt,
@ -636,7 +636,7 @@ SyntaxElementMorph.prototype.getVarNamesDict = function () {
if (!block) { if (!block) {
return {}; return {};
} }
rcvr = block.receiver(); rcvr = block.scriptTarget();
block.allParents().forEach(function (morph) { block.allParents().forEach(function (morph) {
if (morph instanceof PrototypeHatBlockMorph) { if (morph instanceof PrototypeHatBlockMorph) {
tempVars.push.apply( tempVars.push.apply(
@ -1546,7 +1546,7 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
// has issues when loading costumes (asynchronously) // has issues when loading costumes (asynchronously)
// commented out for now // commented out for now
var rcvr = this.definition.receiver || this.receiver(), var rcvr = this.definition.receiver || this.scriptTarget(),
id = spec.slice(1), id = spec.slice(1),
cst; cst;
if (!rcvr) {return this.labelPart('%stop'); } if (!rcvr) {return this.labelPart('%stop'); }
@ -1888,7 +1888,7 @@ SyntaxElementMorph.prototype.showBubble = function (value, exportPic) {
if ((value === undefined) || !wrrld || !this.receiver) { if ((value === undefined) || !wrrld || !this.receiver) {
return null; return null;
} }
rcvr = this.receiver(); rcvr = this.scriptTarget();
if (value instanceof ListWatcherMorph) { if (value instanceof ListWatcherMorph) {
morphToShow = value; morphToShow = value;
morphToShow.update(true); morphToShow.update(true);
@ -2053,7 +2053,7 @@ SyntaxElementMorph.prototype.endLayout = function () {
accessors are: accessors are:
selector - (string) name of method to be triggered selector - (string) name of method to be triggered
receiver() - answer the object (sprite) to which I apply scriptTarget() - answer the object (sprite) to which I apply
inputs() - answer an array with my arg slots and nested reporters inputs() - answer an array with my arg slots and nested reporters
defaults - an optional Array containing default input values defaults - an optional Array containing default input values
topBlock() - answer the top block of the stack I'm attached to topBlock() - answer the top block of the stack I'm attached to
@ -2204,16 +2204,23 @@ BlockMorph.prototype.init = function (silently) {
this.cachedInputs = null; this.cachedInputs = null;
}; };
BlockMorph.prototype.receiver = function () { BlockMorph.prototype.scriptTarget = function () {
// answer the object to which I apply (whose method I represent) // answer the sprite or stage that this block acts on,
var up = this.parent; // if the user clicks on it.
while (!!up) { // NOTE: since scripts can be shared by more than a single sprite
if (up.owner) { // this method only gives the desired result within the context of
return up.owner; // the user actively clicking on a block inside the IDE
} // there is no direct relationship between a block and a sprite.
up = up.parent; var scripts = this.parentThatIsA(ScriptsMorph),
ide;
if (scripts) {
return scripts.scriptTarget();
} }
return null; ide = this.parentThatIsA(IDE_Morph);
if (ide) {
return ide.currentSprite;
}
throw new Error('script target cannot be found for orphaned block');
}; };
BlockMorph.prototype.toString = function () { BlockMorph.prototype.toString = function () {
@ -2461,7 +2468,7 @@ BlockMorph.prototype.userMenu = function () {
// allow toggling inheritable attributes // allow toggling inheritable attributes
if (StageMorph.prototype.enableInheritance) { if (StageMorph.prototype.enableInheritance) {
rcvr = this.receiver(); rcvr = this.scriptTarget();
field = { field = {
xPosition: 'x position', xPosition: 'x position',
yPosition: 'y position', yPosition: 'y position',
@ -2695,7 +2702,7 @@ BlockMorph.prototype.isInheritedVariable = function () {
(this.selector === 'reportGetVar') && (this.selector === 'reportGetVar') &&
(this.parent instanceof FrameMorph)) { (this.parent instanceof FrameMorph)) {
return contains( return contains(
this.receiver().inheritedVariableNames(), this.scriptTarget().inheritedVariableNames(),
this.blockSpec this.blockSpec
); );
} }
@ -2704,13 +2711,13 @@ BlockMorph.prototype.isInheritedVariable = function () {
BlockMorph.prototype.isTransientVariable = function () { BlockMorph.prototype.isTransientVariable = function () {
// private - only for variable getter template inside the palette // private - only for variable getter template inside the palette
var varFrame = this.receiver().variables.silentFind(this.blockSpec); var varFrame = this.scriptTarget().variables.silentFind(this.blockSpec);
return varFrame ? varFrame.vars[this.blockSpec].isTransient : false; return varFrame ? varFrame.vars[this.blockSpec].isTransient : false;
}; };
BlockMorph.prototype.toggleTransientVariable = function () { BlockMorph.prototype.toggleTransientVariable = function () {
// private - only for variable getter template inside the palette // private - only for variable getter template inside the palette
var varFrame = this.receiver().variables.silentFind(this.blockSpec); var varFrame = this.scriptTarget().variables.silentFind(this.blockSpec);
if (!varFrame) {return; } if (!varFrame) {return; }
varFrame.vars[this.blockSpec].isTransient = varFrame.vars[this.blockSpec].isTransient =
!(varFrame.vars[this.blockSpec].isTransient); !(varFrame.vars[this.blockSpec].isTransient);
@ -3212,7 +3219,7 @@ BlockMorph.prototype.refactorThisVar = function (justTheTemplate) {
var myself = this, var myself = this,
oldName = this.blockSpec, oldName = this.blockSpec,
receiver = this.receiver(), receiver = this.scriptTarget(),
ide = this.parentThatIsA(IDE_Morph), ide = this.parentThatIsA(IDE_Morph),
stage = ide.stage, stage = ide.stage,
oldWatcher = receiver.findVariableWatcher(oldName), oldWatcher = receiver.findVariableWatcher(oldName),
@ -3674,14 +3681,7 @@ BlockMorph.prototype.hasLabels = function () {
// BlockMorph copying // BlockMorph copying
BlockMorph.prototype.fullCopy = function (forClone) { BlockMorph.prototype.fullCopy = function () {
if (forClone) {
if (this.hasBlockVars()) {
forClone = false;
} else {
return copy(this);
}
}
var ans = BlockMorph.uber.fullCopy.call(this); var ans = BlockMorph.uber.fullCopy.call(this);
ans.removeHighlight(); ans.removeHighlight();
ans.isDraggable = true; ans.isDraggable = true;
@ -3721,7 +3721,7 @@ BlockMorph.prototype.hasBlockVars = function () {
BlockMorph.prototype.mouseClickLeft = function () { BlockMorph.prototype.mouseClickLeft = function () {
var top = this.topBlock(), var top = this.topBlock(),
receiver = top.receiver(), receiver = top.scriptTarget(),
shiftClicked = this.world().currentKey === 16, shiftClicked = this.world().currentKey === 16,
stage; stage;
if (shiftClicked && !this.isTemplate) { if (shiftClicked && !this.isTemplate) {
@ -3733,7 +3733,7 @@ BlockMorph.prototype.mouseClickLeft = function () {
if (receiver) { if (receiver) {
stage = receiver.parentThatIsA(StageMorph); stage = receiver.parentThatIsA(StageMorph);
if (stage) { if (stage) {
stage.threads.toggleProcess(top); stage.threads.toggleProcess(top, receiver);
} }
} }
}; };
@ -3755,7 +3755,7 @@ BlockMorph.prototype.focus = function () {
BlockMorph.prototype.activeProcess = function () { BlockMorph.prototype.activeProcess = function () {
var top = this.topBlock(), var top = this.topBlock(),
receiver = top.receiver(), receiver = top.scriptTarget(),
stage; stage;
if (top instanceof PrototypeHatBlockMorph) { if (top instanceof PrototypeHatBlockMorph) {
return null; return null;
@ -3763,7 +3763,7 @@ BlockMorph.prototype.activeProcess = function () {
if (receiver) { if (receiver) {
stage = receiver.parentThatIsA(StageMorph); stage = receiver.parentThatIsA(StageMorph);
if (stage) { if (stage) {
return stage.threads.findProcess(top); return stage.threads.findProcess(top, receiver);
} }
} }
return null; return null;
@ -3908,10 +3908,16 @@ BlockMorph.prototype.destroy = function (justThis) {
comment.destroy(); comment.destroy();
}); });
} }
/* +++ needs tweaking:
// stop active process(es) for this block
// for this we need access to the stage...
if ((!this.parent || !this.parent.topBlock) if ((!this.parent || !this.parent.topBlock)
&& this.activeProcess()) { && this.activeProcess()) {
this.activeProcess().stop(); this.activeProcess().stop();
} }
*/
BlockMorph.uber.destroy.call(this); BlockMorph.uber.destroy.call(this);
}; };
@ -3957,7 +3963,7 @@ BlockMorph.prototype.snap = function () {
} }
// register generic hat blocks // register generic hat blocks
if (this.selector === 'receiveCondition') { if (this.selector === 'receiveCondition') {
receiver = top.receiver(); receiver = top.scriptTarget();
if (receiver) { if (receiver) {
stage = receiver.parentThatIsA(StageMorph); stage = receiver.parentThatIsA(StageMorph);
if (stage) { if (stage) {
@ -5156,14 +5162,14 @@ ReporterBlockMorph.prototype.mouseClickLeft = function (pos) {
ReporterBlockMorph.prototype.exportResultPic = function () { ReporterBlockMorph.prototype.exportResultPic = function () {
var top = this.topBlock(), var top = this.topBlock(),
receiver = top.receiver(), receiver = top.scriptTarget(),
stage; stage;
if (top !== this) {return; } if (top !== this) {return; }
if (receiver) { if (receiver) {
stage = receiver.parentThatIsA(StageMorph); stage = receiver.parentThatIsA(StageMorph);
if (stage) { if (stage) {
stage.threads.stopProcess(top); stage.threads.stopProcess(top);
stage.threads.startProcess(top, false, true); stage.threads.startProcess(top, receiver, false, true);
} }
} }
}; };
@ -5711,12 +5717,11 @@ ScriptsMorph.prototype.enableNestedAutoWrapping = true;
// ScriptsMorph instance creation: // ScriptsMorph instance creation:
function ScriptsMorph(owner) { function ScriptsMorph() {
this.init(owner); this.init();
} }
ScriptsMorph.prototype.init = function (owner) { ScriptsMorph.prototype.init = function () {
this.owner = owner || null;
this.feedbackColor = SyntaxElementMorph.prototype.feedbackColor; this.feedbackColor = SyntaxElementMorph.prototype.feedbackColor;
this.feedbackMorph = new BoxMorph(); this.feedbackMorph = new BoxMorph();
this.rejectsHats = false; this.rejectsHats = false;
@ -5744,7 +5749,7 @@ ScriptsMorph.prototype.init = function (owner) {
// ScriptsMorph deep copying: // ScriptsMorph deep copying:
ScriptsMorph.prototype.fullCopy = function (forClone) { ScriptsMorph.prototype.fullCopy = function () {
var cpy = new ScriptsMorph(), var cpy = new ScriptsMorph(),
pos = this.position(), pos = this.position(),
child; child;
@ -5753,21 +5758,17 @@ ScriptsMorph.prototype.fullCopy = function (forClone) {
} }
this.children.forEach(function (morph) { this.children.forEach(function (morph) {
if (!morph.block) { // omit anchored comments if (!morph.block) { // omit anchored comments
child = morph.fullCopy(forClone); child = morph.fullCopy();
cpy.add(child); cpy.add(child);
if (!forClone) { child.setPosition(morph.position().subtract(pos));
child.setPosition(morph.position().subtract(pos)); if (child instanceof BlockMorph) {
if (child instanceof BlockMorph) { child.allComments().forEach(function (comment) {
child.allComments().forEach(function (comment) { comment.align(child);
comment.align(child); });
});
}
} }
} }
}); });
if (!forClone) { cpy.adjustBounds();
cpy.adjustBounds();
}
return cpy; return cpy;
}; };
@ -6073,7 +6074,7 @@ ScriptsMorph.prototype.userMenu = function () {
shiftClicked = this.world().currentKey === 16, shiftClicked = this.world().currentKey === 16,
blockEditor, blockEditor,
myself = this, myself = this,
obj = this.owner, obj = this.scriptTarget(),
hasUndropQueue, hasUndropQueue,
stage = obj.parentThatIsA(StageMorph); stage = obj.parentThatIsA(StageMorph);
@ -6594,6 +6595,28 @@ ScriptsMorph.prototype.edit = function (pos) {
this.focus.getFocus(world); this.focus.getFocus(world);
}; };
// ScriptsMorph context - scripts target
ScriptsMorph.prototype.scriptTarget = function () {
// answer the sprite or stage that this script editor acts on,
// if the user clicks on a block.
// NOTE: since scripts can be shared by more than a single sprite
// this method only gives the desired result within the context of
// the user actively clicking on a block inside the IDE
// there is no direct relationship between a block or a scripts editor
// and a sprite.
var editor = this.parentThatIsA(IDE_Morph);
if (editor) {
return editor.currentSprite;
}
editor = this.parentThatIsA(BlockEditorMorph);
if (editor) {
return editor.target.currentSprite;
}
throw new Error('script target bannot be found for orphaned scripts');
};
// ArgMorph ////////////////////////////////////////////////////////// // ArgMorph //////////////////////////////////////////////////////////
/* /*
@ -6644,7 +6667,7 @@ ArgMorph.prototype.reactToSliderEdit = function () {
block = this.parentThatIsA(BlockMorph); block = this.parentThatIsA(BlockMorph);
if (block) { if (block) {
top = block.topBlock(); top = block.topBlock();
receiver = top.receiver(); receiver = top.scriptTarget();
if (top instanceof PrototypeHatBlockMorph) { if (top instanceof PrototypeHatBlockMorph) {
return; return;
} }
@ -6652,7 +6675,7 @@ ArgMorph.prototype.reactToSliderEdit = function () {
stage = receiver.parentThatIsA(StageMorph); stage = receiver.parentThatIsA(StageMorph);
if (stage && (stage.isThreadSafe || if (stage && (stage.isThreadSafe ||
Process.prototype.enableSingleStepping)) { Process.prototype.enableSingleStepping)) {
stage.threads.startProcess(top, stage.isThreadSafe); stage.threads.startProcess(top, receiver, stage.isThreadSafe);
} else { } else {
top.mouseClickLeft(); top.mouseClickLeft();
} }
@ -7944,7 +7967,7 @@ InputSlotMorph.prototype.menuFromDict = function (choices, noEmptyOption) {
InputSlotMorph.prototype.messagesMenu = function () { InputSlotMorph.prototype.messagesMenu = function () {
var dict = {}, var dict = {},
rcvr = this.parentThatIsA(BlockMorph).receiver(), rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
myself = this, myself = this,
allNames = []; allNames = [];
@ -7977,7 +8000,7 @@ InputSlotMorph.prototype.messagesMenu = function () {
InputSlotMorph.prototype.messagesReceivedMenu = function () { InputSlotMorph.prototype.messagesReceivedMenu = function () {
var dict = {'any message': ['any message']}, var dict = {'any message': ['any message']},
rcvr = this.parentThatIsA(BlockMorph).receiver(), rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
myself = this, myself = this,
allNames = []; allNames = [];
@ -8012,7 +8035,7 @@ InputSlotMorph.prototype.collidablesMenu = function () {
edge : ['edge'], edge : ['edge'],
'pen trails' : ['pen trails'] 'pen trails' : ['pen trails']
}, },
rcvr = this.parentThatIsA(BlockMorph).receiver(), rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
allNames = []; allNames = [];
@ -8036,7 +8059,7 @@ InputSlotMorph.prototype.distancesMenu = function () {
var dict = { var dict = {
'mouse-pointer' : ['mouse-pointer'] 'mouse-pointer' : ['mouse-pointer']
}, },
rcvr = this.parentThatIsA(BlockMorph).receiver(), rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
allNames = []; allNames = [];
@ -8058,7 +8081,7 @@ InputSlotMorph.prototype.distancesMenu = function () {
InputSlotMorph.prototype.clonablesMenu = function () { InputSlotMorph.prototype.clonablesMenu = function () {
var dict = {}, var dict = {},
rcvr = this.parentThatIsA(BlockMorph).receiver(), rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
allNames = []; allNames = [];
@ -8080,7 +8103,7 @@ InputSlotMorph.prototype.clonablesMenu = function () {
}; };
InputSlotMorph.prototype.objectsMenu = function () { InputSlotMorph.prototype.objectsMenu = function () {
var rcvr = this.parentThatIsA(BlockMorph).receiver(), var rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
dict = {}, dict = {},
allNames = []; allNames = [];
@ -8146,7 +8169,7 @@ InputSlotMorph.prototype.gettablesMenu = function () {
InputSlotMorph.prototype.attributesMenu = function () { InputSlotMorph.prototype.attributesMenu = function () {
var block = this.parentThatIsA(BlockMorph), var block = this.parentThatIsA(BlockMorph),
objName = block.inputs()[1].evaluate(), objName = block.inputs()[1].evaluate(),
rcvr = block.receiver(), rcvr = block.scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
obj, obj,
dict = {}, dict = {},
@ -8196,7 +8219,7 @@ InputSlotMorph.prototype.attributesMenu = function () {
}; };
InputSlotMorph.prototype.costumesMenu = function () { InputSlotMorph.prototype.costumesMenu = function () {
var rcvr = this.parentThatIsA(BlockMorph).receiver(), var rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
dict, dict,
allNames = []; allNames = [];
if (rcvr instanceof SpriteMorph) { if (rcvr instanceof SpriteMorph) {
@ -8217,7 +8240,7 @@ InputSlotMorph.prototype.costumesMenu = function () {
}; };
InputSlotMorph.prototype.soundsMenu = function () { InputSlotMorph.prototype.soundsMenu = function () {
var rcvr = this.parentThatIsA(BlockMorph).receiver(), var rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
allNames = [], allNames = [],
dict = {}; dict = {};
@ -8257,7 +8280,7 @@ InputSlotMorph.prototype.shadowedVariablesMenu = function () {
dict = {}; dict = {};
if (!block) {return dict; } if (!block) {return dict; }
rcvr = block.receiver(); rcvr = block.scriptTarget();
if (rcvr && rcvr.exemplar) { if (rcvr && rcvr.exemplar) {
vars = rcvr.inheritedVariableNames(true); vars = rcvr.inheritedVariableNames(true);
vars.forEach(function (name) { vars.forEach(function (name) {
@ -13237,7 +13260,7 @@ ScriptFocusMorph.prototype.deleteLastElement = function () {
}; };
ScriptFocusMorph.prototype.insertBlock = function (block) { ScriptFocusMorph.prototype.insertBlock = function (block) {
var pb, stage, ide; var pb, stage, ide, rcvr;
block.isTemplate = false; block.isTemplate = false;
block.isDraggable = true; block.isDraggable = true;
@ -13303,8 +13326,9 @@ ScriptFocusMorph.prototype.insertBlock = function (block) {
// register generic hat blocks // register generic hat blocks
if (block.selector === 'receiveCondition') { if (block.selector === 'receiveCondition') {
if (this.editor.owner) { rcvr = this.editor.scriptTarget();
stage = this.editor.owner.parentThatIsA(StageMorph); if (rcvr) {
stage = rcvr.parentThatIsA(StageMorph);
if (stage) { if (stage) {
stage.enableCustomHatBlocks = true; stage.enableCustomHatBlocks = true;
stage.threads.pauseCustomHatBlocks = false; stage.threads.pauseCustomHatBlocks = false;
@ -13752,7 +13776,7 @@ ScriptFocusMorph.prototype.reactToKeyEvent = function (key) {
delete this.fps; delete this.fps;
delete this.step; delete this.step;
this.show(); this.show();
this.editor.owner.searchBlocks( this.editor.scriptTarget().searchBlocks(
key, key,
types, types,
vNames, vNames,

23
byob.js
Wyświetl plik

@ -108,7 +108,7 @@ BooleanSlotMorph, XML_Serializer*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.byob = '2017-April-10'; modules.byob = '2017-May-30';
// Declarations // Declarations
@ -799,7 +799,7 @@ CustomCommandBlockMorph.prototype.edit = function () {
); );
} else { } else {
// check for local custom block inheritance // check for local custom block inheritance
rcvr = this.receiver(); rcvr = this.scriptTarget();
if (!this.isGlobal) { if (!this.isGlobal) {
if (contains( if (contains(
Object.keys(rcvr.inheritedBlocks()), Object.keys(rcvr.inheritedBlocks()),
@ -860,8 +860,12 @@ CustomCommandBlockMorph.prototype.attachTargets = function () {
CustomCommandBlockMorph.prototype.isInUse = function () { CustomCommandBlockMorph.prototype.isInUse = function () {
// answer true if an instance of my definition is found // answer true if an instance of my definition is found
// in any of my receiver's scripts or block definitions // in any of my receiver's scripts or block definitions
// NOTE: for sprite-local blocks only to be used in a situation
// where the user actively clicks on a block in the IDE,
// e.g. to edit it (and change its type)
var def = this.definition, var def = this.definition,
ide = this.receiver().parentThatIsA(IDE_Morph); rcvr = this.scriptTarget(),
ide = rcvr.parentThatIsA(IDE_Morph);
if (def.isGlobal && ide) { if (def.isGlobal && ide) {
return ide.sprites.asArray().concat([ide.stage]).some( return ide.sprites.asArray().concat([ide.stage]).some(
function (any, idx) { function (any, idx) {
@ -869,15 +873,14 @@ CustomCommandBlockMorph.prototype.isInUse = function () {
} }
); );
} }
// return this.receiver().usesBlockInstance(def); return rcvr.allDependentInvocationsOf(this.blockSpec).length > 0;
return this.receiver().allDependentInvocationsOf(this.blockSpec).length > 0;
}; };
// CustomCommandBlockMorph menu: // CustomCommandBlockMorph menu:
CustomCommandBlockMorph.prototype.userMenu = function () { CustomCommandBlockMorph.prototype.userMenu = function () {
var hat = this.parentThatIsA(PrototypeHatBlockMorph), var hat = this.parentThatIsA(PrototypeHatBlockMorph),
rcvr = this.receiver(), rcvr = this.scriptTarget(),
myself = this, myself = this,
shiftClicked = this.world().currentKey === 16, shiftClicked = this.world().currentKey === 16,
menu; menu;
@ -999,7 +1002,7 @@ CustomCommandBlockMorph.prototype.exportBlockDefinition = function () {
}; };
CustomCommandBlockMorph.prototype.duplicateBlockDefinition = function () { CustomCommandBlockMorph.prototype.duplicateBlockDefinition = function () {
var rcvr = this.receiver(), var rcvr = this.scriptTarget(),
ide = this.parentThatIsA(IDE_Morph), ide = this.parentThatIsA(IDE_Morph),
def = this.isGlobal ? this.definition : rcvr.getMethod(this.blockSpec), def = this.isGlobal ? this.definition : rcvr.getMethod(this.blockSpec),
dup = def.copyAndBindTo(rcvr); dup = def.copyAndBindTo(rcvr);
@ -1015,7 +1018,7 @@ CustomCommandBlockMorph.prototype.duplicateBlockDefinition = function () {
CustomCommandBlockMorph.prototype.deleteBlockDefinition = function () { CustomCommandBlockMorph.prototype.deleteBlockDefinition = function () {
var idx, stage, ide, method, block, var idx, stage, ide, method, block,
rcvr = this.receiver(), rcvr = this.scriptTarget(),
myself = this; myself = this;
if (this.isPrototype) { if (this.isPrototype) {
return null; // under construction... return null; // under construction...
@ -1093,7 +1096,7 @@ CustomCommandBlockMorph.prototype.relabel = function (alternatives) {
}; };
CustomCommandBlockMorph.prototype.alternatives = function () { CustomCommandBlockMorph.prototype.alternatives = function () {
var rcvr = this.receiver(), var rcvr = this.scriptTarget(),
stage = rcvr.parentThatIsA(StageMorph), stage = rcvr.parentThatIsA(StageMorph),
allDefs = rcvr.customBlocks.concat(stage.globalBlocks), allDefs = rcvr.customBlocks.concat(stage.globalBlocks),
type = this instanceof CommandBlockMorph ? 'command' type = this instanceof CommandBlockMorph ? 'command'
@ -1894,7 +1897,7 @@ BlockEditorMorph.prototype.init = function (definition, target) {
this.createLabel(); this.createLabel();
// create scripting area // create scripting area
scripts = new ScriptsMorph(target); scripts = new ScriptsMorph();
scripts.rejectsHats = true; scripts.rejectsHats = true;
scripts.isDraggable = false; scripts.isDraggable = false;
scripts.color = IDE_Morph.prototype.groupColor; scripts.color = IDE_Morph.prototype.groupColor;

2
gui.js
Wyświetl plik

@ -74,7 +74,7 @@ isRetinaSupported, SliderMorph, Animation*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.gui = '2017-May-12'; modules.gui = '2017-May-30';
// Declarations // Declarations

Wyświetl plik

@ -3428,6 +3428,10 @@ Fixes:
* added inheritance support for the wardrobe (costumes) * added inheritance support for the wardrobe (costumes)
* added inheritance support for costume # * added inheritance support for costume #
170530
------
* let clones share the orginals scripts without shallow-copying them
Features: Features:
* polymorphic sprite-local custom blocks * polymorphic sprite-local custom blocks
@ -3441,6 +3445,7 @@ Features:
* support for codification of String, Number and Boolean value types * support for codification of String, Number and Boolean value types
* costume icons indicate svg costumes * costume icons indicate svg costumes
* spritess rotation centers can be adjusted onstage * spritess rotation centers can be adjusted onstage
* clones share their original sprites scripts, not a shallow-copy of them
Fixes: Fixes:
* changed keyboard shortcut indicator for “find blocks” to “^” * changed keyboard shortcut indicator for “find blocks” to “^”

Wyświetl plik

@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize, BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph*/ TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph*/
modules.objects = '2017-May-15'; modules.objects = '2017-May-30';
var SpriteMorph; var SpriteMorph;
var StageMorph; var StageMorph;
@ -1343,7 +1343,7 @@ function SpriteMorph(globals) {
SpriteMorph.prototype.init = function (globals) { SpriteMorph.prototype.init = function (globals) {
this.name = localize('Sprite'); this.name = localize('Sprite');
this.variables = new VariableFrame(globals || null, this); this.variables = new VariableFrame(globals || null, this);
this.scripts = new ScriptsMorph(this); this.scripts = new ScriptsMorph();
this.customBlocks = []; this.customBlocks = [];
this.costumes = new List(); this.costumes = new List();
this.costume = null; this.costume = null;
@ -1388,7 +1388,7 @@ SpriteMorph.prototype.init = function (globals) {
// sprite inheritance // sprite inheritance
this.exemplar = null; this.exemplar = null;
this.cachedSpecimens = null; // temporary for morphic animations this.cachedSpecimens = null; // not to be persisted
this.inheritedAttributes = []; // 'x position', 'direction', 'size' etc... this.inheritedAttributes = []; // 'x position', 'direction', 'size' etc...
SpriteMorph.uber.init.call(this); SpriteMorph.uber.init.call(this);
@ -1413,11 +1413,10 @@ SpriteMorph.prototype.fullCopy = function (forClone) {
c.color = this.color.copy(); c.color = this.color.copy();
c.blocksCache = {}; c.blocksCache = {};
c.paletteCache = {}; c.paletteCache = {};
c.scripts = this.scripts.fullCopy(forClone);
c.scripts.owner = c;
c.variables = this.variables.copy(); c.variables = this.variables.copy();
c.variables.owner = c; c.variables.owner = c;
if (!forClone) { if (!forClone) {
c.scripts = this.scripts.fullCopy();
c.customBlocks = []; c.customBlocks = [];
this.customBlocks.forEach(function (def) { this.customBlocks.forEach(function (def) {
cb = def.copyAndBindTo(c); cb = def.copyAndBindTo(c);
@ -3159,7 +3158,8 @@ SpriteMorph.prototype.createClone = function (immediately) {
}; };
SpriteMorph.prototype.clonify = function (stage, immediately) { SpriteMorph.prototype.clonify = function (stage, immediately) {
var hats; var hats,
myself = this;
this.parts.forEach(function (part) { this.parts.forEach(function (part) {
part.clonify(stage); part.clonify(stage);
}); });
@ -3173,6 +3173,7 @@ SpriteMorph.prototype.clonify = function (stage, immediately) {
hats.forEach(function (block) { hats.forEach(function (block) {
stage.threads.startProcess( stage.threads.startProcess(
block, block,
myself,
stage.isThreadSafe, stage.isThreadSafe,
null, // export result null, // export result
null, // callback null, // callback
@ -3899,7 +3900,7 @@ SpriteMorph.prototype.prepareToBeGrabbed = function (hand) {
this.recordLayers(); this.recordLayers();
this.shadowAttribute('x position'); this.shadowAttribute('x position');
this.shadowAttribute('y position'); this.shadowAttribute('y position');
this.cachedSpecimens = this.specimens(); this.specimens(); // make sure specimens are cached
if (!this.bounds.containsPoint(hand.position()) && if (!this.bounds.containsPoint(hand.position()) &&
this.isCorrectingOutsideDrag()) { this.isCorrectingOutsideDrag()) {
this.setCenter(hand.position()); this.setCenter(hand.position());
@ -3920,7 +3921,6 @@ SpriteMorph.prototype.justDropped = function () {
if (stage) { if (stage) {
stage.enableCustomHatBlocks = true; stage.enableCustomHatBlocks = true;
} }
this.cachedSpecimens = null;
if (this.exemplar) { if (this.exemplar) {
this.inheritedAttributes.forEach(function (att) { this.inheritedAttributes.forEach(function (att) {
myself.refreshInheritedAttribute(att); myself.refreshInheritedAttribute(att);
@ -4111,17 +4111,17 @@ SpriteMorph.prototype.slideBackTo = function (
var myself = this; var myself = this;
// caching specimens // caching specimens
this.cachedSpecimens = situation.origin.children.filter(function (m) { if (isNil(this.cachedSpecimens)) {
return m instanceof SpriteMorph && (m.exemplar === myself); this.cachedSpecimens = situation.origin.children.filter(function (m) {
}); return m instanceof SpriteMorph && (m.exemplar === myself);
});
}
SpriteMorph.uber.slideBackTo.call( SpriteMorph.uber.slideBackTo.call(
this, this,
situation, situation,
msecs, msecs,
function () { function () {
// make sure to flush cached specimens
myself.cachedSpecimens = null;
if (onBeforeDrop) {onBeforeDrop(); } if (onBeforeDrop) {onBeforeDrop(); }
}, },
onBeforeDrop, onBeforeDrop,
@ -4548,11 +4548,16 @@ SpriteMorph.prototype.mouseDownLeft = function () {
SpriteMorph.prototype.receiveUserInteraction = function (interaction) { SpriteMorph.prototype.receiveUserInteraction = function (interaction) {
var stage = this.parentThatIsA(StageMorph), var stage = this.parentThatIsA(StageMorph),
procs = [], procs = [],
myself = this,
hats; hats;
if (!stage) {return; } // currently dragged if (!stage) {return; } // currently dragged
hats = this.allHatBlocksForInteraction(interaction); hats = this.allHatBlocksForInteraction(interaction);
hats.forEach(function (block) { hats.forEach(function (block) {
procs.push(stage.threads.startProcess(block, stage.isThreadSafe)); procs.push(stage.threads.startProcess(
block,
myself,
stage.isThreadSafe
));
}); });
return procs; return procs;
}; };
@ -5129,6 +5134,7 @@ SpriteMorph.prototype.setExemplar = function (another) {
ide.flushBlocksCache('variables'); ide.flushBlocksCache('variables');
ide.refreshPalette(); ide.refreshPalette();
} }
another.cachedSpecimens = null;
}; };
SpriteMorph.prototype.allExemplars = function () { SpriteMorph.prototype.allExemplars = function () {
@ -5145,9 +5151,12 @@ SpriteMorph.prototype.allExemplars = function () {
SpriteMorph.prototype.specimens = function () { SpriteMorph.prototype.specimens = function () {
// without myself // without myself
var myself = this; var myself = this;
return this.cachedSpecimens || this.siblings().filter(function (m) { if (isNil(this.cachedSpecimens)) {
return m instanceof SpriteMorph && (m.exemplar === myself); this.cachedSpecimens = this.siblings().filter(function (m) {
}); return m instanceof SpriteMorph && (m.exemplar === myself);
});
}
return this.cachedSpecimens;
}; };
SpriteMorph.prototype.allSpecimens = function () { SpriteMorph.prototype.allSpecimens = function () {
@ -5536,6 +5545,16 @@ SpriteMorph.prototype.restoreLayers = function () {
this.layers = null; this.layers = null;
}; };
// SpriteMorph destroying
SpriteMorph.prototype.destroy = function () {
// make sure to invalidate the specimens cache
if (this.exemplar) {
this.exemplar.cachedSpecimens = null;
}
SpriteMorph.uber.destroy.call(this);
};
// SpriteMorph highlighting // SpriteMorph highlighting
SpriteMorph.prototype.addHighlight = function (oldHighlight) { SpriteMorph.prototype.addHighlight = function (oldHighlight) {
@ -5768,7 +5787,7 @@ StageMorph.prototype.init = function (globals) {
this.name = localize('Stage'); this.name = localize('Stage');
this.threads = new ThreadManager(); this.threads = new ThreadManager();
this.variables = new VariableFrame(globals || null, this); this.variables = new VariableFrame(globals || null, this);
this.scripts = new ScriptsMorph(this); this.scripts = new ScriptsMorph();
this.customBlocks = []; this.customBlocks = [];
this.globalBlocks = []; this.globalBlocks = [];
this.costumes = new List(); this.costumes = new List();
@ -6174,25 +6193,24 @@ StageMorph.prototype.step = function () {
}; };
StageMorph.prototype.stepGenericConditions = function (stopAll) { StageMorph.prototype.stepGenericConditions = function (stopAll) {
var hats = [], var hatCount = 0,
myself = this, myself = this,
ide; ide;
this.children.concat(this).forEach(function (morph) { this.children.concat(this).forEach(function (morph) {
if (morph instanceof SpriteMorph || morph instanceof StageMorph) { if (isSnapObject(morph)) {
hats = hats.concat(morph.allGenericHatBlocks()); morph.allGenericHatBlocks().forEach(function (block) {
hatCount += 1;
myself.threads.doWhen(block, morph, stopAll);
});
} }
}); });
if (!hats.length) { if (!hatCount) {
this.enableCustomHatBlocks = false; this.enableCustomHatBlocks = false;
ide = this.parentThatIsA(IDE_Morph); ide = this.parentThatIsA(IDE_Morph);
if (ide) { if (ide) {
ide.controlBar.stopButton.refresh(); ide.controlBar.stopButton.refresh();
} }
return;
} }
hats.forEach(function (block) {
myself.threads.doWhen(block, stopAll);
});
}; };
StageMorph.prototype.developersMenu = function () { StageMorph.prototype.developersMenu = function () {
@ -6266,7 +6284,6 @@ StageMorph.prototype.processKeyEvent = function (event, action) {
StageMorph.prototype.fireKeyEvent = function (key) { StageMorph.prototype.fireKeyEvent = function (key) {
var evt = key.toLowerCase(), var evt = key.toLowerCase(),
hats = [],
procs = [], procs = [],
ide = this.parentThatIsA(IDE_Morph), ide = this.parentThatIsA(IDE_Morph),
myself = this; myself = this;
@ -6311,12 +6328,15 @@ StageMorph.prototype.fireKeyEvent = function (key) {
} }
this.children.concat(this).forEach(function (morph) { this.children.concat(this).forEach(function (morph) {
if (isSnapObject(morph)) { if (isSnapObject(morph)) {
hats = hats.concat(morph.allHatBlocksForKey(evt)); morph.allHatBlocksForKey(evt).forEach(function (block) {
procs.push(myself.threads.startProcess(
block,
morph,
myself.isThreadSafe
));
});
} }
}); });
hats.forEach(function (block) {
procs.push(myself.threads.startProcess(block, myself.isThreadSafe));
});
return procs; return procs;
}; };
@ -6333,21 +6353,20 @@ StageMorph.prototype.inspectKeyEvent
StageMorph.prototype.fireGreenFlagEvent = function () { StageMorph.prototype.fireGreenFlagEvent = function () {
var procs = [], var procs = [],
hats = [],
ide = this.parentThatIsA(IDE_Morph), ide = this.parentThatIsA(IDE_Morph),
myself = this; myself = this;
this.children.concat(this).forEach(function (morph) { this.children.concat(this).forEach(function (morph) {
if (isSnapObject(morph)) { if (isSnapObject(morph)) {
hats = hats.concat(morph.allHatBlocksFor('__shout__go__')); morph.allHatBlocksFor('__shout__go__').forEach(function (block) {
procs.push(myself.threads.startProcess(
block,
morph,
myself.isThreadSafe
));
});
} }
}); });
hats.forEach(function (block) {
procs.push(myself.threads.startProcess(
block,
myself.isThreadSafe
));
});
if (ide) { if (ide) {
ide.controlBar.pauseButton.refresh(); ide.controlBar.pauseButton.refresh();
} }
@ -7210,6 +7229,12 @@ StageMorph.prototype.allSpecimens = function () {
StageMorph.prototype.shadowAttribute = nop; StageMorph.prototype.shadowAttribute = nop;
// StageMorph inheritance support - attributes
StageMorph.prototype.inheritsAttribute = function () {
return false;
};
// StageMorph inheritance support - variables // StageMorph inheritance support - variables
StageMorph.prototype.isVariableNameInUse StageMorph.prototype.isVariableNameInUse

Wyświetl plik

@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
TableFrameMorph, ColorSlotMorph, isSnapObject*/ TableFrameMorph, ColorSlotMorph, isSnapObject*/
modules.threads = '2017-May-12'; modules.threads = '2017-May-30';
var ThreadManager; var ThreadManager;
var Process; var Process;
@ -109,7 +109,7 @@ function snapEquals(a, b) {
function invoke( function invoke(
action, // a BlockMorph or a Context, a reified ("ringified") block action, // a BlockMorph or a Context, a reified ("ringified") block
contextArgs, // optional List of arguments for the context, or null contextArgs, // optional List of arguments for the context, or null
receiver, // optional sprite or environment receiver, // sprite or environment, optional for contexts
timeout, // msecs timeout, // msecs
timeoutErrorMsg, // string timeoutErrorMsg, // string
suppressErrors // bool suppressErrors // bool
@ -126,23 +126,23 @@ function invoke(
// Use ThreadManager::startProcess with a callback instead // Use ThreadManager::startProcess with a callback instead
var proc = new Process(), var proc = new Process(),
deadline = (timeout ? Date.now() + timeout : null), deadline = (timeout ? Date.now() + timeout : null);
rcvr;
if (action instanceof Context) { if (action instanceof Context) {
if (receiver) { if (receiver) { // optional
action = proc.reportContextFor(receiver); action = proc.reportContextFor(receiver);
} }
proc.initializeFor(action, contextArgs || new List()); proc.initializeFor(action, contextArgs || new List());
} else if (action instanceof BlockMorph) { } else if (action instanceof BlockMorph) {
proc.topBlock = action; proc.topBlock = action;
rcvr = receiver || action.receiver(); if (receiver) {
if (rcvr) {
proc.homeContext = new Context(); proc.homeContext = new Context();
proc.homeContext.receiver = rcvr; proc.homeContext.receiver = receiver;
if (rcvr.variables) { if (receiver.variables) {
proc.homeContext.variables.parentFrame = rcvr.variables; proc.homeContext.variables.parentFrame = receiver.variables;
} }
} else {
throw new Error('expecting a receiver but getting ' + receiver);
} }
proc.context = new Context( proc.context = new Context(
null, null,
@ -180,25 +180,26 @@ function ThreadManager() {
ThreadManager.prototype.pauseCustomHatBlocks = false; ThreadManager.prototype.pauseCustomHatBlocks = false;
ThreadManager.prototype.toggleProcess = function (block) { ThreadManager.prototype.toggleProcess = function (block, receiver) {
var active = this.findProcess(block); var active = this.findProcess(block, receiver);
if (active) { if (active) {
active.stop(); active.stop();
} else { } else {
return this.startProcess(block, null, null, null, true); return this.startProcess(block, receiver, null, null, null, true);
} }
}; };
ThreadManager.prototype.startProcess = function ( ThreadManager.prototype.startProcess = function (
block, block,
receiver,
isThreadSafe, isThreadSafe,
exportResult, exportResult, // bool
callback, callback,
isClicked, isClicked,
rightAway rightAway
) { ) {
var active = this.findProcess(block), var top = block.topBlock(),
top = block.topBlock(), active = this.findProcess(top, receiver),
newProc; newProc;
if (active) { if (active) {
if (isThreadSafe) { if (isThreadSafe) {
@ -207,7 +208,7 @@ ThreadManager.prototype.startProcess = function (
active.stop(); active.stop();
this.removeTerminatedProcesses(); this.removeTerminatedProcesses();
} }
newProc = new Process(block.topBlock(), callback, rightAway); newProc = new Process(top, receiver, callback, rightAway);
newProc.exportResult = exportResult; newProc.exportResult = exportResult;
newProc.isClicked = isClicked || false; newProc.isClicked = isClicked || false;
if (!newProc.homeContext.receiver.isClone) { if (!newProc.homeContext.receiver.isClone) {
@ -241,8 +242,8 @@ ThreadManager.prototype.stopAllForReceiver = function (rcvr, excpt) {
}); });
}; };
ThreadManager.prototype.stopProcess = function (block) { ThreadManager.prototype.stopProcess = function (block, receiver) {
var active = this.findProcess(block); var active = this.findProcess(block, receiver);
if (active) { if (active) {
active.stop(); active.stop();
} }
@ -309,7 +310,8 @@ ThreadManager.prototype.removeTerminatedProcesses = function () {
this.processes.forEach(function (proc) { this.processes.forEach(function (proc) {
var result; var result;
if ((!proc.isRunning() && !proc.errorFlag) || proc.isDead) { if ((!proc.isRunning() && !proc.errorFlag) || proc.isDead) {
if (proc.topBlock instanceof BlockMorph) { if (proc.topBlock instanceof BlockMorph
&& (!proc.receiver.isClone)) {
proc.unflash(); proc.unflash();
proc.topBlock.removeHighlight(); proc.topBlock.removeHighlight();
} }
@ -349,19 +351,19 @@ ThreadManager.prototype.removeTerminatedProcesses = function () {
this.processes = remaining; this.processes = remaining;
}; };
ThreadManager.prototype.findProcess = function (block) { ThreadManager.prototype.findProcess = function (block, receiver) {
var top = block.topBlock(); var top = block.topBlock();
return detect( return detect(
this.processes, this.processes,
function (each) { function (each) {
return each.topBlock === top; return each.topBlock === top && (each.receiver === receiver);
} }
); );
}; };
ThreadManager.prototype.doWhen = function (block, stopIt) { ThreadManager.prototype.doWhen = function (block, receiver, stopIt) {
if (this.pauseCustomHatBlocks) {return; } if (this.pauseCustomHatBlocks) {return; }
if ((!block) || this.findProcess(block)) { if ((!block) || this.findProcess(block, receiver)) {
return; return;
} }
var pred = block.inputs()[0], world; var pred = block.inputs()[0], world;
@ -376,12 +378,20 @@ ThreadManager.prototype.doWhen = function (block, stopIt) {
if (invoke( if (invoke(
pred, pred,
null, null,
block.receiver(), // needed for shallow copied clones - was null receiver,
50, 50,
'the predicate takes\ntoo long for a\ncustom hat block', 'the predicate takes\ntoo long for a\ncustom hat block',
true // suppress errors => handle them right here instead true // suppress errors => handle them right here instead
) === true) { ) === true) {
this.startProcess(block, null, null, null, null, true); // atomic this.startProcess(
block,
receiver,
null,
null,
null,
null,
true // atomic
);
} }
} catch (error) { } catch (error) {
block.addErrorHighlight(); block.addErrorHighlight();
@ -476,9 +486,9 @@ Process.prototype.enableSingleStepping = false; // experimental
Process.prototype.flashTime = 0; // experimental Process.prototype.flashTime = 0; // experimental
// Process.prototype.enableJS = false; // Process.prototype.enableJS = false;
function Process(topBlock, onComplete, rightAway) { function Process(topBlock, receiver, onComplete, rightAway) {
this.topBlock = topBlock || null; this.topBlock = topBlock || null;
this.receiver = receiver;
this.readyToYield = false; this.readyToYield = false;
this.readyToTerminate = false; this.readyToTerminate = false;
this.isDead = false; this.isDead = false;
@ -486,7 +496,7 @@ function Process(topBlock, onComplete, rightAway) {
this.isShowingResult = false; this.isShowingResult = false;
this.errorFlag = false; this.errorFlag = false;
this.context = null; this.context = null;
this.homeContext = new Context(); this.homeContext = new Context(null, null, null, receiver);
this.lastYield = Date.now(); this.lastYield = Date.now();
this.isFirstStep = true; this.isFirstStep = true;
this.isAtomic = false; this.isAtomic = false;
@ -502,7 +512,6 @@ function Process(topBlock, onComplete, rightAway) {
this.isInterrupted = false; // experimental, for single-stepping this.isInterrupted = false; // experimental, for single-stepping
if (topBlock) { if (topBlock) {
this.homeContext.receiver = topBlock.receiver();
this.homeContext.variables.parentFrame = this.homeContext.variables.parentFrame =
this.homeContext.receiver.variables; this.homeContext.receiver.variables;
this.context = new Context( this.context = new Context(
@ -651,7 +660,7 @@ Process.prototype.evaluateBlock = function (block, argCount) {
} }
// first evaluate all inputs, then apply the primitive // first evaluate all inputs, then apply the primitive
var rcvr = this.context.receiver || this.topBlock.receiver(), var rcvr = this.context.receiver || this.receiver,
inputs = this.context.inputs; inputs = this.context.inputs;
if (argCount > inputs.length) { if (argCount > inputs.length) {
@ -963,7 +972,7 @@ Process.prototype.reify = function (topBlock, parameterNames, isCustomBlock) {
context.inputs = parameterNames.asArray(); context.inputs = parameterNames.asArray();
context.receiver context.receiver
= this.context ? this.context.receiver : topBlock.receiver(); = this.context ? this.context.receiver : this.receiver;
context.origin = context.receiver; // for serialization context.origin = context.receiver; // for serialization
return context; return context;
@ -1137,6 +1146,9 @@ Process.prototype.initializeFor = function (context, args) {
value, value,
exit; exit;
// remember the receiver
this.context = context.receiver;
// assign parameters if any were passed // assign parameters if any were passed
if (parms.length > 0) { if (parms.length > 0) {
@ -1557,7 +1569,7 @@ Process.prototype.doDeleteAttr = function (attrName) {
if (!isNil(name)) { if (!isNil(name)) {
rcvr.inheritAttribute(name); rcvr.inheritAttribute(name);
} }
return; // +++ error: cannot delete attribute... return; // error: cannot delete attribute...
} }
} }
if (name instanceof Array) { if (name instanceof Array) {
@ -2063,7 +2075,7 @@ Process.prototype.doThinkFor = function (data, secs) {
Process.prototype.blockReceiver = function () { Process.prototype.blockReceiver = function () {
return this.context ? this.context.receiver || this.homeContext.receiver return this.context ? this.context.receiver || this.homeContext.receiver
: this.homeContext.receiver; : this.homeContext.receiver || this.receiver;
}; };
// Process sound primitives (interpolated) // Process sound primitives (interpolated)
@ -2180,7 +2192,6 @@ Process.prototype.doBroadcast = function (message) {
trg, trg,
rcvrs, rcvrs,
myself = this, myself = this,
hats = [],
procs = []; procs = [];
if (message instanceof List && (message.length() === 2)) { if (message instanceof List && (message.length() === 2)) {
@ -2211,40 +2222,19 @@ Process.prototype.doBroadcast = function (message) {
stage.lastMessage = message; // the actual data structure stage.lastMessage = message; // the actual data structure
rcvrs.forEach(function (morph) { rcvrs.forEach(function (morph) {
if (isSnapObject(morph)) { if (isSnapObject(morph)) {
hats = hats.concat(morph.allHatBlocksFor(msg)); morph.allHatBlocksFor(msg).forEach(function (block) {
procs.push(stage.threads.startProcess(
block,
morph,
stage.isThreadSafe
));
});
} }
}); });
hats.forEach(function (block) {
procs.push(stage.threads.startProcess(block, stage.isThreadSafe));
});
} }
return procs; return procs;
}; };
// old purely global broadcast code, commented out and retained in case
// we need to revert
/*
Process.prototype.doBroadcast = function (message) {
var stage = this.homeContext.receiver.parentThatIsA(StageMorph),
hats = [],
procs = [];
if (message !== '') {
stage.lastMessage = message;
stage.children.concat(stage).forEach(function (morph) {
if (isSnapObject(morph)) {
hats = hats.concat(morph.allHatBlocksFor(message));
}
});
hats.forEach(function (block) {
procs.push(stage.threads.startProcess(block, stage.isThreadSafe));
});
}
return procs;
};
*/
Process.prototype.doBroadcastAndWait = function (message) { Process.prototype.doBroadcastAndWait = function (message) {
if (!this.context.activeSends) { if (!this.context.activeSends) {
this.context.activeSends = this.doBroadcast(message); this.context.activeSends = this.doBroadcast(message);