kopia lustrzana https://github.com/backface/turtlestitch
add files(still merging)
rodzic
515024b3fc
commit
d01c6ca3e5
|
@ -0,0 +1,263 @@
|
|||
SymbolMorph.prototype.names.push('largeStage');
|
||||
|
||||
SymbolMorph.prototype.originalSymbolCanvasColored = SymbolMorph.prototype.symbolCanvasColored;
|
||||
SymbolMorph.prototype.symbolCanvasColored = function (aColor) {
|
||||
if (this.name == 'largeStage') {
|
||||
return this.drawSymbolLargeStage(newCanvas(new Point(this.symbolWidth(), this.size)), aColor);
|
||||
} else {
|
||||
return this.originalSymbolCanvasColored(aColor)
|
||||
}
|
||||
}
|
||||
|
||||
SymbolMorph.prototype.drawSymbolFullScreen = function (canvas, color) {
|
||||
// answer a canvas showing two arrows pointing diagonally outwards
|
||||
var ctx = canvas.getContext('2d'),
|
||||
h = canvas.height,
|
||||
c = canvas.width / 2,
|
||||
off = canvas.width / 10,
|
||||
w = canvas.width / 2;
|
||||
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.moveTo(c - off, c + off);
|
||||
ctx.lineTo(0, h);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(c + off, c - off);
|
||||
ctx.lineTo(h, 0);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(0, h);
|
||||
ctx.lineTo(0, h - w);
|
||||
ctx.stroke();
|
||||
ctx.moveTo(0, h);
|
||||
ctx.lineTo(w, h);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(h, 0);
|
||||
ctx.lineTo(h - w, 0);
|
||||
ctx.stroke();
|
||||
ctx.moveTo(h, 0);
|
||||
ctx.lineTo(h, w);
|
||||
ctx.stroke();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolFile= function (canvas, color) {
|
||||
// answer a canvas showing a page symbol
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = Math.min(canvas.width, canvas.height) / 2;
|
||||
|
||||
//ctx.fillStyle = color.toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(w, 0);
|
||||
ctx.lineTo(w, w);
|
||||
ctx.lineTo(canvas.width, w);
|
||||
ctx.lineTo(canvas.width, canvas.height);
|
||||
ctx.lineTo(0, canvas.height);
|
||||
ctx.stroke();
|
||||
//ctx.fill();
|
||||
|
||||
//ctx.fillStyle = color.darker(25).toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(w, 0);
|
||||
ctx.lineTo(canvas.width, w);
|
||||
ctx.lineTo(w, w);
|
||||
ctx.lineTo(w, 0);
|
||||
ctx.stroke();
|
||||
//ctx.fill();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolNormalScreen = function (canvas, color) {
|
||||
// answer a canvas showing two arrows pointing diagonally outwards
|
||||
var ctx = canvas.getContext('2d'),
|
||||
h = canvas.height,
|
||||
c = canvas.width / 2,
|
||||
off = canvas.width / 10,
|
||||
w = canvas.width / 2;
|
||||
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.moveTo(c - off, c + off);
|
||||
ctx.lineTo(0, h);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(c + off, c - off);
|
||||
ctx.lineTo(h, 0);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(0, h);
|
||||
ctx.lineTo(0, h - w);
|
||||
ctx.stroke();
|
||||
ctx.moveTo(0, h);
|
||||
ctx.lineTo(w, h);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(h, 0);
|
||||
ctx.lineTo(h - w, 0);
|
||||
ctx.stroke();
|
||||
ctx.moveTo(h, 0);
|
||||
ctx.lineTo(h, w);
|
||||
ctx.stroke();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
|
||||
SymbolMorph.prototype.drawSymbolLargeStage = function (canvas, color) {
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = canvas.width,
|
||||
h = canvas.height,
|
||||
w2 = w * 1 / 3,
|
||||
h2 = h * 2 / 3;
|
||||
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.rect(0, 0, w, h);
|
||||
ctx.stroke();
|
||||
ctx.rect(w2, 0, w, h2);
|
||||
ctx.stroke();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolNormalStage = function (canvas, color) {
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = canvas.width,
|
||||
h = canvas.height,
|
||||
w2 = w / 2,
|
||||
h2 = h / 2;
|
||||
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.rect(0, 0, w, h);
|
||||
ctx.stroke();
|
||||
ctx.rect(w2, 0, w2, h2);
|
||||
ctx.stroke();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolSmallStage = function (canvas, color) {
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = canvas.width,
|
||||
h = canvas.height,
|
||||
w2 = w * 2 / 3,
|
||||
h2 = h * 1 / 3;
|
||||
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.rect(0, 0, w, h);
|
||||
ctx.stroke();
|
||||
ctx.rect(w2, 0, w2, h2);
|
||||
ctx.stroke();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.originalSymbolWidth = SymbolMorph.prototype.symbolWidth;
|
||||
SymbolMorph.prototype.symbolWidth = function () {
|
||||
switch (this.name) {
|
||||
case 'gears':
|
||||
case 'file':
|
||||
return this.originalSymbolWidth() * 2;
|
||||
default:
|
||||
return this.originalSymbolWidth();
|
||||
}
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolGears = function (canvas, color) {
|
||||
// overriden to add a small triangle to its right
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = canvas.width / 2,
|
||||
r = w / 2,
|
||||
e = w / 6,
|
||||
triangleX = w * 7/6;
|
||||
|
||||
ctx.strokeStyle = color.toString();
|
||||
ctx.fillStyle = color.toString();
|
||||
ctx.lineWidth = canvas.height / 7;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(r, r, e * 1.5, radians(0), radians(360));
|
||||
ctx.fill();
|
||||
|
||||
|
||||
ctx.moveTo(0, r);
|
||||
ctx.lineTo(w, r);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(r, 0);
|
||||
ctx.lineTo(r, w);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(e, e);
|
||||
ctx.lineTo(w - e, w - e);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.moveTo(w - e, e);
|
||||
ctx.lineTo(e, w - e);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.globalCompositeOperation = 'destination-out';
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(r, r, e * 1.5, radians(0), radians(360), true);
|
||||
ctx.fill();
|
||||
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
|
||||
// triangle
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(triangleX + 1, canvas.height / 5 * 2);
|
||||
ctx.lineTo(triangleX + 1 + (canvas.width - triangleX - 2) / 2, canvas.height / 5 * 4);
|
||||
ctx.lineTo(canvas.width - 1, canvas.height / 5 * 2);
|
||||
ctx.lineTo(triangleX + 1, canvas.height / 5 * 2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
||||
SymbolMorph.prototype.drawSymbolFile = function (canvas, color) {
|
||||
// overriden to add a small triangle to its right
|
||||
var ctx = canvas.getContext('2d'),
|
||||
w = canvas.width / 4,
|
||||
maxW = canvas.width / 2;
|
||||
|
||||
ctx.fillStyle = color.toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(w, 0);
|
||||
ctx.lineTo(w, w);
|
||||
ctx.lineTo(maxW, w);
|
||||
ctx.lineTo(maxW, canvas.height);
|
||||
ctx.lineTo(0, canvas.height);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = color.darker(25).toString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(w, 0);
|
||||
ctx.lineTo(maxW, w);
|
||||
ctx.lineTo(w, w);
|
||||
ctx.lineTo(w, 0);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
// triangle
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(maxW + 2, canvas.height / 5 * 2);
|
||||
ctx.lineTo(maxW + 2 + (canvas.width - maxW - 2) / 2, canvas.height / 5 * 4);
|
||||
ctx.lineTo(canvas.width, canvas.height / 5 * 2);
|
||||
ctx.lineTo(maxW + 2, canvas.height / 5 * 2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
return canvas;
|
||||
}
|
||||
;
|
|
@ -0,0 +1,362 @@
|
|||
IDE_Morph.prototype.openIn = function (world) {
|
||||
var hash, usr, myself = this, urlLanguage = null;
|
||||
|
||||
// get persistent user data, if any
|
||||
if (localStorage) {
|
||||
usr = localStorage['-snap-user'];
|
||||
if (usr) {
|
||||
usr = SnapCloud.parseResponse(usr)[0];
|
||||
if (usr) {
|
||||
SnapCloud.username = usr.username || null;
|
||||
SnapCloud.password = usr.password || null;
|
||||
if (SnapCloud.username) {
|
||||
this.source = 'cloud';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SnapCloud.isloggedin(function ()
|
||||
{
|
||||
str = SnapCloud.encodeDict(
|
||||
{
|
||||
username: SnapCloud.username
|
||||
}
|
||||
);
|
||||
localStorage['-snap-user'] = str;
|
||||
myself.source = 'cloud';
|
||||
myself.showMessage('now connected.', 2);
|
||||
}, myself.cloudError()
|
||||
);
|
||||
|
||||
this.buildPanes();
|
||||
world.add(this);
|
||||
world.userMenu = this.userMenu;
|
||||
|
||||
// override SnapCloud's user message with Morphic
|
||||
SnapCloud.message = function (string) {
|
||||
var m = new MenuMorph(null, string),
|
||||
intervalHandle;
|
||||
m.popUpCenteredInWorld(world);
|
||||
intervalHandle = setInterval(function () {
|
||||
m.destroy();
|
||||
clearInterval(intervalHandle);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
// prevent non-DialogBoxMorphs from being dropped
|
||||
// onto the World in user-mode
|
||||
world.reactToDropOf = function (morph) {
|
||||
if (!(morph instanceof DialogBoxMorph)) {
|
||||
if (world.hand.grabOrigin) {
|
||||
morph.slideBackTo(world.hand.grabOrigin);
|
||||
} else {
|
||||
world.hand.grab(morph);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
myself.showMessage('unable to retrieve project');
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// dynamic notifications from non-source text files
|
||||
// has some issues, commented out for now
|
||||
/*
|
||||
this.cloudMsg = getURL('http://snap.berkeley.edu/cloudmsg.txt');
|
||||
motd = getURL('http://snap.berkeley.edu/motd.txt');
|
||||
if (motd) {
|
||||
this.inform('Snap!', motd);
|
||||
}
|
||||
*/
|
||||
function interpretUrlAnchors() {
|
||||
var dict;
|
||||
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));
|
||||
}
|
||||
} else if (location.hash.substr(0, 5) === '#run:') {
|
||||
hash = location.hash.substr(5);
|
||||
if (hash.charAt(0) === '%'
|
||||
|| hash.search(/\%(?:[0-9a-f]{2})/i) > -1) {
|
||||
hash = decodeURIComponent(hash);
|
||||
}
|
||||
if (hash.substr(0, 8) === '<project>') {
|
||||
this.rawOpenProjectString(hash);
|
||||
} else {
|
||||
this.rawOpenProjectString(getURL(hash));
|
||||
}
|
||||
this.toggleAppMode(true);
|
||||
this.runScripts();
|
||||
} else if (location.hash.substr(0, 9) === '#present:') {
|
||||
this.shield = new Morph();
|
||||
this.shield.color = this.color;
|
||||
this.shield.setExtent(this.parent.extent());
|
||||
this.parent.add(this.shield);
|
||||
myself.showMessage('Fetching project\nfrom the cloud...');
|
||||
|
||||
// make sure to lowercase the username
|
||||
dict = SnapCloud.parseDict(location.hash.substr(9));
|
||||
dict.Username = dict.Username.toLowerCase();
|
||||
|
||||
SnapCloud.getPublicProject(
|
||||
SnapCloud.encodeDict(dict),
|
||||
function (projectData) {
|
||||
var msg;
|
||||
myself.nextSteps([
|
||||
function () {
|
||||
msg = myself.showMessage('Opening project...');
|
||||
},
|
||||
function () {nop(); }, // yield (bug in Chrome)
|
||||
function () {
|
||||
if (projectData.indexOf('<snapdata') === 0) {
|
||||
myself.rawOpenCloudDataString(projectData);
|
||||
} else if (
|
||||
projectData.indexOf('<project') === 0
|
||||
) {
|
||||
myself.rawOpenProjectString(projectData);
|
||||
}
|
||||
myself.hasChangedMedia = true;
|
||||
},
|
||||
function () {
|
||||
myself.shield.destroy();
|
||||
myself.shield = null;
|
||||
msg.destroy();
|
||||
|
||||
if (dict.editMode) {
|
||||
myself.toggleAppMode(false);
|
||||
} else {
|
||||
myself.toggleAppMode(true);
|
||||
}
|
||||
|
||||
if (!dict.noRun) {
|
||||
myself.runScripts();
|
||||
}
|
||||
|
||||
if (dict.hideControls) {
|
||||
myself.controlBar.hide();
|
||||
window.onbeforeunload = function () {nop(); };
|
||||
}
|
||||
}
|
||||
]);
|
||||
},
|
||||
this.cloudError()
|
||||
);
|
||||
} else if (location.hash.substr(0, 7) === '#cloud:') {
|
||||
this.shield = new Morph();
|
||||
this.shield.alpha = 0;
|
||||
this.shield.setExtent(this.parent.extent());
|
||||
this.parent.add(this.shield);
|
||||
myself.showMessage('Fetching project\nfrom the cloud...');
|
||||
|
||||
// make sure to lowercase the username
|
||||
dict = SnapCloud.parseDict(location.hash.substr(7));
|
||||
dict.Username = dict.Username.toLowerCase();
|
||||
|
||||
SnapCloud.getPublicProject(
|
||||
SnapCloud.encodeDict(dict),
|
||||
function (projectData) {
|
||||
var msg;
|
||||
myself.nextSteps([
|
||||
function () {
|
||||
msg = myself.showMessage('Opening project...');
|
||||
},
|
||||
function () {nop(); }, // yield (bug in Chrome)
|
||||
function () {
|
||||
if (projectData.indexOf('<snapdata') === 0) {
|
||||
myself.rawOpenCloudDataString(projectData);
|
||||
} else if (
|
||||
projectData.indexOf('<project') === 0
|
||||
) {
|
||||
myself.rawOpenProjectString(projectData);
|
||||
}
|
||||
myself.hasChangedMedia = true;
|
||||
},
|
||||
function () {
|
||||
myself.shield.destroy();
|
||||
myself.shield = null;
|
||||
msg.destroy();
|
||||
myself.toggleAppMode(false);
|
||||
}
|
||||
]);
|
||||
},
|
||||
this.cloudError()
|
||||
);
|
||||
} else if (location.hash.substr(0, 6) === '#lang:') {
|
||||
urlLanguage = location.hash.substr(6);
|
||||
this.setLanguage(urlLanguage);
|
||||
this.loadNewProject = true;
|
||||
} else if (location.hash.substr(0, 7) === '#signup') {
|
||||
this.createCloudAccount();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.userLanguage) {
|
||||
this.loadNewProject = true;
|
||||
this.setLanguage(this.userLanguage, interpretUrlAnchors);
|
||||
} else {
|
||||
interpretUrlAnchors.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// IDE_Morph cloud interface
|
||||
|
||||
IDE_Morph.prototype.initializeCloud = function () {
|
||||
//SnapCloud.reconnect();
|
||||
console.log("init cloud");
|
||||
var myself = this,
|
||||
world = this.world();
|
||||
new DialogBoxMorph(
|
||||
null,
|
||||
function (user) {
|
||||
var pwh = hex_sha512(user.password),
|
||||
str;
|
||||
SnapCloud.login(
|
||||
user.username,
|
||||
user.password, //pwh,
|
||||
function () {
|
||||
str = SnapCloud.encodeDict(
|
||||
{
|
||||
username: user.username,
|
||||
}
|
||||
);
|
||||
localStorage['-snap-user'] = str;
|
||||
console.log(user.username)
|
||||
SnapCloud.username = user.username;
|
||||
myself.source = 'cloud';
|
||||
myself.showMessage('now connected.', 2);
|
||||
},
|
||||
myself.cloudError()
|
||||
);
|
||||
}
|
||||
).withKey('cloudlogin').promptCredentials(
|
||||
'Sign in',
|
||||
'login',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null, //'stay signed in on this computer\nuntil logging out',
|
||||
world,
|
||||
myself.cloudIcon(),
|
||||
myself.cloudMsg
|
||||
);
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.createCloudAccount = function () {
|
||||
window.open('http://' + window.location.hostname + '/signup');
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.resetCloudPassword = function () {
|
||||
var myself = this,
|
||||
world = this.world();
|
||||
/*
|
||||
// force-logout, commented out for now:
|
||||
delete localStorage['-snap-user'];
|
||||
SnapCloud.clear();
|
||||
*/
|
||||
new DialogBoxMorph(
|
||||
null,
|
||||
function (user) {
|
||||
SnapCloud.resetPassword(
|
||||
user.username,
|
||||
function (txt, title) {
|
||||
new DialogBoxMorph().inform(
|
||||
title,
|
||||
txt +
|
||||
'.\n\nAn e-mail with a link to\n' +
|
||||
'reset your password\n' +
|
||||
'has been sent to the address provided',
|
||||
world,
|
||||
myself.cloudIcon(null, new Color(0, 180, 0))
|
||||
);
|
||||
},
|
||||
myself.cloudError()
|
||||
);
|
||||
}
|
||||
).withKey('cloudresetpassword').promptCredentials(
|
||||
'Reset password',
|
||||
'resetPassword',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
world,
|
||||
myself.cloudIcon(),
|
||||
myself.cloudMsg
|
||||
);
|
||||
};
|
||||
|
||||
IDE_Morph.prototype.changeCloudPassword = function () {
|
||||
window.open('http://' + window.location.hostname + '/change_password');
|
||||
};
|
||||
|
||||
ProjectDialogMorph.prototype.init = function (ide, task) {
|
||||
var myself = this;
|
||||
|
||||
// additional properties:
|
||||
this.ide = ide;
|
||||
this.task = task || 'open'; // String describing what do do (open, save)
|
||||
this.source = 'local'; // ide.source || 'local'; // or 'cloud' or 'examples'
|
||||
this.projectList = []; // [{name: , thumb: , notes:}]
|
||||
|
||||
this.handle = null;
|
||||
this.srcBar = null;
|
||||
this.nameField = null;
|
||||
this.listField = null;
|
||||
this.preview = null;
|
||||
this.notesText = null;
|
||||
this.notesField = null;
|
||||
this.deleteButton = null;
|
||||
this.shareButton = null;
|
||||
this.unshareButton = null;
|
||||
|
||||
// initialize inherited properties:
|
||||
ProjectDialogMorph.uber.init.call(
|
||||
this,
|
||||
this, // target
|
||||
null, // function
|
||||
null // environment
|
||||
);
|
||||
|
||||
// override inherited properites:
|
||||
this.labelString = this.task === 'save' ? 'Save Project' : 'Open Project';
|
||||
this.createLabel();
|
||||
this.key = 'project' + task;
|
||||
|
||||
// build contents
|
||||
this.buildContents();
|
||||
this.onNextStep = function () { // yield to show "updating" message
|
||||
myself.setSource(myself.source);
|
||||
};
|
||||
};
|
Ładowanie…
Reference in New Issue