This commit is contained in:
Alan Kligman 2013-05-30 14:57:33 -04:00
parent c80a08bb07
commit 14759635c0
14 changed files with 4509 additions and 63 deletions

View File

@ -0,0 +1,163 @@
#indexedDBViewer {
padding: 0px;
margin: 0px;
font-family: Courier;
font-size: 12px;
width: 100%;
position: absolute;
bottom: 0px;
right: 0px;
height: 100%;
z-index: 999999;
background-color: lightgray;
overflow: hidden;
}
#indexedDBViewer li {
padding: 0px;
margin: 0px;
list-style: none;
}
#indexedDBViewer ul {
list-style: none;
margin: 0px;
padding: 0px 0px 0px 15px;
}
#indexedDBViewer h1 {
padding: 0px 0px 5px 0px;
margin: 0px;
font-size: 14px;
}
#indexedDBViewerHeader {
height: 15px;
width: 100%;
cursor: row-resize;
text-align: right;
}
#indexedDBViewerHeader span {
cursor: pointer;
height: 13px;
width: 13px;
padding-left: 0px;
padding-right: 0px;
border: 1px solid black;
display: inline-block;
text-align: center;
}
#indexedDBViewerNavigation {
display: inline-block;
height: 100%;
width: auto;
min-width: 200px;
vertical-align: top;
padding: 2px 2px 2px 2px;
overflow: auto;
}
#indexedDBViewerContent {
display: inline-block;
height: 100%;
width: auto;
min-width: 400px;
vertical-align: top;
padding: 2px 2px 2px 12px;
overflow: auto;
}
#indexedDBViewerContentObjectStoresTable {
width: 100%
}
#indexedDBViewerContentObjectStoresRowHeaderName {
width: auto;
min-width: 100px;
text-align: left;
}
#indexedDBViewerContentObjectStoresRowHeaderKeyPath {
width: 100px;
text-align: left;
}
#indexedDBViewerContentObjectStoresRowHeaderAutoIncrement {
width: 100px;
text-align: left;
}
#indexedDBViewerContentIndexTable {
width: 100%
}
#indexedDBViewerContentIndexRowHeaderName {
width: auto;
min-width: 150px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderKeyPath {
width: auto;
min-width: 100px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderObjectStore {
width: auto;
min-width: 100px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderMultiEntry {
width: 100px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderUnique {
width: 100px;
text-align: left;
}
#indexedDBViewerContentObjectStoreRowHeaderKey {
width: auto;
min-width: 100px;
text-align: left;
}
#indexedDBViewerContentObjectStoreRowHeaderValue {
width: auto;
min-width: 400px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderKey {
width: auto;
min-width: 100px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderPrimaryKey {
width: auto;
min-width: 100px;
text-align: left;
}
#indexedDBViewerContentIndexRowHeaderValue {
width: auto;
min-width: 400px;
text-align: left;
}
#indexedDBViewerContentObjectStoreTable td, #indexedDBViewerContentIndexTable td {
vertical-align: top;
text-align: left;
padding: 0px;
margin: 0px;
}
#indexedDBViewer .clickable {
cursor: pointer;
}

317
examples/IndexedDBViewer.js Normal file
View File

