summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGubolin <gubolin@fantasymail.de>2015-01-11 10:32:59 +0100
committerGubolin <gubolin@fantasymail.de>2015-01-11 10:32:59 +0100
commita94bd16d95f00fe3f8f27b425be3c7fc8cd3cd76 (patch)
treebde44a9ec9442947c9b46cb6c0f4377eaadcb44e
parent8b7b751c04a0f41129a2d39de93c171e8e516c42 (diff)
parentff3abf9d87a502cdf31a5f4abcbbf1826fd64fc9 (diff)
downloadsnap-a94bd16d95f00fe3f8f27b425be3c7fc8cd3cd76.tar.gz
snap-a94bd16d95f00fe3f8f27b425be3c7fc8cd3cd76.zip
Merge branch 'development' into gh-pages
-rwxr-xr-xbinary.js1099
-rwxr-xr-xbinary.sh92
-rw-r--r--config.xml15
-rwxr-xr-xdesktop.sh34
-rwxr-xr-xindex.html10
-rwxr-xr-x[-rw-r--r--]lang-ko.js492
-rwxr-xr-xmobile.sh65
-rw-r--r--morphic.js5
-rw-r--r--objects.js52
-rw-r--r--package.json8
-rw-r--r--threads.js126
11 files changed, 1896 insertions, 102 deletions
diff --git a/binary.js b/binary.js
new file mode 100755
index 0000000..d1a9b21
--- /dev/null
+++ b/binary.js
@@ -0,0 +1,1099 @@
+/*
+
+ gui.js
+
+ a programming environment
+ based on morphic.js, blocks.js, threads.js and objects.js
+ inspired by Scratch
+
+ written by Jens Mönig
+ jens@moenig.org
+
+ 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/>.
+
+
+ prerequisites:
+ --------------
+ needs blocks.js, threads.js, objects.js and morphic.js
+
+
+ toc
+ ---
+ the following list shows the order in which all constructors are
+ defined. Use this list to locate code in this document:
+
+ IDE_Morph
+
+
+ credits
+ -------
+ Nathan Dinsmore contributed saving and loading of projects,
+ ypr-Snap! project conversion and countless bugfixes
+ Ian Reynolds contributed handling and visualization of sounds
+
+*/
+
+/*global modules, Morph, SpriteMorph, Color, newCanvas,
+VariableFrame, Point, MenuMorph,
+morphicVersion, DialogBoxMorph, ToggleButtonMorph, contains,
+StageMorph, PushButtonMorph, Process, SnapSerializer, MorphicPreferences,
+SymbolMorph,
+BlockImportDialogMorph, SnapTranslator, localize, List */
+
+// Global stuff ////////////////////////////////////////////////////////
+
+modules.gui = '2014-July-30';
+
+// Declarations
+
+var IDE_Morph;
+
+// IDE_Morph ///////////////////////////////////////////////////////////
+
+// I am SNAP's top-level frame, the Editor window
+
+// IDE_Morph inherits from Morph:
+
+IDE_Morph.prototype = new Morph();
+IDE_Morph.prototype.constructor = IDE_Morph;
+IDE_Morph.uber = Morph.prototype;
+
+// IDE_Morph preferences settings and skins
+
+IDE_Morph.prototype.setDefaultDesign = function () {
+ MorphicPreferences.isFlat = false;
+ SpriteMorph.prototype.paletteColor = new Color(55, 55, 55);
+ SpriteMorph.prototype.paletteTextColor = new Color(230, 230, 230);
+ StageMorph.prototype.paletteTextColor
+ = SpriteMorph.prototype.paletteTextColor;
+ StageMorph.prototype.paletteColor = SpriteMorph.prototype.paletteColor;
+ SpriteMorph.prototype.sliderColor
+ = SpriteMorph.prototype.paletteColor.lighter(30);
+
+ IDE_Morph.prototype.buttonContrast = 30;
+ IDE_Morph.prototype.backgroundColor = new Color(40, 40, 40);
+ IDE_Morph.prototype.frameColor = SpriteMorph.prototype.paletteColor;
+
+ IDE_Morph.prototype.groupColor
+ = SpriteMorph.prototype.paletteColor.lighter(8);
+ IDE_Morph.prototype.sliderColor = SpriteMorph.prototype.sliderColor;
+ IDE_Morph.prototype.buttonLabelColor = new Color(255, 255, 255);
+ IDE_Morph.prototype.tabColors = [
+ IDE_Morph.prototype.groupColor.darker(40),
+ IDE_Morph.prototype.groupColor.darker(60),
+ IDE_Morph.prototype.groupColor
+ ];
+ IDE_Morph.prototype.rotationStyleColors = IDE_Morph.prototype.tabColors;
+ IDE_Morph.prototype.appModeColor = new Color();
+ IDE_Morph.prototype.scriptsPaneTexture = 'scriptsPaneTexture.gif';
+ IDE_Morph.prototype.padding = 5;
+};
+
+IDE_Morph.prototype.setFlatDesign = function () {
+ MorphicPreferences.isFlat = true;
+ SpriteMorph.prototype.paletteColor = new Color(255, 255, 255);
+ SpriteMorph.prototype.paletteTextColor = new Color(70, 70, 70);
+ StageMorph.prototype.paletteTextColor
+ = SpriteMorph.prototype.paletteTextColor;
+ StageMorph.prototype.paletteColor = SpriteMorph.prototype.paletteColor;
+ SpriteMorph.prototype.sliderColor = SpriteMorph.prototype.paletteColor;
+
+ IDE_Morph.prototype.buttonContrast = 30;
+ IDE_Morph.prototype.backgroundColor = new Color(200, 200, 200);
+ IDE_Morph.prototype.frameColor = new Color(255, 255, 255);
+
+ IDE_Morph.prototype.groupColor = new Color(230, 230, 230);
+ IDE_Morph.prototype.sliderColor = SpriteMorph.prototype.sliderColor;
+ IDE_Morph.prototype.buttonLabelColor = new Color(70, 70, 70);
+ IDE_Morph.prototype.tabColors = [
+ IDE_Morph.prototype.groupColor.lighter(60),
+ IDE_Morph.prototype.groupColor.darker(10),
+ IDE_Morph.prototype.groupColor
+ ];
+ IDE_Morph.prototype.rotationStyleColors = [
+ IDE_Morph.prototype.groupColor,
+ IDE_Morph.prototype.groupColor.darker(10),
+ IDE_Morph.prototype.groupColor.darker(30)
+ ];
+ IDE_Morph.prototype.appModeColor = IDE_Morph.prototype.frameColor;
+ IDE_Morph.prototype.scriptsPaneTexture = null;
+ IDE_Morph.prototype.padding = 1;
+};
+
+IDE_Morph.prototype.setDefaultDesign();
+
+// IDE_Morph instance creation:
+
+function IDE_Morph(isAutoFill) {
+ this.init(isAutoFill);
+}
+
+IDE_Morph.prototype.init = function (isAutoFill) {
+ // global font setting
+ MorphicPreferences.globalFontFamily = 'Helvetica, Arial';
+
+ // restore saved user preferences
+ this.userLanguage = null;
+
+ // additional properties:
+ this.source = 'local';
+ this.serializer = new SnapSerializer();
+
+ this.globalVariables = new VariableFrame();
+ this.currentSprite = new SpriteMorph(this.globalVariables);
+ this.sprites = new List([this.currentSprite]);
+ this.currentCategory = 'motion';
+ this.currentTab = 'scripts';
+ this.projectName = '';
+ this.projectNotes = '';
+
+ this.logo = null;
+ this.controlBar = null;
+ this.stage = null;
+
+ this.isAutoFill = isAutoFill || true;
+
+ this.filePicker = null;
+ this.hasChangedMedia = false;
+
+ this.isAnimating = true;
+ this.stageRatio = 1; // for IDE animations, e.g. when zooming
+
+ this.loadNewProject = false; // flag when starting up translated
+ this.shield = null;
+
+ // initialize inherited properties:
+ IDE_Morph.uber.init.call(this);
+
+ // override inherited properites:
+ this.color = this.appModeColor;
+};
+
+IDE_Morph.prototype.openIn = function (world) {
+ var hash;
+
+ this.buildPanes();
+ world.add(this);
+
+ this.reactToWorldResize(world.bounds);
+
+ function getURL(url) {
+ try {
+ var request = new XMLHttpRequest();
+ request.open('GET', url, false);
+ request.send();
+ if (request.status === 200) {
+ return request.responseText;
+ }
+ throw new Error('unable to retrieve ' + url);
+ } catch (err) {
+ return;
+ }
+ }
+
+ function interpretUrlAnchors() {
+ if (location.hash.substr(0, 6) === '#open:') {
+ hash = location.hash.substr(6);
+ if (hash.charAt(0) === '%'
+ || hash.search(/\%(?:[0-9a-f]{2})/i) > -1) {
+ hash = decodeURIComponent(hash);
+ }
+ if (contains(
+ ['project', 'blocks', 'sprites', 'snapdata'].map(
+ function (each) {
+ return hash.substr(0, 8).indexOf(each);
+ }
+ ),
+ 1
+ )) {
+ this.droppedText(hash);
+ } else {
+ this.droppedText(getURL(hash));
+ }
+ }
+ }
+
+ if (this.userLanguage) {
+ this.setLanguage(this.userLanguage, interpretUrlAnchors);
+ } else {
+ interpretUrlAnchors.call(this);
+ }
+};
+
+// IDE_Morph construction
+
+IDE_Morph.prototype.buildPanes = function () {
+ this.createLogo();
+ this.createControlBar();
+ this.createStage();
+};
+
+IDE_Morph.prototype.createLogo = function () {
+ var myself = this;
+
+ if (this.logo) {
+ this.logo.destroy();
+ }
+
+ this.logo = new Morph();
+ this.logo.texture = 'snap_logo_sm.png';
+ this.logo.drawNew = function () {
+ this.image = newCanvas(this.extent());
+ var context = this.image.getContext('2d');
+ context.fillStyle = this.color;
+ context.fillRect(0, 0, this.width(), this.height());
+ if (this.texture) {
+ this.drawTexture(this.texture);
+ }
+ };
+
+ this.logo.drawCachedTexture = function () {
+ var context = this.image.getContext('2d');
+ context.drawImage(
+ this.cachedTexture,
+ 5,
+ Math.round((this.height() - this.cachedTexture.height) / 2)
+ );
+ this.changed();
+ };
+
+ this.logo.mouseClickLeft = function () {
+ myself.snapMenu();
+ };
+
+ this.logo.color = new Color();
+ this.logo.setExtent(new Point(200, 28)); // dimensions are fixed
+ this.add(this.logo);
+};
+
+IDE_Morph.prototype.createControlBar = function () {
+ // assumes the logo has already been created
+ var padding = 5,
+ button,
+ stopButton,
+ pauseButton,
+ startButton,
+ x,
+ colors = [
+ this.groupColor,
+ this.frameColor.darker(50),
+ this.frameColor.darker(50)
+ ],
+ myself = this;
+
+ if (this.controlBar) {
+ this.controlBar.destroy();
+ }
+
+ this.controlBar = new Morph();
+ this.controlBar.color = this.appModeColor;
+ this.controlBar.setHeight(this.logo.height()); // height is fixed
+ this.controlBar.mouseClickLeft = function () {
+ this.world().fillPage();
+ };
+ this.add(this.controlBar);
+
+ // stopButton
+ button = new PushButtonMorph(
+ this,
+ 'stopAllScripts',
+ new SymbolMorph('octagon', 14)
+ );
+ button.corner = 12;
+ button.color = colors[0];
+ button.highlightColor = colors[1];
+ button.pressColor = colors[2];
+ button.labelMinExtent = new Point(36, 18);
+ button.padding = 0;
+ button.labelShadowOffset = new Point(-1, -1);
+ button.labelShadowColor = colors[1];
+ button.labelColor = new Color(200, 0, 0);
+ button.contrast = this.buttonContrast;
+ button.drawNew();
+ // button.hint = 'stop\nevery-\nthing';
+ button.fixLayout();
+ stopButton = button;
+ this.controlBar.add(stopButton);
+
+ //pauseButton
+ button = new ToggleButtonMorph(
+ null, //colors,
+ myself, // the IDE is the target
+ 'togglePauseResume',
+ [
+ new SymbolMorph('pause', 12),
+ new SymbolMorph('pointRight', 14)
+ ],
+ function () { // query
+ return myself.isPaused();
+ }
+ );
+
+ button.corner = 12;
+ button.color = colors[0];
+ button.highlightColor = colors[1];
+ button.pressColor = colors[2];
+ button.labelMinExtent = new Point(36, 18);
+ button.padding = 0;
+ button.labelShadowOffset = new Point(-1, -1);
+ button.labelShadowColor = colors[1];
+ button.labelColor = new Color(255, 220, 0);
+ button.contrast = this.buttonContrast;
+ button.drawNew();
+ // button.hint = 'pause/resume\nall scripts';
+ button.fixLayout();
+ button.refresh();
+ pauseButton = button;
+ this.controlBar.add(pauseButton);
+ this.controlBar.pauseButton = pauseButton; // for refreshing
+
+ // startButton
+ button = new PushButtonMorph(
+ this,
+ 'pressStart',
+ new SymbolMorph('flag', 14)
+ );
+ button.corner = 12;
+ button.color = colors[0];
+ button.highlightColor = colors[1];
+ button.pressColor = colors[2];
+ button.labelMinExtent = new Point(36, 18);
+ button.padding = 0;
+ button.labelShadowOffset = new Point(-1, -1);
+ button.labelShadowColor = colors[1];
+ button.labelColor = new Color(0, 200, 0);
+ button.contrast = this.buttonContrast;
+ button.drawNew();
+ // button.hint = 'start green\nflag scripts';
+ button.fixLayout();
+ startButton = button;
+ this.controlBar.add(startButton);
+ this.controlBar.startButton = startButton;
+
+ this.controlBar.fixLayout = function () {
+ x = this.right() - padding;
+ [stopButton, pauseButton, startButton].forEach(
+ function (button) {
+ button.setCenter(myself.controlBar.center());
+ button.setRight(x);
+ x -= button.width();
+ x -= padding;
+ }
+ );
+
+ x = myself.right() - StageMorph.prototype.dimensions.x;
+
+ this.updateLabel();
+ };
+
+ this.controlBar.updateLabel = function () {
+ if (this.label) {
+ this.label.destroy();
+ }
+ };
+};
+
+IDE_Morph.prototype.createStage = function () {
+ // assumes that the logo pane has already been created
+ if (this.stage) {
+ this.stage.destroy();
+ }
+ StageMorph.prototype.frameRate = 0;
+ this.stage = new StageMorph(this.globalVariables);
+ this.stage.setExtent(this.stage.dimensions); // dimensions are fixed
+ if (this.currentSprite instanceof SpriteMorph) {
+ this.currentSprite.setPosition(
+ this.stage.center().subtract(
+ this.currentSprite.extent().divideBy(2)
+ )
+ );
+ this.stage.add(this.currentSprite);
+ }
+ this.add(this.stage);
+};
+
+IDE_Morph.prototype.createCorral = function () {
+};
+
+// IDE_Morph resizing
+
+IDE_Morph.prototype.setExtent = function (point) {
+ var minExt,
+ ext;
+
+ // determine the minimum dimensions making sense for the current mode
+ minExt = StageMorph.prototype.dimensions.add(
+ this.controlBar.height() + 10
+ );
+ ext = point.max(minExt);
+ IDE_Morph.uber.setExtent.call(this, ext);
+ this.fixLayout();
+};
+
+// IDE_Morph events
+
+IDE_Morph.prototype.reactToWorldResize = function (rect) {
+ if (this.isAutoFill) {
+ this.setPosition(rect.origin);
+ this.setExtent(rect.extent());
+ }
+ if (this.filePicker) {
+ document.body.removeChild(this.filePicker);
+ this.filePicker = null;
+ }
+};
+
+// IDE_Morph layout
+
+IDE_Morph.prototype.fixLayout = function () {
+ var padding = this.padding;
+
+ Morph.prototype.trackChanges = false;
+
+ // controlBar
+ this.controlBar.setPosition(this.logo.topRight());
+ this.controlBar.setWidth(this.right() - this.controlBar.left());
+ this.controlBar.fixLayout();
+
+ // stage
+ this.stage.setScale(Math.floor(Math.min(
+ (this.width() - padding * 2) / this.stage.dimensions.x,
+ (this.height() - this.controlBar.height() * 2 - padding * 2)
+ / this.stage.dimensions.y
+ ) * 10) / 10);
+ this.stage.setCenter(this.center());
+
+ Morph.prototype.trackChanges = true;
+ this.changed();
+};
+
+IDE_Morph.prototype.droppedText = function (aString, name) {
+ var lbl = name ? name.split('.')[0] : '';
+ if (aString.indexOf('<project') === 0) {
+ return this.openProjectString(aString);
+ }
+ if (aString.indexOf('<snapdata') === 0) {
+ return this.openCloudDataString(aString);
+ }
+ if (aString.indexOf('<blocks') === 0) {
+ return this.openBlocksString(aString, lbl, true);
+ }
+ if (aString.indexOf('<sprites') === 0) {
+ return this.openSpritesString(aString);
+ }
+ if (aString.indexOf('<media') === 0) {
+ return this.openMediaString(aString);
+ }
+};
+
+// IDE_Morph events
+
+IDE_Morph.prototype.pressStart = function () {
+ if (this.world().currentKey === 16) { // shiftClicked
+ this.toggleFastTracking();
+ } else {
+ this.runScripts();
+ }
+};
+
+IDE_Morph.prototype.toggleFastTracking = function () {
+ if (this.stage.isFastTracked) {
+ this.stopFastTracking();
+ } else {
+ this.startFastTracking();
+ }
+};
+
+IDE_Morph.prototype.toggleVariableFrameRate = function () {
+ if (StageMorph.prototype.frameRate) {
+ StageMorph.prototype.frameRate = 0;
+ this.stage.fps = 0;
+ } else {
+ StageMorph.prototype.frameRate = 30;
+ this.stage.fps = 30;
+ }
+};
+
+IDE_Morph.prototype.startFastTracking = function () {
+ this.stage.isFastTracked = true;
+ this.stage.fps = 0;
+ this.controlBar.startButton.labelString = new SymbolMorph('flash', 14);
+ this.controlBar.startButton.drawNew();
+ this.controlBar.startButton.fixLayout();
+};
+
+IDE_Morph.prototype.stopFastTracking = function () {
+ this.stage.isFastTracked = false;
+ this.stage.fps = this.stage.frameRate;
+ this.controlBar.startButton.labelString = new SymbolMorph('flag', 14);
+ this.controlBar.startButton.drawNew();
+ this.controlBar.startButton.fixLayout();
+};
+
+IDE_Morph.prototype.runScripts = function () {
+ this.stage.fireGreenFlagEvent();
+};
+
+IDE_Morph.prototype.togglePauseResume = function () {
+ if (this.stage.threads.isPaused()) {
+ this.stage.threads.resumeAll(this.stage);
+ } else {
+ this.stage.threads.pauseAll(this.stage);
+ }
+ this.controlBar.pauseButton.refresh();
+};
+
+IDE_Morph.prototype.isPaused = function () {
+ if (!this.stage) {return false; }
+ return this.stage.threads.isPaused();
+};
+
+IDE_Morph.prototype.stopAllScripts = function () {
+ this.stage.fireStopAllEvent();
+};
+
+IDE_Morph.prototype.selectSprite = function (sprite) {
+ this.currentSprite = sprite;
+ this.currentSprite.scripts.fixMultiArgs();
+};
+
+// IDE_Morph menus
+
+IDE_Morph.prototype.snapMenu = function () {
+ var menu,
+ world = this.world();
+
+ menu = new MenuMorph(this);
+ menu.addItem('About...', 'aboutSnap');
+ menu.addLine();
+ menu.addItem(
+ 'Reference manual',
+ function () {
+ window.open('help/SnapManual.pdf', 'SnapReferenceManual');
+ }
+ );
+ menu.addItem(
+ 'Snap! website',
+ function () {
+ window.open('http://snap.berkeley.edu/', 'SnapWebsite');
+ }
+ );
+ menu.addItem(
+ 'Download source',
+ function () {
+ window.open(
+ 'http://snap.berkeley.edu/snapsource/snap.zip',
+ 'SnapSource'
+ );
+ }
+ );
+ if (world.isDevMode) {
+ menu.addLine();
+ menu.addItem(
+ 'Switch back to user mode',
+ 'switchToUserMode',
+ 'disable deep-Morphic\ncontext menus'
+ + '\nand show user-friendly ones',
+ new Color(0, 100, 0)
+ );
+ } else if (world.currentKey === 16) { // shift-click
+ menu.addLine();
+ menu.addItem(
+ 'Switch to dev mode',
+ 'switchToDevMode',
+ 'enable Morphic\ncontext menus\nand inspectors,'
+ + '\nnot user-friendly!',
+ new Color(100, 0, 0)
+ );
+ }
+ menu.popup(world, this.logo.bottomLeft());
+};
+
+// IDE_Morph menu actions
+
+IDE_Morph.prototype.aboutSnap = function () {
+ var dlg, aboutTxt, noticeTxt, creditsTxt, versions = '', translations,
+ module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
+ world = this.world();
+
+ aboutTxt = 'Snap! 4.0\nBuild Your Own Blocks\n\n--- beta ---\n\n'
+ + 'Copyright \u24B8 2014 Jens M\u00F6nig and '
+ + 'Brian Harvey\n'
+ + 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
+
+ + 'Snap! is developed by the University of California, Berkeley\n'
+ + ' with support from the National Science Foundation '
+ + 'and MioSoft. \n'
+
+ + 'The design of Snap! is influenced and inspired by Scratch,\n'
+ + 'from the Lifelong Kindergarten group at the MIT Media Lab\n\n'
+
+ + 'for more information see http://snap.berkeley.edu\n'
+ + 'and http://scratch.mit.edu';
+
+ noticeTxt = localize('License')
+ + '\n\n'
+ + 'Snap! is free software: you can redistribute it and/or modify\n'
+ + 'it under the terms of the GNU Affero General Public License as\n'
+ + 'published by the Free Software Foundation, either version 3 of\n'
+ + 'the License, or (at your option) any later version.\n\n'
+
+ + 'This program is distributed in the hope that it will be useful,\n'
+ + 'but WITHOUT ANY WARRANTY; without even the implied warranty of\n'
+ + 'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n'
+ + 'GNU Affero General Public License for more details.\n\n'
+
+ + 'You should have received a copy of the\n'
+ + 'GNU Affero General Public License along with this program.\n'
+ + 'If not, see http://www.gnu.org/licenses/';
+
+ creditsTxt = localize('Contributors')
+ + '\n\nNathan Dinsmore: Saving/Loading, Snap-Logo Design, '
+ + 'countless bugfixes'
+ + '\nKartik Chandra: Paint Editor'
+ + '\nMichael Ball: Time/Date UI, many bugfixes'
+ + '\n"Ava" Yuan Yuan: Graphic Effects'
+ + '\nKyle Hotchkiss: Block search design'
+ + '\nIan Reynolds: UI Design, Event Bindings, '
+ + 'Sound primitives'
+ + '\nIvan Motyashov: Initial Squeak Porting'
+ + '\nDavide Della Casa: Morphic Optimizations'
+ + '\nAchal Dave: Web Audio'
+ + '\nJoe Otto: Morphic Testing and Debugging';
+
+ for (module in modules) {
+ if (Object.prototype.hasOwnProperty.call(modules, module)) {
+ versions += ('\n' + module + ' (' +
+ modules[module] + ')');
+ }
+ }
+ if (versions !== '') {
+ versions = localize('current module versions:') + ' \n\n' +
+ 'morphic (' + morphicVersion + ')' +
+ versions;
+ }
+ translations = localize('Translations') + '\n' + SnapTranslator.credits();
+
+ dlg = new DialogBoxMorph();
+ dlg.inform('About Snap', aboutTxt, world);
+ btn1 = dlg.buttons.children[0];
+ translatorsBtn = dlg.addButton(
+ function () {
+ dlg.body.text = translations;
+ dlg.body.drawNew();
+ btn1.show();
+ btn2.show();
+ btn3.hide();
+ btn4.hide();
+ licenseBtn.hide();
+ translatorsBtn.hide();
+ dlg.fixLayout();
+ dlg.drawNew();
+ dlg.setCenter(world.center());
+ },
+ 'Translators...'
+ );
+ btn2 = dlg.addButton(
+ function () {
+ dlg.body.text = aboutTxt;
+ dlg.body.drawNew();
+ btn1.show();
+ btn2.hide();
+ btn3.show();
+ btn4.show();
+ licenseBtn.show();
+ translatorsBtn.hide();
+ dlg.fixLayout();
+ dlg.drawNew();
+ dlg.setCenter(world.center());
+ },
+ 'Back...'
+ );
+ btn2.hide();
+ licenseBtn = dlg.addButton(
+ function () {
+ dlg.body.text = noticeTxt;
+ dlg.body.drawNew();
+ btn1.show();
+ btn2.show();
+ btn3.hide();
+ btn4.hide();
+ licenseBtn.hide();
+ translatorsBtn.hide();
+ dlg.fixLayout();
+ dlg.drawNew();
+ dlg.setCenter(world.center());
+ },
+ 'License...'
+ );
+ btn3 = dlg.addButton(
+ function () {
+ dlg.body.text = versions;
+ dlg.body.drawNew();
+ btn1.show();
+ btn2.show();
+ btn3.hide();
+ btn4.hide();
+ licenseBtn.hide();
+ translatorsBtn.hide();
+ dlg.fixLayout();
+ dlg.drawNew();
+ dlg.setCenter(world.center());
+ },
+ 'Modules...'
+ );
+ btn4 = dlg.addButton(
+ function () {
+ dlg.body.text = creditsTxt;
+ dlg.body.drawNew();
+ btn1.show();
+ btn2.show();
+ translatorsBtn.show();
+ btn3.hide();
+ btn4.hide();
+ licenseBtn.hide();
+ dlg.fixLayout();
+ dlg.drawNew();
+ dlg.setCenter(world.center());
+ },
+ 'Credits...'
+ );
+ translatorsBtn.hide();
+ dlg.fixLayout();
+ dlg.drawNew();
+};
+
+IDE_Morph.prototype.openProjectString = function (str) {
+ var msg,
+ myself = this;
+ this.nextSteps([
+ function () {
+ msg = myself.showMessage('Opening project...');
+ },
+ function () {
+ myself.rawOpenProjectString(str);
+ },
+ function () {
+ msg.destroy();
+ }
+ ]);
+};
+
+IDE_Morph.prototype.rawOpenProjectString = function (str) {
+ StageMorph.prototype.hiddenPrimitives = {};
+ StageMorph.prototype.codeMappings = {};
+ StageMorph.prototype.codeHeaders = {};
+ StageMorph.prototype.enableCodeMapping = false;
+ if (Process.prototype.isCatchingErrors) {
+ try {
+ this.serializer.openProject(this.serializer.load(str), this);
+ } catch (err) {
+ this.showMessage('Load failed: ' + err);
+ }
+ } else {
+ this.serializer.openProject(this.serializer.load(str), this);
+ }
+ this.stopFastTracking();
+};
+
+IDE_Morph.prototype.openBlocksString = function (str, name, silently) {
+ var msg,
+ myself = this;
+ this.nextSteps([
+ function () {
+ msg = myself.showMessage('Opening blocks...');
+ },
+ function () {
+ myself.rawOpenBlocksString(str, name, silently);
+ },
+ function () {
+ msg.destroy();
+ }
+ ]);
+};
+
+IDE_Morph.prototype.rawOpenBlocksString = function (str, name, silently) {
+ // name is optional (string), so is silently (bool)
+ var blocks,
+ myself = this;
+ if (Process.prototype.isCatchingErrors) {
+ try {
+ blocks = this.serializer.loadBlocks(str, myself.stage);
+ } catch (err) {
+ this.showMessage('Load failed: ' + err);
+ }
+ } else {
+ blocks = this.serializer.loadBlocks(str, myself.stage);
+ }
+ if (silently) {
+ blocks.forEach(function (def) {
+ def.receiver = myself.stage;
+ myself.stage.globalBlocks.push(def);
+ myself.stage.replaceDoubleDefinitionsFor(def);
+ });
+ this.showMessage(
+ 'Imported Blocks Module' + (name ? ': ' + name : '') + '.',
+ 2
+ );
+ } else {
+ new BlockImportDialogMorph(blocks, this.stage, name).popUp();
+ }
+};
+
+IDE_Morph.prototype.openSpritesString = function (str) {
+ var msg,
+ myself = this;
+ this.nextSteps([
+ function () {
+ msg = myself.showMessage('Opening sprite...');
+ },
+ function () {
+ myself.rawOpenSpritesString(str);
+ },
+ function () {
+ msg.destroy();
+ }
+ ]);
+};
+
+IDE_Morph.prototype.rawOpenSpritesString = function (str) {
+ if (Process.prototype.isCatchingErrors) {
+ try {
+ this.serializer.loadSprites(str, this);
+ } catch (err) {
+ this.showMessage('Load failed: ' + err);
+ }
+ } else {
+ this.serializer.loadSprites(str, this);
+ }
+};
+
+IDE_Morph.prototype.openMediaString = function (str) {
+ if (Process.prototype.isCatchingErrors) {
+ try {
+ this.serializer.loadMedia(str);
+ } catch (err) {
+ this.showMessage('Load failed: ' + err);
+ }
+ } else {
+ this.serializer.loadMedia(str);
+ }
+ this.showMessage('Imported Media Module.', 2);
+};
+
+IDE_Morph.prototype.openProject = function (name) {
+ var str;
+ if (name) {
+ this.showMessage('opening project\n' + name);
+ str = localStorage['-snap-project-' + name];
+ this.openProjectString(str);
+ location.hash = '#open:' + str;
+ }
+};
+
+IDE_Morph.prototype.switchToUserMode = function () {
+ var world = this.world();
+
+ world.isDevMode = false;
+ Process.prototype.isCatchingErrors = true;
+ this.controlBar.updateLabel();
+ this.isAutoFill = true;
+ this.isDraggable = false;
+ this.siblings().forEach(function (morph) {
+ if (morph instanceof DialogBoxMorph) {
+ world.add(morph); // bring to front
+ } else {
+ morph.destroy();
+ }
+ });
+ this.flushBlocksCache();
+ // prevent non-DialogBoxMorphs from being dropped
+ // onto the World in user-mode
+ world.reactToDropOf = function (morph) {
+ if (!(morph instanceof DialogBoxMorph)) {
+ world.hand.grab(morph);
+ }
+ };
+ this.showMessage('entering user mode', 1);
+
+};
+
+IDE_Morph.prototype.switchToDevMode = function () {
+ var world = this.world();
+
+ world.isDevMode = true;
+ Process.prototype.isCatchingErrors = false;
+ this.controlBar.updateLabel();
+ this.isAutoFill = false;
+ this.isDraggable = true;
+ this.setExtent(world.extent().subtract(100));
+ this.setPosition(world.position().add(20));
+ this.flushBlocksCache();
+ // enable non-DialogBoxMorphs to be dropped
+ // onto the World in dev-mode
+ delete world.reactToDropOf;
+ this.showMessage(
+ 'entering development mode.\n\n'
+ + 'error catching is turned off,\n'
+ + 'use the browser\'s web console\n'
+ + 'to see error messages.'
+ );
+};
+
+IDE_Morph.prototype.flushBlocksCache = function (category) {
+ // if no category is specified, the whole cache gets flushed
+ if (category) {
+ this.stage.blocksCache[category] = null;
+ this.stage.children.forEach(function (m) {
+ if (m instanceof SpriteMorph) {
+ m.blocksCache[category] = null;
+ }
+ });
+ } else {
+ this.stage.blocksCache = {};
+ this.stage.children.forEach(function (m) {
+ if (m instanceof SpriteMorph) {
+ m.blocksCache = {};
+ }
+ });
+ }
+};
+
+// IDE_Morph localization
+
+IDE_Morph.prototype.setLanguage = function (lang, callback) {
+ var translation = document.getElementById('language'),
+ src = 'lang-' + lang + '.js',
+ myself = this;
+ SnapTranslator.unload();
+ if (translation) {
+ document.head.removeChild(translation);
+ }
+ if (lang === 'en') {
+ return this.reflectLanguage('en', callback);
+ }
+ myself.userLanguage = lang;
+ translation = document.createElement('script');
+ translation.id = 'language';
+ translation.onload = function () {
+ myself.reflectLanguage(lang, callback);
+ };
+ document.head.appendChild(translation);
+ translation.src = src;
+};
+
+IDE_Morph.prototype.reflectLanguage = function (lang, callback) {
+ var projectData;
+ SnapTranslator.language = lang;
+ if (!this.loadNewProject) {
+ if (Process.prototype.isCatchingErrors) {
+ try {
+ projectData = this.serializer.serialize(this.stage);
+ } catch (err) {
+ this.showMessage('Serialization failed: ' + err);
+ }
+ } else {
+ projectData = this.serializer.serialize(this.stage);
+ }
+ }
+ SpriteMorph.prototype.initBlocks();
+ this.fixLayout();
+ if (this.loadNewProject) {
+ this.newProject();
+ } else {
+ this.openProjectString(projectData);
+ }
+ this.saveSetting('language', lang);
+ if (callback) {callback.call(this); }
+};
+
+// IDE_Morph synchronous Http data fetching
+
+IDE_Morph.prototype.getURL = function (url) {
+ var request = new XMLHttpRequest(),
+ myself = this;
+ try {
+ request.open('GET', url, false);
+ request.send();
+ if (request.status === 200) {
+ return request.responseText;
+ }
+ throw new Error('unable to retrieve ' + url);
+ } catch (err) {
+ myself.showMessage(err);
+ return;
+ }
+};
+
+IDE_Morph.prototype.getURLsbeOrRelative = function (url) {
+ var request = new XMLHttpRequest(),
+ myself = this;
+ try {
+ request.open('GET', 'http://snap.berkeley.edu/snapsource/' +
+ url, false);
+ request.send();
+ if (request.status === 200) {
+ return request.responseText;
+ }
+ return myself.getURL(url);
+ } catch (err) {
+ myself.showMessage(err);
+ return;
+ }
+};
+
+// IDE_Morph user dialog shortcuts
+
+IDE_Morph.prototype.showMessage = function (message, secs) {
+ var m = new MenuMorph(null, message),
+ intervalHandle;
+ m.popUpCenteredInWorld(this.world());
+ if (secs) {
+ intervalHandle = setInterval(function () {
+ m.destroy();
+ clearInterval(intervalHandle);
+ }, secs * 1000);
+ }
+ return m;
+};
+
+IDE_Morph.prototype.inform = function (title, message) {
+ new DialogBoxMorph().inform(
+ title,
+ localize(message),
+ this.world()
+ );
+};
+
+IDE_Morph.prototype.confirm = function (message, title, action) {
+ new DialogBoxMorph(null, action).askYesNo(
+ title,
+ localize(message),
+ this.world()
+ );
+};
+
+IDE_Morph.prototype.prompt = function (message, callback, choices, key) {
+ (new DialogBoxMorph(null, callback)).withKey(key).prompt(
+ message,
+ '',
+ this.world(),
+ null,
+ choices
+ );
+};
diff --git a/binary.sh b/binary.sh
new file mode 100755
index 0000000..212e7cb
--- /dev/null
+++ b/binary.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+if [[ "$snapsource" == "" ]]
+then
+ export snapsource="https://github.com/Gubolin/snap.git"
+fi
+
+if [[ $# < 2 ]]
+then
+ echo "Usage: binary.sh OPTION PLATFORM [FILE]"
+ echo ""
+ echo "OPTIONS:"
+ echo " -m Mobile"
+ echo " -d Desktop"
+ echo ""
+ echo "PLATFORMS:"
+ echo " Mobile amazon-fireos android blackberry10 firefoxos ios ubuntu wp8 win8 tizen"
+ echo " Desktop win osx linux32 linux64"
+ echo ""
+ echo "If FILE is given, it will be #open-ed inside Snap\! immediately"
+ exit 0
+fi
+
+scriptdir=$(readlink -e ".")
+
+# Requirements:
+# git
+# UglifyJS2 (https://github.com/mishoo/UglifyJS2)
+
+ide=true
+platform=$2
+
+# presentation mode
+if [[ "$3" != "" ]]
+then
+ ide=false
+fi
+
+if [ $ide == false ]
+then
+ if [ -f "$3" ]
+ then
+ content=$(cat $3)
+ else
+ ide=true
+ fi
+fi
+
+buildsource=$(mktemp -d)
+git clone $snapsource $buildsource
+cd "$buildsource"
+git checkout mobileapp
+
+rm -rf .git/
+
+if [ $ide == false ]
+then
+ # minimize everything
+ rm lang* ypr.js paint.js cloud.js gui.js
+
+ sed -i '/paint\.js"/d' snap.html
+ sed -i '/cloud\.js"/d' snap.html
+ sed -i 's/gui\.js"/binary\.js"/' snap.html
+
+ # load custom project from file
+ sed -i '/sha512\.js"/a\
+ <script type="text/javascript" src="code.js"></script> ' snap.html
+
+ echo "var code =" > code.js
+ echo "'$content'" >> code.js
+ echo ";" >> code.js
+
+ sed -i "/ide\.openIn/a\
+ ide.droppedText(code); " snap.html
+else
+ rm binary.js
+fi
+
+# compress all js files
+find . -name '*.js' | xargs -I {} uglifyjs {} -o {} -c
+
+# return to the directory where the script was called from
+cd "$scriptdir"
+
+# run helper scripts for building
+
+if [[ $1 == "-m" ]]
+then
+ ./mobile.sh "$2" "$buildsource"
+else
+ ./desktop.sh "$2" "$buildsource"
+fi
diff --git a/config.xml b/config.xml
new file mode 100644
index 0000000..36a7bcf
--- /dev/null
+++ b/config.xml
@@ -0,0 +1,15 @@
+<?xml version='4.0' encoding='utf-8'?>
+<widget id="edu.berkeley.snap" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+ <name>Snap!</name>
+ <description>
+ Snap! Build Your Own Blocks
+ A visual, blocks based programming language inspired by Scratch
+ </description>
+ <author email="jens@moenig.org" href="http://snap.berkeley.edu">
+ Jens Mönig and Brian Harvey
+ </author>
+ <content src="snap.html" />
+ <access origin="*" />
+ <preference name="Fullscreen" value="true" />
+ <icon src="www/snap_logo_sm.png" />
+</widget>
diff --git a/desktop.sh b/desktop.sh
new file mode 100755
index 0000000..72b0786
--- /dev/null
+++ b/desktop.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if [[ "$snapsource" == "" ]]
+then
+ export snapsource="https://github.com/Gubolin/snap.git"
+fi
+
+if [[ $1 = "" ]]
+then
+ echo "Usage: desktop.sh PLATFORM [BUILDSOURCE]"
+ exit 0
+fi
+
+scriptdir=$(readlink -e ".")
+
+# Requirements:
+# git, zip, nodejs
+# node-webkit (https://github.com/rogerwang/node-webkit), node-webkit-builder (https://github.com/mllrsohn/node-webkit-builder)
+
+builddir=$(mktemp -d)
+
+if [[ $2 == "" ]]
+then
+ git clone "$snapsource" $builddir
+ cd $builddir/
+ git checkout mobileapp
+else
+ mv "$2" $builddir
+ cd $builddir/
+fi
+
+nwbuild -p "$1" .
+
+mv build/* $scriptdir/
diff --git a/index.html b/index.html
index 703ccb1..5126b08 100755
--- a/index.html
+++ b/index.html
@@ -21,16 +21,26 @@
<script type="text/javascript" src="octokit.js/octokit.js"></script>
<script type="text/javascript" src="github.js"></script>
<script type="text/javascript" src="sha512.js"></script>
+<<<<<<< HEAD
<script type="text/javascript" src="Snapin8r/snapin8r.min.js"></script>
<script type="text/javascript" src="vkBeautify/vkbeautify.js"></script>
<script type="text/javascript" src="diff-merge/dist/diff.js"></script>
+=======
+
+>>>>>>> mobileapp
<script type="text/javascript">
var world;
window.onload = function () {
world = new WorldMorph(document.getElementById('world'));
world.worldCanvas.focus();
+<<<<<<< HEAD
new IDE_Morph().openIn(world);
setInterval(loop, 10);
+=======
+ var ide = new IDE_Morph()
+ ide.openIn(world);
+ setInterval(loop, 1);
+>>>>>>> mobileapp
};
function loop() {
world.doOneCycle();
diff --git a/lang-ko.js b/lang-ko.js
index a1e50eb..3241c7f 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
+ '2014-11-07', // 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/mobile.sh b/mobile.sh
new file mode 100755
index 0000000..6ec8a0e
--- /dev/null
+++ b/mobile.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+if [[ "$snapsource" == "" ]]
+then
+ export snapsource="https://github.com/Gubolin/snap.git"
+fi
+
+if [[ $1 = "" ]]
+then
+ echo "Usage: mobile.sh PLATFORM [BUILDSOURCE]"
+ exit 0
+fi
+
+scriptdir=$(readlink -e ".")
+
+# Requirements:
+# git, nodejs, android SDK / other platform(s)
+# cordova (https://cordova.apache.org/)
+
+if [[ $2 != "" ]]
+then
+ buildsource=$(readlink -e "$2")
+fi
+
+builddir=$(mktemp -d)
+
+cordova create $builddir edu.berkeley.snap "Snap\!"
+cd $builddir
+rm -rf www config.xml
+
+if [[ $2 == "" ]]
+then
+ git clone "$snapsource" www
+ cd www/
+ git checkout mobileapp
+else
+ mv "$buildsource" www
+ cd www
+fi
+
+# add mobile-specific library; it's made available at runtime
+sed -i '/link rel="shortcut icon"/a\
+ <script type="text/javascript" src="cordova.js"></script>' snap.html
+
+# add everything needed and build for $device
+cordova platform add "$1"
+cordova plugin add org.apache.cordova.plugin.softkeyboard
+cordova plugin add org.apache.cordova.vibration
+cordova plugin add org.apache.cordova.device-motion
+cordova plugin add org.apache.cordova.device-orientation
+cordova plugin add org.apache.cordova.geolocation
+cordova plugin add de.appplant.cordova.plugin.local-notification
+
+if [[ $1 == "android" ]]
+then
+ # Remove default icons
+ cd "$builddir/platforms/android"
+ find -name '*.png' | xargs rm
+fi
+
+cordova build "$1"
+
+cd $builddir
+# TODO other platforms
+find -name '*.apk' | xargs -I {} mv {} $scriptdir
diff --git a/morphic.js b/morphic.js
index 9616897..4a16597 100644
--- a/morphic.js
+++ b/morphic.js
@@ -10790,6 +10790,11 @@ WorldMorph.prototype.edit = function (aStringOrTextMorph) {
this.virtualKeyboard.style.top = this.cursor.top() + pos.y + "px";
this.virtualKeyboard.style.left = this.cursor.left() + pos.x + "px";
this.virtualKeyboard.focus();
+ if (cordova) {
+ if (cordova.plugins.SoftKeyboard) { // Android only
+ cordova.plugins.SoftKeyboard.show(); // Issue #81
+ }
+ }
}
if (MorphicPreferences.useSliderForInput) {
diff --git a/objects.js b/objects.js
index 327dd30..95581c5 100644
--- a/objects.js
+++ b/objects.js
@@ -415,6 +415,11 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'go back %n layers',
defaults: [1]
},
+ doNotify: {
+ type: 'command',
+ category: 'looks',
+ spec: 'notification with title %s and content %s'
+ },
doScreenshot: {
type: 'command',
category: 'looks',
@@ -933,6 +938,31 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'sensing',
spec: 'current %dates'
},
+ doVibrate: {
+ type: 'command',
+ category: 'sensing',
+ spec: 'vibrate %n seconds'
+ },
+ reportCompassHeading: {
+ type: 'reporter',
+ category: 'sensing',
+ spec: 'current compass heading'
+ },
+ reportAccelerationX: {
+ type: 'reporter',
+ category: 'sensing',
+ spec: 'current acceleration along the x axes'
+ },
+ reportAccelerationY: {
+ type: 'reporter',
+ category: 'sensing',
+ spec: 'current acceleration along the y axes'
+ },
+ reportAccelerationZ: {
+ type: 'reporter',
+ category: 'sensing',
+ spec: 'current acceleration along the z axes'
+ },
reportLanguage: {
type: 'reporter',
category: 'sensing',
@@ -1818,6 +1848,8 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push('-');
blocks.push(block('comeToFront'));
blocks.push(block('goBack'));
+ blocks.push('-');
+ blocks.push(block('doNotify'));
// for debugging: ///////////////
@@ -1988,6 +2020,14 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push('-');
blocks.push(block('reportLanguage'));
blocks.push(block('reportLocation'));
+ blocks.push('-');
+ blocks.push(block('doVibrate'));
+ blocks.push('-');
+ blocks.push(block('reportCompassHeading'));
+ blocks.push('-');
+ blocks.push(block('reportAccelerationX'));
+ blocks.push(block('reportAccelerationY'));
+ blocks.push(block('reportAccelerationZ'));
// for debugging: ///////////////
@@ -4434,6 +4474,8 @@ StageMorph.prototype.init = function (globals) {
this.paletteCache = {}; // not to be serialized (!)
this.lastAnswer = ''; // last user input, do not persist
this.activeSounds = []; // do not persist
+ this.acceleration = null; // do not persist
+ this.compassHeading = null; // do not persist
this.streamingCamera = false;
this.lastCameraCanvas = null;
this.lastCameraMotion = new Point(0, 0);
@@ -5082,6 +5124,8 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push('-');
blocks.push(block('show'));
blocks.push(block('hide'));
+ blocks.push('-');
+ blocks.push(block('doNotify'));
// for debugging: ///////////////
@@ -5230,6 +5274,14 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push('-');
blocks.push(block('reportLanguage'));
blocks.push(block('reportLocation'));
+ blocks.push('-');
+ blocks.push(block('doVibrate'));
+ blocks.push('-');
+ blocks.push(block('reportCompassHeading'));
+ blocks.push('-');
+ blocks.push(block('reportAccelerationX'));
+ blocks.push(block('reportAccelerationY'));
+ blocks.push(block('reportAccelerationZ'));
// for debugging: ///////////////
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..678a69c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "Snap!",
+ "version": "4.0",
+ "main": "snap.html",
+ "window": {
+ "toolbar": false
+ }
+}
diff --git a/threads.js b/threads.js
index f6aea65..18fa91e 100644
--- a/threads.js
+++ b/threads.js
@@ -2277,6 +2277,20 @@ Process.prototype.reportTextSplit = function (string, delimiter) {
return new List(str.split(del));
};
+// Process notification operations
+
+Process.prototype.doNotify = function (title, content) {
+ // TODO webkitNotification
+ if (window.plugin) {
+ if (window.plugin.notification) {
+ window.plugin.notification.local.add({
+ message: content,
+ title: title
+ });
+ }
+ }
+};
+
// Process debugging
Process.prototype.alert = function (data) {
@@ -2797,6 +2811,114 @@ Process.prototype.reportDate = function (datefn) {
return result;
};
+Process.prototype.getCompassHeading = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+
+ stage.compassHeading = null;
+ if (navigator.compass) {
+ navigator.compass.getCurrentHeading(
+ function (result) {
+ stage.compassHeading = result;
+ },
+ function () {
+ stage.compassHeading =
+ {'magneticHeading': 0, 'trueHeading': 0,
+ 'headingAccuracy': 0, 'timestamp': 0};
+ }
+ );
+ } else {
+ stage.compassHeading =
+ {'magneticHeading': 0, 'trueHeading': 0,
+ 'headingAccuracy': 0, 'timestamp': 0};
+ }
+};
+
+Process.prototype.reportCompassHeading = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+
+ if (this.context.wait) {
+ if (stage.compassHeading !== null) {
+ return stage.compassHeading.magneticHeading;
+ }
+ } else {
+ this.context.wait = true;
+ this.getCompassHeading();
+ }
+ this.pushContext('doYield');
+ this.pushContext();
+};
+
+Process.prototype.getAcceleration = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+
+ stage.acceleration = null;
+ if (navigator.accelerometer) {
+ navigator.accelerometer.getCurrentAcceleration(
+ function (result) {
+ stage.acceleration = result;
+ },
+ function () {
+ stage.acceleration =
+ {'timestamp': 0, 'z': 0, 'y': 0, 'x': 0};
+ }
+ );
+ } else {
+ stage.acceleration =
+ {'timestamp': 0, 'z': 0, 'y': 0, 'x': 0};
+ }
+};
+
+Process.prototype.reportAccelerationX = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+
+ if (this.context.wait) {
+ if (stage.acceleration !== null) {
+ return stage.acceleration.x;
+ }
+ } else {
+ this.context.wait = true;
+ this.getAcceleration();
+ }
+ this.pushContext('doYield');
+ this.pushContext();
+};
+
+Process.prototype.reportAccelerationY = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+
+ if (this.context.wait) {
+ if (stage.acceleration !== null) {
+ return stage.acceleration.y;
+ }
+ } else {
+ this.context.wait = true;
+ this.getAcceleration();
+ }
+ this.pushContext('doYield');
+ this.pushContext();
+};
+
+Process.prototype.reportAccelerationZ = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+
+ if (this.context.wait) {
+ if (stage.acceleration !== null) {
+ return stage.acceleration.z;
+ }
+ } else {
+ this.context.wait = true;
+ this.getAcceleration();
+ }
+ this.pushContext('doYield');
+ this.pushContext();
+};
+
+Process.prototype.doVibrate = function (seconds) {
+ if ("vibrate" in navigator) {
+ window.navigator.vibrate(seconds * 1000);
+ }
+};
+
// Process code mapping
/*
@@ -3206,8 +3328,6 @@ Process.prototype.reportFrameCount = function () {
activeAudio audio buffer for interpolated operations, don't persist
activeNote audio oscillator for interpolated ops, don't persist
activeStream video element for camera streaming, don't persist
- isLambda marker for return ops
- isImplicitLambda marker for return ops
isCustomBlock marker for return ops
emptySlots caches the number of empty slots for reification
tag string or number to optionally identify the Context,
@@ -3235,8 +3355,6 @@ function Context(
this.activeAudio = null;
this.activeNote = null;
this.activeStream = null;
- this.isLambda = false; // marks the end of a lambda
- this.isImplicitLambda = false; // marks the end of a C-shaped slot
this.isCustomBlock = false; // marks the end of a custom block's stack
this.emptySlots = 0; // used for block reification
this.tag = null; // lexical catch-tag for custom blocks