offline-editor-js/lib/edit/attachmentsStore.js
2015-03-27 17:58:25 -06:00

321 lines
11 KiB
JavaScript

/*global IDBKeyRange,indexedDB */
"use strict";
O.esri.Edit.AttachmentsStore = function () {
this._db = null;
var DB_NAME = "attachments_store";
var OBJECT_STORE_NAME = "attachments";
this.isSupported = function () {
if (!window.indexedDB) {
return false;
}
return true;
};
this.store = function (featureLayerUrl, attachmentId, objectId, attachmentFile, callback) {
try {
// first of all, read file content
this._readFile(attachmentFile, function (fileContent) {
// now, store it in the db
var newAttachment =
{
id: attachmentId,
objectId: objectId,
featureId: featureLayerUrl + "/" + objectId,
contentType: attachmentFile.type,
name: attachmentFile.name,
size: attachmentFile.size,
url: this._createLocalURL(attachmentFile),
content: fileContent
};
var transaction = this._db.transaction([OBJECT_STORE_NAME], "readwrite");
transaction.oncomplete = function (event) {
callback(true, newAttachment);
};
transaction.onerror = function (event) {
callback(false, event.target.error.message);
};
var objectStore = transaction.objectStore(OBJECT_STORE_NAME);
var request = objectStore.put(newAttachment);
request.onsuccess = function (event) {
//console.log("item added to db " + event.target.result);
};
}.bind(this));
}
catch (err) {
console.log("AttachmentsStore: " + err.stack);
callback(false, err.stack);
}
};
this.retrieve = function (attachmentId, callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var objectStore = this._db.transaction([OBJECT_STORE_NAME]).objectStore(OBJECT_STORE_NAME);
var request = objectStore.get(attachmentId);
request.onsuccess = function (event) {
var result = event.target.result;
if (!result) {
callback(false, "not found");
}
else {
callback(true, result);
}
};
request.onerror = function (err) {
console.log(err);
callback(false, err);
};
};
this.getAttachmentsByFeatureId = function (featureLayerUrl, objectId, callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var featureId = featureLayerUrl + "/" + objectId;
var attachments = [];
var objectStore = this._db.transaction([OBJECT_STORE_NAME]).objectStore(OBJECT_STORE_NAME);
var index = objectStore.index("featureId");
var keyRange = IDBKeyRange.only(featureId);
index.openCursor(keyRange).onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
attachments.push(cursor.value);
cursor.continue();
}
else {
callback(attachments);
}
};
};
this.getAttachmentsByFeatureLayer = function (featureLayerUrl, callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var attachments = [];
var objectStore = this._db.transaction([OBJECT_STORE_NAME]).objectStore(OBJECT_STORE_NAME);
var index = objectStore.index("featureId");
var keyRange = IDBKeyRange.bound(featureLayerUrl + "/", featureLayerUrl + "/A");
index.openCursor(keyRange).onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
attachments.push(cursor.value);
cursor.continue();
}
else {
callback(attachments);
}
};
};
this.getAllAttachments = function (callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var attachments = [];
var objectStore = this._db.transaction([OBJECT_STORE_NAME]).objectStore(OBJECT_STORE_NAME);
objectStore.openCursor().onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
attachments.push(cursor.value);
cursor.continue();
}
else {
callback(attachments);
}
};
};
this.deleteAttachmentsByFeatureId = function (featureLayerUrl, objectId, callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var featureId = featureLayerUrl + "/" + objectId;
var objectStore = this._db.transaction([OBJECT_STORE_NAME], "readwrite").objectStore(OBJECT_STORE_NAME);
var index = objectStore.index("featureId");
var keyRange = IDBKeyRange.only(featureId);
var deletedCount = 0;
index.openCursor(keyRange).onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
var attachment = cursor.value;
this._revokeLocalURL(attachment);
objectStore.delete(cursor.primaryKey);
deletedCount++;
cursor.continue();
}
else {
setTimeout(function () {
callback(deletedCount);
}, 0);
}
}.bind(this);
};
this.delete = function (attachmentId, callback) {
console.assert(this._db !== null, "indexeddb not initialized");
// before deleting an attachment we must revoke the blob URL that it contains
// in order to free memory in the browser
this.retrieve(attachmentId, function (success, attachment) {
if (!success) {
callback(false, "attachment " + attachmentId + " not found");
return;
}
this._revokeLocalURL(attachment);
var request = this._db.transaction([OBJECT_STORE_NAME], "readwrite")
.objectStore(OBJECT_STORE_NAME)
.delete(attachmentId);
request.onsuccess = function (event) {
setTimeout(function () {
callback(true);
}, 0);
};
request.onerror = function (err) {
callback(false, err);
};
}.bind(this));
};
this.deleteAll = function (callback) {
console.assert(this._db !== null, "indexeddb not initialized");
this.getAllAttachments(function (attachments) {
attachments.forEach(function (attachment) {
this._revokeLocalURL(attachment);
}, this);
var request = this._db.transaction([OBJECT_STORE_NAME], "readwrite")
.objectStore(OBJECT_STORE_NAME)
.clear();
request.onsuccess = function (event) {
setTimeout(function () {
callback(true);
}, 0);
};
request.onerror = function (err) {
callback(false, err);
};
}.bind(this));
};
this.replaceFeatureId = function (featureLayerUrl, oldId, newId, callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var featureId = featureLayerUrl + "/" + oldId;
var objectStore = this._db.transaction([OBJECT_STORE_NAME], "readwrite").objectStore(OBJECT_STORE_NAME);
var index = objectStore.index("featureId");
var keyRange = IDBKeyRange.only(featureId);
var replacedCount = 0;
index.openCursor(keyRange).onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
var newFeatureId = featureLayerUrl + "/" + newId;
var updated = cursor.value;
updated.featureId = newFeatureId;
updated.objectId = newId;
objectStore.put(updated);
replacedCount++;
cursor.continue();
}
else {
// allow time for all changes to persist...
setTimeout(function () {
callback(replacedCount);
}, 1);
}
};
};
this.getUsage = function (callback) {
console.assert(this._db !== null, "indexeddb not initialized");
var usage = {sizeBytes: 0, attachmentCount: 0};
var transaction = this._db.transaction([OBJECT_STORE_NAME])
.objectStore(OBJECT_STORE_NAME)
.openCursor();
console.log("dumping keys");
transaction.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
console.log(cursor.value.id, cursor.value.featureId, cursor.value.objectId);
var storedObject = cursor.value;
var json = JSON.stringify(storedObject);
usage.sizeBytes += json.length;
usage.attachmentCount += 1;
cursor.continue();
}
else {
callback(usage, null);
}
}.bind(this);
transaction.onerror = function (err) {
callback(null, err);
};
};
// internal methods
this._readFile = function (attachmentFile, callback) {
var reader = new FileReader();
reader.onload = function (evt) {
callback(evt.target.result);
};
reader.readAsBinaryString(attachmentFile);
};
this._createLocalURL = function (attachmentFile) {
return window.URL.createObjectURL(attachmentFile);
};
this._revokeLocalURL = function (attachment) {
window.URL.revokeObjectURL(attachment.url);
};
this.init = function (callback) {
console.log("init AttachmentStore");
var request = indexedDB.open(DB_NAME, 11);
callback = callback || function (success) {
console.log("AttachmentsStore::init() success:", success);
}.bind(this);
request.onerror = function (event) {
console.log("indexedDB error: " + event.target.errorCode);
callback(false, event.target.errorCode);
}.bind(this);
request.onupgradeneeded = function (event) {
var db = event.target.result;
if (db.objectStoreNames.contains(OBJECT_STORE_NAME)) {
db.deleteObjectStore(OBJECT_STORE_NAME);
}
var objectStore = db.createObjectStore(OBJECT_STORE_NAME, {keyPath: "id"});
objectStore.createIndex("featureId", "featureId", {unique: false});
}.bind(this);
request.onsuccess = function (event) {
this._db = event.target.result;
console.log("database opened successfully");
callback(true);
}.bind(this);
};
};