@ -0,0 +1,317 @@
/// <reference path="jquery-1.7.2.js" />
/// <reference path="Linq2IndexedDB.js" />
$(function () {
function initializeViewer() {
var placeholder = $("#indexedDBViewer");
var dbName = placeholder.attr("data-dbName");
createHeader('indexedDBViewerHeader', placeholder);
var navigation = retrieveOrCreateElement('indexedDBViewerNavigation', 'div', placeholder);
var menu = retrieveOrCreateElement('indexedDBViewerMenu', 'ul', navigation);
var menuOverview = expandableListItem('indexedDBViewerMenuOverview', dbName, menu, viewDb, { dbName: dbName, objectStore: null, index: null });
navigation.addClass('nav');
linq2indexedDB.prototype.core.db(dbName).then(function () {
var connection = arguments[0][0];
linq2indexedDB.prototype.core.dbStructureChanged.addListener(linq2indexedDB.prototype.core.databaseEvents.databaseBlocked, function () {
connection.close();
});
var menuObjectStores = retrieveOrCreateElement('indexedDBViewerMenuObjectStores', 'ul', menuOverview);
for (var i = 0; i < connection.objectStoreNames.length; i++) {
var storeName = connection.objectStoreNames[i];
var menuObjectStore = expandableListItem('indexedDBViewerMenuObjectStore' + storeName, storeName, menuObjectStores, viewDb, { dbName: dbName, objectStore: storeName, index: null });
linq2indexedDB.prototype.core.objectStore(linq2indexedDB.prototype.core.transaction(connection, storeName, linq2indexedDB.prototype.core.transactionTypes.READ_ONLY, false), storeName).then(function (args) {
var store = args[1];
var menuObjectStore = retrieveOrCreateElement('indexedDBViewerMenuObjectStore' + storeName, 'li', menuObjectStores);
var menuIndexes = retrieveOrCreateElement('indexedDBViewerMenuObjectStore' + store.name + 'Indexes', 'ul', menuObjectStore);
for (var j = 0; j < store.indexNames.length; j++) {
var indexName = store.indexNames[i];
expandableListItem('indexedDBViewerMenuObjectStore' + store.name + 'Index' + indexName, indexName, menuIndexes, viewDb, { dbName: dbName, objectStore: store.name, index: indexName });
}
});
}
}, null, function (args) {
if (args[1].type == "upgradeneeded") {
args[0].abort();
}
});
}
function viewDb(e) {
var dbName = e.data.dbName;
var objectStore = e.data.objectStore;
var index = e.data.index;
var content = retrieveOrCreateElement('indexedDBViewerContent', 'div', $("#indexedDBViewer"));
content.empty();
if (objectStore != null) {
if (index != null) {
retrieveOrCreateElement('indexedDBViewerContentGeneral', 'h1', content).text(index);
}
else {
retrieveOrCreateElement('indexedDBViewerContentGeneral', 'h1', content).text(objectStore);
}
}
linq2indexedDB.prototype.core.db(dbName).then(function () {
var connection = arguments[0][0];
if (objectStore == null) {
retrieveOrCreateElement('indexedDBViewerContentGeneral', 'h1', content).text("General");
retrieveOrCreateElement('indexedDBViewerContentGeneralName', 'span', content).text("Name: " + connection.name);
content.append("<br/>");
retrieveOrCreateElement('indexedDBViewerContentGeneralVersion', 'span', content).text("Version: " + connection.version);
content.append("<br/>");
content.append("<br/>");
retrieveOrCreateElement('indexedDBViewerContentObjectStores', 'h1', content).text("Object stores");
retrieveOrCreateElement('indexedDBViewerContentObjectStoresTable', 'table', content);
content.append("<br/>");
content.append("<br/>");
retrieveOrCreateElement('indexedDBViewerContentIndex', 'h1', content).text("Indexes");
retrieveOrCreateElement('indexedDBViewerContentIndexTable', 'table', content);
content.append("<br/>");
}
linq2indexedDB.prototype.core.dbStructureChanged.addListener(linq2indexedDB.prototype.core.databaseEvents.databaseBlocked, function () {
connection.close();
});
for (var i = 0; i < connection.objectStoreNames.length; i++) {
var storeName = connection.objectStoreNames[i];
linq2indexedDB.prototype.core.objectStore(linq2indexedDB.prototype.core.transaction(connection, storeName, linq2indexedDB.prototype.core.transactionTypes.READ_ONLY, false), storeName).then(function (args) {
var store = args[1];
if (objectStore == null) {
viewObjectStoreDefinition(store.name, store.keyPath, store.autoIncrement, content);
}
else {
if (index == null && store.name == objectStore) {
linq2indexedDB.prototype.core.cursor(store).then(function () {
}, function () {
}, function (args1) {
var keyValue = args1[0];
viewObjectStoreData(keyValue.key, keyValue.data, content);
});
}
}
for (var j = 0; j < store.indexNames.length; j++) {
linq2indexedDB.prototype.core.index(store, store.indexNames[j], false).then(function (args1) {
var ix = args1[1];
if (objectStore == null) {
viewIndexDefinition(ix.name, ix.keyPath, ix.objectStore.name, ix.multiEntry || ix.multiRow, ix.unique, content);
}
else {
if (index != null && ix.name == index) {
linq2indexedDB.prototype.core.cursor(ix).then(function () {
var x = 1;
}, function () {
}, function (args1) {
var keyValue = args1[0];
viewIndexData(args1[1].key, args1[1].primaryKey, keyValue.data, content);
});
}
}
});
}
});
}
});
}
function viewObjectStoreDefinition(name, keyPath, autoIncrement, parent) {
var table = retrieveOrCreateElement('indexedDBViewerContentObjectStoresTable', 'table', parent);
var headerRow = retrieveOrCreateElement('indexedDBViewerContentObjectStoresRowHeader', 'tr', table);
retrieveOrCreateElement('indexedDBViewerContentObjectStoresRowHeaderName', 'th', headerRow).text("name");
retrieveOrCreateElement('indexedDBViewerContentObjectStoresRowHeaderKeyPath', 'th', headerRow).text("keyPath");
retrieveOrCreateElement('indexedDBViewerContentObjectStoresRowHeaderAutoIncrement', 'th', headerRow).text("autoIncrement");
var dataRow = retrieveOrCreateElement('indexedDBViewerContentObjectStoresRow' + name, 'tr', table);
retrieveOrCreateElement('indexedDBViewerContentObjectStoresRow' + name + 'Name', 'td', dataRow).text(name);
retrieveOrCreateElement('indexedDBViewerContentObjectStoresRow' + name + 'KeyPath', 'td', dataRow).text(keyPath);
retrieveOrCreateElement('indexedDBViewerContentObjectStoresRow' + name + 'AutoIncrement', 'td', dataRow).text(autoIncrement);
}
function viewIndexDefinition(name, keyPath, objectStore, multiEntry, unique, parent) {
var table = retrieveOrCreateElement('indexedDBViewerContentIndexTable', 'table', parent);
var headerRow = retrieveOrCreateElement('indexedDBViewerContentIndexRowHeader', 'tr', table);
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderName', 'th', headerRow).text("name");
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderKeyPath', 'th', headerRow).text("keyPath");
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderObjectStore', 'th', headerRow).text("objectStore");
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderMultiEntry', 'th', headerRow).text("multiEntry");
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderUnique', 'th', headerRow).text("unique");
var dataRow = retrieveOrCreateElement('indexedDBViewerContentIndexRow' + name, 'tr', table);
retrieveOrCreateElement('indexedDBViewerContentIndexRow' + name + 'Name', 'td', dataRow).text(name);
retrieveOrCreateElement('indexedDBViewerContentIndexRow' + name + 'KeyPath', 'td', dataRow).text(keyPath);
retrieveOrCreateElement('indexedDBViewerContentIndexRow' + name + 'ObjectStore', 'td', dataRow).text(objectStore);
retrieveOrCreateElement('indexedDBViewerContentIndexRow' + name + 'MultiEntry', 'td', dataRow).text(multiEntry);
retrieveOrCreateElement('indexedDBViewerContentIndexRow' + name + 'Unique', 'td', dataRow).text(unique);
}
function viewObjectStoreData(key, value, parent) {
var table = retrieveOrCreateElement('indexedDBViewerContentObjectStoreTable', 'table', parent);
var headerRow = retrieveOrCreateElement('indexedDBViewerContentObjectStoreRowHeader', 'tr', table);
retrieveOrCreateElement('indexedDBViewerContentObjectStoreRowHeaderKey', 'th', headerRow).text("key");
retrieveOrCreateElement('indexedDBViewerContentObjectStoreRowHeaderValue', 'th', headerRow).text("value");
var dataRow = retrieveOrCreateElement('indexedDBViewerContentObjectStoreRow' + key, 'tr', table);
viewData(key, retrieveOrCreateElement('indexedDBViewerContentObjectStoreRow' + key + 'Key', 'td', dataRow));
viewData(value, retrieveOrCreateElement('indexedDBViewerContentObjectStoreRow' + key + 'Value', 'td', dataRow));
}
function viewIndexData(key, primaryKey, value, parent) {
var table = retrieveOrCreateElement('indexedDBViewerContentIndexTable', 'table', parent);
var headerRow = retrieveOrCreateElement('indexedDBViewerContentIndexRowHeader', 'tr', table);
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderKey', 'th', headerRow).text("key");
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderPrimaryKey', 'th', headerRow).text("primary key");
retrieveOrCreateElement('indexedDBViewerContentIndexRowHeaderValue', 'th', headerRow).text("value");
var dataRow = retrieveOrCreateElement('indexedDBViewerContentIndexRow' + primaryKey, 'tr', table);
viewData(key, retrieveOrCreateElement('indexedDBViewerContentIndexRow' + primaryKey + 'Key', 'td', dataRow));
viewData(primaryKey, retrieveOrCreateElement('indexedDBViewerContentIndexRow' + primaryKey + 'PrimaryKey', 'td', dataRow));
viewData(value, retrieveOrCreateElement('indexedDBViewerContentIndexRow' + primaryKey + 'Value', 'td', dataRow));
}
function viewData(value, parent, propName) {
var text;
if (propName) {
text = propName + value;
}
else {
parent = retrieveOrCreateElement(null, 'ul', parent);
text = value;
}
if (typeof (value) === "object" && !(value instanceof Date)) {
var object = expandableListItem(null, text, parent);
var properties = retrieveOrCreateElement(null, 'ul', object);
for (prop in value) {
viewData(value[prop], properties, prop + ": ");
}
object.find('.expendable')[0].click();
}
else {
retrieveOrCreateElement(null, 'li', parent).text(text);
}
}
function expandableListItem(id, text, parent, clickEvent, clickEventData) {
var li = retrieveOrCreateElement(id, 'li', parent);
var col = retrieveOrCreateElement(null, 'span', li);
col.text(' - ');
col.data('status', 'open');
col.click(function () {
if ($(this).data('status') == 'closed') {
$($($(this)[0].parentElement).find('ul')[0]).show();
col.text(' - ');
col.data('status', 'open');
}
else if ($(this).data('status') == 'open') {
$($($(this)[0].parentElement).find('ul')[0]).hide();
col.text(' + ');
col.data('status', 'closed');
}
});
col.addClass("clickable");
col.addClass("expendable");
var item = retrieveOrCreateElement(null, 'span', li);
item.text(text);
if (clickEvent) {
item.click(clickEventData, clickEvent);
item.addClass("clickable");
}
return li;
}
function createHeader(id, parent) {
var header = retrieveOrCreateElement(id, 'div', parent);
var col = retrieveOrCreateElement(null, 'span', header);
col.text(' - ');
col.data('status', 'open');
col.addClass("clickable");
col.addClass("expendable");
col.click(function () {
if ($(this).data('status') == 'closed') {
$('#indexedDBViewer').height(170);
$('#indexedDBViewer').width('100%');
$('#indexedDBViewerNavigation').show();
$('#indexedDBViewerContent').show();
col.text(' - ');
col.data('status', 'open');
}
else if ($(this).data('status') == 'open') {
$('#indexedDBViewer').height($(this).outerHeight());
$('#indexedDBViewer').width($(this).outerWidth());
$('#indexedDBViewerNavigation').hide();
$('#indexedDBViewerContent').hide();
col.text(' + ');
col.data('status', 'closed');
}
});
}
function retrieveOrCreateElement(id, element, parent) {
var el;
if (id && id != null && id != '') {
if ($('#' + id).length > 0) {
el = $('#' + id);
} else {
el = $('<' + element + ' id="' + id + '"></' + element + '>');
parent.append(el);
}
}
else {
el = $('<' + element + '></' + element + '>');
parent.append(el);
}
return el;
}
initializeViewer();
// mousedown, mousemove, mouseup and mouseleave for resizing the placeholder
$(window).bind('mousedown', function (event) {
var location = $(window).height() - $("#indexedDBViewer").height();
if ((location - 2) <= event.pageY && event.pageY <= (location + 5)) {
$(window).bind('mousemove', resize);
}
});
$(window).bind('mouseup', function () {
$(window).unbind('mousemove', resize);
});
$(window).bind('mouseleave', function () {
$(window).unbind('mousemove', resize);
});
function resize(event) {
var pageHeight = $(window).height();
if (pageHeight - event.pageY >= 50) {
$("#indexedDBViewer").height(pageHeight - event.pageY);
var height = $("#indexedDBViewer").height() - $("#indexedDBViewerHeader").height();
$("#indexedDBViewerNavigation").height(height);
$("#indexedDBViewerContent").height(height);
}
}
});

