kopia lustrzana https://github.com/backface/turtlestitch
Backups (#2110)
* added backups menu * project recovery dialog * only show recover button in Cloud tab * Human-readable time diffs for recovery dialog * reverted project list context menu, ca and es translationsupd4.2
rodzic
976a964200
commit
f3ffe66a2b
21
cloud.js
21
cloud.js
|
@ -494,10 +494,11 @@ Cloud.prototype.getThumbnail = function (
|
|||
);
|
||||
};
|
||||
|
||||
Cloud.prototype.getProject = function (projectName, onSuccess, onError) {
|
||||
Cloud.prototype.getProject = function (projectName, delta, onSuccess, onError) {
|
||||
this.withCredentialsRequest(
|
||||
'GET',
|
||||
'/projects/%username/' + encodeURIComponent(projectName),
|
||||
'/projects/%username/' +
|
||||
encodeURIComponent(projectName) + (delta ? '?delta=' + delta : ''),
|
||||
onSuccess,
|
||||
onError,
|
||||
'Could not fetch project ' + projectName,
|
||||
|
@ -536,6 +537,22 @@ Cloud.prototype.getProjectMetadata = function (
|
|||
);
|
||||
};
|
||||
|
||||
Cloud.prototype.getProjectVersionMetadata = function (
|
||||
projectName,
|
||||
onSuccess,
|
||||
onError
|
||||
) {
|
||||
this.withCredentialsRequest(
|
||||
'GET',
|
||||
'/projects/%username/' +
|
||||
encodeURIComponent(projectName) +
|
||||
'/versions',
|
||||
onSuccess,
|
||||
onError,
|
||||
'Could not fetch versions for project ' + projectName
|
||||
);
|
||||
};
|
||||
|
||||
Cloud.prototype.deleteProject = function (
|
||||
projectName,
|
||||
username,
|
||||
|
|
285
gui.js
285
gui.js
|
@ -5735,6 +5735,7 @@ ProjectDialogMorph.prototype.init = function (ide, task) {
|
|||
this.deleteButton = null;
|
||||
this.shareButton = null;
|
||||
this.unshareButton = null;
|
||||
this.recoverButton = null;
|
||||
|
||||
// initialize inherited properties:
|
||||
ProjectDialogMorph.uber.init.call(
|
||||
|
@ -5871,6 +5872,8 @@ ProjectDialogMorph.prototype.buildContents = function () {
|
|||
if (this.task === 'open') {
|
||||
this.addButton('openProject', 'Open');
|
||||
this.action = 'openProject';
|
||||
this.recoverButton = this.addButton('recoveryDialog', 'Recover');
|
||||
this.recoverButton.hide();
|
||||
} else { // 'save'
|
||||
this.addButton('saveProject', 'Save');
|
||||
this.action = 'saveProject';
|
||||
|
@ -6161,6 +6164,7 @@ ProjectDialogMorph.prototype.setSource = function (source) {
|
|||
this.body.add(this.listField);
|
||||
this.shareButton.hide();
|
||||
this.unshareButton.hide();
|
||||
this.recoverButton.hide();
|
||||
/*
|
||||
this.publishButton.hide();
|
||||
this.unpublishButton.hide();
|
||||
|
@ -6295,6 +6299,7 @@ ProjectDialogMorph.prototype.installCloudProjectList = function (pl) {
|
|||
myself.edit();
|
||||
};
|
||||
this.body.add(this.listField);
|
||||
this.recoverButton.show();
|
||||
this.shareButton.show();
|
||||
this.unshareButton.hide();
|
||||
this.deleteButton.show();
|
||||
|
@ -6314,6 +6319,13 @@ ProjectDialogMorph.prototype.clearDetails = function () {
|
|||
this.preview.drawNew();
|
||||
};
|
||||
|
||||
ProjectDialogMorph.prototype.recoveryDialog = function () {
|
||||
var proj = this.listField.selected;
|
||||
if (!proj) {return; }
|
||||
new ProjectRecoveryDialogMorph(this.ide, proj.projectname, this).popUp();
|
||||
this.hide();
|
||||
};
|
||||
|
||||
ProjectDialogMorph.prototype.openProject = function () {
|
||||
var proj = this.listField.selected,
|
||||
src;
|
||||
|
@ -6332,22 +6344,23 @@ ProjectDialogMorph.prototype.openProject = function () {
|
|||
}
|
||||
};
|
||||
|
||||
ProjectDialogMorph.prototype.openCloudProject = function (project) {
|
||||
ProjectDialogMorph.prototype.openCloudProject = function (project, delta) {
|
||||
var myself = this;
|
||||
myself.ide.nextSteps([
|
||||
function () {
|
||||
myself.ide.showMessage('Fetching project\nfrom the cloud...');
|
||||
},
|
||||
function () {
|
||||
myself.rawOpenCloudProject(project);
|
||||
myself.rawOpenCloudProject(project, delta);
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
ProjectDialogMorph.prototype.rawOpenCloudProject = function (proj) {
|
||||
ProjectDialogMorph.prototype.rawOpenCloudProject = function (proj, delta) {
|
||||
var myself = this;
|
||||
SnapCloud.getProject(
|
||||
proj.projectname,
|
||||
delta,
|
||||
function (clouddata) {
|
||||
myself.ide.source = 'cloud';
|
||||
myself.ide.nextSteps([
|
||||
|
@ -6742,6 +6755,272 @@ ProjectDialogMorph.prototype.fixLayout = function () {
|
|||
this.changed();
|
||||
};
|
||||
|
||||
// ProjectRecoveryDialogMorph /////////////////////////////////////////
|
||||
// I show previous versions for a particular project and
|
||||
// let users recover them.
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype = new DialogBoxMorph();
|
||||
ProjectRecoveryDialogMorph.prototype.constructor = ProjectRecoveryDialogMorph;
|
||||
ProjectRecoveryDialogMorph.uber = DialogBoxMorph.prototype;
|
||||
|
||||
// ProjectRecoveryDialogMorph instance creation:
|
||||
|
||||
function ProjectRecoveryDialogMorph(ide, project, browser) {
|
||||
this.init(ide, project, browser);
|
||||
}
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.init = function (ide, projectName, browser) {
|
||||
// initialize inherited properties:
|
||||
ProjectRecoveryDialogMorph.uber.init.call(
|
||||
this,
|
||||
this, // target
|
||||
null, // function
|
||||
null // environment
|
||||
);
|
||||
|
||||
this.ide = ide;
|
||||
this.browser = browser;
|
||||
this.key = 'recoverProject';
|
||||
this.projectName = projectName;
|
||||
|
||||
this.versions = null;
|
||||
|
||||
this.handle = null;
|
||||
this.listField = null;
|
||||
this.preview = null;
|
||||
this.notesText = null;
|
||||
this.notesField = null;
|
||||
|
||||
this.labelString = 'Recover project';
|
||||
this.createLabel();
|
||||
|
||||
this.buildContents();
|
||||
};
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.buildContents = function () {
|
||||
this.addBody(new Morph());
|
||||
this.body.color = this.color;
|
||||
|
||||
this.buildListField();
|
||||
|
||||
this.preview = new Morph();
|
||||
this.preview.fixLayout = nop;
|
||||
this.preview.edge = InputFieldMorph.prototype.edge;
|
||||
this.preview.fontSize = InputFieldMorph.prototype.fontSize;
|
||||
this.preview.typeInPadding = InputFieldMorph.prototype.typeInPadding;
|
||||
this.preview.contrast = InputFieldMorph.prototype.contrast;
|
||||
this.preview.drawNew = function () {
|
||||
InputFieldMorph.prototype.drawNew.call(this);
|
||||
if (this.texture) {
|
||||
this.drawTexture(this.texture);
|
||||
}
|
||||
};
|
||||
this.preview.drawCachedTexture = function () {
|
||||
var context = this.image.getContext('2d');
|
||||
context.drawImage(this.cachedTexture, this.edge, this.edge);
|
||||
this.changed();
|
||||
};
|
||||
this.preview.drawRectBorder = InputFieldMorph.prototype.drawRectBorder;
|
||||
this.preview.setExtent(
|
||||
this.ide.serializer.thumbnailSize.add(this.preview.edge * 2)
|
||||
);
|
||||
|
||||
this.body.add(this.preview);
|
||||
this.preview.drawNew();
|
||||
|
||||
this.notesField = new ScrollFrameMorph();
|
||||
this.notesField.fixLayout = nop;
|
||||
|
||||
this.notesField.edge = InputFieldMorph.prototype.edge;
|
||||
this.notesField.fontSize = InputFieldMorph.prototype.fontSize;
|
||||
this.notesField.typeInPadding = InputFieldMorph.prototype.typeInPadding;
|
||||
this.notesField.contrast = InputFieldMorph.prototype.contrast;
|
||||
this.notesField.drawNew = InputFieldMorph.prototype.drawNew;
|
||||
this.notesField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder;
|
||||
|
||||
this.notesField.acceptsDrops = false;
|
||||
this.notesField.contents.acceptsDrops = false;
|
||||
|
||||
this.notesText = new TextMorph('');
|
||||
|
||||
this.notesField.isTextLineWrapping = true;
|
||||
this.notesField.padding = 3;
|
||||
this.notesField.setContents(this.notesText);
|
||||
this.notesField.setWidth(this.preview.width());
|
||||
|
||||
this.body.add(this.notesField);
|
||||
|
||||
this.addButton('recoverProject', 'Recover');
|
||||
this.addButton('cancel', 'Cancel');
|
||||
|
||||
this.setExtent(new Point(360, 300));
|
||||
this.fixLayout();
|
||||
};
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.buildListField = function () {
|
||||
var myself = this;
|
||||
|
||||
this.listField = new ListMorph([]);
|
||||
this.fixListFieldItemColors();
|
||||
this.listField.fixLayout = nop;
|
||||
this.listField.edge = InputFieldMorph.prototype.edge;
|
||||
this.listField.fontSize = InputFieldMorph.prototype.fontSize;
|
||||
this.listField.typeInPadding = InputFieldMorph.prototype.typeInPadding;
|
||||
this.listField.contrast = InputFieldMorph.prototype.contrast;
|
||||
this.listField.drawNew = InputFieldMorph.prototype.drawNew;
|
||||
this.listField.drawRectBorder = InputFieldMorph.prototype.drawRectBorder;
|
||||
|
||||
this.listField.action = function (item) {
|
||||
var version;
|
||||
if (item === undefined) { return; }
|
||||
version = detect(
|
||||
myself.versions,
|
||||
function (version) {
|
||||
return version.lastupdated === item;
|
||||
});
|
||||
myself.notesText.text = version.notes || '';
|
||||
myself.notesText.drawNew();
|
||||
myself.notesField.contents.adjustBounds();
|
||||
myself.preview.texture = version.thumbnail;
|
||||
myself.preview.cachedTexture = null;
|
||||
myself.preview.drawNew();
|
||||
};
|
||||
|
||||
SnapCloud.getProjectVersionMetadata(
|
||||
this.projectName,
|
||||
function (versions) {
|
||||
var today = new Date(),
|
||||
yesterday = new Date();
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
myself.versions = versions;
|
||||
myself.versions.forEach(function (version) {
|
||||
var date = new Date(new Date().getTime() - version.lastupdated * 1000);
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
version.lastupdated = localize('Today, ') + date.toLocaleTimeString();
|
||||
} else if (date.toDateString() === yesterday.toDateString()) {
|
||||
version.lastupdated = localize('Yesterday, ') + date.toLocaleTimeString();
|
||||
} else {
|
||||
version.lastupdated = date.toLocaleString();
|
||||
}
|
||||
});
|
||||
myself.listField.elements =
|
||||
myself.versions.map(function (version) {
|
||||
return version.lastupdated;
|
||||
});
|
||||
myself.clearDetails();
|
||||
myself.listField.buildListContents();
|
||||
myself.fixListFieldItemColors();
|
||||
myself.listField.adjustScrollBars();
|
||||
myself.listField.scrollY(myself.listField.top());
|
||||
myself.fixLayout();
|
||||
},
|
||||
this.ide.cloudError()
|
||||
);
|
||||
|
||||
this.body.add(this.listField);
|
||||
};
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.cancel = function () {
|
||||
var myself = this;
|
||||
this.browser.show();
|
||||
this.browser.listField.select(
|
||||
detect(
|
||||
this.browser.projectList,
|
||||
function (item) { return item.projectname === myself.projectName }
|
||||
)
|
||||
);
|
||||
ProjectRecoveryDialogMorph.uber.cancel.call(this);
|
||||
};
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.recoverProject = function () {
|
||||
var lastupdated = this.listField.selected,
|
||||
version = detect(
|
||||
this.versions,
|
||||
function (version) {
|
||||
return version.lastupdated === lastupdated;
|
||||
});
|
||||
|
||||
this.browser.openCloudProject({ projectname: this.projectName }, version.delta);
|
||||
this.destroy();
|
||||
};
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.popUp = function () {
|
||||
var world = this.ide.world();
|
||||
if (world) {
|
||||
ProjectRecoveryDialogMorph.uber.popUp.call(this, world);
|
||||
this.handle = new HandleMorph(
|
||||
this,
|
||||
300,
|
||||
300,
|
||||
this.corner,
|
||||
this.corner
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.fixListFieldItemColors =
|
||||
ProjectDialogMorph.prototype.fixListFieldItemColors;
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.clearDetails =
|
||||
ProjectDialogMorph.prototype.clearDetails;
|
||||
|
||||
ProjectRecoveryDialogMorph.prototype.fixLayout = function () {
|
||||
var titleHeight = fontHeight(this.titleFontSize) + this.titlePadding * 2,
|
||||
thin = this.padding / 2,
|
||||
oldFlag = Morph.prototype.trackChanges;
|
||||
|
||||
Morph.prototype.trackChanges = false;
|
||||
|
||||
if (this.body) {
|
||||
this.body.setPosition(this.position().add(new Point(
|
||||
this.padding,
|
||||
titleHeight + this.padding
|
||||
)));
|
||||
this.body.setExtent(new Point(
|
||||
this.width() - this.padding * 2,
|
||||
this.height()
|
||||
- this.padding * 3 // top, bottom and button padding.
|
||||
- titleHeight
|
||||
- this.buttons.height()
|
||||
));
|
||||
|
||||
this.listField.setWidth(
|
||||
this.body.width()
|
||||
- this.preview.width()
|
||||
- this.padding
|
||||
);
|
||||
this.listField.contents.children[0].adjustWidths();
|
||||
|
||||
this.listField.setPosition(this.body.position());
|
||||
this.listField.setHeight(this.body.height());
|
||||
|
||||
this.preview.setRight(this.body.right());
|
||||
this.preview.setTop(this.listField.top());
|
||||
|
||||
this.notesField.setTop(this.preview.bottom() + thin);
|
||||
this.notesField.setLeft(this.preview.left());
|
||||
this.notesField.setHeight(
|
||||
this.body.bottom() - this.preview.bottom() - thin
|
||||
);
|
||||
}
|
||||
|
||||
if (this.label) {
|
||||
this.label.setCenter(this.center());
|
||||
this.label.setTop(
|
||||
this.top() + (titleHeight - this.label.height()) / 2
|
||||
);
|
||||
}
|
||||
|
||||
if (this.buttons) {
|
||||
this.buttons.fixLayout();
|
||||
this.buttons.setCenter(this.center());
|
||||
this.buttons.setBottom(this.bottom() - this.padding);
|
||||
}
|
||||
|
||||
Morph.prototype.trackChanges = oldFlag;
|
||||
this.changed();
|
||||
};
|
||||
|
||||
// LibraryImportDialogMorph ///////////////////////////////////////////
|
||||
// I am preview dialog shown before importing a library.
|
||||
// I inherit from a DialogMorph but look similar to
|
||||
|
|
|
@ -1074,6 +1074,12 @@ SnapTranslator.dict.ca = {
|
|||
'Segur que vols esborrar',
|
||||
'rename...':
|
||||
'canvia el nom...',
|
||||
'Recover':
|
||||
'Recupera',
|
||||
'Today, ':
|
||||
'Avui, ',
|
||||
'Yesterday, ':
|
||||
'Ahir, ',
|
||||
|
||||
// costume editor
|
||||
'Costume Editor':
|
||||
|
|
|
@ -2404,6 +2404,12 @@ SnapTranslator.dict.es = {
|
|||
'Publicado.',
|
||||
'unpublished.':
|
||||
'No publicado',
|
||||
'Recover':
|
||||
'Recuperar',
|
||||
'Today, ':
|
||||
'Hoy, ',
|
||||
'Yesterday, ':
|
||||
'Ayer, ',
|
||||
|
||||
// costume editor @todo (wasn't this superseed by paint editor?)
|
||||
'Costume Editor':
|
||||
|
|
Ładowanie…
Reference in New Issue