summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Leper <bl.nero@gmail.com>2015-07-20 21:33:33 +0200
committerBartosz Leper <bl.nero@gmail.com>2015-07-20 21:33:33 +0200
commit81476aa5882ec7a25dc03e4f8f5a14ff412434a9 (patch)
tree9e8e882e250168563afca79636d0dba9351bc3a9
parent12671a1fbd6044f22ba037347b6af1bf170af9da (diff)
parent53068ea25954431c174dca1e76ca924b00243c2f (diff)
downloadsnap-81476aa5882ec7a25dc03e4f8f5a14ff412434a9.tar.gz
snap-81476aa5882ec7a25dc03e4f8f5a14ff412434a9.zip
Merge branch 'master' into manual
-rw-r--r--blocks.js112
-rw-r--r--byob.js2
-rw-r--r--gui.js54
-rwxr-xr-xhistory.txt11
-rw-r--r--index.html7
-rw-r--r--lang-fr.js154
-rw-r--r--lists.js5
-rw-r--r--locale.js4
-rw-r--r--morphic.js372
-rwxr-xr-xmorphic.txt37
-rw-r--r--objects.js19
-rw-r--r--paint.js4
-rw-r--r--store.js2
-rw-r--r--threads.js43
-rw-r--r--widgets.js4
-rwxr-xr-x[-rw-r--r--]xml.js129
16 files changed, 487 insertions, 472 deletions
diff --git a/blocks.js b/blocks.js
index 67324ca..0a4c5ed 100644
--- a/blocks.js
+++ b/blocks.js
@@ -155,8 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph, Costume*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2015-June-08';
-
+modules.blocks = '2015-June-25';
var SyntaxElementMorph;
var BlockMorph;
@@ -360,6 +359,10 @@ SyntaxElementMorph.prototype.init = function () {
this.cachedInputs = null;
};
+// SyntaxElementMorph stepping:
+
+SyntaxElementMorph.prototype.step = null;
+
// SyntaxElementMorph accessing:
SyntaxElementMorph.prototype.parts = function () {
@@ -1111,9 +1114,9 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
acos : ['acos'],
atan : ['atan'],
ln : ['ln'],
- // log : 'log',
- 'e^' : ['e^']
- // '10^' : '10^'
+ log : ['log'],
+ 'e^' : ['e^'],
+ '10^' : ['10^']
},
true
);
@@ -1417,16 +1420,19 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
new Point() : this.embossing;
part.drawNew();
} else {
- part = new StringMorph(spec);
- part.fontName = this.labelFontName;
- part.fontStyle = this.labelFontStyle;
- part.fontSize = this.fontSize;
- part.color = new Color(255, 255, 255);
- part.isBold = true;
- part.shadowColor = this.color.darker(this.labelContrast);
- part.shadowOffset = MorphicPreferences.isFlat ?
- new Point() : this.embossing;
- part.drawNew();
+ part = new StringMorph(
+ spec, // text
+ this.fontSize, // fontSize
+ this.labelFontStyle, // fontStyle
+ true, // bold
+ false, // italic
+ false, // isNumeric
+ MorphicPreferences.isFlat ?
+ new Point() : this.embossing, // shadowOffset
+ this.color.darker(this.labelContrast), // shadowColor
+ new Color(255, 255, 255), // color
+ this.labelFontName // fontName
+ );
}
return part;
};
@@ -2058,7 +2064,8 @@ BlockMorph.prototype.setSpec = function (spec) {
}
part = myself.labelPart(word);
myself.add(part);
- if (!(part instanceof CommandSlotMorph)) {
+ if (!(part instanceof CommandSlotMorph ||
+ part instanceof StringMorph)) {
part.drawNew();
}
if (part instanceof RingMorph) {
@@ -2225,7 +2232,7 @@ BlockMorph.prototype.userMenu = function () {
);
if (this instanceof CommandBlockMorph && this.nextBlock()) {
menu.addItem(
- this.thumbnail(0.5, 60, false),
+ this.thumbnail(0.5, 60),
function () {
var cpy = this.fullCopy(),
nb = cpy.nextBlock(),
@@ -3103,38 +3110,34 @@ BlockMorph.prototype.mouseClickLeft = function () {
// BlockMorph thumbnail
-BlockMorph.prototype.thumbnail = function (scale, clipWidth, noShadow) {
- var block = this.fullCopy(),
- nb = block.nextBlock(),
+BlockMorph.prototype.thumbnail = function (scale, clipWidth) {
+ var nb = this.nextBlock(),
fadeout = 12,
ext,
trgt,
ctx,
gradient;
- if (nb) {nb.destroy(); }
- if (!noShadow) {block.addShadow(); }
- ext = block.fullBounds().extent();
- if (!noShadow) {
- ext = ext.subtract(this.shadowBlur *
- (useBlurredShadows && !MorphicPreferences.isFlat ? 1 : 2));
- }
+
+ if (nb) {nb.isVisible = false; }
+ ext = this.fullBounds().extent();
trgt = newCanvas(new Point(
- Math.min(ext.x * scale, clipWidth || ext.x),
+ clipWidth ? Math.min(ext.x * scale, clipWidth) : ext.x * scale,
ext.y * scale
));
ctx = trgt.getContext('2d');
ctx.scale(scale, scale);
- ctx.drawImage(block.fullImage(), 0, 0);
+ ctx.drawImage(this.fullImage(), 0, 0);
// draw fade-out
- if (trgt.width === clipWidth) {
+ if (clipWidth && ext.x * scale > clipWidth) {
gradient = ctx.createLinearGradient(
trgt.width / scale - fadeout,
0,
trgt.width / scale,
0
);
- gradient.addColorStop(0, new Color(255, 255, 255, 0).toString());
- gradient.addColorStop(1, 'white');
+ gradient.addColorStop(0, 'transparent');
+ gradient.addColorStop(1, 'black');
+ ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = gradient;
ctx.fillRect(
trgt.width / scale - fadeout,
@@ -3143,6 +3146,7 @@ BlockMorph.prototype.thumbnail = function (scale, clipWidth, noShadow) {
trgt.height / scale
);
}
+ if (nb) {nb.isVisible = true; }
return trgt;
};
@@ -6917,7 +6921,8 @@ InputSlotMorph.prototype.setChoices = function (dict, readonly) {
// InputSlotMorph layout:
InputSlotMorph.prototype.fixLayout = function () {
- var contents = this.contents(),
+ var width, height, arrowWidth,
+ contents = this.contents(),
arrow = this.arrow();
contents.isNumeric = this.isNumeric;
@@ -6934,35 +6939,32 @@ InputSlotMorph.prototype.fixLayout = function () {
arrow.setSize(this.fontSize);
arrow.show();
} else {
- arrow.setSize(0);
arrow.hide();
}
- this.setHeight(
- contents.height()
- + this.edge * 2
- // + this.typeInPadding * 2
- );
+ arrowWidth = arrow.isVisible ? arrow.width() : 0;
+
+ height = contents.height() + this.edge * 2; // + this.typeInPadding * 2
if (this.isNumeric) {
- this.setWidth(contents.width()
- + Math.floor(arrow.width() * 0.5)
- + this.height()
- + this.typeInPadding * 2
- );
+ width = contents.width()
+ + Math.floor(arrowWidth * 0.5)
+ + height
+ + this.typeInPadding * 2;
} else {
- this.setWidth(Math.max(
+ width = Math.max(
contents.width()
- + arrow.width()
+ + arrowWidth
+ this.edge * 2
+ this.typeInPadding * 2,
contents.rawHeight ? // single vs. multi-line contents
- contents.rawHeight() + arrow.width()
- : contents.height() / 1.2 + arrow.width(),
+ contents.rawHeight() + arrowWidth
+ : contents.height() / 1.2 + arrowWidth,
this.minWidth // for text-type slots
- ));
+ );
}
+ this.setExtent(new Point(width, height));
if (this.isNumeric) {
contents.setPosition(new Point(
- Math.floor(this.height() / 2),
+ Math.floor(height / 2),
this.edge
).add(new Point(this.typeInPadding, 0)).add(this.position()));
} else {
@@ -6972,10 +6974,12 @@ InputSlotMorph.prototype.fixLayout = function () {
).add(new Point(this.typeInPadding, 0)).add(this.position()));
}
- arrow.setPosition(new Point(
- this.right() - arrow.width() - this.edge,
- contents.top()
- ));
+ if (arrow.isVisible) {
+ arrow.setPosition(new Point(
+ this.right() - arrowWidth - this.edge,
+ contents.top()
+ ));
+ }
if (this.parent) {
if (this.parent.fixLayout) {
diff --git a/byob.js b/byob.js
index 1c2cfee..4c39872 100644
--- a/byob.js
+++ b/byob.js
@@ -106,7 +106,7 @@ SymbolMorph, isNil*/
// Global stuff ////////////////////////////////////////////////////////
-modules.byob = '2015-May-23';
+modules.byob = '2015-June-25';
// Declarations
diff --git a/gui.js b/gui.js
index 026a12c..eee2bd5 100644
--- a/gui.js
+++ b/gui.js
@@ -69,7 +69,7 @@ SpeechBubbleMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2015-May-18';
+modules.gui = '2015-June-25';
// Declarations
@@ -82,6 +82,11 @@ var WardrobeMorph;
var SoundIconMorph;
var JukeboxMorph;
+// Get the full url without "snap.html"
+var baseUrl = document.URL.split('/');
+baseUrl.pop(baseUrl.length - 1);
+baseUrl = baseUrl.join('/') + '/';
+
// IDE_Morph ///////////////////////////////////////////////////////////
// I am SNAP's top-level frame, the Editor window
@@ -304,7 +309,8 @@ IDE_Morph.prototype.openIn = function (world) {
}
throw new Error('unable to retrieve ' + url);
} catch (err) {
- return;
+ myself.showMessage('unable to retrieve project');
+ return '';
}
}
@@ -2491,13 +2497,10 @@ IDE_Morph.prototype.projectMenu = function () {
function () {
// read a list of libraries from an external file,
var libMenu = new MenuMorph(this, 'Import library'),
- libUrl = 'http://snap.berkeley.edu/snapsource/libraries/' +
- 'LIBRARIES';
+ libUrl = baseUrl + 'libraries/' + 'LIBRARIES';
function loadLib(name) {
- var url = 'http://snap.berkeley.edu/snapsource/libraries/'
- + name
- + '.xml';
+ var url = baseUrl + 'libraries/' + name + '.xml';
myself.droppedText(myself.getURL(url), name);
}
@@ -2614,7 +2617,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world();
- aboutTxt = 'Snap! 4.0\nBuild Your Own Blocks\n\n'
+ aboutTxt = 'Snap! 4.0.1\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2015 Jens M\u00F6nig and '
+ 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@@ -2648,7 +2651,7 @@ IDE_Morph.prototype.aboutSnap = function () {
creditsTxt = localize('Contributors')
+ '\n\nNathan Dinsmore: Saving/Loading, Snap-Logo Design, '
- + 'countless bugfixes'
+ + '\ncountless bugfixes and optimizations'
+ '\nKartik Chandra: Paint Editor'
+ '\nMichael Ball: Time/Date UI, many bugfixes'
+ '\n"Ava" Yuan Yuan: Graphic Effects'
@@ -4216,8 +4219,7 @@ IDE_Morph.prototype.getURLsbeOrRelative = function (url) {
var request = new XMLHttpRequest(),
myself = this;
try {
- request.open('GET', 'http://snap.berkeley.edu/snapsource/' +
- url, false);
+ request.open('GET', baseUrl + url, false);
request.send();
if (request.status === 200) {
return request.responseText;
@@ -4658,8 +4660,7 @@ ProjectDialogMorph.prototype.setSource = function (source) {
myself.nameField.setContents(item.name || '');
}
src = myself.ide.getURL(
- 'http://snap.berkeley.edu/snapsource/Examples/' +
- item.name + '.xml'
+ baseUrl + 'Examples/' + item.name + '.xml'
);
xml = myself.ide.serializer.parse(src);
@@ -4713,8 +4714,9 @@ ProjectDialogMorph.prototype.getLocalProjectList = function () {
ProjectDialogMorph.prototype.getExamplesProjectList = function () {
var dir,
projects = [];
+ //alert(baseUrl);
- dir = this.ide.getURL('http://snap.berkeley.edu/snapsource/Examples/');
+ dir = this.ide.getURL(baseUrl + 'Examples/');
dir.split('\n').forEach(
function (line) {
var startIdx = line.search(new RegExp('href=".*xml"')),
@@ -4733,8 +4735,8 @@ ProjectDialogMorph.prototype.getExamplesProjectList = function () {
}
}
);
- projects.sort(function (x, y) {
- return x.name < y.name ? -1 : 1;
+ projects = projects.sort(function (x, y) {
+ return x.name.toLowerCase() < y.name.toLowerCase() ? -1 : 1;
});
return projects;
};
@@ -4833,10 +4835,7 @@ ProjectDialogMorph.prototype.openProject = function () {
if (this.source === 'cloud') {
this.openCloudProject(proj);
} else if (this.source === 'examples') {
- src = this.ide.getURL(
- 'http://snap.berkeley.edu/snapsource/Examples/' +
- proj.name + '.xml'
- );
+ src = this.ide.getURL(baseUrl + 'Examples/' + proj.name + '.xml');
this.ide.openProjectString(src);
this.destroy();
} else { // 'local'
@@ -5006,6 +5005,7 @@ ProjectDialogMorph.prototype.deleteProject = function () {
ProjectDialogMorph.prototype.shareProject = function () {
var myself = this,
+ ide = this.ide,
proj = this.listField.selected,
entry = this.listField.active;
@@ -5036,6 +5036,15 @@ ProjectDialogMorph.prototype.shareProject = function () {
myself.ide.cloudError(),
[proj.ProjectName]
);
+ // Set the Shared URL if the project is currently open
+ if (proj.ProjectName === ide.projectName) {
+ var usr = SnapCloud.username,
+ projectId = 'Username=' +
+ encodeURIComponent(usr.toLowerCase()) +
+ '&ProjectName=' +
+ encodeURIComponent(proj.projectName);
+ location.hash = projectId;
+ }
},
myself.ide.cloudError()
);
@@ -5046,6 +5055,7 @@ ProjectDialogMorph.prototype.shareProject = function () {
ProjectDialogMorph.prototype.unshareProject = function () {
var myself = this,
+ ide = this.ide,
proj = this.listField.selected,
entry = this.listField.active;
@@ -5077,6 +5087,10 @@ ProjectDialogMorph.prototype.unshareProject = function () {
myself.ide.cloudError(),
[proj.ProjectName]
);
+ // Remove the shared URL if the project is open.
+ if (proj.ProjectName === ide.projectName) {
+ location.hash = '';
+ }
},
myself.ide.cloudError()
);
diff --git a/history.txt b/history.txt
index 1262a28..74d6d1f 100755
--- a/history.txt
+++ b/history.txt
@@ -2516,3 +2516,14 @@ ______
150608
------
* Blocks: Fixed #820
+
+150625
+------
+* Morphic, Objects, Blocks, XML: Optimizations and dramatic speed-up. Thanks, Nathan!!
+* Objects: push maximum clone count up to 1000, tweak Note::play
+
+=== Start with v4.0.1 ===
+
+150626
+------
+* Morphic: Fix Inspector duplication, update documentation
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..4c1a0f4
--- /dev/null
+++ b/index.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta HTTP-EQUIV="REFRESH" content="0.1; url=snap.html">
+ </head>
+</html>
+
diff --git a/lang-fr.js b/lang-fr.js
index 4198bf7..20da480 100644
--- a/lang-fr.js
+++ b/lang-fr.js
@@ -185,7 +185,7 @@ SnapTranslator.dict.fr = {
'translator_e-mail':
'i.scool@mac.com', // optional
'last_changed':
- '2014-02-04', // this, too, will appear in the Translators tab
+ '2015-06-25', // this, too, will appear in the Translators tab
// GUI
// control bar:
@@ -392,7 +392,7 @@ SnapTranslator.dict.fr = {
'clear':
'effacer tout',
'pen down':
- 'stylo en position d\u0027\u00EAcriture',
+ 'stylo en position d\u0027\u00E9criture',
'pen up':
'relever le stylo',
'set pen color to %clr':
@@ -419,6 +419,8 @@ SnapTranslator.dict.fr = {
'Quand %keyHat est press\u00E9',
'when I am clicked':
'Quand je suis press\u00E9 ',
+ 'when I am %interaction':
+ 'Quand je suis %interaction',
'when I receive %msgHat':
'Quand je re\u00E7ois %msgHat',
'broadcast %msg':
@@ -447,6 +449,10 @@ SnapTranslator.dict.fr = {
'arr\u00EAter le bloc',
'stop script':
'arr\u00EAter le script',
+ 'stop %stopOthersChoices':
+ 'arr\u00EAter %stopOthersChoices',
+ 'stop %stopChoices':
+ 'arr\u00EAter %stopChoices',
'stop all %stop':
'arr\u00EAter tout %stop',
'run %cmdRing %inputs':
@@ -469,8 +475,16 @@ SnapTranslator.dict.fr = {
'moi-m\u00EAme',
'delete this clone':
'supprime ce clone',
- 'pause all':
- 'mettre en pause',
+ 'pause all %pause':
+ 'mettre en pause %pause',
+ 'all but this script':
+ 'tout sauf ce lutin',
+ 'other scripts in sprite':
+ 'les autres scripts de ce lutin',
+ 'this script':
+ 'ce script',
+ 'this block':
+ 'ce bloc',
// sensing:
'touching %col ?':
@@ -958,6 +972,8 @@ SnapTranslator.dict.fr = {
'tabulations',
'cr':
'retours de ligne',
+ 'letter':
+ 'lettres',
// About Snap
'About Snap':
@@ -1162,5 +1178,133 @@ SnapTranslator.dict.fr = {
'last':
'dernier',
'any':
- 'n\u0027importe quel'
+ 'n\u0027importe quel',
+
+ // miscellaneous
+ 'find blocks...':
+ 'chercher des blocs...',
+ 'hide primitives':
+ 'cacher les primitives',
+ 'show primitives':
+ 'montrer les primitives',
+ 'Login...':
+ 'Connexion...',
+ 'Signup...':
+ 'S\u0027enregistrer...',
+ 'Reset Password...':
+ 'Remise \u00E0 z\u00E9ro du mot de passe',
+ 'show all':
+ 'tout montrer',
+ 'pic...':
+ 'image...',
+ 'open a new window\nwith a picture of the stage':
+ 'ouvre une nouvelle fen\u00EAtre\navec une image de la sc\u00E8ne',
+ 'scripts pic...':
+ 'image des scripts...',
+ 'open a new window\nwith a picture of all scripts':
+ 'ouvre une nouvelle fen\u00EAtre\navec une image de tous les scripts',
+ 'Stage size...':
+ 'Taille de la sc\u00E8ne...',
+ 'Zoom blocks...':
+ 'Agrandir les blocs...',
+
+ 'Plain prototype labels':
+ '\u00C9tiquettes simples de d\u00E9finition',
+ 'uncheck to always show (+) symbols\nin block prototype labels':
+ 'd\u00E9cocher pour montrer en permance le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
+ 'check to hide (+) symbols\nin block prototype labels':
+ 'cocher pour cacher le symbole (+)\ndans les \u00e9tiquettes de d\u00E9finition de bloc',
+
+ 'check for flat ends of lines':
+ 'cocher pour dessiner des fins de ligne plates',
+ 'uncheck for round ends of lines':
+ 'd\u00E9cocher pour dessiner des fins de lignes arrondies',
+ 'Flat line ends':
+ 'Fins de ligne plates',
+
+ 'Codification support':
+ 'Support de la \u00AB codification \u00BB',
+ 'uncheck to disable\nblock to text mapping features':
+ 'd\u00E9cocher pour d\u00E9activer\nla fonction de transformation :\nbloc vers texte',
+ 'check for block\nto text mapping features':
+ 'cocher pour activer\nla fonction de transformation :\nbloc vers texte',
+
+ 'current %dates':
+ 'date courante %dates',
+ 'year':'ann\u00E9e',
+ 'month':'mois',
+ 'date':'jour',
+ 'hour':'heure',
+ 'minute':'minute',
+ 'second':'seconde',
+ 'time in milliseconds':
+ 'heure en millisecondes',
+ 'day of week':
+ 'jour de la semaine',
+
+ 'brightness':
+ 'luminosit\u00E9',
+ 'transparence':
+ 'transparence',
+ 'negative':
+ 'n\u00E9gatif',
+ 'comic':
+ 'bande dessin\u00E9e',
+
+ 'clicked':
+ 'cliqu\u00E9',
+ 'pressed':
+ 'press\u00E9',
+ 'dropped':
+ 'd\u00E9pos\u00E9',
+ 'mouse-entered':
+ 'survol\u00E9',
+ 'mouse-departed':
+ 'quitt\u00E9',
+
+ 'JavaScript function ( %mult%s ) { %code }':
+ 'fonction JavaScript ( %mult%s ) { %code }',
+
+
+ // Copy / Paste
+ 'Press CTRL+C one more time to effectively copy to clipboard.':
+ 'Taper une nouvelle fois sur CTRL+C pour copier effectivement vers le presse-papier.',
+ 'Press CTRL+V one more time to effectively paste from clipboard.':
+ 'Taper une nouvelle fois sur CTRL+V pour coller effectivement depuis le presse-papier.',
+ 'Press CTRL+X one more time to effectively cut to clipboard.':
+ 'Taper une nouvelle fois sur CTRL+X pour couper effectivement vers le presse-papier.',
+
+ // Paint.js
+ 'undo':'d\u00E9faire',
+ 'Paintbrush tool\n(free draw)':
+ 'Pinceau\n(dessin \u00E0 main lev\u00E9)',
+ 'Stroked Rectangle\n(shift: square)':
+ 'Rectangle\n(Maj: carr\u00E9)',
+ 'Stroked Ellipse\n(shift: circle)':
+ 'Ellipse\n(Maj: cercle)',
+ 'Eraser tool':
+ 'Gomme',
+ 'Set the rotation center':
+ 'Fixe le centre de rotation',
+ 'Line tool\n(shift: vertical/horizontal)':
+ 'Ligne\n(Maj: verticale/horizontale)',
+ 'Filled Rectangle\n(shift: square)':
+ 'Rectangle plein\n(Maj: carr\u00E9)',
+ 'Filled Ellipse\n(shift: circle)':
+ 'Ellipse pleine\n(Maj: cercle)',
+ 'Fill a region':
+ 'Remplir une r\u00E9gion',
+ 'Pipette tool\n(pick a color anywhere)':
+ 'Pipette\n(s\u00E9lectionnez une couleur n\u0027importe o\u00F9',
+ 'grow':'agrandir',
+ 'shrink':'r\u00E9duire',
+ 'flip \u2194':
+ 'miroir \u2194',
+ 'flip \u2195':
+ 'miroir \u2195',
+ 'Brush size':
+ 'Taille de pinceau',
+ 'Constrain proportions of shapes?\n(you can also hold shift)':
+ 'Contrainte sur les proportions de la forme ?\n(vous pouvez aussi maintenir appuy\u00E9 Maj)'
+
};
diff --git a/lists.js b/lists.js
index bd856fe..6fc9545 100644
--- a/lists.js
+++ b/lists.js
@@ -7,7 +7,7 @@
written by Jens Mönig and Brian Harvey
jens@moenig.org, bh@cs.berkeley.edu
- Copyright (C) 2014 by Jens Mönig and Brian Harvey
+ Copyright (C) 2015 by Jens Mönig and Brian Harvey
This file is part of Snap!.
@@ -61,7 +61,7 @@ PushButtonMorph, SyntaxElementMorph, Color, Point, WatcherMorph,
StringMorph, SpriteMorph, ScrollFrameMorph, CellMorph, ArrowMorph,
MenuMorph, snapEquals, Morph, isNil, localize, MorphicPreferences*/
-modules.lists = '2014-November-20';
+modules.lists = '2015-June-25';
var List;
var ListWatcherMorph;
@@ -634,6 +634,7 @@ ListWatcherMorph.prototype.setStartIndex = function (index) {
};
ListWatcherMorph.prototype.fixLayout = function () {
+ if (!this.label) {return; }
Morph.prototype.trackChanges = false;
if (this.frame) {
this.arrangeCells();
diff --git a/locale.js b/locale.js
index 7407180..af1e0f4 100644
--- a/locale.js
+++ b/locale.js
@@ -42,7 +42,7 @@
/*global modules, contains*/
-modules.locale = '2015-May-18';
+modules.locale = '2015-June-25';
// Global stuff
@@ -257,7 +257,7 @@ SnapTranslator.dict.fr = {
'translator_e-mail':
'i.scool@mac.com',
'last_changed':
- '2014-02-04'
+ '2015-06-25'
};
SnapTranslator.dict.si = {
diff --git a/morphic.js b/morphic.js
index 2850e32..f26c7bf 100644
--- a/morphic.js
+++ b/morphic.js
@@ -528,7 +528,7 @@
whose "isTemplate" flag is false, in other words: a non-template.
When creating a copy from a template, the copy's
-
+
reactToTemplateCopy
is invoked, if it is present.
@@ -828,13 +828,13 @@
// use context to paint stuff here
};
- If your new morph stores or references other morphs outside of the
- submorph tree in other properties, be sure to also override the
+ If your new morph stores or references to other morphs outside of
+ the submorph tree in other properties, be sure to also override the
default
- copyRecordingReferences()
+ updateReferences()
- method accordingly if you want it to support duplication.
+ method if you want it to support duplication.
(6) development and user modes
@@ -1036,7 +1036,7 @@
----------------------
Joe Otto found and fixed many early bugs and taught me some tricks.
Nathan Dinsmore contributed mouse wheel scrolling, cached
- background texture handling and countless bug fixes.
+ background texture handling, countless bug fixes and optimizations.
Ian Reynolds contributed backspace key handling for Chrome.
Davide Della Casa contributed performance optimizations for Firefox.
@@ -1048,7 +1048,7 @@
/*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio,
FileList, getBlurredShadowSupport*/
-var morphicVersion = '2015-May-01';
+var morphicVersion = '2015-June-26';
var modules = {}; // keep track of additional loaded modules
var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug
@@ -1243,19 +1243,9 @@ function getDocumentPositionOf(aDOMelement) {
return pos;
}
-function clone(target) {
- // answer a new instance of target's type
- if (typeof target === 'object') {
- var Clone = function () {nop(); };
- Clone.prototype = target;
- return new Clone();
- }
- return target;
-}
-
function copy(target) {
// answer a shallow copy of target
- var value, c, property;
+ var value, c, property, keys, l, i;
if (typeof target !== 'object') {
return target;
@@ -1266,18 +1256,16 @@ function copy(target) {
}
if (target instanceof target.constructor &&
target.constructor !== Object) {
- c = clone(target.constructor.prototype);
- for (property in target) {
- if (Object.prototype.hasOwnProperty.call(target, property)) {
- c[property] = target[property];
- }
+ c = Object.create(target.constructor.prototype);
+ keys = Object.keys(target);
+ for (l = keys.length, i = 0; i < l; i += 1) {
+ property = keys[i];
+ c[property] = target[property];
}
} else {
c = {};
for (property in target) {
- if (!c[property]) {
- c[property] = target[property];
- }
+ c[property] = target[property];
}
}
return c;
@@ -2212,7 +2200,7 @@ function Morph() {
// Morph initialization:
-Morph.prototype.init = function () {
+Morph.prototype.init = function (noDraw) {
Morph.uber.init.call(this);
this.isMorph = true;
this.bounds = new Rectangle(0, 0, 50, 40);
@@ -2225,7 +2213,7 @@ Morph.prototype.init = function () {
this.isTemplate = false;
this.acceptsDrops = false;
this.noticesTransparentClick = false;
- this.drawNew();
+ if (!noDraw) {this.drawNew(); }
this.fps = 0;
this.customContextMenu = null;
this.lastTime = Date.now();
@@ -2411,19 +2399,19 @@ Morph.prototype.visibleBounds = function () {
// Morph accessing - simple changes:
Morph.prototype.moveBy = function (delta) {
- this.changed();
- this.bounds = this.bounds.translateBy(delta);
- this.children.forEach(function (child) {
- child.moveBy(delta);
- });
- this.changed();
+ this.fullChanged();
+ this.silentMoveBy(delta);
+ this.fullChanged();
};
Morph.prototype.silentMoveBy = function (delta) {
+ var children = this.children,
+ i = children.length;
this.bounds = this.bounds.translateBy(delta);
- this.children.forEach(function (child) {
- child.silentMoveBy(delta);
- });
+ // ugly optimization avoiding forEach()
+ for (i; i > 0; i -= 1) {
+ children[i - 1].silentMoveBy(delta);
+ }
};
Morph.prototype.setPosition = function (aPoint) {
@@ -2899,7 +2887,7 @@ Morph.prototype.fullChanged = function () {
};
Morph.prototype.childChanged = function () {
- // react to a change in one of my children,
+ // react to a change in one of my children,
// default is to just pass this message on upwards
// override this method for Morphs that need to adjust accordingly
if (this.parent) {
@@ -2936,6 +2924,18 @@ Morph.prototype.addBack = function (aMorph) {
this.addChildFirst(aMorph);
};
+Morph.prototype.topMorphAt = function (point) {
+ var i, result;
+ if (!this.isVisible) {return null; }
+ for (i = this.children.length - 1; i >= 0; i -= 1) {
+ result = this.children[i].topMorphAt(point);
+ if (result) {return result; }
+ }
+ return this.bounds.containsPoint(point) &&
+ (this.noticesTransparentClick || !this.isTransparentAt(point)) ? this
+ : null;
+};
+
Morph.prototype.topMorphSuchThat = function (predicate) {
var next;
if (predicate.call(null, this)) {
@@ -2951,30 +2951,6 @@ Morph.prototype.topMorphSuchThat = function (predicate) {
return null;
};
-Morph.prototype.morphAt = function (aPoint) {
- var morphs = this.allChildren().slice(0).reverse(),
- result = null;
- morphs.forEach(function (m) {
- if (m.fullBounds().containsPoint(aPoint) &&
- (result === null)) {
- result = m;
- }
- });
- return result;
-};
-
-/*
- alternative - more elegant and possibly more
- performant - solution for morphAt.
- Has some issues, commented out for now
-
-Morph.prototype.morphAt = function (aPoint) {
- return this.topMorphSuchThat(function (m) {
- return m.fullBounds().containsPoint(aPoint);
- });
-};
-*/
-
Morph.prototype.overlappedMorphs = function () {
//exclude the World
var world = this.world(),
@@ -3046,45 +3022,54 @@ Morph.prototype.fullCopy = function () {
Other properties are also *shallow* copied, so you must override
to deep copy Arrays and (complex) Objects
*/
- var dict = {}, c;
- c = this.copyRecordingReferences(dict);
+ var map = new Map(), c;
+ c = this.copyRecordingReferences(map);
c.forAllChildren(function (m) {
- m.updateReferences(dict);
+ m.updateReferences(map);
});
return c;
};
-Morph.prototype.copyRecordingReferences = function (dict) {
+Morph.prototype.copyRecordingReferences = function (map) {
/*
Recursively copy this entire composite morph, recording the
correspondence between old and new morphs in the given dictionary.
This dictionary will be used to update intra-composite references
in the copy. See updateReferences().
- Note: This default implementation copies ONLY morphs in the
- submorph hierarchy. If a morph stores morphs in other properties
- that it wants to copy, then it should override this method to do so.
- The same goes for morphs that contain other complex data that
- should be copied when the morph is duplicated.
+
+ Note: This default implementation copies ONLY morphs. If a morph
+ stores morphs in other properties that it wants to copy, then it
+ should override this method to do so. The same goes for morphs that
+ contain other complex data that should be copied when the morph is
+ duplicated.
*/
var c = this.copy();
- dict[this] = c;
+ map.set(this, c);
this.children.forEach(function (m) {
- c.add(m.copyRecordingReferences(dict));
+ c.add(m.copyRecordingReferences(map));
});
return c;
};
-Morph.prototype.updateReferences = function (dict) {
+Morph.prototype.updateReferences = function (map) {
/*
Update intra-morph references within a composite morph that has
been copied. For example, if a button refers to morph X in the
orginal composite then the copy of that button in the new composite
should refer to the copy of X in new composite, not the original X.
*/
- var property;
- for (property in this) {
- if (this[property] && this[property].isMorph && dict[property]) {
- this[property] = dict[property];
+ var properties = Object.keys(this),
+ l = properties.length,
+ property,
+ value,
+ reference,
+ i;
+ for (i = 0; i < l; i += 1) {
+ property = properties[i];
+ value = this[property];
+ if (value && value.isMorph) {
+ reference = map.get(value);
+ if (reference) { this[property] = reference; }
}
}
};
@@ -3155,9 +3140,7 @@ Morph.prototype.slideBackTo = function (situation, inSteps) {
this.fps = 0;
this.step = function () {
- myself.fullChanged();
- myself.silentMoveBy(new Point(xStep, yStep));
- myself.fullChanged();
+ myself.moveBy(new Point(xStep, yStep));
stepCount += 1;
if (stepCount === steps) {
situation.origin.add(myself);
@@ -3706,6 +3689,10 @@ function ShadowMorph() {
this.init();
}
+ShadowMorph.prototype.topMorphAt = function () {
+ return null;
+};
+
// HandleMorph ////////////////////////////////////////////////////////
// I am a resize / move handle that can be attached to any Morph
@@ -3923,20 +3910,6 @@ HandleMorph.prototype.mouseLeave = function () {
this.changed();
};
-// HandleMorph duplicating:
-
-HandleMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = HandleMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.target && dict[this.target]) {
- c.target = (dict[this.target]);
- }
- return c;
-};
-
// HandleMorph menu:
HandleMorph.prototype.attach = function () {
@@ -4260,20 +4233,6 @@ ColorPaletteMorph.prototype.updateTarget = function () {
}
};
-// ColorPaletteMorph duplicating:
-
-ColorPaletteMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = ColorPaletteMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.target && dict[this.target]) {
- c.target = (dict[this.target]);
- }
- return c;
-};
-
// ColorPaletteMorph menu:
ColorPaletteMorph.prototype.developersMenu = function () {
@@ -5840,23 +5799,6 @@ SliderMorph.prototype.updateTarget = function () {
}
};
-// SliderMorph duplicating:
-
-SliderMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = SliderMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.target && dict[this.target]) {
- c.target = (dict[this.target]);
- }
- if (c.button && dict[this.button]) {
- c.button = (dict[this.button]);
- }
- return c;
-};
-
// SliderMorph menu:
SliderMorph.prototype.developersMenu = function () {
@@ -6563,7 +6505,7 @@ InspectorMorph.prototype.setExtent = function (aPoint) {
this.fixLayout();
};
-//InspectorMorph editing ops:
+// InspectorMorph editing ops:
InspectorMorph.prototype.save = function () {
var txt = this.detail.contents.children[0].text.toString(),
@@ -6653,6 +6595,15 @@ InspectorMorph.prototype.step = function () {
this.fixLayout();
};
+// InspectorMorph duplicating:
+
+InspectorMorph.prototype.updateReferences = function (map) {
+ var active = this.list.activeIndex();
+ InspectorMorph.uber.updateReferences.call(this, map);
+ this.buildPanes();
+ this.list.activateIndex(active);
+};
+
// MenuMorph ///////////////////////////////////////////////////////////
// MenuMorph: referenced constructors
@@ -7024,7 +6975,7 @@ StringMorph.prototype.init = function (
this.markedBackgoundColor = new Color(60, 60, 120);
// initialize inherited properties:
- StringMorph.uber.init.call(this);
+ StringMorph.uber.init.call(this, true);
// override inherited properites:
this.color = color || new Color(0, 0, 0);
@@ -7402,6 +7353,11 @@ StringMorph.prototype.selectionStartSlot = function () {
};
StringMorph.prototype.clearSelection = function () {
+ if (!this.currentlySelecting &&
+ this.startMark === 0 &&
+ this.endMark === 0) {
+ return;
+ }
this.currentlySelecting = false;
this.startMark = 0;
this.endMark = 0;
@@ -8141,20 +8097,6 @@ TriggerMorph.prototype.createLabel = function () {
this.add(this.label);
};
-// TriggerMorph duplicating:
-
-TriggerMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = TriggerMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.label && dict[this.label]) {
- c.label = (dict[this.label]);
- }
- return c;
-};
-
// TriggerMorph action:
TriggerMorph.prototype.trigger = function () {
@@ -8500,15 +8442,19 @@ FrameMorph.prototype.fullDrawOn = function (aCanvas, aRect) {
});
};
-// FrameMorph scrolling optimization:
+// FrameMorph navigation:
-FrameMorph.prototype.moveBy = function (delta) {
- this.changed();
- this.bounds = this.bounds.translateBy(delta);
- this.children.forEach(function (child) {
- child.silentMoveBy(delta);
- });
- this.changed();
+FrameMorph.prototype.topMorphAt = function (point) {
+ var i, result;
+ if (!(this.isVisible && this.bounds.containsPoint(point))) {
+ return null;
+ }
+ for (i = this.children.length - 1; i >= 0; i -= 1) {
+ result = this.children[i].topMorphAt(point);
+ if (result) {return result; }
+ }
+ return this.noticesTransparentClick ||
+ !this.isTransparentAt(point) ? this : null;
};
// FrameMorph scrolling support:
@@ -8600,20 +8546,6 @@ FrameMorph.prototype.reactToGrabOf = function () {
this.adjustBounds();
};
-// FrameMorph duplicating:
-
-FrameMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = FrameMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.frame && dict[this.scrollFrame]) {
- c.frame = (dict[this.scrollFrame]);
- }
- return c;
-};
-
// FrameMorph menus:
FrameMorph.prototype.developersMenu = function () {
@@ -8958,32 +8890,23 @@ ScrollFrameMorph.prototype.mouseScroll = function (y, x) {
// ScrollFrameMorph duplicating:
-ScrollFrameMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = ScrollFrameMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.contents && dict[this.contents]) {
- c.contents = (dict[this.contents]);
- }
- if (c.hBar && dict[this.hBar]) {
- c.hBar = (dict[this.hBar]);
- c.hBar.action = function (num) {
- c.contents.setPosition(
- new Point(c.left() - num, c.contents.position().y)
+ScrollFrameMorph.prototype.updateReferences = function (map) {
+ var myself = this;
+ ScrollFrameMorph.uber.updateReferences.call(this, map);
+ if (this.hBar) {
+ this.hBar.action = function (num) {
+ myself.contents.setPosition(
+ new Point(myself.left() - num, myself.contents.position().y)
);
};
}
- if (c.vBar && dict[this.vBar]) {
- c.vBar = (dict[this.vBar]);
- c.vBar.action = function (num) {
- c.contents.setPosition(
- new Point(c.contents.position().x, c.top() - num)
+ if (this.vBar) {
+ this.vBar.action = function (num) {
+ myself.contents.setPosition(
+ new Point(myself.contents.position().x, myself.top() - num)
);
};
}
- return c;
};
// ScrollFrameMorph menu:
@@ -9147,6 +9070,18 @@ ListMorph.prototype.setExtent = function (aPoint) {
ListMorph.uber.setExtent.call(this, aPoint);
};
+ListMorph.prototype.activeIndex = function () {
+ return this.listContents.children.indexOf(this.active);
+};
+
+ListMorph.prototype.activateIndex = function (idx) {
+ var item = this.listContents.children[idx];
+ if (!item) {return; }
+ item.image = item.pressImage;
+ item.changed();
+ item.trigger();
+};
+
// StringFieldMorph ////////////////////////////////////////////////////
// StringFieldMorph inherit from FrameMorph:
@@ -9243,20 +9178,6 @@ StringFieldMorph.prototype.mouseClickLeft = function (pos) {
}
};
-// StringFieldMorph duplicating:
-
-StringFieldMorph.prototype.copyRecordingReferences = function (dict) {
- // inherited, see comment in Morph
- var c = StringFieldMorph.uber.copyRecordingReferences.call(
- this,
- dict
- );
- if (c.text && dict[this.text]) {
- c.text = (dict[this.text]);
- }
- return c;
-};
-
// BouncerMorph ////////////////////////////////////////////////////////
// I am a Demo of a stepping custom Morph
@@ -9384,54 +9305,18 @@ HandMorph.prototype.changed = function () {
if (this.world !== null) {
b = this.fullBounds();
if (!b.extent().eq(new Point())) {
- this.world.broken.push(this.fullBounds().spread());
+ this.world.broken.push(b.spread());
}
}
-
};
-// HandMorph navigation:
-
-HandMorph.prototype.morphAtPointer = function () {
- var morphs = this.world.allChildren().slice(0).reverse(),
- myself = this,
- result = null;
-
- morphs.forEach(function (m) {
- if (m.visibleBounds().containsPoint(myself.bounds.origin) &&
- result === null &&
- m.isVisible &&
- (m.noticesTransparentClick ||
- (!m.isTransparentAt(myself.bounds.origin))) &&
- (!(m instanceof ShadowMorph)) &&
- m.allParents().every(function (each) {
- return each.isVisible;
- })) {
- result = m;
- }
- });
- if (result !== null) {
- return result;
- }
- return this.world;
-};
+HandMorph.prototype.fullChanged = HandMorph.prototype.changed;
-/*
- alternative - more elegant and possibly more
- performant - solution for morphAtPointer.
- Has some issues, commented out for now
+// HandMorph navigation:
HandMorph.prototype.morphAtPointer = function () {
- var myself = this;
- return this.world.topMorphSuchThat(function (m) {
- return m.visibleBounds().containsPoint(myself.bounds.origin) &&
- m.isVisible &&
- (m.noticesTransparentClick ||
- (! m.isTransparentAt(myself.bounds.origin))) &&
- (! (m instanceof ShadowMorph));
- });
+ return this.world.topMorphAt(this.bounds.origin) || this.world;
};
-*/
HandMorph.prototype.allMorphsAtPointer = function () {
var morphs = this.world.allChildren(),
@@ -9971,16 +9856,6 @@ HandMorph.prototype.destroyTemporaries = function () {
});
};
-// HandMorph dragging optimization
-
-HandMorph.prototype.moveBy = function (delta) {
- Morph.prototype.trackChanges = false;
- HandMorph.uber.moveBy.call(this, delta);
- Morph.prototype.trackChanges = true;
- this.fullChanged();
-};
-
-
// WorldMorph //////////////////////////////////////////////////////////
// I represent the <canvas> element
@@ -10009,6 +9884,7 @@ WorldMorph.prototype.init = function (aCanvas, fillPage) {
this.isDraggable = false;
this.currentKey = null; // currently pressed key code
this.worldCanvas = aCanvas;
+ this.noticesTransparentClick = true;
// additional properties:
this.stamp = Date.now(); // reference in multi-world setups
diff --git a/morphic.txt b/morphic.txt
index 042b7e5..11a323d 100755
--- a/morphic.txt
+++ b/morphic.txt
@@ -7,9 +7,9 @@
written by Jens Mönig
jens@moenig.org
- Copyright (C) 2012 by Jens Mönig
+ Copyright (C) 2015 by Jens Mönig
- this documentation last changed: April 07, 2013
+ this documentation last changed: June 26, 2015
This file is part of Snap!.
@@ -465,9 +465,15 @@
MyMorph.prototype.mouseMove = function(pos) {};
- The only optional parameter of such a method is a Point object
+ All of these methods have as optional parameter a Point object
indicating the current position of the Hand inside the World's
- coordinate system.
+ coordinate system. The
+
+ mouseMove(pos, button)
+
+ event method has an additional optional parameter indicating the
+ currently pressed mouse button, which is either 'left' or 'right'.
+ You can use this to let users interact with 3D environments.
Events may be "bubbled" up a morph's owner chain by calling
@@ -522,6 +528,12 @@
a duplicate of the template whose "isDraggable" flag is true and
whose "isTemplate" flag is false, in other words: a non-template.
+ When creating a copy from a template, the copy's
+
+ reactToTemplateCopy
+
+ is invoked, if it is present.
+
Dragging is indicated by adding a drop shadow to the morph in hand.
If a morph follows the hand without displaying a drop shadow it is
merely being moved about without changing its parent (owner morph),
@@ -817,13 +829,13 @@
// use context to paint stuff here
};
- If your new morph stores or references other morphs outside of the
- submorph tree in other properties, be sure to also override the
+ If your new morph stores or references to other morphs outside of
+ the submorph tree in other properties, be sure to also override the
default
- copyRecordingReferences()
+ updateReferences()
- method accordingly if you want it to support duplication.
+ method if you want it to support duplication.
(6) development and user modes
@@ -1015,16 +1027,17 @@
programming hero.
I have originally written morphic.js in Florian Balmer's Notepad2
- editor for Windows and later switched to Apple's Dashcode. I've also
- come to depend on both Douglas Crockford's JSLint, Mozilla's Firebug
- and Google's Chrome to get it right.
+ editor for Windows, later switched to Apple's Dashcode and later
+ still to Apple's Xcode. I've also come to depend on both Douglas
+ Crockford's JSLint, Mozilla's Firebug and Google's Chrome to get
+ it right.
IX. contributors
----------------------
Joe Otto found and fixed many early bugs and taught me some tricks.
Nathan Dinsmore contributed mouse wheel scrolling, cached
- background texture handling and countless bug fixes.
+ background texture handling, countless bug fixes and optimizations.
Ian Reynolds contributed backspace key handling for Chrome.
Davide Della Casa contributed performance optimizations for Firefox.
diff --git a/objects.js b/objects.js
index 8cae1c7..3f95385 100644
--- a/objects.js
+++ b/objects.js
@@ -105,7 +105,7 @@ InspectorMorph, ListMorph, Math, MenuItemMorph, MenuMorph, Morph,
MorphicPreferences, MouseSensorMorph, Node, Object, PenMorph, Point,
Rectangle, ScrollFrameMorph, ShadowMorph, SliderButtonMorph,
SliderMorph, String, StringFieldMorph, StringMorph, TextMorph,
-TriggerMorph, WorldMorph, clone, contains, copy, degrees, detect,
+TriggerMorph, WorldMorph, contains, copy, degrees, detect,
document, getDocumentPositionOf, isNaN, isObject, isString, newCanvas,
nop, parseFloat, radians, standardSettings, touchScreenSettings,
useBlurredShadows, version, window, modules, IDE_Morph, VariableDialogMorph,
@@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2015-May-18';
+modules.objects = '2015-June-25';
var SpriteMorph;
var StageMorph;
@@ -583,7 +583,7 @@ SpriteMorph.prototype.initBlocks = function () {
},
/* migrated to a newer block version:
-
+
receiveClick: {
type: 'hat',
category: 'control',
@@ -2718,7 +2718,7 @@ SpriteMorph.prototype.remove = function () {
SpriteMorph.prototype.createClone = function () {
var stage = this.parentThatIsA(StageMorph);
- if (stage && stage.cloneCount <= 300) {
+ if (stage && stage.cloneCount <= 1000) {
this.fullCopy().clonify(stage);
}
};
@@ -3008,7 +3008,7 @@ SpriteMorph.prototype.applyGraphicsEffects = function (canvas) {
var i;
if (value !== 0) {
for (i = 0; i < p.length; i += 4) {
- p[i] += value; //255 = 100% of this color
+ p[i] += value; //255 = 100% of this color
p[i + 1] += value;
p[i + 2] += value;
}
@@ -3290,7 +3290,7 @@ SpriteMorph.prototype.nestingBounds = function () {
// SpriteMorph motion primitives
-Morph.prototype.setPosition = function (aPoint, justMe) {
+SpriteMorph.prototype.setPosition = function (aPoint, justMe) {
// override the inherited default to make sure my parts follow
// unless it's justMe
var delta = aPoint.subtract(this.topLeft());
@@ -3509,7 +3509,10 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) {
if (morph.selector) {
if (morph.selector === 'receiveMessage') {
event = morph.inputs()[0].evaluate();
- return event === message || (event instanceof Array);
+ return event === message
+ || (event instanceof Array
+ && message !== '__shout__go__'
+ && message !== '__clone__init__');
}
if (morph.selector === 'receiveGo') {
return message === '__shout__go__';
@@ -6429,7 +6432,7 @@ Note.prototype.play = function () {
if (!this.oscillator.stop) {
this.oscillator.stop = this.oscillator.noteOff;
}
- this.oscillator.type = 0;
+ this.oscillator.type = 'sine';
this.oscillator.frequency.value =
Math.pow(2, (this.pitch - 69) / 12) * 440;
this.oscillator.connect(this.gainNode);
diff --git a/paint.js b/paint.js
index 65ae1f6..6d9b09c 100644
--- a/paint.js
+++ b/paint.js
@@ -5,7 +5,7 @@
inspired by the Scratch paint editor.
written by Kartik Chandra
- Copyright (C) 2014 by Kartik Chandra
+ Copyright (C) 2015 by Kartik Chandra
This file is part of Snap!.
@@ -69,7 +69,7 @@
// Global stuff ////////////////////////////////////////////////////////
-modules.paint = '2014-September-29';
+modules.paint = '2015-June-25';
// Declarations
diff --git a/store.js b/store.js
index 5cba3c3..e73ba9f 100644
--- a/store.js
+++ b/store.js
@@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/
// Global stuff ////////////////////////////////////////////////////////
-modules.store = '2015-April-26';
+modules.store = '2015-June-25';
// XML_Serializer ///////////////////////////////////////////////////////
diff --git a/threads.js b/threads.js
index 165ad0e..af899dc 100644
--- a/threads.js
+++ b/threads.js
@@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
// Global stuff ////////////////////////////////////////////////////////
-modules.threads = '2015-May-01';
+modules.threads = '2015-June-25';
var ThreadManager;
var Process;
@@ -339,7 +339,7 @@ ThreadManager.prototype.findProcess = function (block) {
*/
Process.prototype = {};
-Process.prototype.contructor = Process;
+Process.prototype.constructor = Process;
Process.prototype.timeout = 500; // msecs after which to force yield
Process.prototype.isCatchingErrors = true;
@@ -2122,14 +2122,14 @@ Process.prototype.reportMonadic = function (fname, n) {
case 'ln':
result = Math.log(x);
break;
- case 'log':
- result = 0;
+ case 'log': // base 10
+ result = Math.log(x) / Math.LN10;
break;
case 'e^':
result = Math.exp(x);
break;
case '10^':
- result = 0;
+ result = Math.pow(10, x);
break;
default:
nop();
@@ -2640,31 +2640,30 @@ Process.prototype.reportTimer = function () {
};
// Process Dates and times in Snap
-// Map block options to built-in functions
-var dateMap = {
- 'year' : 'getFullYear',
- 'month' : 'getMonth',
- 'date': 'getDate',
- 'day of week' : 'getDay',
- 'hour' : 'getHours',
- 'minute' : 'getMinutes',
- 'second' : 'getSeconds',
- 'time in milliseconds' : 'getTime'
-};
-
Process.prototype.reportDate = function (datefn) {
- var inputFn = this.inputOption(datefn),
- currDate = new Date(),
- func = dateMap[inputFn],
- result = currDate[func]();
+ var currDate, func, result,
+ inputFn = this.inputOption(datefn),
+ // Map block options to built-in functions
+ dateMap = {
+ 'year' : 'getFullYear',
+ 'month' : 'getMonth',
+ 'date': 'getDate',
+ 'day of week' : 'getDay',
+ 'hour' : 'getHours',
+ 'minute' : 'getMinutes',
+ 'second' : 'getSeconds',
+ 'time in milliseconds' : 'getTime'
+ };
if (!dateMap[inputFn]) { return ''; }
+ currDate = new Date();
+ func = dateMap[inputFn];
+ result = currDate[func]();
// Show months as 1-12 and days as 1-7
if (inputFn === 'month' || inputFn === 'day of week') {
result += 1;
}
-
return result;
};
diff --git a/widgets.js b/widgets.js
index bb250a8..a8644af 100644
--- a/widgets.js
+++ b/widgets.js
@@ -7,7 +7,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!.
@@ -74,7 +74,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph,
ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences,
ScrollFrameMorph*/
-modules.widgets = '2014-February-13';
+modules.widgets = '2015-June-25';
var PushButtonMorph;
var ToggleButtonMorph;
diff --git a/xml.js b/xml.js
index fb612ce..b80f520 100644..100755
--- a/xml.js
+++ b/xml.js
@@ -7,7 +7,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!.
@@ -57,15 +57,17 @@
Nathan Dinsmore contributed to the design and implemented a first
working version of a complete XMLSerializer. I have taken much of the
overall design and many of the functions and methods in this file from
- Nathan's fine original prototype.
+ Nathan's fine original prototype. Recently Nathan has once again
+ worked his magic on the parser and optimized it by an order of
+ magnitude.
*/
-/*global modules, isString, detect, Node, isNil*/
+/*global modules, detect, Node, isNil*/
// Global stuff ////////////////////////////////////////////////////////
-modules.xml = '2014-January-09';
+modules.xml = '2015-June-25';
// Declarations
@@ -85,7 +87,8 @@ function ReadStream(arrayOrString) {
// ReadStream constants:
-ReadStream.prototype.space = /[\s]/;
+ReadStream.prototype.nonSpace = /\S|$/g;
+ReadStream.prototype.nonWord = /[\s\>\/\=]|$/g;
// ReadStream accessing:
@@ -115,46 +118,26 @@ ReadStream.prototype.atEnd = function () {
// ReadStream accessing String contents:
-ReadStream.prototype.upTo = function (regex) {
- var i, start;
- if (!isString(this.contents)) {return ''; }
- i = this.contents.substr(this.index).search(regex);
- if (i === -1) {
- return '';
- }
- start = this.index;
- this.index += i;
- return this.contents.substring(start, this.index);
+ReadStream.prototype.upTo = function (str) {
+ var i = this.contents.indexOf(str, this.index);
+ return i === -1 ? '' : this.contents.slice(this.index, this.index = i);
};
-ReadStream.prototype.peekUpTo = function (regex) {
- if (!isString(this.contents)) {return ''; }
- var i = this.contents.substr(this.index).search(regex);
- if (i === -1) {
- return '';
- }
- return this.contents.substring(this.index, this.index + i);
+ReadStream.prototype.peekUpTo = function (str) {
+ var i = this.contents.indexOf(str, this.index);
+ return i === -1 ? '' : this.contents.slice(this.index, i);
};
ReadStream.prototype.skipSpace = function () {
- if (!isString(this.contents)) {return ''; }
- var ch = this.peek();
- while (this.space.test(ch) && ch !== '') {
- this.skip();
- ch = this.peek();
- }
+ this.nonSpace.lastIndex = this.index;
+ var result = this.nonSpace.exec(this.contents);
+ if (result) this.index = result.index;
};
ReadStream.prototype.word = function () {
- var i, start;
- if (!isString(this.contents)) {return ''; }
- i = this.contents.substr(this.index).search(/[\s\>\/\=]|$/);
- if (i === -1) {
- return '';
- }
- start = this.index;
- this.index += i;
- return this.contents.substring(start, this.index);
+ this.nonWord.lastIndex = this.index;
+ var result = this.nonWord.exec(this.contents);
+ return result ? this.contents.slice(this.index, this.index = result.index) : '';
};
// XML_Element ///////////////////////////////////////////////////////////
@@ -166,7 +149,7 @@ ReadStream.prototype.word = function () {
// XML_Element inherits from Node:
-XML_Element.prototype = new Node();
+XML_Element.prototype = Object.create(Node.prototype);
XML_Element.prototype.constructor = XML_Element;
XML_Element.uber = Node.prototype;
@@ -190,9 +173,7 @@ XML_Element.prototype.init = function (tag, contents, parent) {
XML_Element.uber.init.call(this);
// override inherited properties
- if (parent instanceof XML_Element) {
- parent.addChild(this);
- }
+ if (parent) parent.addChild(this);
};
// XML_Element DOM navigation: (aside from what's inherited from Node)
@@ -318,51 +299,18 @@ XML_Element.prototype.escape = function (string, ignoreQuotes) {
};
XML_Element.prototype.unescape = function (string) {
- var stream = new ReadStream(string),
- result = '',
- ch,
- esc;
-
- function nextPut(str) {
- result += str;
- stream.upTo(';');
- stream.skip();
- }
-
- while (!stream.atEnd()) {
- ch = stream.next();
- if (ch === '&') {
- esc = stream.peekUpTo(';');
- switch (esc) {
- case 'apos':
- nextPut('\'');
- break;
- case 'quot':
- nextPut('\"');
- break;
- case 'lt':
- nextPut('<');
- break;
- case 'gt':
- nextPut('>');
- break;
- case 'amp':
- nextPut('&');
- break;
- case '#xD':
- nextPut('\n');
- break;
- case '#126':
- nextPut('~');
- break;
- default:
- result += ch;
- }
- } else {
- result += ch;
+ return string.replace(/&(amp|apos|quot|lt|gt|#xD|#126);/g, function(_, name) {
+ switch (name) {
+ case 'amp': return '&';
+ case 'apos': return '\'';
+ case 'quot': return '"';
+ case 'lt': return '<';
+ case 'gt': return '>';
+ case '#xD': return '\n';
+ case '#126': return '~';
+ default: console.warn('unreachable');
}
- }
- return result;
+ });
};
// XML_Element parsing:
@@ -375,10 +323,7 @@ XML_Element.prototype.parseString = function (string) {
};
XML_Element.prototype.parseStream = function (stream) {
- var key,
- value,
- ch,
- child;
+ var key, value, ch, child;
// tag:
this.tag = stream.word();
@@ -395,9 +340,7 @@ XML_Element.prototype.parseStream = function (stream) {
stream.skipSpace();
ch = stream.next();
if (ch !== '"' && ch !== "'") {
- throw new Error(
- 'Expected single- or double-quoted attribute value'
- );
+ throw new Error('Expected single- or double-quoted attribute value');
}
value = stream.upTo(ch);
stream.skip(1);
@@ -407,7 +350,7 @@ XML_Element.prototype.parseStream = function (stream) {
}
// empty tag:
- if (stream.peek() === '/') {
+ if (ch === '/') {
stream.skip();
if (stream.next() !== '>') {
throw new Error('Expected ">" after "/" in empty tag');