Binary file not shown.

3377
examples/Linq2IndexedDB.js Normal file

File diff suppressed because it is too large Load Diff

15
examples/crypto-test.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="stdout"></div>
</body>
<script src="../lib/crypto-js/rollups/sha256.js"></script>
<script>
console.log(CryptoJS.SHA256('/').toString(CryptoJS.enc.hex));
</script>
</html>

View File

@ -16,45 +16,70 @@ require.config({
} }
}); });
require(["src/indexeddb"], function(idb) { require(["src/indexeddb2"], function(idb) {
var db; var opened = idb.open('test').then(
idb.open('test').then(
function(event) { function(event) {
db = event.target.result; return event.db;
var transaction = db.transaction(['FILES'], 'readwrite');
var files = transaction.objectStore('FILES');
return files.clear();
}, },
function(event) { function(event) {
console.error('error:', event); console.error('error:', event);
}, },
function(event) { function(event) {
if('upgradeneeded' == event.type) {
db = event.target.result; db = event.target.result;
if(db.objectStoreNames().contains('FILES')) { if(db.objectStoreNames.contains('FILES')) {
db.deleteObjectStore('FILES'); db.deleteObjectStore('FILES');
} }
var files = db.createObjectStore('FILES'); var files = db.createObjectStore('FILES');
} }
).then( }
);
opened.then(
function(db) {
console.log(db);
}
);
/*
var db = idb.open('test');
db.progress(
function(event) { function(event) {
var transaction = db.transaction(['FILES'], 'readwrite'); if('upgradeneeded' == event.type) {
db = event.target.result;
if(db.objectStoreNames.contains('FILES')) {
db.deleteObjectStore('FILES');
}
var files = db.createObjectStore('FILES');
}
}
);
db.otherwise(
function(event) {
console.error('error:', event);
}
);
db.transaction(['FILES'], 'readwrite')(
function(transaction) {
var files = transaction.objectStore('FILES'); var files = transaction.objectStore('FILES');
return files.put('value', 'key'); return files.clear();
} }
).then( ).transaction(['FILES'], 'readonly')(
function(event) { function(transaction) {
var transaction = db.transaction(['FILES'], 'readwrite');
var files = transaction.objectStore('FILES');
return files.get('key');
} }
).then( );
function(event) {
console.info('result', event.target.result); db.transaction(['FILES'], 'readwrite')(
function(transaction) {
} }
).otherwise(function(event) { );
console.error('error: ', event);
}); */
}); });

6
examples/jquery-1.10.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="stdout"></div>
</body>
<script src="../lib/require.js"></script>
<script>
require.config({
baseUrl: "../lib",
paths: {
"src": "../src"
}
});
require(["src/fs2"], function(IDBFS) {
var flags = 'FORMAT';
//var flags = undefined;
var fs = new IDBFS.FileSystem('test', flags);
fs.promise.otherwise(
function(error) {
console.error(error);
}
);
function make_tmp_directory() {
return fs.mkdir('/tmp');
};
fs.promise.then(make_tmp_directory);
});
</script>
</html>

View File

@ -1,12 +1,29 @@
var fs = new FileSystem('packages'); var write_buffer = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
var read_buffer = new Uint8Array(16);
var fs = new FileSystem('local');
fs.then(
function() {
return this.mkdir('/tmp');
}
);
var fd = fs.open('/myfile.txt', fs.RW); var fd = fs.open('/myfile.txt', fs.RW);
var buffer = new Uint8Array(16); fd.then(
function() {
fd.write(buffer).then(function(nbytes) { return this.write(write_buffer);
fd.seek(-nbytes); }
return fd.read(buffer); ).then(
}).then(function(nbytes) { function(nbytes) {
this.seek(-nbytes);
return this.read(read_buffer);
}
).then(
function(nbytes) {
console.log(read_buffer);
}
);
}); });

