Michael Aschauer 2018-10-08 12:25:24 +02:00
commit b0c9768952
72 zmienionych plików z 3590 dodań i 4306 usunięć

Plik diff jest za duży Load Diff

86
OFFLINE.md 100755
Wyświetl plik

@ -0,0 +1,86 @@
# Using Snap! Without an Internet Connection
Snap! is a web application hosted at
[https://snap.berkeley.edu/run](https://snap.berkeley.edu/run "Snap! online").
If you would like to use Snap! without being connected to the internet, e.g. in a remote area
or in a school with limited or unreliable online service you can easily set up Snap! locally on
your computer, by following these
## Simple Steps:
1. Download the latest Snap! Release from
[https://github.com/jmoenig/Snap/releases/latest](https://github.com/jmoenig/Snap/releases/latest "Snap! Source Code"), and unpack the contents of the archive to your local disk.
2. Open the file `snap.html` in your browser.
3. There is no step 3.
Snap! is just a web page, you can open it locally in your browser, no need to install anything
on your computer. You can use whichever operating system you like, you don't even need
admin rights. You can also use a memory stick to distribute the directory with source files
among the participants of a workshop or the students of your class, even if some of them
are using MacOS and others run MS Windows or Linux.
## Remember to Unpack
Windows users, this is for you.
Once you've downloaded the source code, please remember to actually unpack the archive
to your computer. If you downloaded the zip file please actually unzip it, before you open
`snap.html`. If you use a Mac simple double-clicking the zip file unpacks it. But if you're
on Windows double clicking the zip fie will *not* unzip it but instead show you the contents of
the archive.
## Which Web Browser?
It's best to open Snap! in Chrome or Firefox.
Snap! is using web standards and runs in any modern web browser. Some browsers are faster
than others, which makes using Snap! more fun. For the best user experience we recommend
Chrome or Firefox. IE does not comply with modern web standards and will not work. Edge
will work, but some operations will be so slow it takes the fun out of programming and playing.
## What about Tablets?
We don't recommend it.
Snap! sorta runs on tablets, but the UI isn't optimized for mobile use. Also, many mobile
web browsers enforce some restrictions that are not web-standards compliant, e.g. they
will not support the soft keyboard or intentionally slow down certain operations to discourage
using web apps in favor of proprietary "native" apps.
## Restrictions of the Offline Version
You can't access the cloud, duh. Everything else just works.
Aside from accessing the cloud using Snap! offline in the browser by opening the `snap.html`
file locally there aren't any restrictions. You can use all the blocks, import pictures, sounds,
libraries, take snapshots with the webcom, record sounds with the microphone, draw your
own costumes etc.
## Saving and Loading
When you use Snap! locally you will not be able to save projects to the cloud, nor can you
access projects saved in the cloud. Instead projects will be exported as xml-files to your
computer, from where they can also be opened again.
There are two ways to load projects and assets from your computer when you use Snap!
without an internet connection:
1. Using the options in Snap's file menu opens an OS-native file dialog that lets you select
which file to import or load.
2. Alternatively you can drag projects and assets (extension libraries, pictures, sounds etc.)
from your computer directly into Snap! and drop it. If you import sounds or images you can
also drag and drop several files all at once.
Easy, isn't it?
## Keeping Snap! up-to-date
From time to time it's wise to check whether a new version of Snap! is available. You can
find out the lastest release using the link above, and compare that to the offline sources on
your computer. If there is a newer version, simply replace the source files with the newer ones.
Enjoy!
-Jens

Plik binarny nie jest wyświetlany.

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -1,18 +0,0 @@
Ideas for optimizing Snap!
--------------------------
Graphics engine
---------------
* reuse (and cache) icons, e.g. for input slot types, in the prototype. Make sure to update when changing display settings (flat design, zoom blocks etc.)
* generate state-images for buttons (push buttons, toggles etc.) just-in-time (and possibly cache them only then), instead of always creating them up-front.
Evaluator
----------
* Get rid of blockSequences, instead evaluate blocks directly.
* Get rid of modifying blocks to evaluate them (solve implicit parameter bindings another way)
* Cache variables (not values) in accessor-blocks (this should speed things up a lot)

Wyświetl plik

@ -1,24 +0,0 @@
readme - Snap! 4.0
------------------
this document is just a stub as of now. For the first official release of Snap! 4.0 it will contain release notes covering the following issues:
saving, loading, exporting, importing
artefacts: projects, blocks, sprites
URL options: #run: #open: #lang: #signup
dynamic content (currently deactivated):
http://snap.berkeley.edu/cloudmsg.txt
http://snap.berkeley.edu/motd.txt
supported browsers, problems with the Android virtual keyboard
supported browser / OS settings
SVG support limitations
OS/X: turn LCD font smoothing off
Beware of third-party Chrome toolbars and iFrames

Wyświetl plik

@ -1,42 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Snap! Build Your Own Blocks 4.2.1.4</title>
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="morphic.js?version=2018-06-21"></script>
<script type="text/javascript" src="widgets.js?version=2018-06-21"></script>
<script type="text/javascript" src="blocks.js?version=2018-09-09"></script>
<script type="text/javascript" src="threads.js?version=2018-09-09"></script>
<script type="text/javascript" src="objects.js?version=2018-07-06"></script>
<script type="text/javascript" src="gui.js?version=2018-09-09"></script>
<script type="text/javascript" src="paint.js?version=2018-06-21"></script>
<script type="text/javascript" src="lists.js?version=2018-06-21"></script>
<script type="text/javascript" src="byob.js?version=2018-06-21"></script>
<script type="text/javascript" src="tables.js?version=2018-06-21"></script>
<script type="text/javascript" src="symbols.js?version=2018-06-21"></script>
<script type="text/javascript" src="sketch.js?version=2018-06-21"></script>
<script type="text/javascript" src="xml.js?version=2018-06-21"></script>
<script type="text/javascript" src="store.js?version=2018-07-09"></script>
<script type="text/javascript" src="locale.js?version=2018-07-09"></script>
<script type="text/javascript" src="cloud.js?version=2018-06-21"></script>
<script type="text/javascript" src="sha512.js?version=2018-06-21"></script>
<script type="text/javascript" src="FileSaver.min.js?version=2018-06-21"></script>
<script type="text/javascript">
var world;
window.onload = function () {
world = new WorldMorph(document.getElementById('world'));
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Snap! Build Your Own Blocks 4.2.2</title>
<link rel="shortcut icon" href="src/favicon.ico">
<script type="text/javascript" src="src/morphic.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/widgets.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/blocks.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/threads.js?version=2018-10-03"></script>
<script type="text/javascript" src="src/objects.js?version=2018-10-05"></script>
<script type="text/javascript" src="src/gui.js?version=2018-10-07"></script>
<script type="text/javascript" src="src/paint.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/lists.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/byob.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/tables.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/symbols.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/sketch.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/xml.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/store.js?version=2018-10-05"></script>
<script type="text/javascript" src="src/locale.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/cloud.js?version=2018-10-04"></script>
<script type="text/javascript" src="src/sha512.js?version=2018-10-02"></script>
<script type="text/javascript" src="src/FileSaver.min.js?version=2018-10-02"></script>
<script type="text/javascript">
var world;
window.onload = function () {
world = new WorldMorph(document.getElementById('world'));
world.worldCanvas.focus();
new IDE_Morph().openIn(world);
loop();
new IDE_Morph().openIn(world);
loop();
};
function loop() {
requestAnimationFrame(loop);
world.doOneCycle();
}
</script>
</head>
<body style="margin: 0;">
<canvas id="world" tabindex="1" style="position: absolute;" />
</body>
function loop() {
requestAnimationFrame(loop);
world.doOneCycle();
}
</script>
</head>
<body style="margin: 0;">
<canvas id="world" tabindex="1" style="position: absolute;" />
</body>
</html>

Wyświetl plik

@ -1,40 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Snap! Build Your Own Blocks</title>
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="morphic.js"></script>
<script type="text/javascript" src="widgets.js"></script>
<script type="text/javascript" src="blocks.js"></script>
<script type="text/javascript" src="threads.js"></script>
<script type="text/javascript" src="objects.js"></script>
<script type="text/javascript" src="gui.js"></script>
<script type="text/javascript" src="paint.js"></script>
<script type="text/javascript" src="lists.js"></script>
<script type="text/javascript" src="byob.js"></script>
<script type="text/javascript" src="tables.js"></script>
<script type="text/javascript" src="symbols.js"></script>
<script type="text/javascript" src="xml.js"></script>
<script type="text/javascript" src="store.js"></script>
<script type="text/javascript" src="locale.js"></script>
<script type="text/javascript" src="cloud.js"></script>
<script type="text/javascript" src="sha512.js"></script>
<script type="text/javascript" src="FileSaver.min.js"></script>
<script type="text/javascript">
var world;
window.onload = function () {
world = new WorldMorph(document.getElementById('world'));
world.worldCanvas.focus();
new IDE_Morph().openIn(world);
setInterval(loop, 1);
};
function loop() {
world.doOneCycle();
}
</script>
</head>
<body style="margin: 0;">
<canvas id="world" tabindex="1" style="position: absolute;" />
</body>
</html>

Wyświetl plik

@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
// Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2018-September-09';
modules.blocks = '2018-October-02';
var SyntaxElementMorph;
var BlockMorph;
@ -2206,7 +2206,7 @@ BlockMorph.prototype.toggleSnapSound = function () {
this.snapSound = null;
} else {
BlockMorph.prototype.snapSound = document.createElement('audio');
BlockMorph.prototype.snapSound.src = 'click.wav';
BlockMorph.prototype.snapSound.src = 'src/click.wav';
}
CommentMorph.prototype.snapSound = BlockMorph.prototype.snapSound;
};

Wyświetl plik

@ -32,7 +32,7 @@
/*global modules, SnapSerializer, nop, hex_sha512, DialogBoxMorph, Color,
normalizeCanvas*/
modules.cloud = '2018-June-15';
modules.cloud = '2018-October-04';
// Global stuff
@ -67,11 +67,13 @@ Cloud.prototype.determineCloudDomain = function () {
// 2. The current page's domain
var currentDomain = window.location.host, // host includes the port.
metaTag = document.head.querySelector("[name='snap-cloud-domain']"),
cloudDomain = this.defaultDomain;
cloudDomain = this.defaultDomain,
domainMap = this.knownDomains;
if (metaTag) { return metaTag.getAttribute('location'); }
Object.values(this.knownDomains).some(function (server) {
Object.keys(domainMap).some(function (name) {
var server = domainMap[name];
if (Cloud.isMatchingDomain(currentDomain, server)) {
cloudDomain = server;
return true;
@ -239,6 +241,10 @@ Cloud.prototype.withCredentialsRequest = function (
Cloud.prototype.initSession = function (onSuccess) {
var myself = this;
if (location.protocol === 'file:') {
// disabled for now (jens)
return;
}
this.request(
'POST',
'/init',

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 7.9 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 7.9 KiB

Wyświetl plik

@ -75,7 +75,7 @@ isRetinaSupported, SliderMorph, Animation, BoxMorph, MediaRecorder*/
// Global stuff ////////////////////////////////////////////////////////
modules.gui = '2018-September-09';
modules.gui = '2018-October-07';
// Declarations
@ -229,7 +229,7 @@ IDE_Morph.prototype.init = function (isAutoFill) {
this.projectName = '';
this.projectNotes = '';
this.logoURL = this.resourceURL('snap_logo_sm.png');
this.logoURL = this.resourceURL('src', 'snap_logo_sm.png');
this.logo = null;
this.controlBar = null;
this.categories = null;
@ -2002,7 +2002,7 @@ IDE_Morph.prototype.droppedBinary = function (anArrayBuffer, name) {
ypr.id = 'ypr';
ypr.onload = function () {loadYPR(anArrayBuffer, name); };
document.head.appendChild(ypr);
ypr.src = 'ypr.js';
ypr.src = this.resourceURL('src', 'ypr.js');
} else {
loadYPR(anArrayBuffer, name);
}
@ -2512,7 +2512,7 @@ IDE_Morph.prototype.snapMenu = function () {
'Download source',
function () {
window.open(
'http://snap.berkeley.edu/snapsource/snap.zip',
'https://github.com/jmoenig/Snap/releases/latest',
'SnapSource'
);
}
@ -2546,6 +2546,11 @@ IDE_Morph.prototype.cloudMenu = function () {
pos = this.controlBar.cloudButton.bottomLeft(),
shiftClicked = (world.currentKey === 16);
if (location.protocol === 'file:' && !shiftClicked) {
this.showMessage('cloud unavailable without a web server.');
return;
}
menu = new MenuMorph(this);
if (shiftClicked) {
menu.addItem(
@ -3121,36 +3126,7 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addLine();
menu.addItem(
'Import...',
function () {
var inp = document.createElement('input');
if (myself.filePicker) {
document.body.removeChild(myself.filePicker);
myself.filePicker = null;
}
inp.type = 'file';
inp.style.color = "transparent";
inp.style.backgroundColor = "transparent";
inp.style.border = "none";
inp.style.outline = "none";
inp.style.position = "absolute";
inp.style.top = "0px";
inp.style.left = "0px";
inp.style.width = "0px";
inp.style.height = "0px";
inp.style.display = "none";
inp.addEventListener(
"change",
function () {
document.body.removeChild(inp);
myself.filePicker = null;
world.hand.processDrop(inp.files);
},
false
);
document.body.appendChild(inp);
myself.filePicker = inp;
inp.click();
},
'importLocalFile',
'file menu import hint' // looks up the actual text in the translator
);
@ -3232,8 +3208,12 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addItem(
'Import tools',
function () {
if (location.protocol === 'file:') {
myself.importLocalFile();
return;
}
myself.getURL(
myself.resourceURL('tools.xml'),
myself.resourceURL('libraries', 'tools.xml'),
function (txt) {
myself.droppedText(txt, 'tools');
}
@ -3244,6 +3224,10 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addItem(
'Libraries...',
function() {
if (location.protocol === 'file:') {
myself.importLocalFile();
return;
}
myself.getURL(
myself.resourceURL('libraries', 'LIBRARIES'),
function (txt) {
@ -3258,6 +3242,10 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addItem(
localize(graphicsName) + '...',
function () {
if (location.protocol === 'file:') {
myself.importLocalFile();
return;
}
myself.importMedia(graphicsName);
},
'Select a costume from the media library'
@ -3265,6 +3253,10 @@ IDE_Morph.prototype.projectMenu = function () {
menu.addItem(
localize('Sounds') + '...',
function () {
if (location.protocol === 'file:') {
myself.importLocalFile();
return;
}
myself.importMedia('Sounds');
},
'Select a sound from the media library'
@ -3338,6 +3330,40 @@ IDE_Morph.prototype.parseResourceFile = function (text) {
return items;
};
IDE_Morph.prototype.importLocalFile = function () {
var inp = document.createElement('input'),
myself = this,
world = this.world();
if (this.filePicker) {
document.body.removeChild(this.filePicker);
this.filePicker = null;
}
inp.type = 'file';
inp.style.color = "transparent";
inp.style.backgroundColor = "transparent";
inp.style.border = "none";
inp.style.outline = "none";
inp.style.position = "absolute";
inp.style.top = "0px";
inp.style.left = "0px";
inp.style.width = "0px";
inp.style.height = "0px";
inp.style.display = "none";
inp.addEventListener(
"change",
function () {
document.body.removeChild(inp);
myself.filePicker = null;
world.hand.processDrop(inp.files);
},
false
);
document.body.appendChild(inp);
this.filePicker = inp;
inp.click();
};
IDE_Morph.prototype.importMedia = function (folderName) {
// open a dialog box letting the user browse available "built-in"
// costumes, backgrounds or sounds
@ -3513,7 +3539,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world();
aboutTxt = 'Snap! 4.2.1.4\nBuild Your Own Blocks\n\n'
aboutTxt = 'Snap! 4.2.2\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2018 Jens M\u00F6nig and '
+ 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@ -3754,6 +3780,21 @@ IDE_Morph.prototype.newProject = function () {
};
IDE_Morph.prototype.save = function () {
var myself = this;
// temporary hack - only allow exporting projects to disk
// when running Snap! locally without a web server
if (location.protocol === 'file:') {
if (this.projectName) {
this.exportProject(myself.projectName, false);
} else {
this.prompt('Export Project As...', function (name) {
myself.exportProject(name, false);
}, null, 'exportProject');
}
return;
}
if (this.source === 'examples') {
this.source = 'local'; // cannot save to examples
}
@ -4935,10 +4976,30 @@ IDE_Morph.prototype.createNewProject = function () {
};
IDE_Morph.prototype.openProjectsBrowser = function () {
if (location.protocol === 'file:') {
// bypass the project import dialog and directly pop up
// the local file picker.
// this should not be necessary, we should be able
// to access the cloud even when running Snap! locally
// to be worked on.... (jens)
this.importLocalFile();
return;
}
new ProjectDialogMorph(this, 'open').popUp();
};
IDE_Morph.prototype.saveProjectsBrowser = function () {
var myself = this;
// temporary hack - only allow exporting projects to disk
// when running Snap! locally without a web server
if (location.protocol === 'file:') {
this.prompt('Export Project As...', function (name) {
myself.exportProject(name, false);
}, null, 'exportProject');
return;
}
if (this.source === 'examples') {
this.source = 'local'; // cannot save to examples
}
@ -4967,7 +5028,7 @@ IDE_Morph.prototype.languageMenu = function () {
IDE_Morph.prototype.setLanguage = function (lang, callback, noSave) {
var translation = document.getElementById('language'),
src = this.resourceURL('lang-' + lang + '.js'),
src = this.resourceURL('locale', 'lang-' + lang + '.js'),
myself = this;
SnapTranslator.unload();
if (translation) {

Wyświetl plik

@ -83,7 +83,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
modules.objects = '2018-July-06';
modules.objects = '2018-October-05';
var SpriteMorph;
var StageMorph;
@ -3534,9 +3534,14 @@ SpriteMorph.prototype.getHue = function () {
SpriteMorph.prototype.setHue = function (num) {
var hsv = this.color.hsv(),
x = this.xPosition(),
y = this.yPosition();
y = this.yPosition(),
n = +num;
hsv[0] = Math.max(Math.min(+num || 0, 100), 0) / 100;
if (n < 0 || n > 100) { // wrap the hue
n = (n < 0 ? 100 : 0) + n % 100;
}
hsv[0] = n / 100;
// hsv[0] = Math.max(Math.min(+num || 0, 100), 0) / 100; // old code
hsv[1] = 1; // we gotta fix this at some time
this.color.set_hsv.apply(this.color, hsv);
if (!this.costume) {
@ -3560,7 +3565,7 @@ SpriteMorph.prototype.setBrightness = function (num) {
y = this.yPosition();
hsv[1] = 1; // we gotta fix this at some time
hsv[2] = Math.max(Math.min(+num || 0, 100), 0) / 100;
hsv[2] = Math.max(Math.min(+num || 0, 100), 0) / 100; // shade doesn't wrap
this.color.set_hsv.apply(this.color, hsv);
if (!this.costume) {
this.drawNew();

Wyświetl plik

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.6 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.6 KiB

Wyświetl plik

@ -61,7 +61,7 @@ normalizeCanvas, contains*/
// Global stuff ////////////////////////////////////////////////////////
modules.store = '2018-July-09';
modules.store = '2018-October-05';
// XML_Serializer ///////////////////////////////////////////////////////
@ -483,6 +483,7 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
sprite.setExemplar(exemplar);
}
sprite.inheritedAttributes = sprite.inheritanceInfo.delegated || [];
sprite.updatePropagationCache();
}
if (sprite.nestingInfo) { // only sprites may have nesting info
anchor = myself.project.sprites[sprite.nestingInfo.anchor];
@ -2024,9 +2025,10 @@ CustomBlockDefinition.prototype.toXML = function (serializer) {
' readonly="true"' : '',
myself.declarations.get(decl)[1],
myself.declarations.get(decl)[2] ?
'<options>' + myself.declarations.get(decl)[2] +
'</options>'
: ''
serializer.format(
'<options>@</options>',
myself.declarations.get(decl)[2]
) : ''
);
}, ''),
this.body ? serializer.store(this.body.expression) : '',

Wyświetl plik

@ -62,7 +62,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
TableFrameMorph, ColorSlotMorph, isSnapObject*/
modules.threads = '2018-September-09';
modules.threads = '2018-October-03';
var ThreadManager;
var Process;
@ -2706,14 +2706,14 @@ Process.prototype.reportLetter = function (idx, string) {
if (string instanceof List) { // catch a common user error
return '';
}
str = isNil(string) ? '' : string.toString();
if (this.inputOption(idx) === 'any') {
idx = this.reportRandom(1, string.length);
idx = this.reportRandom(1, str.length);
}
if (this.inputOption(idx) === 'last') {
idx = string.length;
idx = str.length;
}
i = +(idx || 0);
str = isNil(string) ? '' : string.toString();
return str[i - 1] || '';
};
@ -4504,7 +4504,7 @@ JSCompiler.prototype.compileFunction = function (aContext, implicitParamCount) {
parms = ['p0'];
}
}
// compile using gensyms
if (block instanceof CommandBlockMorph) {

File diff suppressed because one or more lines are too long