summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--byob.js20
-rw-r--r--cloud.js1281
-rw-r--r--gui.js81
-rwxr-xr-xhistory.txt22
-rw-r--r--lang-ca.js72
-rw-r--r--lang-it.js103
-rwxr-xr-x[-rw-r--r--]lang-ko.js492
-rw-r--r--locale.js18
-rw-r--r--manifest.mf3
-rw-r--r--objects.js45
-rwxr-xr-xscriptsPaneTexture.gifbin155 -> 0 bytes
-rw-r--r--store.js31
-rw-r--r--threads.js8
14 files changed, 1361 insertions, 817 deletions
diff --git a/README.md b/README.md
index cf17e18..878274d 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ inspired by Scratch
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
Snap! is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
diff --git a/byob.js b/byob.js
index b5905ce..ec714f1 100644
--- a/byob.js
+++ b/byob.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!.
@@ -106,7 +106,7 @@ SymbolMorph, isNil*/
// Global stuff ////////////////////////////////////////////////////////
-modules.byob = '2014-November-20';
+modules.byob = '2015-January-21';
// Declarations
@@ -209,12 +209,14 @@ CustomBlockDefinition.prototype.copyAndBindTo = function (sprite) {
c.receiver = sprite; // only for (kludgy) serialization
c.declarations = copy(this.declarations); // might have to go deeper
- c.body = Process.prototype.reify.call(
- null,
- this.body.expression,
- new List(this.inputNames())
- );
- c.body.outerContext = null;
+ if (c.body) {
+ c.body = Process.prototype.reify.call(
+ null,
+ this.body.expression,
+ new List(this.inputNames())
+ );
+ c.body.outerContext = null;
+ }
return c;
};
@@ -1649,7 +1651,7 @@ BlockEditorMorph.prototype.init = function (definition, target) {
scripts = new ScriptsMorph(target);
scripts.isDraggable = false;
scripts.color = IDE_Morph.prototype.groupColor;
- scripts.texture = IDE_Morph.prototype.scriptsPaneTexture;
+ scripts.cachedTexture = IDE_Morph.prototype.scriptsPaneTexture;
scripts.cleanUpMargin = 10;
proto = new PrototypeHatBlockMorph(this.definition);
diff --git a/cloud.js b/cloud.js
index 54189d8..ed7233f 100644
--- a/cloud.js
+++ b/cloud.js
@@ -1,639 +1,642 @@
-/*
-
- cloud.js
-
- a backend API for SNAP!
-
- written by Jens Mönig
-
- Copyright (C) 2014 by Jens Mönig
-
- This file is part of Snap!.
-
- Snap! is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-// Global settings /////////////////////////////////////////////////////
-
-/*global modules, IDE_Morph, SnapSerializer, hex_sha512, alert, nop,
-localize*/
-
-modules.cloud = '2014-May-26';
-
-// Global stuff
-
-var Cloud;
-
-var SnapCloud = new Cloud(
- 'https://snapcloud.miosoft.com/miocon/app/login?_app=SnapCloud'
-);
-
-// Cloud /////////////////////////////////////////////////////////////
-
-function Cloud(url) {
- this.username = null;
- this.password = null; // hex_sha512 hashed
- this.url = url;
- this.session = null;
- this.api = {};
-}
-
-Cloud.prototype.clear = function () {
- this.username = null;
- this.password = null;
- this.session = null;
- this.api = {};
-};
-
-Cloud.prototype.hasProtocol = function () {
- return this.url.toLowerCase().indexOf('http') === 0;
-};
-
-// Cloud: Snap! API
-
-Cloud.prototype.signup = function (
- username,
- email,
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://')
- + this.url + 'SignUp'
- + '&Username='
- + encodeURIComponent(username)
- + '&Email='
- + encodeURIComponent(email),
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- if (request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText,
- 'Signup'
- );
- } else {
- callBack.call(
- null,
- request.responseText,
- 'Signup'
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url + 'SignUp',
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
-
-Cloud.prototype.getPublicProject = function (
- id,
- callBack,
- errorCall
-) {
- // id is Username=username&projectName=projectname,
- // where the values are url-component encoded
- // callBack is a single argument function, errorCall take two args
- var request = new XMLHttpRequest(),
- responseList,
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://')
- + this.url + 'Public'
- + '&'
- + id,
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- if (request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText
- );
- } else {
- responseList = myself.parseResponse(
- request.responseText
- );
- callBack.call(
- null,
- responseList[0].SourceCode
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url + 'Public',
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
-
-Cloud.prototype.resetPassword = function (
- username,
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://')
- + this.url + 'ResetPW'
- + '&Username='
- + encodeURIComponent(username),
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- if (request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText,
- 'Reset Password'
- );
- } else {
- callBack.call(
- null,
- request.responseText,
- 'Reset Password'
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url + 'ResetPW',
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
-
-Cloud.prototype.connect = function (
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://') + this.url,
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- myself.api = myself.parseAPI(request.responseText);
- myself.session = request.getResponseHeader('MioCracker')
- .split(';')[0];
- if (myself.api.login) {
- callBack.call(null, myself.api, 'Snap!Cloud');
- } else {
- errorCall.call(
- null,
- 'connection failed'
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url,
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
-
-
-Cloud.prototype.login = function (
- username,
- password,
- callBack,
- errorCall
-) {
- var myself = this;
- this.connect(
- function () {
- myself.rawLogin(username, password, callBack, errorCall);
- myself.disconnect();
- },
- errorCall
- );
-};
-
-Cloud.prototype.rawLogin = function (
- username,
- password,
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var myself = this,
- pwHash = hex_sha512("miosoft%20miocon,"
- + this.session.split('=')[1] + ","
- + encodeURIComponent(username.toLowerCase()) + ","
- + password // alreadey hex_sha512 hashed
- );
- this.callService(
- 'login',
- function (response, url) {
- if (myself.api.logout) {
- myself.username = username;
- myself.password = password;
- callBack.call(null, response, url);
- } else {
- errorCall.call(
- null,
- 'Service catalog is not available,\nplease retry',
- 'Connection Error:'
- );
- }
- },
- errorCall,
- [username, pwHash]
- );
-};
-
-Cloud.prototype.reconnect = function (
- callBack,
- errorCall
-) {
- if (!(this.username && this.password)) {
- this.message('You are not logged in');
- return;
- }
- this.login(
- this.username,
- this.password,
- callBack,
- errorCall
- );
-};
-
-Cloud.prototype.saveProject = function (ide, callBack, errorCall) {
- var myself = this,
- pdata,
- media;
-
- ide.serializer.isCollectingMedia = true;
- pdata = ide.serializer.serialize(ide.stage);
- media = ide.hasChangedMedia ?
- ide.serializer.mediaXML(ide.projectName) : null;
- ide.serializer.isCollectingMedia = false;
- ide.serializer.flushMedia();
-
- // check if serialized data can be parsed back again
- try {
- ide.serializer.parse(pdata);
- } catch (err) {
- ide.showMessage('Serialization of program data failed:\n' + err);
- throw new Error('Serialization of program data failed:\n' + err);
- }
- if (media !== null) {
- try {
- ide.serializer.parse(media);
- } catch (err) {
- ide.showMessage('Serialization of media failed:\n' + err);
- throw new Error('Serialization of media failed:\n' + err);
- }
- }
- ide.serializer.isCollectingMedia = false;
- ide.serializer.flushMedia();
-
- myself.reconnect(
- function () {
- myself.callService(
- 'saveProject',
- function (response, url) {
- callBack.call(null, response, url);
- myself.disconnect();
- ide.hasChangedMedia = false;
- },
- errorCall,
- [
- ide.projectName,
- pdata,
- media,
- pdata.length,
- media ? media.length : 0
- ]
- );
- },
- errorCall
- );
-};
-
-Cloud.prototype.getProjectList = function (callBack, errorCall) {
- var myself = this;
- this.reconnect(
- function () {
- myself.callService(
- 'getProjectList',
- function (response, url) {
- callBack.call(null, response, url);
- myself.disconnect();
- },
- errorCall
- );
- },
- errorCall
- );
-};
-
-Cloud.prototype.changePassword = function (
- oldPW,
- newPW,
- callBack,
- errorCall
-) {
- var myself = this;
- this.reconnect(
- function () {
- myself.callService(
- 'changePassword',
- function (response, url) {
- callBack.call(null, response, url);
- myself.disconnect();
- },
- errorCall,
- [oldPW, newPW]
- );
- },
- errorCall
- );
-};
-
-Cloud.prototype.logout = function (callBack, errorCall) {
- this.clear();
- this.callService(
- 'logout',
- callBack,
- errorCall
- );
-};
-
-Cloud.prototype.disconnect = function () {
- this.callService(
- 'logout',
- nop,
- nop
- );
-};
-
-// Cloud: backend communication
-
-Cloud.prototype.callURL = function (url, callBack, errorCall) {
- // both callBack and errorCall are optional two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open('GET', url, true);
- request.withCredentials = true;
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.setRequestHeader('MioCracker', this.session);
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- var responseList = myself.parseResponse(
- request.responseText
- );
- callBack.call(null, responseList, url);
- } else {
- errorCall.call(
- null,
- url,
- 'no response from:'
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), url);
- }
-};
-
-Cloud.prototype.callService = function (
- serviceName,
- callBack,
- errorCall,
- args
-) {
- // both callBack and errorCall are optional two-argument functions
- var request = new XMLHttpRequest(),
- service = this.api[serviceName],
- myself = this,
- postDict;
-
- if (!this.session) {
- errorCall.call(null, 'You are not connected', 'Cloud');
- return;
- }
- if (!service) {
- errorCall.call(
- null,
- 'service ' + serviceName + ' is not available',
- 'API'
- );
- return;
- }
- if (args && args.length > 0) {
- postDict = {};
- service.parameters.forEach(function (parm, idx) {
- postDict[parm] = args[idx];
- });
- }
- try {
- request.open(service.method, service.url, true);
- request.withCredentials = true;
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.setRequestHeader('MioCracker', this.session);
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- var responseList = [];
- if (request.responseText &&
- request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText,
- localize('Service:') + ' ' + localize(serviceName)
- );
- return;
- }
- if (serviceName === 'login') {
- myself.api = myself.parseAPI(request.responseText);
- }
- responseList = myself.parseResponse(
- request.responseText
- );
- callBack.call(null, responseList, service.url);
- }
- };
- request.send(this.encodeDict(postDict));
- } catch (err) {
- errorCall.call(this, err.toString(), service.url);
- }
-};
-
-// Cloud: payload transformation
-
-Cloud.prototype.parseAPI = function (src) {
- var api = {},
- services;
- services = src.split(" ");
- services.forEach(function (service) {
- var entries = service.split("&"),
- serviceDescription = {},
- parms;
- entries.forEach(function (entry) {
- var pair = entry.split("="),
- key = decodeURIComponent(pair[0]).toLowerCase(),
- val = decodeURIComponent(pair[1]);
- if (key === "service") {
- api[val] = serviceDescription;
- } else if (key === "parameters") {
- parms = val.split(",");
- if (!(parms.length === 1 && !parms[0])) {
- serviceDescription.parameters = parms;
- }
- } else {
- serviceDescription[key] = val;
- }
- });
- });
- return api;
-};
-
-Cloud.prototype.parseResponse = function (src) {
- var ans = [],
- lines;
- if (!src) {return ans; }
- lines = src.split(" ");
- lines.forEach(function (service) {
- var entries = service.split("&"),
- dict = {};
- entries.forEach(function (entry) {
- var pair = entry.split("="),
- key = decodeURIComponent(pair[0]),
- val = decodeURIComponent(pair[1]);
- dict[key] = val;
- });
- ans.push(dict);
- });
- return ans;
-};
-
-Cloud.prototype.parseDict = function (src) {
- var dict = {};
- if (!src) {return dict; }
- src.split("&").forEach(function (entry) {
- var pair = entry.split("="),
- key = decodeURIComponent(pair[0]),
- val = decodeURIComponent(pair[1]);
- dict[key] = val;
- });
- return dict;
-};
-
-Cloud.prototype.encodeDict = function (dict) {
- var str = '',
- pair,
- key;
- if (!dict) {return null; }
- for (key in dict) {
- if (dict.hasOwnProperty(key)) {
- pair = encodeURIComponent(key)
- + '='
- + encodeURIComponent(dict[key]);
- if (str.length > 0) {
- str += '&';
- }
- str += pair;
- }
- }
- return str;
-};
-
-// Cloud: user messages (to be overridden)
-
-Cloud.prototype.message = function (string) {
- alert(string);
-};
+/*
+
+ cloud.js
+
+ a backend API for SNAP!
+
+ written by Jens Mönig
+
+ Copyright (C) 2015 by Jens Mönig
+
+ This file is part of Snap!.
+
+ Snap! is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// Global settings /////////////////////////////////////////////////////
+
+/*global modules, IDE_Morph, SnapSerializer, hex_sha512, alert, nop,
+localize*/
+
+modules.cloud = '2015-January-12';
+
+// Global stuff
+
+var Cloud;
+var SnapCloud = new Cloud(
+ 'https://snap.apps.miosoft.com/SnapCloud'
+);
+
+// Cloud /////////////////////////////////////////////////////////////
+
+function Cloud(url) {
+ this.username = null;
+ this.password = null; // hex_sha512 hashed
+ this.url = url;
+ this.session = null;
+ this.limo = null;
+ this.route = null;
+ this.api = {};
+}
+
+Cloud.prototype.clear = function () {
+ this.username = null;
+ this.password = null;
+ this.session = null;
+ this.limo = null;
+ this.route = null;
+ this.api = {};
+};
+
+Cloud.prototype.hasProtocol = function () {
+ return this.url.toLowerCase().indexOf('http') === 0;
+};
+
+Cloud.prototype.setRoute = function (username) {
+ var routes = 10,
+ userNum = 0,
+ i;
+
+ for (i = 0; i < username.length; i += 1) {
+ userNum += username.charCodeAt(i);
+ }
+ userNum = userNum % routes + 1;
+ this.route = '.sc1m' +
+ (userNum < 10 ? '0' : '') +
+ userNum;
+};
+
+// Cloud: Snap! API
+
+Cloud.prototype.signup = function (
+ username,
+ email,
+ callBack,
+ errorCall
+) {
+ // both callBack and errorCall are two-argument functions
+ var request = new XMLHttpRequest(),
+ myself = this;
+ try {
+ request.open(
+ "GET",
+ (this.hasProtocol() ? '' : 'http://')
+ + this.url + 'SignUp'
+ + '?Username='
+ + encodeURIComponent(username)
+ + '&Email='
+ + encodeURIComponent(email),
+ true
+ );
+ request.setRequestHeader(
+ "Content-Type",
+ "application/x-www-form-urlencoded"
+ );
+ request.withCredentials = true;
+ request.onreadystatechange = function () {
+ if (request.readyState === 4) {
+ if (request.responseText) {
+ if (request.responseText.indexOf('ERROR') === 0) {
+ errorCall.call(
+ this,
+ request.responseText,
+ 'Signup'
+ );
+ } else {
+ callBack.call(
+ null,
+ request.responseText,
+ 'Signup'
+ );
+ }
+ } else {
+ errorCall.call(
+ null,
+ myself.url + 'SignUp',
+ localize('could not connect to:')
+ );
+ }
+ }
+ };
+ request.send(null);
+ } catch (err) {
+ errorCall.call(this, err.toString(), 'Snap!Cloud');
+ }
+};
+
+Cloud.prototype.getPublicProject = function (
+ id,
+ callBack,
+ errorCall
+) {
+ // id is Username=username&projectName=projectname,
+ // where the values are url-component encoded
+ // callBack is a single argument function, errorCall take two args
+ var request = new XMLHttpRequest(),
+ responseList,
+ myself = this;
+ try {
+ request.open(
+ "GET",
+ (this.hasProtocol() ? '' : 'http://')
+ + this.url + 'Public'
+ + '?'
+ + id,
+ true
+ );
+ request.setRequestHeader(
+ "Content-Type",
+ "application/x-www-form-urlencoded"
+ );
+ request.withCredentials = true;
+ request.onreadystatechange = function () {
+ if (request.readyState === 4) {
+ if (request.responseText) {
+ if (request.responseText.indexOf('ERROR') === 0) {
+ errorCall.call(
+ this,
+ request.responseText
+ );
+ } else {
+ responseList = myself.parseResponse(
+ request.responseText
+ );
+ callBack.call(
+ null,
+ responseList[0].SourceCode
+ );
+ }
+ } else {
+ errorCall.call(
+ null,
+ myself.url + 'Public',
+ localize('could not connect to:')
+ );
+ }
+ }
+ };
+ request.send(null);
+ } catch (err) {
+ errorCall.call(this, err.toString(), 'Snap!Cloud');
+ }
+};
+
+Cloud.prototype.resetPassword = function (
+ username,
+ callBack,
+ errorCall
+) {
+ // both callBack and errorCall are two-argument functions
+ var request = new XMLHttpRequest(),
+ myself = this;
+ try {
+ request.open(
+ "GET",
+ (this.hasProtocol() ? '' : 'http://')
+ + this.url + 'ResetPW'
+ + '?Username='
+ + encodeURIComponent(username),
+ true
+ );
+ request.setRequestHeader(
+ "Content-Type",
+ "application/x-www-form-urlencoded"
+ );
+ request.withCredentials = true;
+ request.onreadystatechange = function () {
+ if (request.readyState === 4) {
+ if (request.responseText) {
+ if (request.responseText.indexOf('ERROR') === 0) {
+ errorCall.call(
+ this,
+ request.responseText,
+ 'Reset Password'
+ );
+ } else {
+ callBack.call(
+ null,
+ request.responseText,
+ 'Reset Password'
+ );
+ }
+ } else {
+ errorCall.call(
+ null,
+ myself.url + 'ResetPW',
+ localize('could not connect to:')
+ );
+ }
+ }
+ };
+ request.send(null);
+ } catch (err) {
+ errorCall.call(this, err.toString(), 'Snap!Cloud');
+ }
+};
+
+Cloud.prototype.login = function (
+ username,
+ password,
+ callBack,
+ errorCall
+) {
+ // both callBack and errorCall are two-argument functions
+ var request = new XMLHttpRequest(),
+ usr = JSON.stringify({'__h': password, '__u': username}),
+ myself = this;
+ this.setRoute(username);
+ try {
+ request.open(
+ "POST",
+ (this.hasProtocol() ? '' : 'http://') +
+ this.url +
+ '?SESSIONGLUE=' +
+ this.route,
+ true
+ );
+ request.setRequestHeader(
+ "Content-Type",
+ "application/json; charset=utf-8"
+ );
+ // glue this session to a route:
+ request.setRequestHeader('SESSIONGLUE', this.route);
+ request.withCredentials = true;
+ request.onreadystatechange = function () {
+ if (request.readyState === 4) {
+ if (request.responseText) {
+ myself.api = myself.parseAPI(request.responseText);
+ myself.session = request.getResponseHeader('MioCracker')
+ .split(';')[0];
+ // set the cookie identifier:
+ myself.limo = this.getResponseHeader("miocracker")
+ .substring(
+ 9,
+ this.getResponseHeader("miocracker").indexOf("=")
+ );
+ if (myself.api.logout) {
+ myself.username = username;
+ myself.password = password;
+ callBack.call(null, myself.api, 'Snap!Cloud');
+ } else {
+ errorCall.call(
+ null,
+ request.responseText,
+ 'connection failed'
+ );
+ }
+ } else {
+ errorCall.call(
+ null,
+ myself.url,
+ localize('could not connect to:')
+ );
+ }
+ }
+ };
+ request.send(usr);
+ } catch (err) {
+ errorCall.call(this, err.toString(), 'Snap!Cloud');
+ }
+};
+
+Cloud.prototype.reconnect = function (
+ callBack,
+ errorCall
+) {
+ if (!(this.username && this.password)) {
+ this.message('You are not logged in');
+ return;
+ }
+ this.login(
+ this.username,
+ this.password,
+ callBack,
+ errorCall
+ );
+};
+
+Cloud.prototype.saveProject = function (ide, callBack, errorCall) {
+ var myself = this,
+ pdata,
+ media;
+
+ ide.serializer.isCollectingMedia = true;
+ pdata = ide.serializer.serialize(ide.stage);
+ media = ide.hasChangedMedia ?
+ ide.serializer.mediaXML(ide.projectName) : null;
+ ide.serializer.isCollectingMedia = false;
+ ide.serializer.flushMedia();
+
+ // check if serialized data can be parsed back again
+ try {
+ ide.serializer.parse(pdata);
+ } catch (err) {
+ ide.showMessage('Serialization of program data failed:\n' + err);
+ throw new Error('Serialization of program data failed:\n' + err);
+ }
+ if (media !== null) {
+ try {
+ ide.serializer.parse(media);
+ } catch (err) {
+ ide.showMessage('Serialization of media failed:\n' + err);
+ throw new Error('Serialization of media failed:\n' + err);
+ }
+ }
+ ide.serializer.isCollectingMedia = false;
+ ide.serializer.flushMedia();
+
+ myself.reconnect(
+ function () {
+ myself.callService(
+ 'saveProject',
+ function (response, url) {
+ callBack.call(null, response, url);
+ myself.disconnect();
+ ide.hasChangedMedia = false;
+ },
+ errorCall,
+ [
+ ide.projectName,
+ pdata,
+ media,
+ pdata.length,
+ media ? media.length : 0
+ ]
+ );
+ },
+ errorCall
+ );
+};
+
+Cloud.prototype.getProjectList = function (callBack, errorCall) {
+ var myself = this;
+ this.reconnect(
+ function () {
+ myself.callService(
+ 'getProjectList',
+ function (response, url) {
+ callBack.call(null, response, url);
+ myself.disconnect();
+ },
+ errorCall
+ );
+ },
+ errorCall
+ );
+};
+
+Cloud.prototype.changePassword = function (
+ oldPW,
+ newPW,
+ callBack,
+ errorCall
+) {
+ var myself = this;
+ this.reconnect(
+ function () {
+ myself.callService(
+ 'changePassword',
+ function (response, url) {
+ callBack.call(null, response, url);
+ myself.disconnect();
+ },
+ errorCall,
+ [hex_sha512(oldPW), hex_sha512(newPW)]
+ );
+ },
+ errorCall
+ );
+};
+
+Cloud.prototype.logout = function (callBack, errorCall) {
+ this.clear();
+ this.callService(
+ 'logout',
+ callBack,
+ errorCall
+ );
+};
+
+Cloud.prototype.disconnect = function () {
+ this.callService(
+ 'logout',
+ nop,
+ nop
+ );
+};
+
+// Cloud: backend communication
+
+Cloud.prototype.callURL = function (url, callBack, errorCall) {
+ // both callBack and errorCall are optional two-argument functions
+ var request = new XMLHttpRequest(),
+ stickyUrl,
+ myself = this;
+ try {
+ // set the Limo. Also set the glue as a query paramter for backup.
+ stickyUrl = url +
+ '&SESSIONGLUE=' +
+ this.route +
+ '&_Limo=' +
+ this.limo;
+ request.open('GET', stickyUrl, true);
+ request.withCredentials = true;
+ request.setRequestHeader(
+ "Content-Type",
+ "application/x-www-form-urlencoded"
+ );
+ request.setRequestHeader('MioCracker', this.session);
+ // Set the glue as a request header.
+ request.setRequestHeader('SESSIONGLUE', this.route);
+ request.onreadystatechange = function () {
+ if (request.readyState === 4) {
+ if (request.responseText) {
+ var responseList = myself.parseResponse(
+ request.responseText
+ );
+ callBack.call(null, responseList, url);
+ } else {
+ errorCall.call(
+ null,
+ url,
+ 'no response from:'
+ );
+ }
+ }
+ };
+ request.send(null);
+ } catch (err) {
+ errorCall.call(this, err.toString(), url);
+ }
+};
+
+Cloud.prototype.callService = function (
+ serviceName,
+ callBack,
+ errorCall,
+ args
+) {
+ // both callBack and errorCall are optional two-argument functions
+ var request = new XMLHttpRequest(),
+ service = this.api[serviceName],
+ myself = this,
+ stickyUrl,
+ postDict;
+
+ if (!this.session) {
+ errorCall.call(null, 'You are not connected', 'Cloud');
+ return;
+ }
+ if (!service) {
+ errorCall.call(
+ null,
+ 'service ' + serviceName + ' is not available',
+ 'API'
+ );
+ return;
+ }
+ if (args && args.length > 0) {
+ postDict = {};
+ service.parameters.forEach(function (parm, idx) {
+ postDict[parm] = args[idx];
+ });
+ }
+ try {
+ stickyUrl = this.url +
+ '/' +
+ service.url +
+ '&SESSIONGLUE=' +
+ this.route +
+ '&_Limo=' +
+ this.limo;
+ request.open(service.method, stickyUrl, true);
+ request.withCredentials = true;
+ request.setRequestHeader(
+ "Content-Type",
+ "application/x-www-form-urlencoded"
+ );
+ request.setRequestHeader('MioCracker', this.session);
+ request.setRequestHeader('SESSIONGLUE', this.route);
+ request.onreadystatechange = function () {
+ if (request.readyState === 4) {
+ var responseList = [];
+ if (request.responseText &&
+ request.responseText.indexOf('ERROR') === 0) {
+ errorCall.call(
+ this,
+ request.responseText,
+ localize('Service:') + ' ' + localize(serviceName)
+ );
+ return;
+ }
+ if (serviceName === 'login') {
+ myself.api = myself.parseAPI(request.responseText);
+ }
+ responseList = myself.parseResponse(
+ request.responseText
+ );
+ callBack.call(null, responseList, service.url);
+ }
+ };
+ request.send(this.encodeDict(postDict));
+ } catch (err) {
+ errorCall.call(this, err.toString(), service.url);
+ }
+};
+
+// Cloud: payload transformation
+
+Cloud.prototype.parseAPI = function (src) {
+ var api = {},
+ services;
+ services = src.split(" ");
+ services.forEach(function (service) {
+ var entries = service.split("&"),
+ serviceDescription = {},
+ parms;
+ entries.forEach(function (entry) {
+ var pair = entry.split("="),
+ key = decodeURIComponent(pair[0]).toLowerCase(),
+ val = decodeURIComponent(pair[1]);
+ if (key === "service") {
+ api[val] = serviceDescription;
+ } else if (key === "parameters") {
+ parms = val.split(",");
+ if (!(parms.length === 1 && !parms[0])) {
+ serviceDescription.parameters = parms;
+ }
+ } else {
+ serviceDescription[key] = val;
+ }
+ });
+ });
+ return api;
+};
+
+Cloud.prototype.parseResponse = function (src) {
+ var ans = [],
+ lines;
+ if (!src) {return ans; }
+ lines = src.split(" ");
+ lines.forEach(function (service) {
+ var entries = service.split("&"),
+ dict = {};
+ entries.forEach(function (entry) {
+ var pair = entry.split("="),
+ key = decodeURIComponent(pair[0]),
+ val = decodeURIComponent(pair[1]);
+ dict[key] = val;
+ });
+ ans.push(dict);
+ });
+ return ans;
+};
+
+Cloud.prototype.parseDict = function (src) {
+ var dict = {};
+ if (!src) {return dict; }
+ src.split("&").forEach(function (entry) {
+ var pair = entry.split("="),
+ key = decodeURIComponent(pair[0]),
+ val = decodeURIComponent(pair[1]);
+ dict[key] = val;
+ });
+ return dict;
+};
+
+Cloud.prototype.encodeDict = function (dict) {
+ var str = '',
+ pair,
+ key;
+ if (!dict) {return null; }
+ for (key in dict) {
+ if (dict.hasOwnProperty(key)) {
+ pair = encodeURIComponent(key)
+ + '='
+ + encodeURIComponent(dict[key]);
+ if (str.length > 0) {
+ str += '&';
+ }
+ str += pair;
+ }
+ }
+ return str;
+};
+
+// Cloud: user messages (to be overridden)
+
+Cloud.prototype.message = function (string) {
+ alert(string);
+};
diff --git a/gui.js b/gui.js
index 063433a..206b27a 100644
--- a/gui.js
+++ b/gui.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!.
@@ -69,7 +69,7 @@ SpeechBubbleMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2014-December-04';
+modules.gui = '2015-January-21';
// Declarations
@@ -119,7 +119,7 @@ IDE_Morph.prototype.setDefaultDesign = function () {
];
IDE_Morph.prototype.rotationStyleColors = IDE_Morph.prototype.tabColors;
IDE_Morph.prototype.appModeColor = new Color();
- IDE_Morph.prototype.scriptsPaneTexture = 'scriptsPaneTexture.gif';
+ IDE_Morph.prototype.scriptsPaneTexture = this.scriptsTexture();
IDE_Morph.prototype.padding = 5;
SpriteIconMorph.prototype.labelColor
@@ -172,6 +172,22 @@ IDE_Morph.prototype.setFlatDesign = function () {
= IDE_Morph.prototype.buttonLabelColor;
};
+IDE_Morph.prototype.scriptsTexture = function () {
+ var pic = newCanvas(new Point(100, 100)), // bigger scales faster
+ ctx = pic.getContext('2d'),
+ i;
+ for (i = 0; i < 100; i += 4) {
+ ctx.fillStyle = this.frameColor.toString();
+ ctx.fillRect(i, 0, 1, 100);
+ ctx.fillStyle = this.groupColor.lighter(6).toString();
+ ctx.fillRect(i + 1, 0, 1, 100);
+ ctx.fillRect(i + 3, 0, 1, 100);
+ ctx.fillStyle = this.groupColor.toString();
+ ctx.fillRect(i + 2, 0, 1, 100);
+ }
+ return pic;
+};
+
IDE_Morph.prototype.setDefaultDesign();
// IDE_Morph instance creation:
@@ -300,7 +316,6 @@ IDE_Morph.prototype.openIn = function (world) {
this.inform('Snap!', motd);
}
*/
-
function interpretUrlAnchors() {
var dict;
if (location.hash.substr(0, 6) === '#open:') {
@@ -353,6 +368,7 @@ IDE_Morph.prototype.openIn = function (world) {
function () {
msg = myself.showMessage('Opening project...');
},
+ function () {nop(); }, // yield (bug in Chrome)
function () {
if (projectData.indexOf('<snapdata') === 0) {
myself.rawOpenCloudDataString(projectData);
@@ -1152,7 +1168,7 @@ IDE_Morph.prototype.createSpriteEditor = function () {
if (this.currentTab === 'scripts') {
scripts.isDraggable = false;
scripts.color = this.groupColor;
- scripts.texture = this.scriptsPaneTexture;
+ scripts.cachedTexture = this.scriptsPaneTexture;
this.spriteEditor = new ScrollFrameMorph(
scripts,
@@ -2046,6 +2062,7 @@ IDE_Morph.prototype.cloudMenu = function () {
'Opening project...'
);
},
+ function () {nop(); }, // yield (Chrome)
function () {
myself.rawOpenCloudDataString(
projectData
@@ -2509,7 +2526,7 @@ IDE_Morph.prototype.aboutSnap = function () {
world = this.world();
aboutTxt = 'Snap! 4.0\nBuild Your Own Blocks\n\n--- beta ---\n\n'
- + 'Copyright \u24B8 2014 Jens M\u00F6nig and '
+ + 'Copyright \u24B8 2015 Jens M\u00F6nig and '
+ 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@@ -2925,6 +2942,7 @@ IDE_Morph.prototype.openProjectString = function (str) {
function () {
msg = myself.showMessage('Opening project...');
},
+ function () {nop(); }, // yield (bug in Chrome)
function () {
myself.rawOpenProjectString(str);
},
@@ -2943,12 +2961,18 @@ IDE_Morph.prototype.rawOpenProjectString = function (str) {
StageMorph.prototype.enableCodeMapping = false;
if (Process.prototype.isCatchingErrors) {
try {
- this.serializer.openProject(this.serializer.load(str), this);
+ this.serializer.openProject(
+ this.serializer.load(str, this),
+ this
+ );
} catch (err) {
this.showMessage('Load failed: ' + err);
}
} else {
- this.serializer.openProject(this.serializer.load(str), this);
+ this.serializer.openProject(
+ this.serializer.load(str, this),
+ this
+ );
}
this.stopFastTracking();
};
@@ -2960,6 +2984,7 @@ IDE_Morph.prototype.openCloudDataString = function (str) {
function () {
msg = myself.showMessage('Opening project...');
},
+ function () {nop(); }, // yield (bug in Chrome)
function () {
myself.rawOpenCloudDataString(str);
},
@@ -2980,7 +3005,10 @@ IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
model = this.serializer.parse(str);
this.serializer.loadMediaModel(model.childNamed('media'));
this.serializer.openProject(
- this.serializer.loadProjectModel(model.childNamed('project')),
+ this.serializer.loadProjectModel(
+ model.childNamed('project'),
+ this
+ ),
this
);
} catch (err) {
@@ -2990,7 +3018,10 @@ IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
model = this.serializer.parse(str);
this.serializer.loadMediaModel(model.childNamed('media'));
this.serializer.openProject(
- this.serializer.loadProjectModel(model.childNamed('project')),
+ this.serializer.loadProjectModel(
+ model.childNamed('project'),
+ this
+ ),
this
);
}
@@ -3004,6 +3035,7 @@ IDE_Morph.prototype.openBlocksString = function (str, name, silently) {
function () {
msg = myself.showMessage('Opening blocks...');
},
+ function () {nop(); }, // yield (bug in Chrome)
function () {
myself.rawOpenBlocksString(str, name, silently);
},
@@ -3050,6 +3082,7 @@ IDE_Morph.prototype.openSpritesString = function (str) {
function () {
msg = myself.showMessage('Opening sprite...');
},
+ function () {nop(); }, // yield (bug in Chrome)
function () {
myself.rawOpenSpritesString(str);
},
@@ -3326,6 +3359,15 @@ IDE_Morph.prototype.toggleAppMode = function (appMode) {
}).forEach(function (s) {
s.adjustScrollBars();
});
+ // prevent rotation and draggability controls from
+ // showing for the stage
+ if (this.currentSprite === this.stage) {
+ this.spriteBar.children.forEach(function (child) {
+ if (child instanceof PushButtonMorph) {
+ child.hide();
+ }
+ });
+ }
}
this.setExtent(this.world().extent()); // resume trackChanges
};
@@ -3502,7 +3544,8 @@ IDE_Morph.prototype.userSetBlocksScale = function () {
sample = new FrameMorph();
sample.acceptsDrops = false;
- sample.texture = this.scriptsPaneTexture;
+ sample.color = IDE_Morph.prototype.groupColor;
+ sample.cachedTexture = this.scriptsPaneTexture;
sample.setExtent(new Point(250, 180));
scrpt.setPosition(sample.position().add(10));
sample.add(scrpt);
@@ -3975,6 +4018,9 @@ IDE_Morph.prototype.cloudResponse = function () {
IDE_Morph.prototype.cloudError = function () {
var myself = this;
+ // try finding an eplanation what's going on
+ // has some issues, commented out for now
+ /*
function getURL(url) {
try {
var request = new XMLHttpRequest();
@@ -3988,13 +4034,15 @@ IDE_Morph.prototype.cloudError = function () {
return null;
}
}
+ */
return function (responseText, url) {
// first, try to find out an explanation for the error
// and notify the user about it,
// if none is found, show an error dialog box
var response = responseText,
- explanation = getURL('http://snap.berkeley.edu/cloudmsg.txt');
+ // explanation = getURL('http://snap.berkeley.edu/cloudmsg.txt'),
+ explanation = null;
if (myself.shield) {
myself.shield.destroy();
myself.shield = null;
@@ -4045,14 +4093,7 @@ IDE_Morph.prototype.setCloudURL = function () {
null,
{
'Snap!Cloud' :
- 'https://snapcloud.miosoft.com/miocon/app/' +
- 'login?_app=SnapCloud',
- 'local network lab' :
- '192.168.2.107:8087/miocon/app/login?_app=SnapCloud',
- 'local network office' :
- '192.168.186.146:8087/miocon/app/login?_app=SnapCloud',
- 'localhost dev' :
- 'localhost/miocon/app/login?_app=SnapCloud'
+ 'https://snap.apps.miosoft.com/SnapCloud'
}
);
};
diff --git a/history.txt b/history.txt
index 6d6f0ff..deb76a6 100755
--- a/history.txt
+++ b/history.txt
@@ -2404,3 +2404,25 @@ ______
* Objects, Store: Experimental “processes” count watcher (hidden in dev mode)
* Threads: Remove terminated processes from expired clones
* Threads: Let “zombifying” scripts access receivers’ local vars
+
+150112
+------
+* Cloud, GUI: Backend load balancing support, eliminate now obsolete authentication roundtrip, Cloud error message tweaks
+* Store: notify users of potential incompatibilities when opening projects created in other forks (e.g. BeetleBlocks)
+* Threads: Don’t highlight scripts running inside clones (boosts performance), Thanks, @aranlunzer, for the hint!
+* Objects: Disable clones from being edited via their context menus or double-click
+* Italian translation update, thanks, Alberto Firpo!
+* GUI: add additional yields to nextSteps() (work around a bug in Chrome)
+
+150113
+------
+* BYOB: fixed #702
+* GUI: fixed #680
+
+150121
+------
+* Objects: Keep layering of nested sprites thru drag & drop
+* GUI, Store, BYOB: Generate ScriptsPaneTexture programmatically
+* GUI: Fix Zoom Dialog’s sample background in “flat” design
+* Updated Korean and Catalan translations, thanks, Yunjae Jang and Bernat Romagosa!
+* Objects: Fix speech bubbles of dragged nested sprites
diff --git a/lang-ca.js b/lang-ca.js
index 8991d45..c57d0d2 100644
--- a/lang-ca.js
+++ b/lang-ca.js
@@ -6,7 +6,7 @@
written by Jens Mönig
- Copyright (C) 2013 by Jens Mönig
+ Copyright (C) 2014 by Jens Mönig
This file is part of Snap!.
@@ -183,9 +183,9 @@ SnapTranslator.dict.ca = {
'language_translator':
'Bernat Romagosa Carrasquer', // your name for the Translators tab
'translator_e-mail':
- 'tibabenfortlapalanca@gmail.com', // optional
+ 'bromagosa@citilab.eu', // optional
'last_changed':
- '2013-11-26', // this, too, will appear in the Translators tab
+ '2015-01-21', // this, too, will appear in the Translators tab
// GUI
// control bar:
@@ -447,12 +447,20 @@ SnapTranslator.dict.ca = {
'si %b llavors %c si no %c',
'report %s':
'retorna %s',
- 'stop block':
- 'atura el bloc',
- 'stop script':
- 'atura aquest programa',
- 'stop all %stop':
- 'atura-ho tot %stop',
+ 'stop %stopChoices':
+ 'atura %stopChoices',
+ 'all':
+ 'tot',
+ 'this script':
+ 'aquest programa',
+ 'this block':
+ 'aquest block',
+ 'stop %stopOthersChoices':
+ 'atura %stopOthersChoices',
+ 'all but this script':
+ 'tot excepte aquest programa',
+ 'other scripts in sprite':
+ 'els altres programes d\'aquest objecte',
'pause all %pause':
'pausa-ho tot %pause',
'run %cmdRing %inputs':
@@ -645,7 +653,7 @@ SnapTranslator.dict.ca = {
'Import...':
'Importar...',
'file menu import hint':
- 'pistes del menú d\'importació',
+ 'carrega una llibreria de projecte\no de blocs exportada, un vestit\no un so',
'Export project as plain text...':
'Exportar projecte en text pla...',
'Export project...':
@@ -676,6 +684,16 @@ SnapTranslator.dict.ca = {
'Idioma...',
'Zoom blocks...':
'Mida dels blocs...',
+ 'Stage size...':
+ 'Mida de l\'escenari...',
+ 'Stage size':
+ 'Mida de l\'escenari',
+ 'Stage width':
+ 'Amplada de l\'escenari',
+ 'Stage height':
+ 'Alçada de l\'escenari',
+ 'Default':
+ 'Per defecte',
'Blurred shadows':
'Ombres suavitzades',
'uncheck to use solid drop\nshadows and highlights':
@@ -744,9 +762,9 @@ SnapTranslator.dict.ca = {
'marca\'m per habilitar\nles animacions de la interfície',
'Thread safe scripts':
'Fil d\'execució segur',
- 'uncheck to allow\nscript reentrancy':
+ 'uncheck to allow\nscript reentrance':
'desmarca\'m per permetre\nla re-entrada als programes',
- 'check to disallow\nscript reentrancy':
+ 'check to disallow\nscript reentrance':
'marca\'m per no permetre\nla re-entrada als programes',
'Prefer smooth animations':
'Suavitza les animacions',
@@ -754,6 +772,12 @@ SnapTranslator.dict.ca = {
'desmarca\'m per augmentar la velocitat de\nles animacions fins la màxima capacitat d\'aquesta màquina',
'check for smooth, predictable\nanimations across computers':
'marca\'m per aconseguir unes animacions\nmés suaus i a velocitat predible en màquines diferents',
+ 'Flat line ends':
+ 'Línies del llapis rectes',
+ 'check for flat ends of lines':
+ 'marca\'m per fer que els\nextrems de les línies del\nllapis siguin rectes',
+ 'uncheck for round ends of lines':
+ 'desmarca\'m per fer que\nels extrems de les línies\ndel llapis siguin arrodonits',
// inputs
'with inputs':
@@ -806,6 +830,8 @@ SnapTranslator.dict.ca = {
// sprites:
'edit':
'editar',
+ 'move':
+ 'moure',
'detach from':
'desenganxa de',
'detach all parts':
@@ -878,9 +904,9 @@ SnapTranslator.dict.ca = {
// zoom blocks
'Zoom blocks':
- 'Canvia la mida dels blocs',
+ 'Canvia la mida dels blocs',
'build':
- 'fes',
+ 'construeix',
'your own':
'els teus propis',
'blocks':
@@ -934,7 +960,7 @@ SnapTranslator.dict.ca = {
// save project
'Save Project As...':
- 'Anomena i desa projecte...',
+ 'Anomena i desa projecte...',
// export blocks
'Export blocks':
@@ -945,8 +971,6 @@ SnapTranslator.dict.ca = {
'aquest projecte encara no\nté cap bloc personalitzat',
'select':
'seleccionar',
- 'all':
- 'tots els blocs',
'none':
'cap bloc',
@@ -1024,7 +1048,7 @@ SnapTranslator.dict.ca = {
'About Snap':
'Sobre Snap',
'Back...':
- 'Enrera...',
+ 'Enrere...',
'License...':
'Llicència...',
'Modules...':
@@ -1094,8 +1118,16 @@ SnapTranslator.dict.ca = {
'Buit',
// graphical effects
+ 'brightness':
+ 'brillantor',
'ghost':
'fantasma',
+ 'negative':
+ 'negatiu',
+ 'comic':
+ 'còmic',
+ 'confetti':
+ 'confeti',
// keys
'space':
@@ -1187,7 +1219,7 @@ SnapTranslator.dict.ca = {
// math functions
'abs':
- 'abs',
+ 'valor absolut',
'floor':
'part entera',
'sqrt':
@@ -1210,6 +1242,8 @@ SnapTranslator.dict.ca = {
'e^',
// delimiters
+ 'letter':
+ 'lletra',
'whitespace':
'espai en blanc',
'line':
diff --git a/lang-it.js b/lang-it.js
index 44111aa..85600a0 100644
--- a/lang-it.js
+++ b/lang-it.js
@@ -181,11 +181,11 @@ SnapTranslator.dict.it = {
'language_name':
'Italiano', // the name as it should appear in the language menu
'language_translator':
- 'Stefano Federici', // your name for the Translators tab
+ 'Stefano Federici, Alberto Firpo', // your name for the Translators tab
'translator_e-mail':
- 's_federici@yahoo.com', // optional
+ 's_federici@yahoo.com, albertofirpo12@gmail.com', // optional
'last_changed':
- '2012-10-16', // this, too, will appear in the Translators tab
+ '2015-01-12', // this, too, will appear in the Translators tab
// GUI
// control bar:
@@ -426,6 +426,10 @@ SnapTranslator.dict.it = {
'invia a tutti %msg e attendi',
'Message name':
'Nome messaggio',
+ 'message':
+ 'messaggio',
+ 'any message':
+ 'qualunque messaggio',
'wait %n secs':
'attendi %n secondi',
'wait until %b':
@@ -444,10 +448,22 @@ SnapTranslator.dict.it = {
'risultato %s',
'stop block':
'ferma il blocco',
+ 'all':
+ 'tutti',
+ 'this script':
+ 'questo script',
+ 'this block':
+ 'questo Blocco',
'stop script':
'ferma lo script',
'stop all %stop':
'ferma tutto %stop',
+ 'all but this script':
+ 'tutto tranne questo script',
+ 'other scripts in sprite':
+ 'altri script dello sprite',
+ 'pause all %pause':
+ 'pausa tutto %pause',
'run %cmdRing %inputs':
'esegui %cmdRing %inputs',
'launch %cmdRing %inputs':
@@ -533,6 +549,8 @@ SnapTranslator.dict.it = {
'falso',
'join %words':
'unione di %words',
+ 'split %s by %delim':
+ 'separa %s di %delim',
'hello':
'ciao',
'world':
@@ -558,6 +576,8 @@ SnapTranslator.dict.it = {
'Nuova variabile',
'Variable name':
'Nome della variabile?',
+ 'Script variable name':
+ 'Nome della variabile locale?',
'Delete a variable':
'Cancella variabile',
@@ -604,6 +624,8 @@ SnapTranslator.dict.it = {
// snap menu
'About...':
'Informazioni su Snap!...',
+ 'Reference manual':
+ 'Manuale',
'Snap! website':
'Sito web di Snap!',
'Download source':
@@ -648,6 +670,10 @@ SnapTranslator.dict.it = {
'Importa tools',
'load the official library of\npowerful blocks':
'carica la libreria ufficiale di\nblocchi Snap',
+ 'Libraries...':
+ 'Modulo...',
+ 'Import library':
+ 'Importa modulo',
// cloud menu
'Login...':
@@ -660,6 +686,16 @@ SnapTranslator.dict.it = {
'Lingua...',
'Zoom blocks...':
'Zoom dei blocchi...',
+ 'Stage size...':
+ 'Dimensione pannello...',
+ 'Stage size':
+ 'Dimensione pannello',
+ 'Stage width':
+ 'Larghezza pannello',
+ 'Stage height':
+ 'Altezza pannello',
+ 'Default':
+ 'Default',
'Blurred shadows':
'Ombreggiature attenuate',
'uncheck to use solid drop\nshadows and highlights':
@@ -688,6 +724,13 @@ SnapTranslator.dict.it = {
'disabilitare per permettere agli slot di espellere\ni reporter inclusi al loro interno',
'Long form input dialog':
'Usa finestra degli input estesa',
+ 'Plain prototype labels':
+ 'Etichetta prototipo base',
+ 'uncheck to always show (+) symbols\nin block prototype labels':
+ 'disabilitare per visualizzare sempre (+) \nnelle etichette dei blocchi prototipo',
+ 'check to hide (+) symbols\nin block prototype labels':
+ 'abilitare per visualizzare sempre (+) \nnelle etichette dei blocchi prototipo',
+
'check to always show slot\ntypes in the input dialog':
'abilitare per mostrare sempre i tipi degli slot\nnella finestra di creazione degli input',
'uncheck to use the input\ndialog in short form':
@@ -734,6 +777,13 @@ SnapTranslator.dict.it = {
'disabilitare per massima velocità\na framerate variabile',
'check for smooth, predictable\nanimations across computers':
'abilitare per avere animazioni\nfluide su tutti i computer',
+ 'Flat line ends':
+ 'fine linea piana',
+ 'check for flat ends of lines':
+ 'abilitare per fine linea netti',
+ 'uncheck for round ends of lines':
+ 'disabilitare per fine linea arrotondati',
+
// inputs
'with inputs':
@@ -742,11 +792,20 @@ SnapTranslator.dict.it = {
'con variabili:',
'Input Names:':
'Con Variabili:',
+ 'input list:':
+ 'con liste:',
+
// context menus:
'help':
'aiuto',
+ // palette:
+ 'hide primitives':
+ 'nascondi primitive',
+ 'show primitives':
+ 'mostra primitive',
+
// blocks:
'help...':
'aiuto...',
@@ -778,6 +837,12 @@ SnapTranslator.dict.it = {
// sprites:
'edit':
'modifica',
+ 'move':
+ 'muovi',
+ 'detach from':
+ 'stacca da',
+ 'detach all parts':
+ 'stacca tutte le parti',
'export...':
'esporta...',
@@ -796,6 +861,15 @@ SnapTranslator.dict.it = {
'riordina gli script\nuno sotto l\'altro',
'add comment':
'aggiungi un commento',
+ 'undrop':
+ 'annulla cancellazione',
+ 'undo the last\nblock drop\nin this pane':
+ 'annulla ultima cancellazione\ndi blocco\n in questo pannello',
+ 'scripts pic...':
+ 'immagine script...',
+ 'open a new window\nwith a picture of all scripts':
+ 'apri una nuova finestra\ncon immagine dello script',
+
'make a block...':
'crea un blocco...',
@@ -823,6 +897,8 @@ SnapTranslator.dict.it = {
// buttons
'OK':
'OK',
+ 'Ok':
+ 'OK',
'Cancel':
'Annulla',
'Yes':
@@ -1057,8 +1133,17 @@ SnapTranslator.dict.it = {
'Vuoto',
// graphical effects
+ 'brightness':
+ 'Luminosita',
'ghost':
'fantasma',
+ 'negative':
+ 'negativo',
+ 'comic':
+ 'comic',
+ 'confetti':
+ 'confetti',
+
// keys
'space':
@@ -1170,6 +1255,18 @@ SnapTranslator.dict.it = {
'e^':
'e^',
+ // delimiters
+ 'letter':
+ 'lettera',
+ 'whitespace':
+ 'spazio',
+ 'line':
+ 'linea',
+ 'tab':
+ 'tabulatore',
+ 'cr':
+ 'A capo',
+
// data types
'number':
'numero',
diff --git a/lang-ko.js b/lang-ko.js
index a1e50eb..8cedf44 100644..100755
--- a/lang-ko.js
+++ b/lang-ko.js
@@ -179,13 +179,13 @@ SnapTranslator.dict.ko = {
// translations meta information
'language_name':
- 'Korean', // the name as it should appear in the language menu
+ '한국어', // the name as it should appear in the language menu
'language_translator':
'Yunjae Jang', // your name for the Translators tab
'translator_e-mail':
- 'yunjae.jang@inc.korea.ac.kr', // optional
+ 'janggoons@gmail.com', // optional
'last_changed':
- '2012-11-18', // this, too, will appear in the Translators tab
+ '2015-01-21', // this, too, will appear in the Translators tab
// GUI
// control bar:
@@ -218,7 +218,7 @@ SnapTranslator.dict.ko = {
// editor:
'draggable':
- '드래그 가능?',
+ '마우스로 직접 움직이기',
// tabs:
'Scripts':
@@ -243,8 +243,16 @@ SnapTranslator.dict.ko = {
'왼쪽에서 오른쪽으로만',
// new sprite button:
- 'add a new sprite':
- '새로운 스프라이트 추가',
+ 'add a new Turtle sprite':
+ '새로운 스프라이트 추가하기',
+
+ // new paint sprite button:
+ 'paint a new sprite':
+ '새로운 스프라이트 그리기',
+
+ // new paint costume button:
+ 'Paint a new costume':
+ '새로운 모양 그리기',
// tab help
'costumes tab help':
@@ -300,19 +308,19 @@ SnapTranslator.dict.ko = {
'point towards %dst':
'%dst 쪽 보기',
'go to x: %n y: %n':
- 'x: %n 、y: %n 쪽으로 가기',
+ 'x: %n 、y: %n 쪽으로 이동하기',
'go to %dst':
- '%dst 위치로 가기',
+ '%dst 위치로 이동하기',
'glide %n secs to x: %n y: %n':
- '%n 초 동안 x: %n 、y: %n 쪽으로 움직이기',
+ '%n 초 동안 x: %n 、y: %n 쪽으로 이동하기',
'change x by %n':
'x좌표 %n 만큼 바꾸기',
'set x to %n':
- 'x좌표 %n 로 정하기',
+ 'x좌표 %n (으)로 정하기',
'change y by %n':
'y좌표 %n 만큼 바꾸기',
'set y to %n':
- 'y좌표 %n 로 정하기',
+ 'y좌표 %n (으)로 정하기',
'if on edge, bounce':
'벽에 닿으면 튕기기',
'x position':
@@ -328,13 +336,13 @@ SnapTranslator.dict.ko = {
'next costume':
'다음 모양',
'costume #':
- '모양 #',
+ '모양 번호',
'say %s for %n secs':
- '%s %n 초 동안 말하기',
+ '%s 을(를) %n 초 동안 말하기',
'say %s':
'%s 말하기',
'think %s for %n secs':
- '%s %n 초간 생각하기',
+ '%s 을(를) %n 초 동안 생각하기',
'think %s':
'%s 생각하기',
'Hello!':
@@ -342,15 +350,15 @@ SnapTranslator.dict.ko = {
'Hmm...':
'흠…',
'change %eff effect by %n':
- '%eff 효과 %n 만큼 바꾸기',
+ '%eff 효과를 %n 만큼 바꾸기',
'set %eff effect to %n':
- '%eff 효과 %n 만큼 주기',
+ '%eff 효과를 %n 만큼 정하기',
'clear graphic effects':
'그래픽 효과 지우기',
'change size by %n':
- '크기 %n 만큼 바꾸기',
+ '크기를 %n 만큼 바꾸기',
'set size to %n %':
- '크기 %n % 로 정하기',
+ '크기를 %n % 로 정하기',
'size':
'크기',
'show':
@@ -373,82 +381,96 @@ SnapTranslator.dict.ko = {
'play sound %snd':
'%snd 소리내기',
'play sound %snd until done':
- '끝날때까지 %snd 소리내기',
+ '%snd 을(를) 끝까지 소리내기',
'stop all sounds':
'모든 소리 끄기',
'rest for %n beats':
- '%n 비트 동안 쉬기',
+ '%n 박자 동안 쉬기',
'play note %n for %n beats':
- '%n 음을 %n 비트로 연주하기',
+ '%n 음을 %n 박자로 연주하기',
'change tempo by %n':
- '템포를 %n 만큼 바꾸기',
+ '빠르기를 %n 만큼 바꾸기',
'set tempo to %n bpm':
- '템포를 %n bpm으로 맞추기',
+ '빠르기를 %n bpm으로 정하기',
'tempo':
- '템포',
+ '빠르기',
// pen:
'clear':
- '지우기',
+ '펜 자국 지우기',
'pen down':
'펜 내리기',
'pen up':
'펜 올리기',
'set pen color to %clr':
- '펜의 색 %clr 으로 정하기',
+ '펜 색깔을 %clr 으로 정하기',
'change pen color by %n':
- '펜의 색 %n 만큼 바꾸기',
+ '펜 색깔을 %n 만큼 바꾸기',
'set pen color to %n':
- '펜의 색 %n 으로 정하기',
+ '펜 색깔을 %n (으)로 정하기',
'change pen shade by %n':
- '펜의 그림자 %n 만큼 바꾸기',
+ '펜 음영을 %n 만큼 바꾸기',
'set pen shade to %n':
- '펜의 그림자 %n 으로 정하기',
+ '펜 음영을 %n 으로 정하기',
'change pen size by %n':
- '펜의 크기 %n 만큼 바꾸기',
+ '펜 굵기를 %n 만큼 바꾸기',
'set pen size to %n':
- '펜의 크기 %n 으로 정하기',
+ '펜 굵기를 %n (으)로 정하기',
'stamp':
- '스탬프',
+ '도장찍기',
// control:
'when %greenflag clicked':
- '%greenflag 클릭되었을 때',
+ '%greenflag 클릭했을 때',
'when %keyHat key pressed':
- '%keyHat 키 눌렀을 때',
+ '%keyHat 키를 눌렀을 때',
'when I am clicked':
- '자신이 클릭되었을 때',
+ '이 스프라이트를 클릭했을 때',
'when I receive %msgHat':
- '%msgHat 받을 때',
+ '%msgHat 을(를) 받았을 때',
'broadcast %msg':
'%msg 방송하기',
'broadcast %msg and wait':
'%msg 방송하고 기다리기',
'Message name':
- '메세지 이름',
+ '메시지 이름',
+ 'message':
+ '메시지',
+ 'any message':
+ '어떤 메시지',
'wait %n secs':
'%n 초 기다리기',
'wait until %b':
'%b 까지 기다리기',
'forever %c':
- '무한반복 %c',
+ '무한 반복하기 %c',
'repeat %n %c':
- '반복 %n 회 %c',
+ '%n 번 반복하기 %c',
'repeat until %b %c':
- '반복 %b 계속 확인 %c',
+ '%b 까지 반복하기 %c',
'if %b %c':
'만약 %b 라면 %c',
'if %b %c else %c':
'만약 %b 라면 %c 아니면 %c',
'report %s':
'%s 출력하기',
- 'stop block':
- '블록 멈추기',
- 'stop script':
- '스크립트 멈추기',
- 'stop all %stop':
- '모두 멈추기 %stop',
+ 'stop %stopChoices':
+ '%stopChoices 멈추기',
+ 'all':
+ '모두',
+ 'this script':
+ '이 스크립트',
+ 'this block':
+ '이 블록',
+ 'stop %stopOthersChoices':
+ '%stopOthersChoices 멈추기',
+ 'all but this script':
+ '이 스크립트를 제외한 모두',
+ 'other scripts in sprite':
+ '이 스프라이트에 있는 다른 스크립트',
+ 'pause all %pause':
+ '모두 잠시 멈추기 %pause',
'run %cmdRing %inputs':
'%cmdRing 을(를) %inputs 으로 실행하기',
'launch %cmdRing %inputs':
@@ -461,14 +483,23 @@ SnapTranslator.dict.ko = {
'반복해서 %cmdRing 을(를) 호출하기',
'warp %c':
'워프 %c',
+ 'when I start as a clone':
+ '복제되었을 때',
+ 'create a clone of %cln':
+ '%cln 을(를) 복제하기',
+ 'myself':
+ '나 자신',
+ 'delete this clone':
+ '이 복제본 삭제하기',
+
// sensing:
'touching %col ?':
- '%col 에 닿기?',
+ '%col 에 닿았는가?',
'touching %clr ?':
- '%clr 색에 닿기?',
+ '%clr 색에 닿았는가?',
'color %clr is touching %clr ?':
- '%clr 색이 %clr 색에 닿기?',
+ '%clr 색이 %clr 색에 닿았는가?',
'ask %s and wait':
'%s 을(를) 묻고 기다리기',
'what\'s your name?':
@@ -476,36 +507,59 @@ SnapTranslator.dict.ko = {
'answer':
'대답',
'mouse x':
- '마우스 x좌표',
+ '마우스의 x좌표',
'mouse y':
- '마우스 y좌표',
+ '마우스의 y좌표',
'mouse down?':
- '마우스 클릭하기?',
+ '마우스를 클릭했는가?',
'key %key pressed?':
- '%key 키 클릭하기?',
+ '%key 키를 눌렀는가?',
'distance to %dst':
'%dst 까지 거리',
'reset timer':
'타이머 초기화',
'timer':
'타이머',
+ '%att of %spr':
+ '%att ( %spr 에 대한)',
'http:// %s':
'http:// %s',
-
+ 'turbo mode?':
+ '터보 모드인가?',
+ 'set turbo mode to %b':
+ '터보 모드 %b 으로 설정하기',
'filtered for %clr':
'%clr 색 추출하기',
'stack size':
'스택 크기',
'frames':
'프레임',
+ 'current %dates':
+ '현재 %dates',
+ 'year':
+ '연도',
+ 'month':
+ '월',
+ 'date':
+ '일',
+ 'day of week':
+ '요일(1~7)',
+ 'hour':
+ '시간',
+ 'minute':
+ '분',
+ 'second':
+ '초',
+ 'time in milliseconds':
+ '밀리세컨드초',
// operators:
'%n mod %n':
- '%n 나누기 %n 의 나머지',
+ '( %n / %n ) 의 나머지',
'round %n':
'%n 반올림',
'%fun of %n':
- '%n 의 %fun',
+ '%fun ( %n 에 대한)',
'pick random %n to %n':
'%n 부터 %n 사이의 난수',
'%b and %b':
@@ -520,12 +574,14 @@ SnapTranslator.dict.ko = {
'거짓',
'join %words':
'%words 결합하기',
+ 'split %s by %delim':
+ '%s 를 %delim 기준으로 나누기',
'hello':
'안녕',
'world':
- '세계',
+ '세상',
'letter %n of %s':
- '%n 의 %s 번째 글자',
+ '%n 번째 글자 ( %s 에 대한)',
'length of %s':
'%s 의 길이',
'unicode of %s':
@@ -533,9 +589,11 @@ SnapTranslator.dict.ko = {
'unicode %n as letter':
'유니코드 %n 에 대한 문자',
'is %s a %typ ?':
- '%s 이(가) %typ 인가요?',
+ '%s 이(가) %typ 인가?',
+ 'is %s identical to %s ?':
+ '%s 와(과) %s 가 동일한가?',
'type of %s':
- '%s 타입',
+ '%s 의 타입',
// variables:
'Make a variable':
@@ -543,12 +601,12 @@ SnapTranslator.dict.ko = {
'Variable name':
'변수 이름',
'Delete a variable':
- '변수 삭제',
+ '변수 삭제하기',
'set %var to %s':
- '%var 을(를) %s 로 저장',
+ '변수 %var 에 %s 저장하기',
'change %var by %n':
- '%var 에 %n 씩 누적하기',
+ '변수 %var 을(를) %n 만큼 바꾸기',
'show variable %var':
'변수 %var 보이기',
'hide variable %var':
@@ -560,38 +618,78 @@ SnapTranslator.dict.ko = {
'list %exp':
'리스트 %exp',
'%s in front of %l':
- '%s 을(를) %l 처음에 추가하기 ',
+ '%s 을(를) 리스트 %l 의 맨 앞에 추가하기 ',
'item %idx of %l':
- '%idx 항목 %l',
+ '%idx 번째 항목 (리스트 %l 에 대한)',
'all but first of %l':
- '%l 첫번째 아이템 제외한 모든 아이템',
+ '리스트 %l 에서 첫 번째 항목 제외하기',
'length of %l':
- '%l 의 크기',
+ '리스트 %l 의 항목 갯수',
'%l contains %s':
- '%l 에 %s 포함?',
+ '리스트 %l 에 %s 포함되었는가?',
'thing':
- '아이템',
+ '어떤 것',
'add %s to %l':
- '%s 을(를) %l 마지막에 추가하기 ',
+ '%s 을(를) 리스트 %l 의 마지막에 추가하기 ',
'delete %ida of %l':
- '%ida 을(를) %l 에서 삭제하기 ',
+ '%ida 번째 항목 삭제하기 (리스트 %l 에 대한)',
'insert %s at %idx of %l':
- '%s 을(를) %idx 위치에 추가하기 %l',
+ '%s 을(를) %idx 위치에 추가하기 (리스트 %l 에 대한)',
'replace item %idx of %l with %s':
- '%idx 항목 %l 에 %s 로 교체하기',
+ '%idx 번째 (리스트 %l 에 대한) 를 %s (으)로 바꾸기',
// other
'Make a block':
'블록 만들기',
+ // Paint Editor
+ 'Paint Editor':
+ '그림 편집기',
+ 'undo':
+ '되돌리기',
+ 'grow':
+ '확대',
+ 'shrink':
+ '축소',
+ 'flip ↔':
+ '↔ 반전',
+ 'flip ↕':
+ '↕ 반전',
+ 'Brush size':
+ '펜 크기',
+ 'Constrain proportions of shapes?\n(you can also hold shift)':
+ '도형 크기 비율을 고정하는가?\n(shift 키를 눌러서 사용할 수 있습니다.)',
+ 'Paintbrush tool\n(free draw)':
+ '붓 도구',
+ 'Stroked Rectangle\n(shift: square)':
+ '사각형 그리기 도구\n(shift: 정사각형)',
+ 'Stroked Ellipse\n(shift: circle)':
+ '타원 그리기 도구\n(shift: 원)',
+ 'Eraser tool':
+ '지우개 도구',
+ 'Set the rotation center':
+ '회전축 설정하기',
+ 'Line tool\n(shift: vertical/horizontal)':
+ '선 그리기 도구\n(shift: 수평/수직)',
+ 'Filled Rectangle\n(shift: square)':
+ '채워진 사각형 그리기 도구\n(shift: 정사각형)',
+ 'Filled Ellipse\n(shift: circle)':
+ '채워진 타원 그리기 도구\n(shift: 원)',
+ 'Fill a region':
+ '색 채우기',
+ 'Pipette tool\n(pick a color anywhere)':
+ '스포이드 도구\n(원하는 색 선택하기)',
+
// menus
// snap menu
'About...':
'Snap! 에 대해서...',
+ 'Reference manual':
+ '참고자료 다운로드',
'Snap! website':
'Snap! 웹사이트',
'Download source':
- '소스 다운로드',
+ '소스코드 다운로드',
'Switch back to user mode':
'사용자 모드로 전환',
'disable deep-Morphic\ncontext menus\nand show user-friendly ones':
@@ -609,15 +707,18 @@ SnapTranslator.dict.ko = {
'Open...':
'열기...',
'Save':
- '저장',
+ '저장하기',
+ 'Save to disk':
+ '내 컴퓨터에 저장하기',
+ 'experimental - store this project\nin your downloads folder':
+ '실험적 - 이 프로젝트를\n 다운로드 폴더에 저장합니다.',
'Save As...':
- '다른 이름으로 저장...',
+ '다른 이름으로 저장하기...',
'Import...':
'가져오기...',
'file menu import hint':
'내보낸 프로젝트 파일, 블록 라이브러리\n'
- + '스프라이트 모양 또는 소리를 가져옵니다.\n\n'
- + '일부 웹브라우저에서는 지원되지 않습니다.',
+ + '스프라이트 모양 또는 소리를 가져옵니다.',
'Export project as plain text...':
'프로젝트를 텍스트 파일로 내보내기...',
'Export project...':
@@ -628,58 +729,171 @@ SnapTranslator.dict.ko = {
'블록 내보내기...',
'show global custom block definitions as XML\nin a new browser window':
'새롭게 정의한 전역 블록 데이터를\n새로운 윈도우에 XML 형태로 보여주기',
+ 'Export all scripts as pic...':
+ '모든 스크립트를 그림파일로 내보내기',
+ 'show a picture of all scripts\nand block definitions':
+ '모든 스크립트와 정의된 블록을 그림파일로 보여줍니다.',
+ 'Import tools':
+ '추가 도구 가져오기',
+ 'load the official library of\npowerful blocks':
+ '강력한 기능을 제공하는\n 블록들을 가져옵니다.',
+ 'Libraries...':
+ '라이브러리...',
+ 'Select categories of additional blocks to add to this project.':
+ '추가적인 블록을 선택해서\n 사용할 수 있습니다.',
+ 'Import library':
+ '라이브러리 가져오기',
+
+ // cloud menu
+ 'Login...':
+ '로그인...',
+ 'Signup...':
+ '계정만들기...',
+ 'Reset Password...':
+ '비밀번호 재설정...',
+ 'url...':
+ 'url...',
+ 'export project media only...':
+ 'export project media only...',
+ 'export project without media...':
+ 'export project without media...',
+ 'export project as cloud data...':
+ 'export project as cloud data...',
+ 'open shared project from cloud...':
+ 'open shared project from cloud...',
// settings menu
'Language...':
'언어선택...',
+ 'Zoom blocks...':
+ '블록 크기 설정...',
+ 'Stage size...':
+ '무대 크기 설정...',
+ 'Stage size':
+ '무대 크기',
+ 'Stage width':
+ '가로(너비)',
+ 'Stage height':
+ '세로(높이)',
+ 'Default':
+ '기본설정',
+
'Blurred shadows':
'반투명 그림자',
'uncheck to use solid drop\nshadows and highlights':
'체크해제하면, 그림자와 하이라이트가\n불투명 상태로 됩니다.',
'check to use blurred drop\nshadows and highlights':
'체크하면, 그림자와 하이라이트가\n반투명 상태로 됩니다.',
+
'Zebra coloring':
'중첩 블록 구분하기',
'check to enable alternating\ncolors for nested blocks':
'체크하면, 중첩된 블록을\n다른 색으로 구분할 수 있습니다.',
'uncheck to disable alternating\ncolors for nested block':
'체크해제하면, 중첩된 블록을\n다른 색으로 구분할 수 없습니다.',
+
+ 'Dynamic input labels':
+ 'Dynamic input labels',
+ 'uncheck to disable dynamic\nlabels for variadic inputs':
+ 'uncheck to disable dynamic\nlabels for variadic inputs',
+ 'check to enable dynamic\nlabels for variadic inputs':
+ 'check to enable dynamic\nlabels for variadic inputs',
+
'Prefer empty slot drops':
'빈 슬롯에 입력 가능',
'settings menu prefer empty slots hint':
'설정 메뉴에 빈 슬롯의\n힌트를 사용할 수 있습니다.',
'uncheck to allow dropped\nreporters to kick out others':
'체크해제하면, 기존 리포터 블록에\n새로운 리포터 블록으로 대체할 수 있습니다.',
+
'Long form input dialog':
'긴 형태의 입력 대화창',
'check to always show slot\ntypes in the input dialog':
'체크하면, 입력 대화창에\n항상 슬롯의 형태를 보여줍니다.',
'uncheck to use the input\ndialog in short form':
'체크해제하면, 입력 대화창을\n짧은 형태로 사용합니다.',
+
+ 'Plain prototype labels':
+ '새로 만든 블록 인수 설정',
+ 'uncheck to always show (+) symbols\nin block prototype labels':
+ '체크해제하면, 블록 편집기에서\n 블록 인수 추가 버튼(+)을\n 보입니다.',
+ 'check to hide (+) symbols\nin block prototype labels':
+ '체크하면, 블록 편집기에서\n 블록 인수 추가 버튼(+)을\n 숨깁니다.',
+
'Virtual keyboard':
'가상 키보드',
'uncheck to disable\nvirtual keyboard support\nfor mobile devices':
'체크해제하면, 모바일 기기에서\n가상 키보드를 사용할 수 없습니다.',
'check to enable\nvirtual keyboard support\nfor mobile devices':
'체크하면, 모바일 기기에서\n가상 키보드를 사용할 수 있습니다.',
+
'Input sliders':
'입력창에서 슬라이더 사용',
'uncheck to disable\ninput sliders for\nentry fields':
'체크해제하면, 입력창에서\n슬라이더를 사용할 수 없습니다.',
'check to enable\ninput sliders for\nentry fields':
'체크하면, 입력창에서\n슬라이더를 사용할 수 있습니다.',
+
'Clicking sound':
'블록 클릭시 소리',
'uncheck to turn\nblock clicking\nsound off':
'체크해제하면, 블록 클릭시\n소리가 꺼집니다.',
'check to turn\nblock clicking\nsound on':
'체크하면, 블록 클릭시\n소리가 켜집니다.',
+
+ 'Animations':
+ '애니메이션',
+ 'uncheck to disable\nIDE animations':
+ '체크해제하면, IDE 애니메이션을\n 사용할 수 없습니다.',
+
+ 'Turbo mode':
+ '터보 모드',
+ 'check to prioritize\nscript execution':
+ '체크하면, 스크립트를\n 빠르게 실행합니다.',
+ 'uncheck to run scripts\nat normal speed':
+ '체크해제하면, 스크립트 실행 속도를\n 보통으로 합니다.',
+
+ 'Flat design':
+ '플랫(Flat) 디자인',
+ 'uncheck for default\nGUI design':
+ '체크해제하면,\n 기본 GUI 디자인으로\n 변경합니다.',
+ 'check for alternative\nGUI design':
+ '체크하면, 플랫(Flat)\n 디자인으로 변경합니다.',
+
+ 'Sprite Nesting':
+ 'Sprite Nesting',
+ 'uncheck to disable\nsprite composition':
+ 'uncheck to disable\nsprite composition',
+ 'check to enable\nsprite composition':
+ 'check to enable\nsprite composition',
+
'Thread safe scripts':
'스레드 안전 스크립트',
- 'uncheck to allow\nscript reentrancy':
+ 'uncheck to allow\nscript reentrance':
'체크해제하면, 스크립트\n재진입성을 허락합니다.',
- 'check to disallow\nscript reentrancy':
+ 'check to disallow\nscript reentrance':
'체크하면, 스크립트\n재진입성을 허락하지 않습니다.',
+
+ 'Prefer smooth animations':
+ '자연스러운 애니메이션',
+ 'uncheck for greater speed\nat variable frame rates':
+ '체크해제하면, 프레임\n 전환 비율이 빨라집니다.',
+ 'check for smooth, predictable\nanimations across computers':
+ '체크하면, 애니메이션이\n 자연스러워 집니다.',
+
+ 'Flat line ends':
+ '선 끝을 평평하게 만들기',
+ 'check for flat ends of lines':
+ '체크하면, 선 끝을\n 평평하게 만듭니다.',
+ 'uncheck for round ends of lines':
+ '체크해제하면, 선 끝을\n 둥글게 만듭니다.',
+
+ 'Codification support':
+ '체계화 지원',
+ 'uncheck to disable\nblock to text mapping features':
+ 'uncheck to disable\nblock to text mapping features',
+ 'check for block\nto text mapping features':
+ '체크하면, check for block\nto text mapping features',
// inputs
'with inputs':
@@ -692,35 +906,55 @@ SnapTranslator.dict.ko = {
// context menus:
'help':
'도움말',
+
+ // palette:
+ 'find blocks...':
+ '블록 찾기...',
+ 'hide primitives':
+ '기본 블록 숨기기',
+ 'show primitives':
+ '기본 블록 보이기',
// blocks:
'help...':
'블록 도움말...',
+ 'relabel...':
+ '블록 바꾸기...',
'duplicate':
- '복사',
+ '복사하기',
'make a copy\nand pick it up':
- '복사해서\n그 블록을 들고 있습니다.',
+ '복사해서\n들고 있습니다.',
'delete':
- '삭제',
+ '삭제하기',
'script pic...':
- '스크립트 그림...',
+ '이 스크립트를 그림파일로 내보내기...',
'open a new window\nwith a picture of this script':
'이 스크립트 그림을\n새로운 윈도우에서 엽니다.',
'ringify':
- '형태변환',
+ '블록형태 변환하기',
+ 'unringify':
+ 'unringify',
// custom blocks:
'delete block definition...':
- '블록 삭제',
+ '블록 삭제하기',
'edit...':
'편집…',
// sprites:
'edit':
- '편집',
+ '스크립트 편집하기',
'export...':
'내보내기...',
+ // stage:
+ 'show all':
+ '모든 스프라이트 나타내기',
+ 'pic...':
+ '그림파일로 내보내기...',
+ 'open a new window\nwith a picture of the stage':
+ '새로운 창을 열고\n무대의 화면을\n그림파일로 저장한다.',
+
// scripting area
'clean up':
'스크립트 정리하기',
@@ -728,12 +962,20 @@ SnapTranslator.dict.ko = {
'스크립트를\n수직으로 정렬한다.',
'add comment':
'주석 추가하기',
+ 'undrop':
+ '마지막으로 가져온 블록',
+ 'undo the last\nblock drop\nin this pane':
+ '마지막으로\n 가져온 블록을\n 확인한다.',
+ 'scripts pic...':
+ '모든 스크립트를 그림파일로 내보내기...',
+ 'open a new window\nwith a picture of all scripts':
+ '새로운 창을 열어서\n 모든 스크립트를\n 그림으로 저장한다.',
'make a block...':
'블록 만들기...',
// costumes
'rename':
- '이름수정',
+ '이름 수정하기',
'export':
'내보내기',
@@ -750,7 +992,9 @@ SnapTranslator.dict.ko = {
// dialogs
// buttons
'OK':
- 'OK',
+ '확인',
+ 'Ok':
+ '확인',
'Cancel':
'취소',
'Yes':
@@ -762,6 +1006,31 @@ SnapTranslator.dict.ko = {
'Help':
'도움말',
+ // zoom blocks
+ 'Zoom blocks':
+ '블록 크기 설정',
+ 'build':
+ '만들기',
+ 'your own':
+ '나만의',
+ 'blocks':
+ '블록',
+ 'normal (1x)':
+ '기본 크기 (1x)',
+ 'demo (1.2x)':
+ '데모 크기 (1.2x)',
+ 'presentation (1.4x)':
+ '발표용 크기 (1.4x)',
+ 'big (2x)':
+ '큰 크기 (2x)',
+ 'huge (4x)':
+ '매우 큰 크기(4x)',
+ 'giant (8x)':
+ '정말 큰 크기 (8x)',
+ 'monstrous (10x)':
+ '믿을 수 없는 크기 (10x)',
+
+
// costume editor
'Costume Editor':
'모양 편집기',
@@ -822,7 +1091,7 @@ SnapTranslator.dict.ko = {
// block deletion dialog
'Delete Custom Block':
- '블록 삭제',
+ '블록 삭제하기',
'block deletion dialog text':
'이 블록과 모든 인스턴스를\n 삭제해도 괜찮습니까?',
@@ -911,6 +1180,8 @@ SnapTranslator.dict.ko = {
// coments
'add comment here...':
'여기에 주석 추가…',
+ 'comment pic...':
+ '주석을 그림파일로 내보내기...',
// drow downs
// directions
@@ -933,11 +1204,22 @@ SnapTranslator.dict.ko = {
// costumes
'Turtle':
- '터틀',
+ '화살표',
+ 'Empty':
+ 'Leer',
- // graphical effects
+ // graphical effects
+ 'brightness':
+ '밝기',
'ghost':
'유령',
+ 'negative':
+ '반전',
+ 'comic':
+ '코믹',
+ 'confetti':
+ '색종이',
+
// keys
'space':
@@ -1029,9 +1311,11 @@ SnapTranslator.dict.ko = {
// math functions
'abs':
- '절대값',
+ '절대값(abs)',
'sqrt':
- '제곱근',
+ '제곱근(sqrt)',
+ 'floor':
+ '바닥(floor)',
'sin':
'sin',
'cos':
@@ -1049,11 +1333,23 @@ SnapTranslator.dict.ko = {
'e^':
'e^',
+ // delimiters
+ 'letter':
+ '글자',
+ 'whitespace':
+ '빈칸',
+ 'line':
+ '줄',
+ 'tab':
+ '탭',
+ 'cr':
+ '새줄(cr)',
+
// data types
'number':
'숫자',
'text':
- '텍스트',
+ '문자',
'Boolean':
'불리언',
'list':
@@ -1087,12 +1383,12 @@ SnapTranslator.dict.ko = {
'Are you sure you want to delete':
'정말로 삭제합니까?',
'unringify':
- '형태변환취소',
+ '블록형태변환 취소하기',
'rename...':
'이름수정...',
'(180) down':
'(180) 아래',
'Ok':
- 'OK'
+ '확인'
};
diff --git a/locale.js b/locale.js
index b3c2ce5..5ec6013 100644
--- a/locale.js
+++ b/locale.js
@@ -6,7 +6,7 @@
written by Jens Mönig
- Copyright (C) 2014 by Jens Mönig
+ Copyright (C) 2015 by Jens Mönig
This file is part of Snap!.
@@ -42,7 +42,7 @@
/*global modules, contains*/
-modules.locale = '2014-December-15';
+modules.locale = '2015-January-21';
// Global stuff
@@ -157,11 +157,11 @@ SnapTranslator.dict.it = {
'language_name':
'Italiano',
'language_translator':
- 'Stefano Federici',
+ 'Stefano Federici, Alberto Firpo',
'translator_e-mail':
- 's_federici@yahoo.com',
+ 's_federici@yahoo.com, albertofirpo12@gmail.com',
'last_changed':
- '2013-04-08'
+ '2015-01-12'
};
SnapTranslator.dict.ja = {
@@ -195,9 +195,9 @@ SnapTranslator.dict.ko = {
'language_translator':
'Yunjae Jang',
'translator_e-mail':
- 'yunjae.jang@inc.korea.ac.kr',
+ 'janggoons@gmail.com',
'last_changed':
- '2012-11-18'
+ '2015-01-21'
};
SnapTranslator.dict.pt = {
@@ -375,9 +375,9 @@ SnapTranslator.dict.ca = {
'language_translator':
'Bernat Romagosa Carrasquer',
'translator_e-mail':
- 'tibabenfortlapalanca@gmail.com',
+ 'bromagosa@citilab.eu',
'last_changed':
- '2013-11-26'
+ '2015-01-21'
};
SnapTranslator.dict.fi = {
diff --git a/manifest.mf b/manifest.mf
index 353d47f..d040961 100644
--- a/manifest.mf
+++ b/manifest.mf
@@ -10,5 +10,4 @@ threads.js
widgets.js
store.js
xml.js
-scriptsPaneTexture.gif
-snap_logo_sm.gif
+snap_logo_sm.png
diff --git a/objects.js b/objects.js
index 140ac69..cb9ad4b 100644
--- a/objects.js
+++ b/objects.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!.
@@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2014-December-17';
+modules.objects = '2015-January-21';
var SpriteMorph;
var StageMorph;
@@ -1382,6 +1382,7 @@ SpriteMorph.prototype.init = function (globals) {
this.anchor = null;
this.nestingScale = 1;
this.rotatesWithAnchor = true;
+ this.layers = null; // cache for dragging nested sprites, don't serialize
this.blocksCache = {}; // not to be serialized (!)
this.paletteCache = {}; // not to be serialized (!)
@@ -2726,7 +2727,9 @@ SpriteMorph.prototype.userMenu = function () {
menu.addItem("duplicate", 'duplicate');
menu.addItem("delete", 'remove');
menu.addItem("move", 'move');
- menu.addItem("edit", 'edit');
+ if (!this.isClone) {
+ menu.addItem("edit", 'edit');
+ }
menu.addLine();
if (this.anchor) {
menu.addItem(
@@ -2742,6 +2745,7 @@ SpriteMorph.prototype.userMenu = function () {
};
SpriteMorph.prototype.exportSprite = function () {
+ if (this.isCoone) {return; }
var ide = this.parentThatIsA(IDE_Morph);
if (ide) {
ide.exportSprite(this);
@@ -3235,13 +3239,11 @@ SpriteMorph.prototype.positionTalkBubble = function () {
bubble.changed();
};
-// dragging and dropping adjustments b/c of talk bubbles
+// dragging and dropping adjustments b/c of talk bubbles and parts
SpriteMorph.prototype.prepareToBeGrabbed = function (hand) {
- var bubble = this.talkBubble();
- if (!bubble) {return null; }
this.removeShadow();
- bubble.hide();
+ this.recordLayers();
if (!this.bounds.containsPoint(hand.position())) {
this.setCenter(hand.position());
}
@@ -3249,6 +3251,7 @@ SpriteMorph.prototype.prepareToBeGrabbed = function (hand) {
};
SpriteMorph.prototype.justDropped = function () {
+ this.restoreLayers();
this.positionTalkBubble();
};
@@ -3614,6 +3617,7 @@ SpriteMorph.prototype.mouseClickLeft = function () {
};
SpriteMorph.prototype.mouseDoubleClick = function () {
+ if (this.isClone) {return; }
this.edit();
};
@@ -4125,6 +4129,33 @@ SpriteMorph.prototype.allAnchors = function () {
return result;
};
+SpriteMorph.prototype.recordLayers = function () {
+ var stage = this.parentThatIsA(StageMorph);
+ if (!stage) {
+ this.layerCache = null;
+ return;
+ }
+ this.layers = this.allParts();
+ this.layers.forEach(function (part) {
+ var bubble = part.talkBubble();
+ if (bubble) {bubble.hide(); }
+ });
+ this.layers.sort(function (x, y) {
+ return stage.children.indexOf(x) < stage.children.indexOf(y) ?
+ -1 : 1;
+ });
+};
+
+SpriteMorph.prototype.restoreLayers = function () {
+ if (this.layers && this.layers.length > 1) {
+ this.layers.forEach(function (sprite) {
+ sprite.comeToFront();
+ sprite.positionTalkBubble();
+ });
+ }
+ this.layers = null;
+};
+
// SpriteMorph highlighting
SpriteMorph.prototype.addHighlight = function (oldHighlight) {
diff --git a/scriptsPaneTexture.gif b/scriptsPaneTexture.gif
deleted file mode 100755
index 846c77f..0000000
--- a/scriptsPaneTexture.gif
+++ /dev/null
Binary files differ
diff --git a/store.js b/store.js
index 8cbc10f..056767f 100644
--- a/store.js
+++ b/store.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!.
@@ -61,7 +61,7 @@ SyntaxElementMorph, Variable*/
// Global stuff ////////////////////////////////////////////////////////
-modules.store = '2014-December-17';
+modules.store = '2015-January-21';
// XML_Serializer ///////////////////////////////////////////////////////
@@ -306,16 +306,33 @@ XML_Serializer.prototype.mediaXML = function (name) {
return xml + '</media>';
};
-
// SnapSerializer loading:
-SnapSerializer.prototype.load = function (xmlString) {
+SnapSerializer.prototype.load = function (xmlString, ide) {
// public - answer a new Project represented by the given XML String
- return this.loadProjectModel(this.parse(xmlString));
+ return this.loadProjectModel(this.parse(xmlString), ide);
};
-SnapSerializer.prototype.loadProjectModel = function (xmlNode) {
+SnapSerializer.prototype.loadProjectModel = function (xmlNode, ide) {
// public - answer a new Project represented by the given XML top node
+ // show a warning if the origin apps differ
+
+ var appInfo = xmlNode.attributes.app,
+ app = appInfo ? appInfo.split(' ')[0] : null;
+
+ if (ide && app !== this.app.split(' ')[0]) {
+ ide.inform(
+ app + ' Project',
+ 'This project has been created by a different app:\n\n' +
+ app +
+ '\n\nand may be incompatible or fail to load here.'
+ );
+ }
+ return this.rawLoadProjectModel(xmlNode);
+};
+
+SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
+ // private
var myself = this,
project = {sprites: {}},
model,
@@ -844,7 +861,7 @@ SnapSerializer.prototype.loadScripts = function (scripts, model) {
// private
var myself = this,
scale = SyntaxElementMorph.prototype.scale;
- scripts.texture = 'scriptsPaneTexture.gif';
+ scripts.cachedTexture = IDE_Morph.prototype.scriptsPaneTexture;
model.children.forEach(function (child) {
var element;
if (child.tag === 'script') {
diff --git a/threads.js b/threads.js
index 8780de5..06454e3 100644
--- a/threads.js
+++ b/threads.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!.
@@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
// Global stuff ////////////////////////////////////////////////////////
-modules.threads = '2014-December-17';
+modules.threads = '2015-January-12';
var ThreadManager;
var Process;
@@ -159,9 +159,11 @@ ThreadManager.prototype.startProcess = function (
active.stop();
this.removeTerminatedProcesses();
}
- top.addHighlight();
newProc = new Process(block.topBlock(), callback);
newProc.exportResult = exportResult;
+ if (!newProc.homeContext.receiver.isClone) {
+ top.addHighlight();
+ }
this.processes.push(newProc);
return newProc;
};