14
examples/viewer.html Normal file
View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<link rel='stylesheet' href='IndexedDBViewer.css'></link>
</head>
<script src="jquery-1.10.0.min.js"></script>
<script src="Linq2IndexedDB.js"></script>
<script src="IndexedDBViewer.js"></script>
<body>
<div id="stdout"></div>
<div id="indexedDBViewer" data-dbName="test"></div>
</body>
</html>

View File

@ -746,13 +746,11 @@ define(function () {
// capture setTimeout to avoid being caught by fake timers used in time based tests // capture setTimeout to avoid being caught by fake timers used in time based tests
setTimeout = global.setTimeout; setTimeout = global.setTimeout;
// Prefer setImmediate, cascade to node, vertx and finally setTimeout // Prefer setImmediate, cascade to node, vertx and finally setTimeout
/*
nextTick = typeof setImmediate === 'function' ? setImmediate.bind(global) nextTick = typeof setImmediate === 'function' ? setImmediate.bind(global)
: typeof process === 'object' && process.nextTick ? process.nextTick : typeof process === 'object' && process.nextTick ? process.nextTick
: typeof vertx === 'object' ? vertx.runOnLoop // vert.x : typeof vertx === 'object' ? vertx.runOnLoop // vert.x
: function(task) { setTimeout(task, 0); }; // fallback : function(task) { setTimeout(task, 0); }; // fallback
*/ // nextTick = function(task) { task.call(); };
nextTick = function(task) { task.call(); };
// Safe function calls // Safe function calls
funcProto = Function.prototype; funcProto = Function.prototype;

View File

@ -1,10 +1,12 @@
define function(require) { define(function(require) {
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var _ = require('lodash'); var _ = require('lodash');
var when = require('when'); var when = require('when');
var Path = require('src/path'); var Path = require('src/path');
var guid = require("src/guid");
require("crypto-js/rollups/sha256"); var Crypto = CryptoJS;
var METADATA_STORE_NAME = 'metadata'; var METADATA_STORE_NAME = 'metadata';
var FILE_STORE_NAME = 'files'; var FILE_STORE_NAME = 'files';
@ -12,46 +14,320 @@ define function(require) {
var IDB_RO = 'readonly'; var IDB_RO = 'readonly';
var IDB_RW = 'readwrite'; var IDB_RW = 'readwrite';
function Operation(fs, stores, mode) { var MODE_FILE = 'FILE';
var MODE_DIRECTORY = 'DIRECTORY';
var MODE_SYMBOLIC_LINK = 'SYMLINK';
var BINARY_MIME_TYPE = 'application/octet-stream';
var JSON_MIME_TYPE = 'application/json';
var ROOT_DIRECTORY_NAME = '/'; // basename(normalize(path))
var ROOT_NODE_ID = '8a5edab282632443219e051e4ade2d1d5bbc671c781051bf1437897cbdfea0f1'; // sha256(ROOT_DIRECTORY_NAME)
// FileSystem flags
var FS_FORMAT = 'FORMAT';
// FileSystem readyState
var FS_READY = 'READY';
var FS_PENDING = 'PENDING';
var FS_ERROR = 'ERROR';
function nop() {};
function hash(string) {
return Crypto.SHA256(string).toString(Crypto.enc.hex);
}; };
var FS_FORMAT = 'format'; function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, links, version) {
var now = Date.now();
this.id = id || hash(guid()),
this.mode = mode || MODE_FILE; // node type (file, directory, etc)
this.size = size || 0; // size (bytes for files, entries for directories)
this.atime = atime || now; // access time
this.ctime = ctime || now; // creation time
this.mtime = mtime || now; // modified time
this.flags = flags || ''; // file flags
this.xattrs = xattrs || {}; // extended attributes
this.links = links || 0; // links count
this.version = version || 0; // node version
this.data = hash(id) // id for data object
};
function DirectoryEntry(id, type) {
this.id = id;
this.type = type || MODE_FILE;
};
function read_object(objectStore, id, callback) {
var getRequest = objectStore.get(id);
getRequest.onsuccess = function onsuccess(event) {
var result = event.target.result;
callback(undefined, result);
};
getRequest.onerror = function onerror(error) {
callback(error);
};
};
function write_object(objectStore, object, id, callback) {
var putRequest = objectStore.put(object, id);
putRequest.onsuccess = function onsuccess(event) {
var result = event.target.result;
callback(undefined, result);
};
putRequest.onerror = function onerror(error) {
callback(error);
};
};
// in: file or directory path
// out: node structure, or error
function find_node(objectStore, path, callback) {
path = Path.normalize(path);
var name = Path.basename(path);
if(ROOT_DIRECTORY_NAME == name) {
function check_root_directory_node(error, rootDirectoryNode) {
if(error) {
callback(error);
} else if(!rootDirectoryNode) {
callback(new Error('ENOENT'));
} else {
callback(undefined, rootDirectoryNode);
}
};
read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
} else {
// in: parent directory node
// out: parent directory data
function read_parent_directory_data(error, parentDirectoryNode) {
if(error) {
callback(error);
} else if(!_(parentDirectoryNode).has('data') || !parentDirectoryNode.type == MODE_DIRECTORY) {
callback(new Error('ENOTDIR'));
} else {
read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data);
}
};
// in: parent directory data
// out: searched node id
function get_node_id_from_parent_directory_data(error, parentDirectoryData) {
if(error) {
callback(error);
} else {
if(!_(parentDirectoryData).has(name)) {
callback(new Error('ENOENT'));
} else {
var nodeId = parentDirectoryData[name].id;
read_object(objectStore, nodeId, callback);
}
}
};
var parentPath = Path.dirname(path);
find_node(objectStore, parentPath, read_parent_directory_data);
}
};
function make_root_directory(objectStore, callback) {
var directoryNode;
var directoryData;
function write_directory_node(error, existingNode) {
if(!error && existingNode) {
callback(new Error('EEXIST'));
} else if(error && 'ENOENT' != error.message) {
callback(error);
} else {
directoryNode = new Node(ROOT_NODE_ID, MODE_DIRECTORY);
directoryNode.links += 1;
write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
}
};
function write_directory_data(error) {
if(error) {
callback(error);
} else {
directoryData = {};
write_object(objectStore, directoryData, directoryNode.data, callback);
}
};
find_node(objectStore, ROOT_DIRECTORY_NAME, write_directory_node);
}
function make_directory(objectStore, path, callback) {
path = Path.normalize(path);
var name = Path.basename(path);
var parentPath = Path.dirname(path);
var _directoryNode;
var _directoryData;
var _parentDirectoryNode;
var _parentDirectoryData;
function check_if_directory_exists(error, existingNode) {
if(!error && existingNode) {
callback(new Error('EEXIST'));
} else if(error && 'ENOENT' != error.message) {
callback(error);
} else {
find_node(objectStore, parentPath, read_parent_directory_data);
}
}
function read_parent_directory_data(error, parentDirectoryNode) {
if(error) {
callback(error);
} else {
_parentDirectoryNode = parentDirectoryNode;
read_object(objectStore, _parentDirectoryNode.data, write_directory_node);
}
};
function write_directory_node(error, parentDirectoryData) {
if(error) {
callback(error);
} else {
_parentDirectoryData = parentDirectoryData;
_directoryNode = new Node(undefined, MODE_DIRECTORY);
_directoryNode.links += 1;
write_object(objectStore, _directoryNode, _directoryNode.id, write_directory_data);
}
};
function write_directory_data(error) {
if(error) {
callback(error);
} else {
_directoryData = {};
write_object(objectStore, _directoryData, _directoryNode.data, update_parent_directory_data);
}
};
function update_parent_directory_data(error) {
if(error) {
callback(error);
} else {
_parentDirectoryData[name] = new DirectoryEntry(_directoryNode.id, MODE_DIRECTORY);
write_object(objectStore, _parentDirectoryData, _parentDirectoryNode.data, callback);
}
}
find_node(objectStore, path, check_if_directory_exists);
};
/*
* FileSystem
*/
function FileSystem(name, flags) { function FileSystem(name, flags) {
var format = _(flags).contains(FS_FORMAT); var format = _(flags).contains(FS_FORMAT);
var that = this;
var deferred = when.defer();
this.promise = deferred.promise;
var openRequest = indexedDB.open(name); var openRequest = indexedDB.open(name);
openRequest.onupgradeneeded = function onupgradeneeded(event) {
var db = event.target.result;
if(db.objectStoreNames.contains(FILE_STORE_NAME)) {
db.deleteObjectStore(FILE_STORE_NAME);
}
var files = db.createObjectStore(FILE_STORE_NAME);
if(db.objectStoreNames.contains(METADATA_STORE_NAME)) {
db.deleteObjectStore(METADATA_STORE_NAME);
}
var metadata = db.createObjectStore(METADATA_STORE_NAME);
format = true;
}; };
FileSystem.prototype.open = function open(transaction, path, flags, mode) { openRequest.onsuccess = function onsuccess(event) {
var db = event.target.result;
function complete(error) {
if(error) {
that.readyState = FS_ERROR;
deferred.reject(error);
} else {
that.readyState = FS_READY;
that.db = db;
deferred.resolve();
}
};
if(format) {
var transaction = db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME);
var clearRequest = files.clear();
clearRequest.onsuccess = function onsuccess(event) {
make_root_directory(files, complete);
};
clearRequest.onerror = function onerror(error) {
complete(error);
};
} else {
complete();
}
};
openRequest.onerror = function onerror(error) {
this.readyState = FS_ERROR;
deferred.reject(error);
};
this.readyState = FS_PENDING;
this.db = null;
};
FileSystem.prototype.open = function open(path, flags, mode) {
}; };
FileSystem.prototype.opendir = function opendir(transaction, path) { FileSystem.prototype.opendir = function opendir(path) {
}; };
FileSystem.prototype.mkdir = function mkdir(transaction, path) { FileSystem.prototype.mkdir = function mkdir(path) {
var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME);
function check_result(error) {
if(error) {
deferred.reject(error);
} else {
deferred.resolve();
}
};
make_directory(files, path, check_result);
return deferred.promise();
};
FileSystem.prototype.rmdir = function rmdir(path) {
}; };
FileSystem.prototype.rmdir = function rmdir(transaction, path) { FileSystem.prototype.stat = function stat(path) {
}; };
FileSystem.prototype.stat = function stat(transaction, path) { FileSystem.prototype.link = function link(oldpath, newpath) {
}; };
FileSystem.prototype.link = function link(transaction, oldpath, newpath) { FileSystem.prototype.unlink = function unlink(path) {
}; };
FileSystem.prototype.unlink = function unlink(transaction, path) { FileSystem.prototype.getxattr = function getxattr(path, name) {
}; };
FileSystem.prototype.getxattr = function getxattr(transaction, path, name) { FileSystem.prototype.setxattr = function setxattr(path, name, value) {
};
FileSystem.prototype.setxattr = function setxattr(transaction, path, name, value) {
}; };
return { return {
FileSystem: FileSystem FileSystem: FileSystem,
}; };
}; });

