Issue #640 - migrate local browser save to indexeddb
This commit is contained in:
parent
30ecd41452
commit
ed749a747f
7 changed files with 273 additions and 23 deletions
|
@ -114,6 +114,9 @@
|
|||
this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController();
|
||||
this.canvasBackgroundController.init();
|
||||
|
||||
this.indexedDbStorageService = new pskl.service.storage.IndexedDbStorageService(this.piskelController);
|
||||
this.indexedDbStorageService.init();
|
||||
|
||||
this.localStorageService = new pskl.service.storage.LocalStorageService(this.piskelController);
|
||||
this.localStorageService.init();
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
this.localStorageItemTemplate_ = pskl.utils.Template.get('local-storage-item-template');
|
||||
|
||||
this.service_ = pskl.app.localStorageService;
|
||||
this.service_ = pskl.app.indexedDbStorageService;
|
||||
this.piskelList = $('.local-piskel-list');
|
||||
this.prevSessionContainer = $('.previous-session');
|
||||
|
||||
|
@ -36,24 +36,24 @@
|
|||
};
|
||||
|
||||
ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () {
|
||||
var html = '';
|
||||
var keys = this.service_.getKeys();
|
||||
|
||||
keys.sort(function (k1, k2) {
|
||||
if (k1.date < k2.date) {return 1;}
|
||||
if (k1.date > k2.date) {return -1;}
|
||||
return 0;
|
||||
});
|
||||
|
||||
keys.forEach((function (key) {
|
||||
var date = pskl.utils.DateUtils.format(key.date, '{{Y}}/{{M}}/{{D}} {{H}}:{{m}}');
|
||||
html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {
|
||||
name : key.name,
|
||||
date : date
|
||||
this.service_.getKeys().then(function (keys) {
|
||||
var html = '';
|
||||
keys.sort(function (k1, k2) {
|
||||
if (k1.date < k2.date) {return 1;}
|
||||
if (k1.date > k2.date) {return -1;}
|
||||
return 0;
|
||||
});
|
||||
}).bind(this));
|
||||
|
||||
var tableBody_ = this.piskelList.get(0).tBodies[0];
|
||||
tableBody_.innerHTML = html;
|
||||
keys.forEach((function (key) {
|
||||
var date = pskl.utils.DateUtils.format(key.date, '{{Y}}/{{M}}/{{D}} {{H}}:{{m}}');
|
||||
html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {
|
||||
name : key.name,
|
||||
date : date
|
||||
});
|
||||
}).bind(this));
|
||||
|
||||
var tableBody_ = this.piskelList.get(0).tBodies[0];
|
||||
tableBody_.innerHTML = html;
|
||||
}.bind(this));
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
this.saveDesktopAsNewButton = document.querySelector('#save-desktop-as-new-button');
|
||||
this.saveFileDownloadButton = document.querySelector('#save-file-download-button');
|
||||
|
||||
this.safeAddEventListener_(this.saveLocalStorageButton, 'click', this.saveToLocalStorage_);
|
||||
this.safeAddEventListener_(this.saveLocalStorageButton, 'click', this.saveToIndexedDb_);
|
||||
this.safeAddEventListener_(this.saveGalleryButton, 'click', this.saveToGallery_);
|
||||
this.safeAddEventListener_(this.saveDesktopButton, 'click', this.saveToDesktop_);
|
||||
this.safeAddEventListener_(this.saveDesktopAsNewButton, 'click', this.saveToDesktopAsNew_);
|
||||
|
@ -99,7 +99,7 @@
|
|||
if (pskl.app.isLoggedIn()) {
|
||||
this.saveToGallery_();
|
||||
} else {
|
||||
this.saveToLocalStorage_();
|
||||
this.saveToIndexedDb_();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -111,8 +111,8 @@
|
|||
this.saveTo_('saveToGallery', false);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveToLocalStorage_ = function () {
|
||||
this.saveTo_('saveToLocalStorage', false);
|
||||
ns.SaveController.prototype.saveToIndexedDb_ = function () {
|
||||
this.saveTo_('saveToIndexedDb', false);
|
||||
};
|
||||
|
||||
ns.SaveController.prototype.saveToDesktop_ = function () {
|
||||
|
|
171
src/js/service/storage/IndexedDbStorageService.js
Normal file
171
src/js/service/storage/IndexedDbStorageService.js
Normal file
|
@ -0,0 +1,171 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.service.storage');
|
||||
var DB_NAME = 'PiskelDatabase';
|
||||
var DB_VERSION = 1;
|
||||
|
||||
ns.IndexedDbStorageService = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.init = function () {
|
||||
var request = window.indexedDB.open(DB_NAME, DB_VERSION);
|
||||
|
||||
request.onerror = this.onRequestError_.bind(this);
|
||||
request.onupgradeneeded = this.onUpgradeNeeded_.bind(this);
|
||||
request.onsuccess = this.onRequestSuccess_.bind(this);
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.save = function (piskel) {
|
||||
var name = piskel.getDescriptor().name;
|
||||
var description = piskel.getDescriptor().description;
|
||||
var date = Date.now();
|
||||
var serialized = pskl.utils.serialization.Serializer.serialize(piskel);
|
||||
|
||||
return this.save_(name, description, date, serialized);
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.save_ = function (name, description, date, serialized) {
|
||||
var deferred = Q.defer();
|
||||
var objectStore = this.db.transaction(['piskels'], 'readwrite').objectStore('piskels');
|
||||
|
||||
var getRequest = objectStore.get(name);
|
||||
getRequest.onsuccess = function (event) {
|
||||
console.log('get request successful for name: ' + name);
|
||||
var data = event.target.result;
|
||||
if (typeof data !== 'undefined') {
|
||||
|
||||
data.serialized = serialized;
|
||||
data.date = date;
|
||||
data.description = description;
|
||||
|
||||
var putRequest = objectStore.put(data);
|
||||
putRequest.onerror = function(event) {
|
||||
console.log('put request failed for name: ' + name);
|
||||
deferred.reject();
|
||||
};
|
||||
putRequest.onsuccess = function(event) {
|
||||
console.log('put request successful for name: ' + name);
|
||||
deferred.resolve();
|
||||
};
|
||||
} else {
|
||||
var request = objectStore.add({
|
||||
name: name,
|
||||
description: description,
|
||||
serialized: serialized,
|
||||
date: date
|
||||
});
|
||||
|
||||
request.onerror = function(event) {
|
||||
console.log('Failed to save a piskel');
|
||||
deferred.reject();
|
||||
};
|
||||
request.onsuccess = function(event) {
|
||||
console.log('Successfully saved a piskel');
|
||||
deferred.resolve();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
getRequest.onerror = function () {
|
||||
console.log('get request failed for name: ' + name);
|
||||
deferred.reject();
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.load = function (name) {
|
||||
var objectStore = this.db.transaction(['piskels'], 'readwrite').objectStore('piskels');
|
||||
|
||||
var getRequest = objectStore.get(name);
|
||||
getRequest.onsuccess = function (event) {
|
||||
console.log('get request successful for name: ' + name);
|
||||
var data = event.target.result;
|
||||
if (typeof data !== 'undefined') {
|
||||
var serialized = data.serialized;
|
||||
pskl.utils.serialization.Deserializer.deserialize(
|
||||
JSON.parse(serialized),
|
||||
function (piskel) {
|
||||
pskl.app.piskelController.setPiskel(piskel);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('no local browser save found for name: ' + name);
|
||||
}
|
||||
};
|
||||
|
||||
getRequest.onerror = function () {
|
||||
console.log('get request failed for name: ' + name);
|
||||
};
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.remove = function (name) {
|
||||
var objectStore = this.db.transaction(['piskels'], 'readwrite').objectStore('piskels');
|
||||
var deleteRequest = objectStore.delete(name);
|
||||
deleteRequest.onsuccess = function (event) {
|
||||
console.log('successfully deleted local browser save for name: ' + name);
|
||||
};
|
||||
|
||||
deleteRequest.onerror = function (event) {
|
||||
console.log('failed to delete local browser save for name: ' + name);
|
||||
};
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.list = function () {
|
||||
var deferred = Q.defer();
|
||||
var piskels = [];
|
||||
var objectStore = this.db.transaction(['piskels']).objectStore('piskels');
|
||||
|
||||
var cursor = objectStore.openCursor();
|
||||
cursor.onsuccess = function(event) {
|
||||
var cursor = event.target.result;
|
||||
if (cursor) {
|
||||
piskels.push({
|
||||
name: cursor.value.name,
|
||||
date: cursor.value.date,
|
||||
description: cursor.value.description
|
||||
});
|
||||
cursor.continue();
|
||||
} else {
|
||||
console.log('Cursor consumed all availabled piskels');
|
||||
deferred.resolve(piskels);
|
||||
}
|
||||
};
|
||||
|
||||
cursor.onerror = function () {
|
||||
deferred.reject();
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.getKeys = function () {
|
||||
return this.list();
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.onRequestError_ = function (event) {
|
||||
console.log('Failed to initialize IndexedDB, local browser saves will be unavailable.');
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.onRequestSuccess_ = function (event) {
|
||||
this.db = event.target.result;
|
||||
console.log('Successfully initialized IndexedDB, local browser saves are available.');
|
||||
};
|
||||
|
||||
ns.IndexedDbStorageService.prototype.onUpgradeNeeded_ = function (event) {
|
||||
// Set this.db early to allow migration scripts to access it in oncomplete.
|
||||
this.db = event.target.result;
|
||||
|
||||
// Create an object store "piskels" with the autoIncrement flag set as true.
|
||||
var objectStore = this.db.createObjectStore('piskels', { keyPath : 'name' });
|
||||
objectStore.transaction.oncomplete = function(event) {
|
||||
// Migrate existing sprites from LocalStorage
|
||||
pskl.service.storage.migrate.MigrateLocalStorageToIndexedDb.migrate().then(function () {
|
||||
console.log('Successfully migrated local storage data to indexed db');
|
||||
}).catch(function (e) {
|
||||
console.log('Failed to migrate local storage data to indexed db');
|
||||
console.error(e);
|
||||
});
|
||||
};
|
||||
};
|
||||
})();
|
|
@ -27,10 +27,15 @@
|
|||
return this.delegateSave_(pskl.app.galleryStorageService, piskel);
|
||||
};
|
||||
|
||||
// @deprecated, use saveToIndexedDb unless indexedDb is not available.
|
||||
ns.StorageService.prototype.saveToLocalStorage = function (piskel) {
|
||||
return this.delegateSave_(pskl.app.localStorageService, piskel);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.saveToIndexedDb = function (piskel) {
|
||||
return this.delegateSave_(pskl.app.indexedDbStorageService, piskel);
|
||||
};
|
||||
|
||||
ns.StorageService.prototype.saveToFileDownload = function (piskel) {
|
||||
return this.delegateSave_(pskl.app.fileDownloadStorageService, piskel);
|
||||
};
|
||||
|
@ -67,7 +72,7 @@
|
|||
// wrap in timeout in order to start saving only after event.preventDefault
|
||||
// has been done
|
||||
window.setTimeout(function () {
|
||||
this.saveToLocalStorage(this.piskelController.getPiskel());
|
||||
this.saveToIndexedDb(this.piskelController.getPiskel());
|
||||
}.bind(this), 0);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.service.storage.migrate');
|
||||
|
||||
// Simple migration helper to move local storage saves to indexed db.
|
||||
ns.MigrateLocalStorageToIndexedDb = {};
|
||||
|
||||
ns.MigrateLocalStorageToIndexedDb.migrate = function () {
|
||||
var deferred = Q.defer();
|
||||
|
||||
var localStorageService = pskl.app.localStorageService;
|
||||
var indexedDbStorageService = pskl.app.indexedDbStorageService;
|
||||
|
||||
var localStorageKeys = localStorageService.getKeys();
|
||||
var migrationData = localStorageKeys.map(function (key) {
|
||||
return {
|
||||
name: key.name,
|
||||
description: key.description,
|
||||
date: key.date,
|
||||
serialized: localStorageService.getPiskel(key.name)
|
||||
};
|
||||
});
|
||||
|
||||
// Define the sequential migration process.
|
||||
// Wait for each sprite to be saved before saving the next one.
|
||||
var success = true;
|
||||
var migrateSprite = function (index) {
|
||||
var data = migrationData[index];
|
||||
if (!data) {
|
||||
console.log('Data migration from local storage to indexed db finished.');
|
||||
if (success) {
|
||||
ns.MigrateLocalStorageToIndexedDb.deleteLocalStoragePiskels();
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
indexedDbStorageService.save_(
|
||||
data.name,
|
||||
data.description,
|
||||
data.date,
|
||||
data.serialized
|
||||
).then(function () {
|
||||
migrateSprite(index + 1);
|
||||
}).catch(function (e) {
|
||||
var success = false;
|
||||
console.error('Failed to migrate local storage sprite for name: ' + data.name);
|
||||
migrateSprite(index + 1);
|
||||
});
|
||||
};
|
||||
|
||||
// Start the migration.
|
||||
migrateSprite(0);
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ns.MigrateLocalStorageToIndexedDb.deleteLocalStoragePiskels = function () {
|
||||
var localStorageKeys = pskl.app.localStorageService.getKeys();
|
||||
|
||||
// Remove all sprites.
|
||||
localStorageKeys.forEach(function (key) {
|
||||
window.localStorage.removeItem('piskel.' + key.name);
|
||||
});
|
||||
|
||||
// Remove keys.
|
||||
window.localStorage.removeItem('piskel.keys');
|
||||
};
|
||||
|
||||
})();
|
|
@ -168,8 +168,10 @@
|
|||
"js/widgets/Wizard.js",
|
||||
|
||||
// Services
|
||||
"js/service/storage/migrate/MigrateLocalStorageToIndexedDb.js",
|
||||
"js/service/storage/StorageService.js",
|
||||
"js/service/storage/FileDownloadStorageService.js",
|
||||
"js/service/storage/IndexedDbStorageService.js",
|
||||
"js/service/storage/LocalStorageService.js",
|
||||
"js/service/storage/GalleryStorageService.js",
|
||||
"js/service/storage/DesktopStorageService.js",
|
||||
|
|
Loading…
Reference in a new issue