kopia lustrzana https://github.com/backface/turtlestitch
let clones share the orginal’s scripts without shallow-copying them
rodzic
cc47a6fb5a
commit
eea1d08c82
160
blocks.js
160
blocks.js
|
@ -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
23
byob.js
|
@ -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
2
gui.js
|
@ -74,7 +74,7 @@ isRetinaSupported, SliderMorph, Animation*/
|
||||||
|
|
||||||
// Global stuff ////////////////////////////////////////////////////////
|
// Global stuff ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
modules.gui = '2017-May-12';
|
modules.gui = '2017-May-30';
|
||||||
|
|
||||||
// Declarations
|
// Declarations
|
||||||
|
|
||||||
|
|
|
@ -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 orginal’s 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
|
||||||
* sprites’s rotation centers can be adjusted onstage
|
* sprites’s rotation centers can be adjusted onstage
|
||||||
|
* clones share their original sprite’s 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 “^”
|
||||||
|
|
103
objects.js
103
objects.js
|
@ -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
|
||||||
|
|
116
threads.js
116
threads.js
|
@ -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);
|
||||||
|
|
Ładowanie…
Reference in New Issue