View File

@ -16,6 +16,74 @@ define(function(require) {
this.result = result || idbTarget.result; this.result = result || idbTarget.result;
}; };
/*
* Cursor
*/
function Cursor(idbCursor) {
this.idbCursor = idbCursor;
Object.defineProperty(this, 'source', {
get: function() {
return idbCursor.source;
}
});
Object.defineProperty(this, 'direction', {
get: function() {
return idbCursor.direction;
}
});
Object.defineProperty(this, 'key', {
get: function() {
return idbCursor.key;
}
});
Object.defineProperty(this, 'primaryKey', {
get: function() {
return idbCursor.primaryKey;
}
});
};
Cursor.prototype.update = function update(value) {
var idbCursor = this.idbCursor;
var deferred = when.defer();
var request = idbCursor.update(value);
request.onsuccess = function(event) {
deferred.resolve(event);
};
request.onerror = function(event) {
deferred.reject(event);
};
return deferred.promise;
};
Cursor.prototype.advance = function advance(count) {
var idbCursor = this.idbCursor;
return idbCursor.advance(count);
};
Cursor.prototype.continue = function continue(key) {
var idbCursor = this.idbCursor;
return idbCursor.continue(key);
};
Cursor.prototype.delete = function delete() {
var idbCursor = this.idbCursor;
var deferred = when.defer();
var request = idbCursor.delete();
request.onsuccess = function(event) {
deferred.resolve(event);
};
request.onerror = function(event) {
deferred.reject(event);
};
return deferred.promise;
};
/* /*
* ObjectStore * ObjectStore
*/ */
@ -27,7 +95,7 @@ define(function(require) {
var idbObjectStore = this.idbObjectStore; var idbObjectStore = this.idbObjectStore;
var deferred = when.defer(); var deferred = when.defer();
var request = idbObjectStore.add.call(idbObjectStore, value, key); var request = idbObjectStore.add(value, key);
request.onsuccess = function(event) { request.onsuccess = function(event) {
deferred.resolve(event); deferred.resolve(event);
}; };
@ -67,7 +135,7 @@ define(function(require) {
}; };
ObjectStore.prototype.createIndex = function createIndex(name, keyPath, optionalParameters) { ObjectStore.prototype.createIndex = function createIndex(name, keyPath, optionalParameters) {
var idbObjectStore = this.idbObjectStore; var idbObjectStore = this.idbObjectStore;
return idbObjectStore.createIndex.call(idbObjectStore, name, keyPath, optionalParameters); return idbObjectStore.createIndex(name, keyPath, optionalParameters);
}; };
ObjectStore.prototype.delete = function delete(key) { ObjectStore.prototype.delete = function delete(key) {
var idbObjectStore = this.idbObjectStore; var idbObjectStore = this.idbObjectStore;
@ -85,7 +153,7 @@ define(function(require) {
}; };
ObjectStore.prototype.deleteIndex = function deleteIndex(name) { ObjectStore.prototype.deleteIndex = function deleteIndex(name) {
var idbObjectStore = this.idbObjectStore; var idbObjectStore = this.idbObjectStore;
return idbObjectStore.deleteIndex.call(idbObjectStore, name); return idbObjectStore.deleteIndex(name);
}; };
ObjectStore.prototype.get = function get(key) { ObjectStore.prototype.get = function get(key) {
var idbObjectStore = this.idbObjectStore; var idbObjectStore = this.idbObjectStore;
@ -109,9 +177,15 @@ define(function(require) {
var idbObjectStore = this.idbObjectStore; var idbObjectStore = this.idbObjectStore;
var deferred = when.defer(); var deferred = when.defer();
var request = idbObjectStore.openCursor(range, direction); var request = (!(range || direction)) ? idbObjectStore.openCursor() : idbObjectStore.openCursor(range, direction);
request.onsuccess = function(event) { request.onsuccess = function(event) {
deferred.resolve(event); var wrappedEvent = new Event(event);
wrappedEvent.result = event.result;
if(!event.result) {
deferred.resolve(wrappedEvent);
} else {
deferred.notify(wrappedEvent);
}
}; };
request.onerror = function(event) { request.onerror = function(event) {
deferred.reject(event); deferred.reject(event);
@ -156,8 +230,24 @@ define(function(require) {
function Database(idbDatabase) { function Database(idbDatabase) {
this.idbDatabase = idbDatabase; this.idbDatabase = idbDatabase;
this.name = idbDatabase.name;
this.version = idbDatabase.version; Object.defineProperty(this, 'name', {
get: function() {
return idbDatabase.name;
}
});
Object.defineProperty(this, 'version', {
get: function() {
return idbDatabase.version;
}
});
Object.defineProperty(this, 'objectStoreNames', {
get: function() {
return idbDatabase.objectStoreNames;
}
});
}; };
Database.prototype.createObjectStore = function createObjectStore(name, optionalParameters) { Database.prototype.createObjectStore = function createObjectStore(name, optionalParameters) {
var idbDatabase = this.idbDatabase; var idbDatabase = this.idbDatabase;
@ -189,12 +279,12 @@ define(function(require) {
var request = indexedDB.open(name); var request = indexedDB.open(name);
request.onupgradeneeded = function(event) { request.onupgradeneeded = function(event) {
var result = new Event(event, new Target(event.target, new Database(event.target.result))); var wrappedEvent = new Event(event, new Target(event.target, new Database(event.target.result)));
deferred.notify(result); deferred.notify(wrappedEvent);
}; };
request.onsuccess = function(event) { request.onsuccess = function(event) {
var result = new Event(event, new Target(event.target, new Database(event.target.result))); var wrappedEvent = new Event(event, new Target(event.target, new Database(event.target.result)));
deferred.resolve(result); deferred.resolve(wrappedEvent);
}; };
request.onerror = function(event) { request.onerror = function(event) {
deferred.reject(event); deferred.reject(event);
@ -222,7 +312,9 @@ define(function(require) {
return { return {
open: open, open: open,
deleteDatabase: deleteDatabase deleteDatabase: deleteDatabase,
KeyRange: indexedDB.KeyRange,
when: when,
}; };
}); });

108
src/indexeddb2.js Normal file
View File

@ -0,0 +1,108 @@
define(function(require) {
var when = require('when');
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
/*
* Transaction
*/
function Transaction(idbDatabase, storeNames, mode) {
this.idbTransaction = idbDatabase.transaction(storeNames, mode);
};
Transaction.prototype.objectStore = function objectStore(name) {
var idbTransaction = this.idbTransaction;
return new ObjectStore(idbTransaction, name);
};
Transaction.prototype.abort = function abort() {
var idbTransaction = this.idbTransaction;
return idbTransaction.abort();
};
/*
* Database
*/
function Database(idbDatabase) {
this.idbDatabase = idbDatabase;
Object.defineProperty(this, 'name', {
get: function() {
return idbDatabase.name;
}
});
Object.defineProperty(this, 'version', {
get: function() {
return idbDatabase.version;
}
});
Object.defineProperty(this, 'objectStoreNames', {
get: function() {
return idbDatabase.objectStoreNames;
}
});
};
Database.prototype.createObjectStore = function createObjectStore(name, optionalParameters) {
var idbDatabase = this.idbDatabase;
return idbDatabase.createObjectStore(name, optionalParameters);
};
Database.prototype.deleteObjectStore = function deleteObjectStore(name) {
var idbDatabase = this.idbDatabase;
return idbDatabase.deleteObjectStore(name);
};
Database.prototype.transaction = function transaction(storeNames, mode) {
var idbDatabase = this.idbDatabase;
return new Transaction(idbDatabase, storeNames, mode);
};
Database.prototype.close = function close() {
var idbDatabase = this.idbDatabase;
return idbDatabase.close();
};
Database.prototype.objectStoreNames = function objectStoreNames() {
var idbDatabase = this.idbDatabase;
return idbDatabase.objectStoreNames;
};
/*
* Factory
*/
function Factory() {
this.when = when;
};
Factory.prototype.open = function open(name, version) {
var deferred = when.defer();
var request = indexedDB.open(name);
request.onupgradeneeded = function(idbEvent) {
var db = new Database(idbEvent.target.result);
var event = {
type: 'upgradeneeded',
db: db
};
deferred.notify(event);
};
request.onsuccess = function(idbEvent) {
var db = new Database(idbEvent.target.result);
var event = {
type: 'success',
db: db
};
deferred.resolve(event);
};
request.onerror = function(idbError) {
deferred.reject(idbError);
};
return deferred.promise;
};
Factory.prototype.deleteDatabase = function deleteDatabase(name) {
};
return new Factory();
});