summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blocks.js43
-rw-r--r--byob.js4
-rw-r--r--gui.js17
-rw-r--r--help/receiveInteraction.png (renamed from help/receiveClick.png)bin49453 -> 49453 bytes
-rwxr-xr-xhistory.txt17
-rw-r--r--lang-de.js21
-rw-r--r--locale.js4
-rw-r--r--objects.js89
-rw-r--r--store.js11
-rw-r--r--threads.js4
10 files changed, 171 insertions, 39 deletions
diff --git a/blocks.js b/blocks.js
index e56d0ed..5cdcc1c 100644
--- a/blocks.js
+++ b/blocks.js
@@ -155,7 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2014-November-21';
+modules.blocks = '2015-February-28';
var SyntaxElementMorph;
@@ -340,6 +340,7 @@ SyntaxElementMorph.prototype.setScale = function (num) {
};
SyntaxElementMorph.prototype.setScale(1);
+SyntaxElementMorph.prototype.isCachingInputs = true;
// 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,12 @@ 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;
+ });
+ }
+ return this.cachedInputs;
};
SyntaxElementMorph.prototype.allInputs = function () {
@@ -494,6 +498,7 @@ SyntaxElementMorph.prototype.replaceInput = function (oldArg, newArg) {
replacement.drawNew();
this.fixLayout();
}
+ this.cachedInputs = null;
this.endLayout();
};
@@ -529,6 +534,7 @@ SyntaxElementMorph.prototype.silentReplaceInput = function (oldArg, newArg) {
replacement.drawNew();
this.fixLayout();
}
+ this.cachedInputs = null;
};
SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) {
@@ -571,6 +577,7 @@ SyntaxElementMorph.prototype.revertToDefaultInput = function (arg, noValues) {
} else if (deflt instanceof RingMorph) {
deflt.fixBlockColor();
}
+ this.cachedInputs = null;
};
SyntaxElementMorph.prototype.isLocked = function () {
@@ -848,6 +855,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
@@ -1928,6 +1949,7 @@ BlockMorph.prototype.init = function () {
BlockMorph.uber.init.call(this);
this.color = new Color(0, 17, 173);
+ this.cashedInputs = null;
};
BlockMorph.prototype.receiver = function () {
@@ -2033,6 +2055,7 @@ BlockMorph.prototype.setSpec = function (spec) {
});
this.blockSpec = spec;
this.fixLayout();
+ this.cachedInputs = null;
};
BlockMorph.prototype.buildSpec = function () {
@@ -2425,6 +2448,7 @@ BlockMorph.prototype.restoreInputs = function (oldInputs) {
}
i += 1;
});
+ this.cachedInputs = null;
};
BlockMorph.prototype.showHelp = function () {
@@ -3020,6 +3044,7 @@ BlockMorph.prototype.fullCopy = function () {
//block.comment = null;
});
+ ans.cachedInputs = null;
return ans;
};
@@ -9172,6 +9197,10 @@ MultiArgMorph.prototype = new ArgMorph();
MultiArgMorph.prototype.constructor = MultiArgMorph;
MultiArgMorph.uber = ArgMorph.prototype;
+// MultiArgMorph preferences settings
+
+MultiArgMorph.prototype.isCachingInputs = false;
+
// MultiArgMorph instance creation:
function MultiArgMorph(
@@ -9602,6 +9631,10 @@ ArgLabelMorph.prototype = new ArgMorph();
ArgLabelMorph.prototype.constructor = ArgLabelMorph;
ArgLabelMorph.uber = ArgMorph.prototype;
+// ArgLabelMorph preferences settings
+
+ArgLabelMorph.prototype.isCachingInputs = false;
+
// MultiArgMorph instance creation:
function ArgLabelMorph(argMorph, labelTxt) {
diff --git a/byob.js b/byob.js
index ec714f1..634d62d 100644
--- a/byob.js
+++ b/byob.js
@@ -106,7 +106,7 @@ SymbolMorph, isNil*/
// Global stuff ////////////////////////////////////////////////////////
-modules.byob = '2015-January-21';
+modules.byob = '2015-February-28';
// Declarations
@@ -2974,7 +2974,7 @@ InputSlotDialogMorph.prototype.editSlotOptions = function () {
new DialogBoxMorph(
myself,
function (options) {
- myself.fragment.options = options;
+ myself.fragment.options = options.trim();
},
myself
).promptCode(
diff --git a/gui.js b/gui.js
index ec24661..a8fb59a 100644
--- a/gui.js
+++ b/gui.js
@@ -69,7 +69,7 @@ SpeechBubbleMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2015-February-20';
+modules.gui = '2015-February-28';
// Declarations
@@ -2268,6 +2268,17 @@ IDE_Morph.prototype.settingsMenu = function () {
'check to prioritize\nscript execution'
);
addPreference(
+ 'Cache Inputs',
+ function () {
+ SyntaxElementMorph.prototype.isCachingInputs =
+ !SyntaxElementMorph.prototype.isCachingInputs;
+ },
+ SyntaxElementMorph.prototype.isCachingInputs,
+ 'uncheck to stop caching\ninputs (for debugging the evaluator)',
+ 'check to cache inputs\nboosts recursion',
+ true
+ );
+ addPreference(
'Rasterize SVGs',
function () {
MorphicPreferences.rasterizeSVGs =
@@ -2377,8 +2388,8 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addItem(
'Save to disk',
'saveProjectToDisk',
- 'store this project\nin your downloads folder\n'
- + '(not supported by all browsers)'
+ 'store this project\nin the downloads folder\n'
+ + '(in supporting browsers)'
);
menu.addItem('Save As...', 'saveProjectsBrowser');
menu.addLine();
diff --git a/help/receiveClick.png b/help/receiveInteraction.png
index 6ace2e3..6ace2e3 100644
--- a/help/receiveClick.png
+++ b/help/receiveInteraction.png
Binary files differ
diff --git a/history.txt b/history.txt
index e125b70..1f0ec00 100755
--- a/history.txt
+++ b/history.txt
@@ -2441,3 +2441,20 @@ ______
* Un-hide “Save to disk” feature (currently supported by both Chrome and Firefox, but not by Safari)
* Update German translation
* GUI: Make “project data in URLs” a hidden dev option (prevent long urls per default)
+
+150223
+------
+* Blocks, Objects: Add user-interaction choices to the “When I am ...” hat block
+* Update German translation
+* Store: Avoid incompatibility warning for very old (pre-earmarked) projects
+
+150224
+------
+* Store: fixed #725
+
+150228
+------
+* Blocks, Store, GUI: Cache inputs, accelerates evaluating recursive reporters and warped / turbo recursive commands by up to 40%
+* Objects: slightly optimize warped / turbo execution
+* Threads: fixed #715
+* BYOB: fixed #716
diff --git a/lang-de.js b/lang-de.js
index 2a0dff7..3040cc2 100644
--- a/lang-de.js
+++ b/lang-de.js
@@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
'translator_e-mail':
'jens@moenig.org', // optional
'last_changed':
- '2015-02-20', // this, too, will appear in the Translators tab
+ '2015-02-23', // this, too, will appear in the Translators tab
// GUI
// control bar:
@@ -417,8 +417,18 @@ SnapTranslator.dict.de = {
'Wenn %greenflag angeklickt',
'when %keyHat key pressed':
'Wenn Taste %keyHat gedr\u00fcckt',
- 'when I am clicked':
- 'Wenn ich angeklickt werde',
+ 'when I am %interaction':
+ 'Wenn ich %interaction werde',
+ 'clicked':
+ 'angeklickt',
+ 'pressed':
+ 'gedr\u00fcckt',
+ 'dropped':
+ 'abgestellt',
+ 'mouse-entered':
+ 'vom Mauszeiger betreten',
+ 'mouse-departed':
+ 'vom Mauszeiger verlassen',
'when I receive %msgHat':
'Wenn ich %msgHat empfange',
'broadcast %msg':
@@ -649,8 +659,9 @@ SnapTranslator.dict.de = {
'Sichern',
'Save to disk':
'Abpeichern',
- 'store this project\nin your downloads folder\n(not supported by all browsers)':
- 'dieses Projekt herunterladen\nund lokal speichern\n(nicht von allen Browsern unters\u00fctzt)',
+ 'store this project\nin the downloads folder\n(in supporting browsers)':
+ 'dieses Projekt herunterladen\nund lokal speichern\n'
+ + '(nicht von allen Browsern unters\u00fctzt)',
'Save As...':
'Sichern als...',
'Import...':
diff --git a/locale.js b/locale.js
index af9ea6f..f6059d6 100644
--- a/locale.js
+++ b/locale.js
@@ -42,7 +42,7 @@
/*global modules, contains*/
-modules.locale = '2015-February-20';
+modules.locale = '2015-February-23';
// Global stuff
@@ -149,7 +149,7 @@ SnapTranslator.dict.de = {
'translator_e-mail':
'jens@moenig.org',
'last_changed':
- '2015-02-20'
+ '2015-02-23'
};
SnapTranslator.dict.it = {
diff --git a/objects.js b/objects.js
index 0f77351..a00c9cc 100644
--- a/objects.js
+++ b/objects.js
@@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2015-January-28';
+modules.objects = '2015-February-28';
var SpriteMorph;
var StageMorph;
@@ -621,11 +621,22 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'control',
spec: 'when %keyHat key pressed'
},
+
+ /* migrated to a newer block version:
+
receiveClick: {
type: 'hat',
category: 'control',
spec: 'when I am clicked'
},
+ */
+
+ receiveInteraction: {
+ type: 'hat',
+ category: 'control',
+ spec: 'when I am %interaction',
+ defaults: ['clicked']
+ },
receiveMessage: {
type: 'hat',
category: 'control',
@@ -1245,6 +1256,10 @@ SpriteMorph.prototype.initBlockMigrations = function () {
doStopBlock: {
selector: 'doStopThis',
inputs: [['this block']]
+ },
+ receiveClick: {
+ selector: 'receiveInteraction',
+ inputs: [['clicked']]
}
};
};
@@ -1293,8 +1308,6 @@ SpriteMorph.prototype.blockAlternatives = {
setSize: ['changeSize'],
// control:
- receiveGo: ['receiveClick'],
- receiveClick: ['receiveGo'],
doBroadcast: ['doBroadcastAndWait'],
doBroadcastAndWait: ['doBroadcast'],
doIf: ['doIfElse', 'doUntil'],
@@ -1496,15 +1509,13 @@ SpriteMorph.prototype.setName = function (string) {
SpriteMorph.prototype.drawNew = function () {
var myself = this,
- currentCenter = this.center(),
+ currentCenter,
facing, // actual costume heading based on my rotation style
isFlipped,
- isLoadingCostume = this.costume &&
- typeof this.costume.loaded === 'function',
+ isLoadingCostume,
cst,
pic, // (flipped copy of) actual costume based on my rotation style
- stageScale = this.parent instanceof StageMorph ?
- this.parent.scale : 1,
+ stageScale,
newX,
corners = [],
origin,
@@ -1518,6 +1529,11 @@ SpriteMorph.prototype.drawNew = function () {
this.wantsRedraw = true;
return;
}
+ currentCenter = this.center();
+ isLoadingCostume = this.costume &&
+ typeof this.costume.loaded === 'function';
+ stageScale = this.parent instanceof StageMorph ?
+ this.parent.scale : 1;
facing = this.rotationStyle ? this.heading : 90;
if (this.rotationStyle === 2) {
facing = 90;
@@ -1666,7 +1682,7 @@ SpriteMorph.prototype.blockForSelector = function (selector, setDefaults) {
: new ReporterBlockMorph(info.type === 'predicate');
block.color = this.blockColor[info.category];
block.category = info.category;
- block.selector = selector;
+ block.selector = migration ? migration.selector : selector;
if (contains(['reifyReporter', 'reifyPredicate'], block.selector)) {
block.isStatic = true;
}
@@ -1920,7 +1936,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('receiveGo'));
blocks.push(block('receiveKey'));
- blocks.push(block('receiveClick'));
+ blocks.push(block('receiveInteraction'));
blocks.push(block('receiveMessage'));
blocks.push('-');
blocks.push(block('doBroadcast'));
@@ -3274,6 +3290,7 @@ SpriteMorph.prototype.prepareToBeGrabbed = function (hand) {
SpriteMorph.prototype.justDropped = function () {
this.restoreLayers();
this.positionTalkBubble();
+ this.receiveUserInteraction('dropped');
};
// SpriteMorph drawing:
@@ -3604,9 +3621,6 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) {
if (morph.selector === 'receiveOnClone') {
return message === '__clone__init__';
}
- if (morph.selector === 'receiveClick') {
- return message === '__click__';
- }
}
return false;
});
@@ -3623,13 +3637,37 @@ SpriteMorph.prototype.allHatBlocksForKey = function (key) {
});
};
+SpriteMorph.prototype.allHatBlocksForInteraction = function (interaction) {
+ return this.scripts.children.filter(function (morph) {
+ if (morph.selector) {
+ if (morph.selector === 'receiveInteraction') {
+ return morph.inputs()[0].evaluate()[0] === interaction;
+ }
+ }
+ return false;
+ });
+};
+
// SpriteMorph events
SpriteMorph.prototype.mouseClickLeft = function () {
- var stage = this.parentThatIsA(StageMorph),
- hats = this.allHatBlocksFor('__click__'),
- procs = [];
+ return this.receiveUserInteraction('clicked');
+};
+
+SpriteMorph.prototype.mouseEnter = function () {
+ return this.receiveUserInteraction('mouse-entered');
+};
+
+SpriteMorph.prototype.mouseDownLeft = function () {
+ return this.receiveUserInteraction('pressed');
+};
+SpriteMorph.prototype.receiveUserInteraction = function (interaction) {
+ var stage = this.parentThatIsA(StageMorph),
+ procs = [],
+ hats;
+ if (!stage) {return; } // currently dragged
+ hats = this.allHatBlocksForInteraction(interaction);
hats.forEach(function (block) {
procs.push(stage.threads.startProcess(block, stage.isThreadSafe));
});
@@ -4294,6 +4332,7 @@ SpriteMorph.prototype.mouseEnterDragging = function () {
};
SpriteMorph.prototype.mouseLeave = function () {
+ this.receiveUserInteraction('mouse-departed');
if (!this.enableNesting) {return; }
this.removeHighlight();
};
@@ -5063,7 +5102,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('receiveGo'));
blocks.push(block('receiveKey'));
- blocks.push(block('receiveClick'));
+ blocks.push(block('receiveInteraction'));
blocks.push(block('receiveMessage'));
blocks.push('-');
blocks.push(block('doBroadcast'));
@@ -5617,11 +5656,27 @@ StageMorph.prototype.allHatBlocksFor
StageMorph.prototype.allHatBlocksForKey
= SpriteMorph.prototype.allHatBlocksForKey;
+StageMorph.prototype.allHatBlocksForInteraction
+ = SpriteMorph.prototype.allHatBlocksForInteraction;
+
// StageMorph events
StageMorph.prototype.mouseClickLeft
= SpriteMorph.prototype.mouseClickLeft;
+StageMorph.prototype.mouseEnter
+ = SpriteMorph.prototype.mouseEnter;
+
+StageMorph.prototype.mouseLeave = function () {
+ this.receiveUserInteraction('mouse-departed');
+};
+
+StageMorph.prototype.mouseDownLeft
+ = SpriteMorph.prototype.mouseDownLeft;
+
+StageMorph.prototype.receiveUserInteraction
+ = SpriteMorph.prototype.receiveUserInteraction;
+
// StageMorph custom blocks
StageMorph.prototype.deleteAllBlockInstances
diff --git a/store.js b/store.js
index 8d78578..edee641 100644
--- a/store.js
+++ b/store.js
@@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/
// Global stuff ////////////////////////////////////////////////////////
-modules.store = '2015-January-21';
+modules.store = '2015-February-28';
// XML_Serializer ///////////////////////////////////////////////////////
@@ -320,7 +320,7 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode, ide) {
var appInfo = xmlNode.attributes.app,
app = appInfo ? appInfo.split(' ')[0] : null;
- if (ide && app !== this.app.split(' ')[0]) {
+ if (ide && app && app !== this.app.split(' ')[0]) {
ide.inform(
app + ' Project',
'This project has been created by a different app:\n\n' +
@@ -977,7 +977,11 @@ SnapSerializer.prototype.loadBlock = function (model, isReporter) {
);
}
if (!receiver) {
- return this.obsoleteBlock(isReporter);
+ if (!isGlobal) {
+ receiver = this.project.stage;
+ } else {
+ return this.obsoleteBlock(isReporter);
+ }
}
if (isGlobal) {
info = detect(receiver.globalBlocks, function (block) {
@@ -1023,6 +1027,7 @@ SnapSerializer.prototype.loadBlock = function (model, isReporter) {
this.loadInput(child, inputs[i], block);
}
}, this);
+ block.cachedInputs = null;
return block;
};
diff --git a/threads.js b/threads.js
index 1804737..10f263f 100644
--- a/threads.js
+++ b/threads.js
@@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
// Global stuff ////////////////////////////////////////////////////////
-modules.threads = '2015-January-12';
+modules.threads = '2015-February-28';
var ThreadManager;
var Process;
@@ -1926,7 +1926,7 @@ Process.prototype.reportTypeOf = function (thing) {
if (thing === true || (thing === false)) {
return 'Boolean';
}
- if (!isNaN(parseFloat(thing))) {
+ if (!isNaN(+thing)) {
return 'number';
}
if (isString(thing)) {