Feature : Save Piskel project as File
First commit : Removed Local storage feature Added 'download project' 'open project' options First attempt at simplifying right panel. To be continued ...
This commit is contained in:
parent
23fd3c464c
commit
89466d582a
23 changed files with 366 additions and 214 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,6 +18,7 @@ diff.txt
|
|||
|
||||
# build destination
|
||||
dest
|
||||
build/closure/closure_compiled_binary.js
|
||||
|
||||
# marked as private
|
||||
*.private.*
|
|
@ -34,3 +34,7 @@ ul, li {
|
|||
::-webkit-scrollbar-track {
|
||||
background-color: rgba(50, 50, 50, 0.4);
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
color:gold;
|
||||
}
|
|
@ -70,7 +70,7 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.upload-cloud-icon .label {
|
||||
.tool-icon .label {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 4px;
|
||||
|
@ -126,6 +126,7 @@
|
|||
text-transform: uppercase;
|
||||
border-bottom: 1px #aaa solid;
|
||||
padding-bottom: 5px;
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.settings-description {
|
||||
|
@ -141,6 +142,10 @@
|
|||
margin : 10px 0;
|
||||
}
|
||||
|
||||
[name*=checkbox] {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
/* Application settings */
|
||||
/************************************************************************************************/
|
||||
|
@ -203,13 +208,6 @@
|
|||
background:gold;
|
||||
}
|
||||
|
||||
.gif-export-preview,
|
||||
.png-export-preview {
|
||||
margin-top:20px;
|
||||
max-width:240px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.png-export-preview {
|
||||
margin:10px 0;
|
||||
overflow: hidden;
|
||||
|
@ -223,6 +221,38 @@
|
|||
margin : 10px 0;
|
||||
}
|
||||
|
||||
.gif-upload-status,
|
||||
.gif-export-preview {
|
||||
float : left;
|
||||
}
|
||||
|
||||
.gif-export-preview {
|
||||
|
||||
}
|
||||
|
||||
.gif-upload-status {
|
||||
width: 180px;
|
||||
margin-left: 5px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.gif-export-preview,
|
||||
.png-export-preview {
|
||||
margin-top:10px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.png-export-preview {
|
||||
max-width:240px;
|
||||
}
|
||||
|
||||
.gif-export-preview,
|
||||
.png-export-preview {
|
||||
max-width:32px;
|
||||
max-height:32px;
|
||||
}
|
||||
|
||||
.preview-upload-ongoing:before{
|
||||
content: "Upload ongoing ...";
|
||||
position: absolute;
|
||||
|
@ -243,7 +273,7 @@
|
|||
|
||||
.import-section,
|
||||
.resize-section {
|
||||
margin: 15px 0;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.import-section-title {
|
||||
|
@ -296,26 +326,36 @@
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
.save-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#save-status {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.status {
|
||||
height: 1.5rem;
|
||||
vertical-align: middle;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
[name=smooth-resize-checkbox] {
|
||||
margin : 0 8px;
|
||||
}
|
||||
|
||||
[name*=checkbox] {
|
||||
/************************************************************************************************/
|
||||
/* Save panel */
|
||||
/************************************************************************************************/
|
||||
|
||||
.save-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#save-online-status {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#save-local-status {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.save-status {
|
||||
vertical-align: middle;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.save-local-name {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ body {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.allow-user-select {
|
||||
-webkit-touch-callout: initial;
|
||||
-webkit-user-select: initial;
|
||||
|
|
|
@ -54,9 +54,8 @@
|
|||
<iframe src="templates/settings/application.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/resize.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/import.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/localstorage.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/export-gif.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/export-png.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<!-- <iframe src="templates/settings/localstorage.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe> -->
|
||||
<iframe src="templates/settings/export.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -56,8 +56,8 @@ var Constants = {
|
|||
SAVE : 'save'
|
||||
}
|
||||
},
|
||||
IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-a.appspot.com/__/upload',
|
||||
IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-a.appspot.com/img/',
|
||||
IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload',
|
||||
IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/',
|
||||
|
||||
ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0',
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
(function () {
|
||||
var ns = $.namespace("pskl.controller.settings");
|
||||
|
||||
var URL_MAX_LENGTH = 60;
|
||||
var URL_MAX_LENGTH = 30;
|
||||
var MAX_GIF_COLORS = 256;
|
||||
|
||||
ns.GifExportController = function (piskelController) {
|
||||
|
@ -27,12 +27,12 @@
|
|||
];
|
||||
|
||||
ns.GifExportController.prototype.init = function () {
|
||||
this.radioTemplate_ = pskl.utils.Template.get("gif-export-radio-template");
|
||||
this.optionTemplate_ = pskl.utils.Template.get("gif-export-option-template");
|
||||
|
||||
this.uploadStatusContainerEl = document.querySelector(".gif-upload-status");
|
||||
|
||||
this.previewContainerEl = document.querySelector(".gif-export-preview");
|
||||
this.radioGroupEl = document.querySelector(".gif-export-radio-group");
|
||||
this.selectResolutionEl = document.querySelector(".gif-export-select-resolution");
|
||||
|
||||
this.uploadButton = $(".gif-upload-button");
|
||||
this.uploadButton.click(this.onUploadButtonClick_.bind(this));
|
||||
|
@ -45,7 +45,7 @@
|
|||
this.exportProgressStatusEl = document.querySelector('.gif-export-progress-status');
|
||||
this.exportProgressBarEl = document.querySelector('.gif-export-progress-bar');
|
||||
|
||||
this.createRadioElements_();
|
||||
this.createOptionElements_();
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) {
|
||||
|
@ -63,8 +63,8 @@
|
|||
|
||||
this.renderAsImageDataAnimatedGIF(zoom, fps, function (imageData) {
|
||||
pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this));
|
||||
pskl.utils.ImageToBlob.imageDataToBlob(imageData, "image/gif", function(blob) {
|
||||
pskl.utils.FileUtils.downloadAsFile(fileName, blob);
|
||||
pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) {
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
});
|
||||
}.bind(this));
|
||||
};
|
||||
|
@ -82,43 +82,30 @@
|
|||
};
|
||||
|
||||
ns.GifExportController.prototype.updatePreview_ = function (src) {
|
||||
this.previewContainerEl.innerHTML = "<div><img style='max-width:240px;' src='"+src+"'/></div>";
|
||||
this.previewContainerEl.innerHTML = "<div><img style='max-width:32px;' src='"+src+"'/></div>";
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.getSelectedZoom_ = function () {
|
||||
var radiosColl = this.exportForm.get(0).querySelectorAll("[name=gif-zoom-level]"),
|
||||
radios = Array.prototype.slice.call(radiosColl,0);
|
||||
var selectedRadios = radios.filter(function(radio) {return !!radio.checked;});
|
||||
|
||||
if (selectedRadios.length == 1) {
|
||||
return selectedRadios[0].value;
|
||||
} else {
|
||||
throw "Unexpected error when retrieving selected zoom";
|
||||
}
|
||||
return this.selectResolutionEl.value;
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.createRadioElements_ = function () {
|
||||
ns.GifExportController.prototype.createOptionElements_ = function () {
|
||||
var resolutions = ns.GifExportController.RESOLUTIONS;
|
||||
for (var i = 0 ; i < resolutions.length ; i++) {
|
||||
var radio = this.createRadioForResolution_(resolutions[i]);
|
||||
this.radioGroupEl.appendChild(radio);
|
||||
var option = this.createOptionForResolution_(resolutions[i]);
|
||||
this.selectResolutionEl.appendChild(option);
|
||||
}
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.createRadioForResolution_ = function (resolution) {
|
||||
ns.GifExportController.prototype.createOptionForResolution_ = function (resolution) {
|
||||
var zoom = resolution.zoom;
|
||||
var label = zoom*this.piskelController.getWidth() + "x" + zoom*this.piskelController.getHeight();
|
||||
var value = zoom;
|
||||
|
||||
var radioHTML = pskl.utils.Template.replace(this.radioTemplate_, {value : value, label : label});
|
||||
var radioEl = pskl.utils.Template.createFromHTML(radioHTML);
|
||||
var optionHTML = pskl.utils.Template.replace(this.optionTemplate_, {value : value, label : label});
|
||||
var optionEl = pskl.utils.Template.createFromHTML(optionHTML);
|
||||
|
||||
if (resolution['default']) {
|
||||
var input = radioEl.getElementsByTagName("input")[0];
|
||||
input.setAttribute("checked", "checked");
|
||||
}
|
||||
|
||||
return radioEl;
|
||||
return optionEl;
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) {
|
||||
|
@ -181,8 +168,10 @@
|
|||
|
||||
ns.GifExportController.prototype.shorten_ = function (url, maxLength, suffix) {
|
||||
if (url.length > maxLength) {
|
||||
url = url.substring(0, maxLength);
|
||||
url += suffix;
|
||||
var index = Math.round((maxLength-suffix.length) / 2);
|
||||
var part1 = url.substring(0, index);
|
||||
var part2 = url.substring(url.length - index, url.length);
|
||||
url = part1 + suffix + part2;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings');
|
||||
var DEFAULT_FILE_STATUS = 'No file selected ...';
|
||||
var DEFAULT_FILE_STATUS = '';
|
||||
var PREVIEW_HEIGHT = 60;
|
||||
|
||||
ns.ImportController = function (piskelController) {
|
||||
|
@ -9,6 +9,9 @@
|
|||
};
|
||||
|
||||
ns.ImportController.prototype.init = function () {
|
||||
this.hiddenOpenPiskelInput = $('[name=open-piskel-input]');
|
||||
this.openPiskelInputButton = $('.open-piskel-button');
|
||||
|
||||
this.importForm = $('[name=import-form]');
|
||||
this.hiddenFileInput = $('[name=file-upload-input]');
|
||||
this.fileInputButton = $('.file-input-button');
|
||||
|
@ -20,12 +23,16 @@
|
|||
this.resizeWidth = $('[name=resize-width]');
|
||||
this.resizeHeight = $('[name=resize-height]');
|
||||
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
||||
this.submitButton = $('[name=import-submit]');
|
||||
|
||||
$('.import-options').hide();
|
||||
|
||||
this.importForm.submit(this.onImportFormSubmit_.bind(this));
|
||||
this.hiddenFileInput.change(this.onFileUploadChange_.bind(this));
|
||||
this.fileInputButton.click(this.onFileInputClick_.bind(this));
|
||||
|
||||
this.hiddenOpenPiskelInput.change(this.onOpenPiskelChange_.bind(this));
|
||||
this.openPiskelInputButton.click(this.onOpenPiskelClick_.bind(this));
|
||||
|
||||
this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width'));
|
||||
this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height'));
|
||||
};
|
||||
|
@ -61,14 +68,47 @@
|
|||
};
|
||||
|
||||
ns.ImportController.prototype.onFileUploadChange_ = function (evt) {
|
||||
this.importFromFile_();
|
||||
this.importPictureFromFile_();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onFileInputClick_ = function (evt) {
|
||||
this.hiddenFileInput.click();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.importFromFile_ = function () {
|
||||
ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) {
|
||||
this.openPiskelFile_();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) {
|
||||
this.hiddenOpenPiskelInput.click();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.openPiskelFile_ = function () {
|
||||
var files = this.hiddenOpenPiskelInput.get(0).files;
|
||||
if (files.length == 1) {
|
||||
|
||||
var file = files[0];
|
||||
if (this.isPiskel_(file)){
|
||||
pskl.utils.FileUtils.readFile(file, function (content) {
|
||||
var rawPiskel = window.atob(content.replace('data:;base64,',''));
|
||||
var serializedPiskel = JSON.parse(rawPiskel);
|
||||
var name = serializedPiskel.piskel.name;
|
||||
var description = serializedPiskel.piskel.description;
|
||||
var fps = serializedPiskel.piskel.fps;
|
||||
|
||||
pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) {
|
||||
piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, description, true));
|
||||
pskl.app.piskelController.setPiskel(piskel);
|
||||
pskl.app.animationController.setFPS(fps);
|
||||
});
|
||||
});
|
||||
this.reset_();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ns.ImportController.prototype.importPictureFromFile_ = function () {
|
||||
var files = this.hiddenFileInput.get(0).files;
|
||||
if (files.length == 1) {
|
||||
var file = files[0];
|
||||
|
@ -83,15 +123,9 @@
|
|||
};
|
||||
|
||||
ns.ImportController.prototype.enableDisabledSections_ = function () {
|
||||
this.resizeWidth.removeAttr('disabled');
|
||||
this.resizeHeight.removeAttr('disabled');
|
||||
this.smoothResize.removeAttr('disabled');
|
||||
this.submitButton.removeAttr('disabled');
|
||||
|
||||
this.fileInputButton.removeClass('button-primary');
|
||||
this.fileInputButton.blur();
|
||||
|
||||
$('.import-section-disabled').removeClass('import-section-disabled');
|
||||
$('.import-options').show();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.readImageFile_ = function (imageFile) {
|
||||
|
@ -200,4 +234,8 @@
|
|||
return file.type.indexOf('image') === 0;
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.isPiskel_ = function (file) {
|
||||
return (/\.piskel$/).test(file.name);
|
||||
};
|
||||
|
||||
})();
|
|
@ -9,28 +9,23 @@
|
|||
|
||||
ns.PngExportController.prototype.init = function () {
|
||||
this.previewContainerEl = document.querySelectorAll(".png-export-preview")[0];
|
||||
this.uploadStatusContainerEl = document.querySelectorAll(".png-upload-status")[0];
|
||||
|
||||
document.querySelector(".png-upload-button").addEventListener('click', this.onPngUploadButtonClick_.bind(this));
|
||||
document.querySelector(".png-download-button").addEventListener('click', this.onPngDownloadButtonClick_.bind(this));
|
||||
|
||||
document.querySelector(".zip-generate-button").addEventListener('click', this.onZipButtonClick_.bind(this));
|
||||
|
||||
this.updatePreview_(this.getFramesheetAsCanvas().toDataURL("image/png"));
|
||||
|
||||
(new ns.GifExportController(this.piskelController)).init();
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) {
|
||||
var fileName = this.getPiskelName_() + '.png';
|
||||
pskl.utils.ImageToBlob.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) {
|
||||
pskl.utils.FileUtils.downloadAsFile(fileName, blob);
|
||||
pskl.utils.BlobUtils.canvasToBlob(this.getFramesheetAsCanvas(), function(blob) {
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
});
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onPngUploadButtonClick_ = function (evt) {
|
||||
this.previewContainerEl.classList.add("preview-upload-ongoing");
|
||||
pskl.app.imageUploadService.upload(this.getFramesheetAsCanvas().toDataURL("image/png"), this.onImageUploadCompleted_.bind(this));
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onZipButtonClick_ = function () {
|
||||
var zip = new window.JSZip();
|
||||
|
||||
|
@ -43,8 +38,8 @@
|
|||
|
||||
var fileName = this.getPiskelName_() + '.zip';
|
||||
|
||||
var fileContent = zip.generate({type:"blob"});
|
||||
pskl.utils.FileUtils.downloadAsFile(fileName, fileContent);
|
||||
var blob = zip.generate({type:"blob"});
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) {
|
||||
|
|
|
@ -13,13 +13,16 @@
|
|||
this.nameInput = $('#save-name');
|
||||
this.descriptionInput = $('#save-description');
|
||||
this.isPublicCheckbox = $('input[name=save-public-checkbox]');
|
||||
this.saveCloudButton = $('#save-cloud-button');
|
||||
this.saveOnlineButton = $('#save-online-button');
|
||||
this.saveLocalButton = $('#save-local-button');
|
||||
|
||||
// Only available in app-engine mode ...
|
||||
this.piskelName = $('.piskel-name').get(0);
|
||||
|
||||
this.status = $('#save-status');
|
||||
this.saveOnlineStatus = $('#save-online-status');
|
||||
|
||||
this.saveLocalStatus = $('#save-local-status');
|
||||
this.timestamp = new Date();
|
||||
|
||||
var descriptor = this.piskelController.getPiskel().getDescriptor();
|
||||
this.nameInput.val(descriptor.name);
|
||||
|
@ -27,27 +30,38 @@
|
|||
|
||||
this.isPublicCheckbox.prop('checked', descriptor.isPublic);
|
||||
|
||||
if (!pskl.app.isLoggedIn()) {
|
||||
this.saveCloudButton.attr('disabled', 'disabled');
|
||||
this.status.html('You are not logged in. Only Local Save is available.');
|
||||
} else {
|
||||
this.saveLocalButton.click(this.onSaveLocalClick_.bind(this));
|
||||
this.nameInput.keyup(this.updateLocalStatusFilename_.bind(this));
|
||||
|
||||
if (pskl.app.isLoggedIn()) {
|
||||
this.saveForm.submit(this.onSaveFormSubmit_.bind(this));
|
||||
} else {
|
||||
this.saveOnlineButton.hide();
|
||||
$('.save-public-section').hide();
|
||||
this.saveOnlineStatus.html(pskl.utils.Template.get('save-please-login-partial'));
|
||||
this.saveLocalButton.get(0).classList.add('button-primary');
|
||||
this.saveForm.submit(this.onSaveLocalClick_.bind(this));
|
||||
}
|
||||
|
||||
this.saveLocalButton.click(this.onSaveLocalClick_.bind(this));
|
||||
this.updateLocalStatusFilename_();
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.updateLocalStatusFilename_ = function () {
|
||||
this.saveLocalStatus.html(pskl.utils.Template.getAndReplace('save-local-status-template', {
|
||||
name : this.getLocalFilename_()
|
||||
}));
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getLocalFilename_ = function () {
|
||||
var piskelName = this.getName();
|
||||
var timestamp = pskl.utils.DateUtils.format(this.timestamp, "{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}");
|
||||
return piskelName + "-" + timestamp + ".piskel";
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
var name = this.getName();
|
||||
var description = this.getDescription();
|
||||
var isPublic = !!this.isPublicCheckbox.prop('checked');
|
||||
|
||||
var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic);
|
||||
this.piskelController.getPiskel().setDescriptor(descriptor);
|
||||
|
||||
this.beforeSaving_();
|
||||
pskl.app.storageService.store({
|
||||
success : this.onSaveSuccess_.bind(this),
|
||||
|
@ -57,22 +71,13 @@
|
|||
};
|
||||
|
||||
ns.SaveController.prototype.onSaveLocalClick_ = function (evt) {
|
||||
var localStorageService = pskl.app.localStorageService;
|
||||
var isOk = true;
|
||||
var name = this.getName();
|
||||
var description = this.getDescription();
|
||||
if (localStorageService.getPiskel(name)) {
|
||||
isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?');
|
||||
}
|
||||
this.beforeSaving_();
|
||||
|
||||
if (isOk) {
|
||||
this.beforeSaving_();
|
||||
localStorageService.save(name, description, pskl.app.piskelController.serialize());
|
||||
window.setTimeout(function () {
|
||||
this.onSaveSuccess_();
|
||||
this.afterSaving_();
|
||||
}.bind(this), 1000);
|
||||
}
|
||||
pskl.utils.BlobUtils.stringToBlob(pskl.app.piskelController.serialize(), function(blob) {
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, this.getLocalFilename_());
|
||||
this.onSaveSuccess_();
|
||||
this.afterSaving_();
|
||||
}.bind(this), "application/piskel+json");
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getName = function () {
|
||||
|
@ -84,14 +89,25 @@
|
|||
};
|
||||
|
||||
ns.SaveController.prototype.beforeSaving_ = function () {
|
||||
this.saveCloudButton.attr('disabled', true);
|
||||
this.status.html('Saving ...');
|
||||
this.updatePiskelDescriptor_();
|
||||
|
||||
this.saveOnlineButton.attr('disabled', true);
|
||||
this.saveOnlineStatus.html('Saving ...');
|
||||
|
||||
if (this.piskelName) {
|
||||
this.piskelName.classList.add('piskel-name-saving');
|
||||
}
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.updatePiskelDescriptor_ = function () {
|
||||
var name = this.getName();
|
||||
var description = this.getDescription();
|
||||
var isPublic = !!this.isPublicCheckbox.prop('checked');
|
||||
|
||||
var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic);
|
||||
this.piskelController.getPiskel().setDescriptor(descriptor);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.onSaveSuccess_ = function () {
|
||||
$.publish(Events.CLOSE_SETTINGS_DRAWER);
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]);
|
||||
|
@ -103,8 +119,8 @@
|
|||
};
|
||||
|
||||
ns.SaveController.prototype.afterSaving_ = function () {
|
||||
this.saveCloudButton.attr('disabled', false);
|
||||
this.status.html('');
|
||||
this.saveOnlineButton.attr('disabled', false);
|
||||
this.submitButton.html('');
|
||||
|
||||
if (this.piskelName) {
|
||||
this.piskelName.classList.remove('piskel-name-saving');
|
||||
|
|
|
@ -10,12 +10,8 @@
|
|||
template : 'templates/settings/resize.html',
|
||||
controller : ns.ResizeController
|
||||
},
|
||||
'gif' : {
|
||||
template : 'templates/settings/export-gif.html',
|
||||
controller : ns.GifExportController
|
||||
},
|
||||
'png' : {
|
||||
template : 'templates/settings/export-png.html',
|
||||
template : 'templates/settings/export.html',
|
||||
controller : ns.PngExportController
|
||||
},
|
||||
'import' : {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i;
|
||||
|
||||
ns.ImageToBlob = {
|
||||
imageDataToBlob : function(dataURI, type, callback) {
|
||||
ns.BlobUtils = {
|
||||
dataToBlob : function(dataURI, type, callback) {
|
||||
var header_end = dataURI.indexOf(","),
|
||||
data = dataURI.substring(header_end + 1),
|
||||
isBase64 = BASE64_REGEX.test(dataURI.substring(0, header_end)),
|
||||
|
@ -26,13 +26,18 @@
|
|||
canvasToBlob : function(canvas, callback, type /*, ...args*/) {
|
||||
type = type || "image/png";
|
||||
|
||||
if (this.mozGetAsFile) {
|
||||
callback(this.mozGetAsFile("canvas", type));
|
||||
if (canvas.mozGetAsFile) {
|
||||
callback(canvas.mozGetAsFile("canvas", type));
|
||||
} else {
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
var dataURI = canvas.toDataURL.apply(canvas, args);
|
||||
pskl.utils.ImageToBlob.imageDataToBlob(dataURI, type, callback);
|
||||
pskl.utils.BlobUtils.dataToBlob(dataURI, type, callback);
|
||||
}
|
||||
},
|
||||
|
||||
stringToBlob : function (string, callback, type) {
|
||||
type = type || "text/plain";
|
||||
pskl.utils.BlobUtils.dataToBlob('data:'+type+',' + string, type, callback);
|
||||
}
|
||||
};
|
||||
})();
|
24
src/js/utils/DateUtils.js
Normal file
24
src/js/utils/DateUtils.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.utils');
|
||||
|
||||
var pad = function (num) {
|
||||
if (num < 10) {
|
||||
return "0" + num;
|
||||
} else {
|
||||
return "" + num;
|
||||
}
|
||||
};
|
||||
|
||||
ns.DateUtils = {
|
||||
format : function (date, format) {
|
||||
return pskl.utils.Template.replace(format, {
|
||||
Y : date.getFullYear(),
|
||||
M : pad(date.getMonth() + 1),
|
||||
D : pad(date.getDate()),
|
||||
H : pad(date.getHours()),
|
||||
m : pad(date.getMinutes()),
|
||||
s : pad(date.getSeconds())
|
||||
});
|
||||
}
|
||||
};
|
||||
})();
|
|
@ -10,7 +10,7 @@
|
|||
reader.readAsDataURL(file);
|
||||
},
|
||||
|
||||
downloadAsFile : function (filename, content) {
|
||||
downloadAsFile : function (content, filename) {
|
||||
var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator));
|
||||
if (saveAs) {
|
||||
saveAs(content, filename);
|
||||
|
|
|
@ -17,6 +17,15 @@
|
|||
return dummyEl.children[0];
|
||||
},
|
||||
|
||||
getAndReplace : function (templateId, dict) {
|
||||
var result = "";
|
||||
var tpl = pskl.utils.Template.get(templateId);
|
||||
if (tpl) {
|
||||
result = pskl.utils.Template.replace(tpl, dict);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
replace : function (template, dict) {
|
||||
for (var key in dict) {
|
||||
if (dict.hasOwnProperty(key)) {
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
return JSON.stringify({
|
||||
modelVersion : Constants.MODEL_VERSION,
|
||||
piskel : {
|
||||
name : piskel.getDescriptor().name,
|
||||
description : piskel.getDescriptor().description,
|
||||
fps : pskl.app.piskelController.getFPS(),
|
||||
height : piskel.getHeight(),
|
||||
width : piskel.getWidth(),
|
||||
layers : serializedLayers,
|
||||
|
|
|
@ -24,13 +24,14 @@
|
|||
"js/utils/core.js",
|
||||
"js/utils/UserAgent.js",
|
||||
"js/utils/Base64.js",
|
||||
"js/utils/BlobUtils.js",
|
||||
"js/utils/CanvasUtils.js",
|
||||
"js/utils/DateUtils.js",
|
||||
"js/utils/Dom.js",
|
||||
"js/utils/Math.js",
|
||||
"js/utils/FileUtils.js",
|
||||
"js/utils/FrameUtils.js",
|
||||
"js/utils/LayerUtils.js",
|
||||
"js/utils/ImageToBlob.js",
|
||||
"js/utils/ImageResizer.js",
|
||||
"js/utils/PixelUtils.js",
|
||||
"js/utils/Template.js",
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
<div class="vertical-centerer">
|
||||
<div
|
||||
data-setting="save"
|
||||
class="tool-icon save-icon"
|
||||
title="Save to gallery"
|
||||
rel="tooltip" data-placement="left" >
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
data-setting="user"
|
||||
|
@ -16,37 +11,43 @@
|
|||
<div
|
||||
data-setting="resize"
|
||||
class="tool-icon resize-icon"
|
||||
title="Resize"
|
||||
title="Modify Canvas"
|
||||
rel="tooltip" data-placement="left">
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-setting="save"
|
||||
class="tool-icon save-icon"
|
||||
title="Save to gallery"
|
||||
rel="tooltip" data-placement="left" >
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-setting="import"
|
||||
class="tool-icon import-icon"
|
||||
title="Import an existing picture"
|
||||
class="tool-icon local-storage-icon"
|
||||
title="Import piskel"
|
||||
rel="tooltip" data-placement="left">
|
||||
</div>
|
||||
|
||||
<div
|
||||
<!-- <div
|
||||
data-setting="localstorage"
|
||||
class="tool-icon local-storage-icon"
|
||||
title="Browse piskels saved locally"
|
||||
rel="tooltip" data-placement="left">
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div
|
||||
<!-- <div
|
||||
data-setting="gif"
|
||||
class="tool-icon upload-cloud-icon"
|
||||
title="Export Animation"
|
||||
rel="tooltip" data-placement="left">
|
||||
<span class="label">ANIM</span>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div
|
||||
data-setting="png"
|
||||
class="tool-icon upload-cloud-icon"
|
||||
title="Export Spritesheet"
|
||||
class="tool-icon import-icon"
|
||||
title="Export"
|
||||
rel="tooltip" data-placement="left">
|
||||
<span class="label">SHEET</span>
|
||||
</div>
|
||||
</div>
|
|
@ -1,22 +0,0 @@
|
|||
<div class="settings-section">
|
||||
<div class="settings-title">
|
||||
Export to Animated GIF
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" class="gif-export-form">
|
||||
<label>Select resolution:</label>
|
||||
<script type="text/template" id="gif-export-radio-template">
|
||||
<label style="display:block"><input type="radio" name="gif-zoom-level" value="{{value}}"/>
|
||||
{{label}}</label>
|
||||
</script>
|
||||
<div class="gif-export-radio-group"></div>
|
||||
|
||||
<button type="button" class="button button-primary gif-download-button">Download GIF</button>
|
||||
<button type="button" class="button button gif-upload-button">Export online</button>
|
||||
</form>
|
||||
<span class="gif-export-progress-status"></span>
|
||||
<div class="gif-export-progress-bar"></div>
|
||||
<div class="gif-export-preview"></div>
|
||||
<div class="gif-upload-status"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,23 +0,0 @@
|
|||
<div class="settings-section">
|
||||
<div class="settings-title">
|
||||
Export Spritesheet as PNG
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<span>Preview : </span>
|
||||
<div class="png-export-preview"></div>
|
||||
<div class="png-export-radio-group"></div>
|
||||
<button type="button" class="button button-primary png-download-button">Download PNG</button>
|
||||
<button type="button" class="button png-upload-button">Export online</button>
|
||||
<!-- <input type="button" class="button png-download-button" value="Download" /> -->
|
||||
<div class="png-upload-status"></div>
|
||||
</div>
|
||||
<div class="settings-title">
|
||||
Export Spritesheet as ZIP
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<span class="settings-description">A ZIP archive will be created with one PNG file per frame.</span>
|
||||
<div>
|
||||
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
40
src/templates/settings/export.html
Normal file
40
src/templates/settings/export.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
<div class="settings-section">
|
||||
<div class="settings-title">
|
||||
Export Spritesheet
|
||||
</div>
|
||||
<div class="png-export-preview"></div>
|
||||
<div class="settings-item">
|
||||
<span class="settings-description">PNG with all frames side by side.</span>
|
||||
<button type="button" class="button button-primary png-download-button">Download PNG</button>
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<span class="settings-description">ZIP with one PNG file per frame.</span>
|
||||
<div>
|
||||
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-title">
|
||||
Export to Animated GIF
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" class="gif-export-form">
|
||||
<div style="margin:10px 0;">
|
||||
<label>Select resolution:</label>
|
||||
<select class="gif-export-select-resolution"></select>
|
||||
<script type="text/template" id="gif-export-option-template">
|
||||
<option value="{{value}}">{{label}}</option>
|
||||
</script>
|
||||
</div>
|
||||
<div style="margin:10px 0;">
|
||||
<button type="button" class="button button-primary gif-download-button">Download GIF</button>
|
||||
<button type="button" class="button button gif-upload-button">Get public URL</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="clearfix">
|
||||
<div class="gif-export-preview"></div>
|
||||
<div class="gif-upload-status"></div>
|
||||
</div>
|
||||
<span class="gif-export-progress-status"></span>
|
||||
<div class="gif-export-progress-bar"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,33 +1,50 @@
|
|||
<div class="settings-section">
|
||||
<div class="settings-title">
|
||||
Import Picture
|
||||
Open Piskel Project
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" name="open-piskel-form">
|
||||
<span>Load a <span style="font-weight:bold;color:white">.piskel</span> file from your computer.</span>
|
||||
|
||||
<div class="import-section">
|
||||
<button type="button" class="button button-primary open-piskel-button">Open...</button>
|
||||
<span class="file-input-open-piskel-status"></span>
|
||||
<input style="display:none"
|
||||
type="file" name="open-piskel-input"
|
||||
value="file" accept=".piskel"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="settings-title">
|
||||
Import From Picture
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" name="import-form">
|
||||
<div style="margin-top:5px;margin-bottom:5px;">Supports : PNG, JPG, BMP, Animated GIF ...</div>
|
||||
<div class="import-section">
|
||||
<span class="import-section-title import-section-title-small">File :</span>
|
||||
<button type="button" class="button button-primary file-input-button">Browse</button>
|
||||
<button type="button" class="button button-primary file-input-button">Browse...</button>
|
||||
<span class="file-input-status"></span>
|
||||
<input style="display:none"
|
||||
type="file" name="file-upload-input"
|
||||
value="file" accept="image/*"/>
|
||||
</div>
|
||||
<div class="import-section import-section-disabled">
|
||||
<span class="import-section-title import-section-title-small" style="vertical-align:top">Info :</span>
|
||||
<div class="import-section-preview"></div>
|
||||
</div>
|
||||
<div class="import-section import-section-disabled">
|
||||
<span class="import-section-title import-section-title-small">Size :</span>
|
||||
<input type="text" disabled="disabled" class="textfield import-size-field" name="resize-width"/>x
|
||||
<input type="text" disabled="disabled" class="textfield import-size-field" name="resize-height"/>
|
||||
</div>
|
||||
<div class="import-section import-section-disabled">
|
||||
<span class="import-section-title">Smooth resize :</span>
|
||||
<input type="checkbox" disabled="disabled" checked="checked" name="smooth-resize-checkbox" value="1"/>
|
||||
</div>
|
||||
<input type="submit" name="import-submit" disabled="disabled" class="button button-primary import-button" value="Import" />
|
||||
|
||||
<span class="settings-description" style="margin-top:5px;">Animated GIFs will be split in several frames. Other images will be imported as a single-frame.</span>
|
||||
<div class="import-options">
|
||||
<div class="import-section">
|
||||
<span class="import-section-title import-section-title-small" style="vertical-align:top">Info :</span>
|
||||
<div class="import-section-preview"></div>
|
||||
</div>
|
||||
<div class="import-section">
|
||||
<span class="import-section-title import-section-title-small">Size :</span>
|
||||
<input type="text" class="textfield import-size-field" name="resize-width"/>x
|
||||
<input type="text" class="textfield import-size-field" name="resize-height"/>
|
||||
</div>
|
||||
<div class="import-section">
|
||||
<span class="import-section-title">Smooth resize :</span>
|
||||
<input type="checkbox" checked="checked" name="smooth-resize-checkbox" value="1"/>
|
||||
</div>
|
||||
<input type="submit" name="import-submit" class="button button-primary import-button" value="Import" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="settings-section">
|
||||
<div class="settings-title">Save</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" name="save-form">
|
||||
<form action="" method="POST" name="save-form">
|
||||
<div class="settings-title">Describe your piskel</div>
|
||||
<div class="settings-item">
|
||||
<div class="settings-form-section">
|
||||
<label class="row">Title : </label>
|
||||
<input id="save-name" type="text" class="save-field textfield"/>
|
||||
|
@ -10,14 +10,29 @@
|
|||
<label class="row">Description :</label>
|
||||
<textarea id="save-description" class="save-field textfield" placeholder="Your piskel in a few words"></textarea>
|
||||
</div>
|
||||
<div class="settings-form-section">
|
||||
<div class="settings-form-section save-public-section">
|
||||
<label class="row">
|
||||
Public : <input type="checkbox" value="1" name="save-public-checkbox"/>
|
||||
</label>
|
||||
</div>
|
||||
<input type="submit" class="button button-primary" id="save-cloud-button" value="Upload" />
|
||||
<input type="button" class="button" id="save-local-button" value="Local save" />
|
||||
<div id="save-status" class="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-title">Save online</div>
|
||||
<div class="settings-item">
|
||||
<input type="submit" class="button button-primary" id="save-online-button" value="Upload" />
|
||||
<div id="save-online-status" class="save-status"></div>
|
||||
</div>
|
||||
<div class="settings-title">Download Project</div>
|
||||
<div class="settings-item">
|
||||
<div id="save-local-status" class="save-status"></div>
|
||||
<input type="button" class="button" id="save-local-button" value="Download Piskel Project" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script type="text/template" id="save-please-login-partial">
|
||||
<span>Login to <a href="http://piskelapp.com" target="_blank">piskelapp.com</a> to save and share your sprites online !</span>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="save-local-status-template">
|
||||
<span>Your piskel will be downloaded as <span class="save-local-name">{{name}}<span></span>
|
||||
</script>
|
||||
</div>
|
Loading…
Reference in a new issue