mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Issue #277 : Add global StorageService, enable CTRL+S
This commit is contained in:
parent
758cc6202a
commit
6620f7e5a9
@ -41,6 +41,8 @@ var Events = {
|
||||
HISTORY_STATE_LOADED: 'HISTORY_STATE_LOADED',
|
||||
|
||||
PISKEL_SAVED: 'PISKEL_SAVED',
|
||||
BEFORE_SAVING_PISKEL: 'BEFORE_SAVING_PISKEL',
|
||||
AFTER_SAVING_PISKEL: 'AFTER_SAVING_PISKEL',
|
||||
|
||||
FRAME_SIZE_CHANGED : 'FRAME_SIZE_CHANGED',
|
||||
|
||||
|
@ -109,15 +109,21 @@
|
||||
this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController();
|
||||
this.canvasBackgroundController.init();
|
||||
|
||||
this.galleryStorageService = new pskl.service.storage.GalleryStorageService(this.piskelController);
|
||||
this.galleryStorageService.init();
|
||||
|
||||
this.localStorageService = new pskl.service.storage.LocalStorageService(this.piskelController);
|
||||
this.localStorageService.init();
|
||||
|
||||
this.fileDownloadStorageService = new pskl.service.storage.FileDownloadStorageService(this.piskelController);
|
||||
this.fileDownloadStorageService.init();
|
||||
|
||||
this.desktopStorageService = new pskl.service.storage.DesktopStorageService(this.piskelController);
|
||||
this.desktopStorageService.init();
|
||||
|
||||
this.galleryStorageService = new pskl.service.storage.GalleryStorageService(this.piskelController);
|
||||
this.galleryStorageService.init();
|
||||
|
||||
this.storageService = new pskl.service.storage.StorageService(this.piskelController);
|
||||
this.storageService.init();
|
||||
|
||||
this.imageUploadService = new pskl.service.ImageUploadService();
|
||||
this.imageUploadService.init();
|
||||
|
||||
|
@ -11,52 +11,61 @@
|
||||
* @public
|
||||
*/
|
||||
ns.SaveController.prototype.init = function () {
|
||||
// timestamp used to generate unique name when saving as .piskel
|
||||
this.timestamp = new Date();
|
||||
var saveForm = document.querySelector('.save-form');
|
||||
this.getPartials_().forEach(function (partial) {
|
||||
pskl.utils.Template.insert(saveForm, 'beforeend', partial);
|
||||
});
|
||||
|
||||
this.insertPartials_();
|
||||
|
||||
// Only available in app-engine mode
|
||||
this.piskelName = document.querySelector('.piskel-name');
|
||||
this.saveOnlineStatus = document.querySelector('#save-online-status');
|
||||
this.saveFileStatus = document.querySelector('#save-file-status');
|
||||
this.descriptionInput = document.querySelector('#save-description');
|
||||
this.nameInput = document.querySelector('#save-name');
|
||||
this.saveOnlineButton = document.querySelector('#save-online-button');
|
||||
this.isPublicCheckbox = document.querySelector('input[name=save-public-checkbox]');
|
||||
|
||||
this.saveFileButton = document.querySelector('#save-file-button');
|
||||
this.saveBrowserButton = document.querySelector('#save-browser-button');
|
||||
|
||||
var descriptor = this.piskelController.getPiskel().getDescriptor();
|
||||
this.descriptionInput.value = descriptor.description;
|
||||
this.nameInput.value = descriptor.name;
|
||||
if (descriptor.isPublic) {
|
||||
this.isPublicCheckbox.setAttribute('checked', true);
|
||||
|
||||
this.addEventListener(this.saveFileButton, 'click', this.saveFile_);
|
||||
this.addEventListener(this.saveBrowserButton, 'click', this.saveBrowser_);
|
||||
this.addEventListener('form[name=save-form]', 'submit', this.onSaveFormSubmit_);
|
||||
|
||||
$.subscribe(Events.BEFORE_SAVING_PISKEL, this.disableSaveButtons_.bind(this));
|
||||
$.subscribe(Events.AFTER_SAVING_PISKEL, this.enableSaveButtons_.bind(this));
|
||||
|
||||
if (pskl.app.isLoggedIn()) {
|
||||
this.authenticatedUserInit_();
|
||||
}
|
||||
|
||||
if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
this.addEventListener('#save-as-button', 'click', this.saveAs_);
|
||||
}
|
||||
|
||||
this.addEventListener('#save-file-button', 'click', this.saveFile_);
|
||||
this.addEventListener('#save-browser-button', 'click', this.saveLocal_);
|
||||
this.addEventListener(this.saveOnlineButton, 'click', this.saveOnline_);
|
||||
this.addEventListener('form[name=save-form]', 'submit', this.onSaveFormSubmit_);
|
||||
|
||||
if (pskl.app.isLoggedIn()) {
|
||||
pskl.utils.Template.insert(this.saveOnlineStatus, 'beforeend', 'save-online-status-partial');
|
||||
} else {
|
||||
pskl.utils.Template.insert(this.saveOnlineStatus, 'beforeend', 'save-please-login-partial');
|
||||
var container = document.querySelector('.setting-save-section');
|
||||
container.classList.add('anonymous');
|
||||
this.desktopApplicationInit_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.insertPartials_ = function () {
|
||||
ns.SaveController.prototype.authenticatedUserInit_ = function () {
|
||||
var descriptor = this.piskelController.getPiskel().getDescriptor();
|
||||
this.isPublicCheckbox = document.querySelector('input[name=save-public-checkbox]');
|
||||
if (descriptor.isPublic) {
|
||||
this.isPublicCheckbox.setAttribute('checked', true);
|
||||
}
|
||||
this.saveOnlineButton = document.querySelector('#save-online-button');
|
||||
this.addEventListener(this.saveOnlineButton, 'click', this.saveOnline_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.desktopApplicationInit_ = function () {
|
||||
this.saveAsNewButton = document.querySelector('#save-as-button');
|
||||
this.addEventListener('#save-as-button', 'click', this.saveAs_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getPartials_ = function () {
|
||||
var partials = [];
|
||||
if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
partials = [
|
||||
'save-file-nw-partial',
|
||||
'save-localstorage-partial',
|
||||
'save-online-partial'
|
||||
'save-online-unavailable-partial'
|
||||
];
|
||||
} else if (pskl.app.isLoggedIn()) {
|
||||
partials = [
|
||||
@ -68,21 +77,11 @@
|
||||
partials = [
|
||||
'save-file-partial',
|
||||
'save-localstorage-partial',
|
||||
'save-online-partial'
|
||||
'save-online-unavailable-partial'
|
||||
];
|
||||
}
|
||||
|
||||
var container = document.querySelector('.save-form');
|
||||
partials.forEach(function (partial) {
|
||||
pskl.utils.Template.insert(container, 'beforeend', partial);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
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';
|
||||
return partials;
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) {
|
||||
@ -94,127 +93,105 @@
|
||||
} else {
|
||||
this.saveLocal_();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveOnline_ = function () {
|
||||
var name = this.getName();
|
||||
|
||||
if (!name) {
|
||||
name = window.prompt('Please specify a name', 'New piskel');
|
||||
}
|
||||
|
||||
if (name) {
|
||||
var description = this.getDescription();
|
||||
var isPublic = this.isPublic_();
|
||||
|
||||
var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic);
|
||||
this.piskelController.getPiskel().setDescriptor(descriptor);
|
||||
|
||||
this.beforeSaving_();
|
||||
|
||||
this.saveOnlineButton.setAttribute('disabled', true);
|
||||
this.saveOnlineStatus.innerHTML = 'Saving ...';
|
||||
|
||||
pskl.app.storageService.store({
|
||||
success : this.onSaveSuccess_.bind(this),
|
||||
error : this.onSaveError_.bind(this),
|
||||
after : this.afterOnlineSaving_.bind(this)
|
||||
});
|
||||
}
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
pskl.app.storageService.saveToGallery(piskel).then(this.onSaveSuccess_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveLocal_ = function () {
|
||||
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 ?');
|
||||
}
|
||||
|
||||
if (isOk) {
|
||||
ns.SaveController.prototype.saveBrowser_ = function () {
|
||||
this.beforeSaving_();
|
||||
localStorageService.save(name, description, pskl.app.piskelController.serialize());
|
||||
window.setTimeout(function () {
|
||||
this.onSaveSuccess_();
|
||||
this.afterSaving_();
|
||||
}.bind(this), 500);
|
||||
}
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
pskl.app.storageService.saveToLocalStorage(piskel).then(this.onSaveSuccess_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveFile_ = function () {
|
||||
// detect if this is running in NodeWebkit
|
||||
if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
pskl.app.desktopStorageService.save();
|
||||
this.saveFileDesktop_();
|
||||
} else {
|
||||
this.saveFileBrowser_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveAs_ = function () {
|
||||
pskl.app.desktopStorageService.savePiskelAs();
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveFileBrowser_ = function () {
|
||||
this.beforeSaving_();
|
||||
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');
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
pskl.app.storageService.saveToFileBrowser(piskel).then(this.onSaveSuccess_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getName = function () {
|
||||
ns.SaveController.prototype.saveFileDesktop_ = function () {
|
||||
this.beforeSaving_();
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
pskl.app.storageService.saveToFileNodeWebkit(piskel).then(this.onSaveSuccess_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveAs_ = function () {
|
||||
this.beforeSaving_();
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
pskl.app.storageService.saveToFileNodeWebkit(piskel, true).then(this.onSaveSuccess_);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getDescriptor_ = function () {
|
||||
var name = this.getName_();
|
||||
var description = this.getDescription_();
|
||||
var isPublic = this.isPublic_();
|
||||
return new pskl.model.piskel.Descriptor(name, description, isPublic);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getName_ = function () {
|
||||
return this.nameInput.value;
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.getDescription = function () {
|
||||
ns.SaveController.prototype.getDescription_ = function () {
|
||||
return this.descriptionInput.value;
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.isPublic_ = function () {
|
||||
return !!this.isPublicCheckbox.checked;
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.beforeSaving_ = function () {
|
||||
this.updatePiskelDescriptor_();
|
||||
|
||||
if (this.piskelName) {
|
||||
this.piskelName.classList.add('piskel-name-saving');
|
||||
if (!this.isPublicCheckbox) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.updatePiskelDescriptor_ = function () {
|
||||
var name = this.getName();
|
||||
var description = this.getDescription();
|
||||
var isPublic = this.isPublic_();
|
||||
|
||||
var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic);
|
||||
this.piskelController.getPiskel().setDescriptor(descriptor);
|
||||
return !!this.isPublicCheckbox.checked;
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.onSaveSuccess_ = function () {
|
||||
$.publish(Events.CLOSE_SETTINGS_DRAWER);
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{'content': 'Successfully saved !'}]);
|
||||
$.publish(Events.PISKEL_SAVED);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.onSaveError_ = function (status) {
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{'content': 'Saving failed (' + status + ')'}]);
|
||||
ns.SaveController.prototype.beforeSaving_ = function () {
|
||||
this.piskelController.getPiskel().setDescriptor(this.getDescriptor_());
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.afterOnlineSaving_ = function () {
|
||||
this.saveOnlineButton.setAttribute('disabled', false);
|
||||
this.saveOnlineStatus.innerHTML = '';
|
||||
this.afterSaving_();
|
||||
ns.SaveController.prototype.disableSaveButtons_ = function () {
|
||||
this.setDisabled_(this.saveFileButton, true);
|
||||
this.setDisabled_(this.saveBrowserButton, true);
|
||||
this.setDisabled_(this.saveOnlineButton, true);
|
||||
this.setDisabled_(this.saveAsNewButton, true);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.afterSaving_ = function () {
|
||||
if (this.piskelName) {
|
||||
this.piskelName.classList.remove('piskel-name-saving');
|
||||
ns.SaveController.prototype.enableSaveButtons_ = function () {
|
||||
this.setDisabled_(this.saveFileButton, false);
|
||||
this.setDisabled_(this.saveBrowserButton, false);
|
||||
this.setDisabled_(this.saveOnlineButton, false);
|
||||
this.setDisabled_(this.saveAsNewButton, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Safely update the disabled attribute on a HTML element.
|
||||
* Noop if the element is falsy
|
||||
*/
|
||||
ns.SaveController.prototype.setDisabled_ = function (element, isDisabled) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000);
|
||||
if (isDisabled) {
|
||||
element.setAttribute('disabled', 'disabled');
|
||||
} else {
|
||||
element.removeAttribute('disabled');
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -1,41 +1,42 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.service.storage');
|
||||
var PISKEL_EXTENSION = '.piskel';
|
||||
|
||||
ns.DesktopStorageService = function(piskelController) {
|
||||
this.piskelController = piskelController || pskl.app.piskelController;
|
||||
this.hideNotificationTimeoutID = 0;
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.init = function () {
|
||||
// activate keyboard shortcuts if this is the desktop version
|
||||
if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
pskl.app.shortcutService.addShortcut('ctrl+o', this.openPiskel.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+s', this.save.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+shift+s', this.savePiskelAs.bind(this));
|
||||
}
|
||||
};
|
||||
ns.DesktopStorageService.prototype.init = function () {};
|
||||
|
||||
ns.DesktopStorageService.prototype.save = function () {
|
||||
var savePath = this.piskelController.getSavePath();
|
||||
// if we already have a filename, just save the file (using nodejs 'fs' api)
|
||||
if (savePath) {
|
||||
this.savePiskel(savePath);
|
||||
ns.DesktopStorageService.prototype.save = function (piskel, saveAsNew) {
|
||||
if (piskel.savePath && !saveAsNew) {
|
||||
return this.saveAtPath_(piskel, piskel.savePath);
|
||||
} else {
|
||||
this.savePiskelAs();
|
||||
var name = piskel.getDescriptor().name;
|
||||
var filenamePromise = pskl.utils.FileUtilsDesktop.chooseFilenameDialog(name, PISKEL_EXTENSION);
|
||||
return filenamePromise.then(this.saveAtPath_.bind(this, piskel));
|
||||
}
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.savePiskel = function (savePath) {
|
||||
var serialized = this.piskelController.serialize();
|
||||
pskl.utils.FileUtilsDesktop.saveToFile(serialized, savePath, function () {
|
||||
this.onSaveSuccess_();
|
||||
}.bind(this));
|
||||
ns.DesktopStorageService.prototype.saveAtPath_ = function (piskel, savePath) {
|
||||
if (!savePath) {
|
||||
return Q.reject('Invalid file name');
|
||||
}
|
||||
|
||||
var serialized = pskl.utils.Serializer.serializePiskel(piskel, false);
|
||||
savePath = this.addExtensionIfNeeded_(savePath);
|
||||
piskel.savePath = savePath;
|
||||
piskel.setName(this.extractFilename_(savePath));
|
||||
return pskl.utils.FileUtilsDesktop.saveToFile(serialized, savePath);
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.openPiskel = function () {
|
||||
pskl.utils.FileUtilsDesktop.chooseFileDialog(function (filename) {
|
||||
var savePath = filename;
|
||||
pskl.utils.FileUtilsDesktop.readFile(savePath, function (content) {
|
||||
return pskl.utils.FileUtilsDesktop.chooseFilenameDialog().then(this.load);
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.load = function (savePath) {
|
||||
pskl.utils.FileUtilsDesktop.readFile(savePath).then(function (content) {
|
||||
pskl.utils.PiskelFileUtils.decodePiskelFile(content, function (piskel, descriptor, fps) {
|
||||
piskel.setDescriptor(descriptor);
|
||||
// store save path so we can re-save without opening the save dialog
|
||||
@ -44,26 +45,14 @@
|
||||
pskl.app.previewController.setFPS(fps);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.savePiskelAs = function () {
|
||||
var serialized = this.piskelController.serialize();
|
||||
var name = this.piskelController.getPiskel().getDescriptor().name;
|
||||
// TODO: if there is already a file path, use it for the dialog's
|
||||
// working directory and filename
|
||||
pskl.utils.FileUtilsDesktop.saveAs(serialized, name, 'piskel', function (selectedSavePath) {
|
||||
this.piskelController.setSavePath(selectedSavePath);
|
||||
|
||||
var filename = this.extractFilename_(selectedSavePath);
|
||||
if (filename) {
|
||||
var descriptor = this.piskelController.getPiskel().getDescriptor();
|
||||
descriptor.name = filename;
|
||||
this.piskelController.getPiskel().setDescriptor(descriptor);
|
||||
ns.DesktopStorageService.prototype.addExtensionIfNeeded_ = function (filename) {
|
||||
var hasExtension = filename.substr(-PISKEL_EXTENSION.length) === PISKEL_EXTENSION;
|
||||
if (!hasExtension) {
|
||||
return filename + PISKEL_EXTENSION;
|
||||
}
|
||||
|
||||
this.onSaveSuccess_();
|
||||
}.bind(this));
|
||||
return filename;
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.extractFilename_ = function (savePath) {
|
||||
@ -72,15 +61,4 @@
|
||||
return matches[1];
|
||||
}
|
||||
};
|
||||
|
||||
ns.DesktopStorageService.prototype.onSaveSuccess_ = function () {
|
||||
var savePath = this.piskelController.getSavePath();
|
||||
$.publish(Events.CLOSE_SETTINGS_DRAWER);
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{'content': 'Successfully saved: ' + savePath}]);
|
||||
$.publish(Events.PISKEL_SAVED);
|
||||
// clear the old time out, if any.
|
||||
window.clearTimeout(this.hideNotificationTimeoutID);
|
||||
this.hideNotificationTimeoutID = window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 3000);
|
||||
};
|
||||
|
||||
})();
|
||||
|
27
src/js/service/storage/FileDownloadStorageService.js
Normal file
27
src/js/service/storage/FileDownloadStorageService.js
Normal file
@ -0,0 +1,27 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.service.storage');
|
||||
|
||||
ns.FileDownloadStorageService = function () {};
|
||||
ns.FileDownloadStorageService.prototype.init = function () {};
|
||||
|
||||
ns.FileDownloadStorageService.prototype.save = function (piskel) {
|
||||
var serialized = pskl.utils.Serializer.serializePiskel(piskel, false);
|
||||
var deferred = Q.defer();
|
||||
|
||||
pskl.utils.BlobUtils.stringToBlob(serialized, function(blob) {
|
||||
var piskelName = piskel.getDescriptor().name;
|
||||
var timestamp = pskl.utils.DateUtils.format(new Date(), '{{Y}}{{M}}{{D}}-{{H}}{{m}}{{s}}');
|
||||
var fileName = piskelName + '-' + timestamp + '.piskel';
|
||||
|
||||
try {
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
deferred.resolve();
|
||||
} catch (e) {
|
||||
deferred.reject(e.message);
|
||||
}
|
||||
}.bind(this), 'application/piskel+json');
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
})();
|
@ -7,8 +7,9 @@
|
||||
|
||||
ns.GalleryStorageService.prototype.init = function () {};
|
||||
|
||||
ns.GalleryStorageService.prototype.store = function (piskel, onSuccess, onError) {
|
||||
ns.GalleryStorageService.prototype.save = function (piskel) {
|
||||
var descriptor = piskel.getDescriptor();
|
||||
var deferred = Q.defer();
|
||||
|
||||
var data = {
|
||||
framesheet : this.piskelController.serialize(),
|
||||
@ -24,10 +25,30 @@
|
||||
data.public = true;
|
||||
}
|
||||
|
||||
var errorCallback = function (response) {
|
||||
onError(response.status);
|
||||
var successCallback = function (response) {
|
||||
deferred.resolve();
|
||||
};
|
||||
|
||||
pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, onSuccess, errorCallback);
|
||||
var errorCallback = function (response) {
|
||||
deferred.reject(this.getErrorMessage_(response));
|
||||
};
|
||||
|
||||
pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, successCallback, errorCallback.bind(this));
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ns.GalleryStorageService.prototype.getErrorMessage_ = function (response) {
|
||||
var errorMessage = '';
|
||||
if (response.status === 401) {
|
||||
errorMessage = 'Session expired, please log in again.';
|
||||
} else if (response.status === 403) {
|
||||
errorMessage = 'Unauthorized action, this sprite belongs to another account.';
|
||||
} else if (response.status === 500) {
|
||||
errorMessage = 'Unexpected server error, please contact us on Github (piskel) or Twitter (@piskelapp)';
|
||||
} else {
|
||||
errorMessage = 'Unknown error';
|
||||
}
|
||||
return errorMessage;
|
||||
};
|
||||
})();
|
||||
|
@ -10,10 +10,26 @@
|
||||
|
||||
ns.LocalStorageService.prototype.init = function() {};
|
||||
|
||||
ns.LocalStorageService.prototype.save = function(name, description, piskel) {
|
||||
ns.LocalStorageService.prototype.save = function(piskel) {
|
||||
var name = piskel.getDescriptor().name;
|
||||
var description = piskel.getDescriptor().description;
|
||||
var serialized = pskl.utils.Serializer.serializePiskel(piskel, false);
|
||||
|
||||
if (pskl.app.localStorageService.getPiskel(name)) {
|
||||
var confirmOverwrite = window.confirm('There is already a piskel saved as ' + name + '. Overwrite ?');
|
||||
if (!confirmOverwrite) {
|
||||
return Q.reject('Cancelled by user, "' + name + '" already exists');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.removeFromKeys_(name);
|
||||
this.addToKeys_(name, description, Date.now());
|
||||
window.localStorage.setItem('piskel.' + name, piskel);
|
||||
window.localStorage.setItem('piskel.' + name, serialized);
|
||||
return Q.resolve();
|
||||
} catch (e) {
|
||||
return Q.reject(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
ns.LocalStorageService.prototype.load = function(name) {
|
||||
|
82
src/js/service/storage/StorageService.js
Normal file
82
src/js/service/storage/StorageService.js
Normal file
@ -0,0 +1,82 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.service.storage');
|
||||
|
||||
ns.StorageService = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
|
||||
this.onSaveSuccess_ = this.onSaveSuccess_.bind(this);
|
||||
this.onSaveError_ = this.onSaveError_.bind(this);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.init = function () {
|
||||
pskl.app.shortcutService.addShortcut('ctrl+o', this.onOpenKey_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+s', this.onSaveKey_.bind(this));
|
||||
pskl.app.shortcutService.addShortcut('ctrl+shift+s', this.onSaveAsKey_.bind(this));
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.onOpenKey_ = function () {
|
||||
if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
pskl.app.desktopStorageService.openPiskel();
|
||||
}
|
||||
// no other implementation for now
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.onSaveKey_ = function () {
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
if (pskl.app.isLoggedIn()) {
|
||||
this.saveToGallery(this.piskelController.getPiskel());
|
||||
} else if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
this.saveToFileNodeWebkit(this.piskelController.getPiskel());
|
||||
} else {
|
||||
this.saveToLocalStorage(this.piskelController.getPiskel());
|
||||
}
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.onSaveAsKey_ = function () {
|
||||
if (pskl.utils.Environment.detectNodeWebkit()) {
|
||||
this.saveToFileNodeWebkit(this.piskelController.getPiskel(), true);
|
||||
}
|
||||
// no other implementation for now
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.saveToGallery = function (piskel) {
|
||||
$.publish(Events.BEFORE_SAVING_PISKEL);
|
||||
return pskl.app.galleryStorageService.save(piskel).then(this.onSaveSuccess_, this.onSaveError_);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.saveToLocalStorage = function (piskel) {
|
||||
$.publish(Events.BEFORE_SAVING_PISKEL);
|
||||
return pskl.app.localStorageService.save(piskel).then(this.onSaveSuccess_, this.onSaveError_);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.saveToFileBrowser = function (piskel) {
|
||||
$.publish(Events.BEFORE_SAVING_PISKEL);
|
||||
return pskl.app.fileDownloadStorageService.save(piskel).then(this.onSaveSuccess_, this.onSaveError_);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.saveToFileNodeWebkit = function (piskel, saveAsNew) {
|
||||
$.publish(Events.BEFORE_SAVING_PISKEL);
|
||||
return pskl.app.desktopStorageService.save(piskel, saveAsNew).then(this.onSaveSuccess_, this.onSaveError_);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.onSaveSuccess_ = function () {
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{'content': 'Successfully saved !'}]);
|
||||
$.publish(Events.PISKEL_SAVED);
|
||||
this.afterSaving_();
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.onSaveError_ = function (errorMessage) {
|
||||
var errorText = 'Saving failed';
|
||||
if (errorMessage) {
|
||||
errorText += ' : ' + errorMessage;
|
||||
}
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{'content': errorText}]);
|
||||
this.afterSaving_();
|
||||
return Q.reject(errorMessage);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.afterSaving_ = function () {
|
||||
$.publish(Events.AFTER_SAVING_PISKEL);
|
||||
window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 5000);
|
||||
};
|
||||
})();
|
@ -1,63 +1,39 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.utils');
|
||||
|
||||
var stopPropagation = function (e) {
|
||||
e.stopPropagation();
|
||||
var getFileInputElement = function (nwsaveas, accept) {
|
||||
var fileInputElement = document.createElement('INPUT');
|
||||
fileInputElement.setAttribute('type', 'file');
|
||||
fileInputElement.setAttribute('nwworkingdir', '');
|
||||
if (nwsaveas) {
|
||||
fileInputElement.setAttribute('nwsaveas', nwsaveas);
|
||||
}
|
||||
if (accept) {
|
||||
fileInputElement.setAttribute('accept', accept);
|
||||
}
|
||||
|
||||
return fileInputElement;
|
||||
};
|
||||
|
||||
var CONFIRM_OVERRIDE = 'File already exists, do you want to override it ?';
|
||||
|
||||
ns.FileUtilsDesktop = {
|
||||
chooseFilenameDialog : function (nwsaveas, accept) {
|
||||
var deferred = Q.defer();
|
||||
var fileInputElement = getFileInputElement(nwsaveas, accept);
|
||||
var changeListener = function (evt) {
|
||||
fileInputElement.removeEventListener('change', changeListener);
|
||||
document.removeEventListener('click', changeListener);
|
||||
deferred.resolve(fileInputElement.value);
|
||||
};
|
||||
|
||||
chooseFileDialog: function (callback) {
|
||||
var tagString = '<input type="file" nwworkingdir=""/>';
|
||||
var $chooser = $(tagString);
|
||||
$chooser.change(function (e) {
|
||||
var filename = $(this).val();
|
||||
callback(filename);
|
||||
});
|
||||
$chooser.trigger('click');
|
||||
},
|
||||
fileInputElement.click();
|
||||
|
||||
addExtensionIfNeeded : function (filename, extension) {
|
||||
if (typeof extension == 'string') {
|
||||
if (extension[0] !== '.') {
|
||||
extension = '.' + extension;
|
||||
}
|
||||
var hasExtension = (filename.substring(filename.length - extension.length) === extension);
|
||||
if (!hasExtension) {
|
||||
filename += extension;
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
},
|
||||
fileInputElement.addEventListener('change', changeListener);
|
||||
// there is no way to detect a cancelled fileInput popup
|
||||
// as a crappy workaround we add a click listener on the document
|
||||
// on top the change event listener
|
||||
document.addEventListener('click', changeListener);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param content
|
||||
* @param defaultFilename - file name to pre-populate the dialog
|
||||
* @param extension - if supplied, the selected extension will guaranteed to be on the filename -
|
||||
* NOTE: there is a possible danger here... If the extension is added to a fileName, but there
|
||||
* is already another file of the same name *with* the extension, it will get overwritten.
|
||||
* @param callback
|
||||
*/
|
||||
saveAs: function (content, defaultFilename, extension, callback) {
|
||||
// NodeWebkit has no js api for opening the save dialog.
|
||||
// Instead, it adds two new attributes to the anchor tag: nwdirectory and nwsaveas
|
||||
// (see: https://github.com/nwjs/nw.js/wiki/File-dialogs )
|
||||
defaultFilename = defaultFilename || 'New Piskel';
|
||||
defaultFilename = pskl.utils.FileUtilsDesktop.addExtensionIfNeeded(defaultFilename, extension);
|
||||
var tagString = '<input type="file" accept=".piskel" nwsaveas="' + defaultFilename + '" nwworkingdir=""/>';
|
||||
var $chooser = $(tagString);
|
||||
$chooser.change(function (e) {
|
||||
var filename = $(this).val();
|
||||
filename = pskl.utils.FileUtilsDesktop.addExtensionIfNeeded(filename, extension);
|
||||
pskl.utils.FileUtilsDesktop.saveToFile(content, filename, function () {
|
||||
callback(filename);
|
||||
});
|
||||
});
|
||||
|
||||
$chooser.trigger('click');
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -67,26 +43,32 @@
|
||||
* @param {string} filename - fill path to the file
|
||||
* @callback callback
|
||||
*/
|
||||
saveToFile : function(content, filename, callback) {
|
||||
saveToFile : function(content, filename) {
|
||||
var deferred = Q.defer();
|
||||
var fs = window.require('fs');
|
||||
fs.writeFile(filename, content, function (err) {
|
||||
if (err) {
|
||||
//throw err;
|
||||
console.log('FileUtilsDesktop::savetoFile() - error saving file:', filename, 'Error:', err);
|
||||
deferred.reject('FileUtilsDesktop::savetoFile() - error saving file: ' + filename + ' Error: ' + err);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
callback();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
readFile : function(filename, callback) {
|
||||
readFile : function(filename) {
|
||||
var deferred = Q.defer();
|
||||
var fs = window.require('fs');
|
||||
// NOTE: currently loading everything as utf8, which may not be desirable in future
|
||||
fs.readFile(filename, 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
console.log('FileUtilsDesktop::readFile() - error reading file:', filename, 'Error:', err);
|
||||
deferred.reject('FileUtilsDesktop::readFile() - error reading file: ' + filename + ' Error: ' + err);
|
||||
} else {
|
||||
deferred.resolve(data);
|
||||
}
|
||||
callback(data);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -136,6 +136,11 @@
|
||||
"js/widgets/SizeInput.js",
|
||||
|
||||
// Services
|
||||
"js/service/storage/StorageService.js",
|
||||
"js/service/storage/FileDownloadStorageService.js",
|
||||
"js/service/storage/LocalStorageService.js",
|
||||
"js/service/storage/GalleryStorageService.js",
|
||||
"js/service/storage/DesktopStorageService.js",
|
||||
"js/service/BackupService.js",
|
||||
"js/service/BeforeUnloadService.js",
|
||||
"js/service/HistoryService.js",
|
||||
|
@ -25,7 +25,18 @@
|
||||
<div class="settings-title">Save online</div>
|
||||
<div class="settings-item">
|
||||
<input type="button" class="button button-primary" id="save-online-button" value="Save to your gallery" />
|
||||
<div id="save-online-status" class="save-status"></div>
|
||||
<div id="save-online-status" class="save-status">
|
||||
<span>Your piskel will be stored online in your gallery.</span>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="save-online-unavailable-partial">
|
||||
<div class="settings-title">Save online</div>
|
||||
<div class="settings-item">
|
||||
<div id="save-online-status" class="save-status">
|
||||
<span>Login to <a href="http://piskelapp.com" target="_blank">piskelapp.com</a> to save and share your sprites online !</span>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
@ -57,20 +68,4 @@
|
||||
<div id="save-file-status" class="save-status">Your sprite will be downloaded as a .piskel file.</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<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-online-status-partial">
|
||||
<span>Your piskel will be stored online in your gallery.</span>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="save-file-status-template">
|
||||
<span>Your piskel will be downloaded as: <span class="save-file-name">{{name}}<span></span>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="save-file-status-desktop-template">
|
||||
<span>Saving as: <span class="save-desktop-file-name">{{name}}<span></span>
|
||||
</script>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user