not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

498 lines
12 KiB

define(["sugar-web/bus", "sugar-web/env"], function(bus, env) {
'use strict';
var datastore = {};
var html5storage = {};
var html5indexedDB = {};
var datastorePrefix = 'sugar_datastore_';
var filestoreName = 'sugar_filestore';
var initialized = false;
var pending = 0;
var waiter = null;
//- Utility function
// Get parameter from query string
datastore.getUrlParameter = function(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
};
// Create a uuid
datastore.createUUID = function() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4";
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
};
// Callback checker
datastore.callbackChecker = function(callback) {
if (callback === undefined || callback === null) {
callback = function() {};
}
return callback;
};
// Handle pending requests
function addPending() {
pending++;
}
function removePending() {
if (--pending == 0 && waiter) {
waiter();
waiter = null;
}
}
function waitPending(callback) {
setTimeout(function(){
if (pending == 0) {
if (callback) {
callback()
}
} else {
waiter = callback;
}
}, 50);
}
//- Static Datastore methods
// Create a new datastore entry
datastore.create = function(metadata, callback, text) {
var callback_c = datastore.callbackChecker(callback);
var objectId = datastore.createUUID();
if (text !== undefined) {
metadata["textsize"] = text.length;
}
var sugar_settings = html5storage.getValue("sugar_settings");
if (sugar_settings) {
metadata["buddy_name"] = sugar_settings.name;
metadata["buddy_color"] = sugar_settings.colorvalue;
}
if (html5storage.setValue(datastorePrefix + objectId, {
metadata: metadata,
text: (text === undefined) ? null : { link: objectId }
})) {
if (text !== undefined) {
html5indexedDB.setValue(objectId, text, function(err) {
if (err) {
callback_c(-1, null);
} else {
callback_c(null, objectId);
}
});
} else {
callback_c(null, objectId);
}
} else {
callback_c(-1, null);
}
}
// Find entries matching an activity type
datastore.find = function(id) {
var results = [];
if (!html5storage.test())
return results;
for (var key in html5storage.getAll()) {
if (key.substr(0, datastorePrefix.length) == datastorePrefix) {
var entry = html5storage.getValue(key);
entry.objectId = key.substr(datastorePrefix.length);
if (id === undefined || entry.metadata.activity == id) {
results.push(entry);
}
}
}
return results;
}
// Remove an entry in the datastore
datastore.remove = function(objectId, then) {
html5storage.removeValue(datastorePrefix + objectId);
html5indexedDB.removeValue(objectId, then);
}
// Wait for pending save actions
datastore.waitPendingSave = function(callback) {
waitPending(callback);
};
//- Instance datastore methods
function DatastoreObject(objectId) {
this.objectId = objectId;
this.newMetadata = {};
this.newDataAsText = null;
this.toload = false;
// Init environment from query string values
if (!initialized) {
env.getEnvironment(function() {
initialized = true;
});
}
// Init or create objectId if need
var that = this;
if (this.objectId === undefined) {
var env_objectId = window.top.sugar.environment.objectId;
if (env_objectId != null) {
this.objectId = env_objectId;
this.toload = true;
}
}
}
// Load metadata
DatastoreObject.prototype.getMetadata = function(callback) {
var callback_c = datastore.callbackChecker(callback);
var result = html5storage.getValue(datastorePrefix + this.objectId);
if (result != null) {
this.setMetadata(result.metadata);
this.toload = false;
callback_c(null, result.metadata);
}
};
// Load text
DatastoreObject.prototype.loadAsText = function(callback) {
var callback_c = datastore.callbackChecker(callback);
var that = this;
var result = html5storage.getValue(datastorePrefix + that.objectId);
if (result != null) {
that.setMetadata(result.metadata);
var text = null;
if (result.text) {
html5indexedDB.getValue(that.objectId, function(err, text) {
if (err) {
callback_c(-1, null, null);
} else {
that.setDataAsText(text);
that.toload = false;
callback_c(null, result.metadata, text);
}
});
} else {
that.toload = false;
callback_c(null, result.metadata, text);
}
}
};
// Set metadata
DatastoreObject.prototype.setMetadata = function(metadata) {
for (var key in metadata) {
this.newMetadata[key] = metadata[key];
}
};
// Set text
DatastoreObject.prototype.setDataAsText = function(text) {
this.newDataAsText = text;
};
// Save data
DatastoreObject.prototype.save = function(callback, dontupdatemetadata) {
addPending();
if (this.objectId === undefined) {
var that = this;
this.newMetadata["timestamp"] = this.newMetadata["creation_time"] = new Date().getTime();
this.newMetadata["file_size"] = 0;
datastore.create(this.newMetadata, function(error, oid) {
if (error == null) {
that.objectId = oid;
}
});
} else {
if (this.toload) {
this.getMetadata(null);
this.toload = false;
}
}
var callback_c = datastore.callbackChecker(callback);
if (!dontupdatemetadata) {
this.newMetadata["timestamp"] = new Date().getTime();
}
var sugar_settings = html5storage.getValue("sugar_settings");
if (sugar_settings && !dontupdatemetadata) {
this.newMetadata["buddy_name"] = sugar_settings.name;
this.newMetadata["buddy_color"] = sugar_settings.colorvalue;
}
if (this.newDataAsText != null) {
if (!dontupdatemetadata) {
this.newMetadata["textsize"] = this.newDataAsText.length;
}
}
var that = this;
if (html5storage.setValue(datastorePrefix + this.objectId, {
metadata: this.newMetadata,
text: (this.newDataAsText === undefined) ? null : { link: this.objectId }
})) {
if (this.newDataAsText != null) {
html5indexedDB.setValue(that.objectId, this.newDataAsText, function(err) {
if (err) {
callback_c(-1, null, null);
} else {
callback_c(null, that.newMetadata, that.newDataAsText);
}
removePending();
});
} else {
callback_c(null, this.newMetadata, this.newDataAsText);
removePending();
}
} else {
callback_c(-1, null);
removePending();
}
};
datastore.DatastoreObject = DatastoreObject;
datastore.localStorage = html5storage;
datastore.indexedDB = html5indexedDB;
// -- HTML5 local storage handling
// Load storage - Need for Chrome App
html5storage.load = function(then) {
if (then) {
then();
}
};
html5storage.load();
// Test if HTML5 storage is available
html5storage.test = function() {
return (typeof(Storage) !== "undefined" && typeof(window.localStorage) !== "undefined");
};
// Set a value in the storage
html5storage.setValue = function(key, value) {
if (this.test()) {
try {
window.localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (err) {
console.log("ERROR: Unable to update local storage");
return false;
}
}
};
// Get a value in the storage
html5storage.getValue = function(key) {
if (this.test()) {
try {
return JSON.parse(window.localStorage.getItem(key));
} catch (err) {
return null;
}
}
return null;
};
// Remove a value in the storage
html5storage.removeValue = function(key) {
if (this.test()) {
try {
window.localStorage.removeItem(key);
} catch (err) {}
}
};
// Get all values
html5storage.getAll = function() {
if (this.test()) {
try {
return window.localStorage;
} catch (err) {
return null;
}
}
return null;
};
// -- HTML5 IndexedDB handling
html5indexedDB.db = null;
// Test indexedDB support
html5indexedDB.test = function() {
return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
}
// Load database or create database on first launch
html5indexedDB.load = function(then) {
if (html5indexedDB.db != null) {
then(null);
return;
}
if (!html5indexedDB.test()) {
if (then) {
then(-1);
}
return;
}
var request = window.indexedDB.open(filestoreName, 1);
request.onerror = function(event) {
if (then) {
then(-2);
}
};
request.onsuccess = function(event) {
html5indexedDB.db = request.result;
if (then) {
then(null);
}
};
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore(filestoreName, {keyPath: "objectId"});
objectStore.createIndex("objectId", "objectId", { unique: true });
};
}
// Set a value in the database
function indexedDB_setValue(key, value, then) {
var transaction = html5indexedDB.db.transaction([filestoreName], "readwrite");
var objectStore = transaction.objectStore(filestoreName);
var request = objectStore.put({objectId: key, text: value});
request.onerror = function(event) {
if (then) {
then(request.errorCode);
}
};
request.onsuccess = function(event) {
if (then) {
then(null);
}
};
}
html5indexedDB.setValue = function(key, value, then) {
if (html5indexedDB.db == null) {
html5indexedDB.load(function(err) {
if (err) {
console.log("FATAL ERROR: indexedDB not supported, could be related to use of private mode");
} else {
indexedDB_setValue(key, value, then);
}
});
} else {
indexedDB_setValue(key, value, then);
}
};
// Get a value from the database
function indexedDB_getValue(key, then) {
var transaction = html5indexedDB.db.transaction([filestoreName], "readonly");
var objectStore = transaction.objectStore(filestoreName);
var request = objectStore.get(key);
request.onerror = function(event) {
if (then) {
then(request.errorCode, null);
}
};
request.onsuccess = function(event) {
if (then) {
then(null, request.result?request.result.text:null);
}
};
}
html5indexedDB.getValue = function(key, then) {
if (html5indexedDB.db == null) {
html5indexedDB.load(function(err) {
if (err) {
console.log("FATAL ERROR: indexedDB not supported, could be related to use of private mode");
} else {
indexedDB_getValue(key, then);
}
});
} else {
indexedDB_getValue(key, then);
}
};
// Get all existing keys in the database
function indexedDB_getAll(then) {
var transaction = html5indexedDB.db.transaction([filestoreName], "readonly");
var objectStore = transaction.objectStore(filestoreName);
var request = objectStore.openCursor();
var keys = [];
request.onerror = function(event) {
if (then) {
then(request.errorCode, null);
}
};
request.onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
keys.push(cursor.key);
cursor.continue();
} else {
if (then) {
then(null, keys);
}
}
};
}
html5indexedDB.getAll = function(then) {
if (html5indexedDB.db == null) {
html5indexedDB.load(function(err) {
if (err) {
console.log("FATAL ERROR: indexedDB not supported, could be related to use of private mode");
} else {
indexedDB_getAll(then);
}
});
} else {
indexedDB_getAll(then);
}
};
// Remove a value from the database
function indexedDB_removeValue(key, then) {
var transaction = html5indexedDB.db.transaction([filestoreName], "readwrite");
var objectStore = transaction.objectStore(filestoreName);
var request = objectStore.delete(key);
request.onerror = function(event) {
if (then) {
then(request.errorCode);
}
};
request.onsuccess = function(event) {
if (then) {
then(null);
}
};
}
html5indexedDB.removeValue = function(key, then) {
if (html5indexedDB.db == null) {
html5indexedDB.load(function(err) {
if (err) {
console.log("FATAL ERROR: indexedDB not supported, could be related to use of private mode");
} else {
indexedDB_removeValue(key, then);
}
});
} else {
indexedDB_removeValue(key, then);
}
};
return datastore;
});