summaryrefslogtreecommitdiff
path: root/blocks.js
diff options
context:
space:
mode:
Diffstat (limited to 'blocks.js')
-rw-r--r--blocks.js114
1 files changed, 95 insertions, 19 deletions
diff --git a/blocks.js b/blocks.js
index 82ef601..8e428d0 100644
--- a/blocks.js
+++ b/blocks.js
@@ -9,7 +9,7 @@
written by Jens Mönig
jens@moenig.org
- Copyright (C) 2014 by Jens Mönig
+ Copyright (C) 2015 by Jens Mönig
This file is part of Snap!.
@@ -155,7 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2014-November-17';
+modules.blocks = '2015-May-01';
var SyntaxElementMorph;
@@ -340,6 +340,7 @@ SyntaxElementMorph.prototype.setScale = function (num) {
};
SyntaxElementMorph.prototype.setScale(1);
+SyntaxElementMorph.prototype.isCachingInputs = false;
// SyntaxElementMorph instance creation:
@@ -356,6 +357,7 @@ SyntaxElementMorph.prototype.init = function () {
SyntaxElementMorph.uber.init.call(this);
this.defaults = [];
+ this.cachedInputs = null;
};
// SyntaxElementMorph accessing:
@@ -375,10 +377,39 @@ SyntaxElementMorph.prototype.parts = function () {
SyntaxElementMorph.prototype.inputs = function () {
// answer my arguments and nested reporters
- return this.parts().filter(function (part) {
- return part instanceof SyntaxElementMorph;
- });
+ if (isNil(this.cachedInputs) || !this.isCachingInputs) {
+ this.cachedInputs = this.parts().filter(function (part) {
+ return part instanceof SyntaxElementMorph;
+ });
+ }
+ // this.debugCachedInputs();
+ return this.cachedInputs;
+};
+SyntaxElementMorph.prototype.debugCachedInputs = function () {
+ // private - only used for manually debugging inputs caching
+ var realInputs, i;
+ if (!isNil(this.cachedInputs)) {
+ realInputs = this.parts().filter(function (part) {
+ return part instanceof SyntaxElementMorph;
+ });
+ }
+ if (this.cachedInputs.length !== realInputs.length) {
+ throw new Error('cached inputs size do not match: ' +
+ this.constructor.name);
+ }
+ for (i = 0; i < realInputs.length; i += 1) {
+ if (this.cachedInputs[i] !== realInputs[i]) {
+ throw new Error('cached input does not match: ' +
+ this.constructor.name +
+ ' #' +
+ i +
+ ' ' +
+ this.cachedInputs[i].constructor.name +
+ ' != ' +
+ realInputs[i].constructor.name);
+ }
+ }
};
SyntaxElementMorph.prototype.allInputs = function () {
@@ -395,7 +426,9 @@ SyntaxElementMorph.prototype.allInputs = function () {
SyntaxElementMorph.prototype.allEmptySlots = function () {
// answer empty input slots of all children excluding myself,
- // but omit those in nested rings (lambdas) and JS-Function primitives
+ // but omit those in nested rings (lambdas) and JS-Function primitives.
+ // Used by the evaluator when binding implicit formal parameters
+ // to empty input slots
var empty = [];
if (!(this instanceof RingMorph) &&
(this.selector !== 'reportJSFunction')) {
@@ -410,19 +443,24 @@ SyntaxElementMorph.prototype.allEmptySlots = function () {
return empty;
};
-SyntaxElementMorph.prototype.allReportBlocks = function () {
- // answer report blocks of all children including myself,
- // but omit those in nested rings (lambdas)
- if (this.selector === 'doReport') {return [this]; }
- var reports = [];
- if (!(this instanceof RingMorph)) {
- this.children.forEach(function (morph) {
- if (morph.allReportBlocks) {
- reports = reports.concat(morph.allReportBlocks());
- }
- });
+SyntaxElementMorph.prototype.tagExitBlocks = function (stopTag, isCommand) {
+ // tag 'report' and 'stop this block' blocks of all children including
+ // myself, with either a stopTag (for "stop" blocks) or an indicator of
+ // being inside a command block definition, but omit those in nested
+ // rings (lambdas. Used by the evaluator when entering a procedure
+ if (this.selector === 'doReport') {
+ this.partOfCustomCommand = isCommand;
+ } else if (this.selector === 'doStopThis') {
+ this.exitTag = stopTag;
+ } else {
+ if (!(this instanceof RingMorph)) {
+ this.children.forEach(function (morph) {
+ if (morph.tagExitBlocks) {
+ morph.tagExitBlocks(stopTag, isCommand);
+ }
+ });
+ }
}
- return reports;
};
SyntaxElementMorph.prototype.replaceInput = function (oldArg, newArg) {
@@ -487,6 +525,7 @@ SyntaxElementMorph.prototype.replaceInput = function (oldArg, newArg) {
replacement.drawNew();
this.fixLayout();
}
+ this.cachedInputs = null;
this.endLayout();
};
@@ -522,6 +561,7 @@ SyntaxElementMorph.prototype.silentReplaceInput = function (oldArg, newArg) {
replacement.drawNew();
this.fixLayout();
}
+ this.cachedInputs = null;
};
SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) {
@@ -564,6 +604,7 @@ SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) {
} else if (deflt instanceof RingMorph) {
deflt.fixBlockColor();
}
+ this.cachedInputs = null;
};
SyntaxElementMorph.prototype.isLocked = function () {
@@ -841,6 +882,20 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
true // read-only
);
break;
+ case '%interaction':
+ part = new InputSlotMorph(
+ null, // text
+ false, // numeric?
+ {
+ 'clicked' : ['clicked'],
+ 'pressed' : ['pressed'],
+ 'dropped' : ['dropped'],
+ 'mouse-entered' : ['mouse-entered'],
+ 'mouse-departed' : ['mouse-departed']
+ },
+ true // read-only
+ );
+ break;
case '%dates':
part = new InputSlotMorph(
null, // text
@@ -1888,6 +1943,7 @@ BlockMorph.uber = SyntaxElementMorph.prototype;
// BlockMorph preferences settings:
+BlockMorph.prototype.isCachingInputs = true;
BlockMorph.prototype.zebraContrast = 40; // alternating color brightness
// BlockMorph sound feedback:
@@ -1921,6 +1977,7 @@ BlockMorph.prototype.init = function () {
BlockMorph.uber.init.call(this);
this.color = new Color(0, 17, 173);
+ this.cashedInputs = null;
};
BlockMorph.prototype.receiver = function () {
@@ -2026,6 +2083,7 @@ BlockMorph.prototype.setSpec = function (spec) {
});
this.blockSpec = spec;
this.fixLayout();
+ this.cachedInputs = null;
};
BlockMorph.prototype.buildSpec = function () {
@@ -2418,6 +2476,7 @@ BlockMorph.prototype.restoreInputs = function (oldInputs) {
}
i += 1;
});
+ this.cachedInputs = null;
};
BlockMorph.prototype.showHelp = function () {
@@ -3005,6 +3064,9 @@ BlockMorph.prototype.fullCopy = function () {
ans.setSpec(this.instantiationSpec);
}
ans.allChildren().filter(function (block) {
+ if (block instanceof SyntaxElementMorph) {
+ block.cachedInputs = null;
+ }
return !isNil(block.comment);
}).forEach(function (block) {
var cmnt = block.comment.fullCopy();
@@ -3013,6 +3075,7 @@ BlockMorph.prototype.fullCopy = function () {
//block.comment = null;
});
+ ans.cachedInputs = null;
return ans;
};
@@ -3186,9 +3249,10 @@ BlockMorph.prototype.snap = function () {
bottomBlock() - answer the bottom block of my stack
blockSequence() - answer an array of blocks starting with myself
- and the following "lexical awareness" indicator:
+ and the following "lexical awareness" indicators:
partOfCustomCommand - temporary bool set by the evaluator
+ exitTag - temporary string or number set by the evaluator
*/
// CommandBlockMorph inherits from BlockMorph:
@@ -3206,6 +3270,8 @@ function CommandBlockMorph() {
CommandBlockMorph.prototype.init = function () {
CommandBlockMorph.uber.init.call(this);
this.setExtent(new Point(200, 100));
+ this.partOfCustomCommand = false;
+ this.exitTag = null;
};
// CommandBlockMorph enumerating:
@@ -4579,6 +4645,7 @@ RingMorph.uber = ReporterBlockMorph.prototype;
// RingMorph preferences settings:
+RingMorph.prototype.isCachingInputs = false;
// RingMorph.prototype.edge = 2;
// RingMorph.prototype.rounding = 9;
// RingMorph.prototype.alpha = 0.8;
@@ -6920,6 +6987,15 @@ InputSlotMorph.prototype.fixLayout = function () {
// InputSlotMorph events:
+InputSlotMorph.prototype.mouseDownLeft = function (pos) {
+ if (this.isReadOnly || this.arrow().bounds.containsPoint(pos)) {
+ this.escalateEvent('mouseDownLeft', pos);
+ } else {
+ this.contents().edit();
+ this.contents().selectAll();
+ }
+};
+
InputSlotMorph.prototype.mouseClickLeft = function (pos) {
if (this.arrow().bounds.containsPoint(pos)) {
this.dropDownMenu();