forerunnerdb
Version:
A NoSQL document store database for browsers and Node.js.
441 lines (371 loc) • 12 kB
JavaScript
// TODO: The tree is too complex using a third party tool to output...
// TODO: How about we use ForerunnerDB and binding to automatically build
// TODO: and maintain udpates to the tree? That way we can have in-line
// TODO: bound updates to the tree and then just run a refresh every 5 seconds
// TODO: and any changes will then get reflected as the underlying data
// TODO: is updated! - This hasn't been started yet.
(function () {
var self = this,
fdb = new ForerunnerDB(),
db = fdb.db('fdbChromeExtension');
self._expanded = {
'Databases': true
};
// Setup the main db data view collection
db.collection('dataView').setData([]);
var getCall = function (js, callback) {
chrome.devtools.inspectedWindow.eval(js, callback);
};
var typeIcon = function (module) {
switch (module) {
case 'collection':
return 'glyphicon glyphicon-th-list';
case 'view':
return 'glyphicon glyphicon-log-out';
case 'overview':
return 'glyphicon glyphicon-filter';
case 'grid':
return 'glyphicon glyphicon-th';
case 'document':
return 'glyphicon glyphicon-file';
case 'collectionGroup':
return 'glyphicon glyphicon-book';
}
};
var expandNodes = function (tree, node) {
var i;
if (self._expanded[node.nodeId]) {
tree.setExpandedState(node, true, {});
} else {
tree.setExpandedState(node, false, {});
}
// Loop node's child nodes
tree.render();
if (node.nodes && node.nodes.length) {
for (i = 0; i < node.nodes.length; i++) {
expandNodes(tree, node.nodes[i]);
}
}
};
var nodeChildren = function (node, callback) {
var entityItem,
entityNodes,
dbNode,
tree,
tmpNode,
postProcess,
totalCount,
processCount,
i, j, processPostNodeChildRequest;
tree = $('#tree').data('treeview').tree;
if (node.fdb) {
switch (node.fdb.type) {
case 'database':
// Loop the children of this db object
if (node.fdb.children) {
entityNodes = [];
postProcess = [];
processCount = 0;
totalCount = 0;
debugger;
for (j = 0; j < node.fdb.children.length; j++) {
entityItem = node.fdb.children[j];
tmpNode = {
parentId: node.nodeId,
fdb: {
id: entityItem.module,
type: 'module',
moduleData: entityItem
},
nodeId: db.objectId(entityItem.module),
text: entityItem.moduleName + ' (' + entityItem.count + ')',
icon: typeIcon(entityItem.module),
nodes: []
};
entityNodes.push(tmpNode);
if (self._expanded[tmpNode.nodeId]) {
// Add node to post-process array
postProcess.push(tmpNode);
totalCount++;
}
}
if (postProcess.length) {
processPostNodeChildRequest = function (tmpNode, callback) {
nodeChildren(tmpNode, function (err, tmpNodeData) {
tmpNode.nodes = tmpNodeData;
processCount++;
if (processCount === totalCount) {
callback(false, entityNodes);
}
});
};
while ((tmpNode = postProcess.shift())) {
processPostNodeChildRequest(tmpNode, callback);
}
} else {
callback(false, entityNodes);
}
}
break;
case 'module':
switch (node.fdb.moduleData.module) {
default:
dbNode = tree.getNode(node.parentId);
if (!dbNode || dbNode.fdb.type !== 'database') {
debugger;
}
(function (dbNode, node, callback) {
if (!dbNode) {
debugger;
}
// Get collections for this DB
getCall("ForerunnerDB.instances()[0].db('" + dbNode.fdb.id + "')." + node.fdb.moduleData.module + "s()", function (result, isException) {
var moduleNodes = [];
debugger;
for (i = 0; i < result.length; i++) {
moduleNodes.push({
parentId: node.nodeId,
fdb: {
type: node.fdb.moduleData.module,
id: result[i].name,
linked: result[i].linked
},
nodeId: db.objectId(result[i].name),
text: result[i].name + ' (' + result[i].count + ')',
icon: typeIcon(node.fdb.moduleData.module)
});
}
callback(false, moduleNodes);
});
})(dbNode, node, callback);
break;
}
break;
}
}
};
var refreshDatabaseTree = function () {
// Get number of instances
getCall('ForerunnerDB.instantiatedCount()', function (result, isException) {
//console.log('Instance count', result, isException);
if (result > 0) {
$('#noInstances').hide();
getCall('ForerunnerDB.instances()[0].databases()', function (result, isException) {
//console.log('databases', result);
var dbNodes = [],
postProcess = [],
tree,
node,
finishLoad,
tmpNode,
totalCount = 0,
processCount = 0,
i, processPostNodeChildRequest;
finishLoad = function (dbNodes) {
$('#tree').treeview({
data: [{
nodeId: 'Databases',
text: "Databases",
nodes: dbNodes
}],
onNodeCollapsed: function (event, data) {
// Record tree expanded data
self._expanded[data.nodeId] = false;
console.log(self._expanded);
},
onNodeExpanded: function (event, data) {
// Record tree expanded data
self._expanded[data.nodeId] = true;
console.log(self._expanded);
// Get child node data
tree = $('#tree').data('treeview').tree;
node = tree.getNode(data.nodeId);
nodeChildren(node, function (err, data) {
node.nodes = data;
tree.setInitialStates(node, 0);
tree.render();
});
},
onNodeSelected: function (event, data) {
var moduleNode,
dbNode;
tree = $('#tree').data('treeview').tree;
node = tree.getNode(data.nodeId);
if (node.fdb) {
switch (node.fdb.type) {
case 'collection':
moduleNode = tree.getNode(node.parentId);
dbNode = tree.getNode(moduleNode.parentId);
// Grab the collection data and display in the right pane
getCall("ForerunnerDB.instances()[0].db('" + dbNode.fdb.id + "')." + moduleNode.fdb.moduleData.module + "('" + node.fdb.id + "').find()", function (result, isException) {
// Unlink any previous data-binding
db.view('dataView').unlink();
db.view('dataView').drop();
db.document('dataViewStatus').drop();
// Set the new data in the data view collection
db.collection('dataView').setData(result);
db.view('dataView').from(db.collection('dataView'));
db.view('dataView').queryData({}, {
$page: 0,
$limit: 10,
$orderBy: {
_id: 1
}
});
// Create document to wrap data in
var wrapperDoc = db.document('dataViewStatus')
.setData({
records: 0,
page: 1,
pages: 1
});
// Keep the record count up to date as changes occur to the view
db.view('dataView').on('change', function () {
var cursor = db.view('dataView').cursor();
if (cursor) {
wrapperDoc.update({}, {
records: cursor.records,
page: cursor.page + 1,
pages: cursor.pages
});
}
});
// Link the data view to collection data template
db.view('dataView').link('#dataView', '#dataViewTable', {
$wrap: 'items',
$wrapIn: wrapperDoc
});
});
break;
case 'view':
case 'document':
case 'overview':
case 'collectionGroup':
moduleNode = tree.getNode(node.parentId);
dbNode = tree.getNode(moduleNode.parentId);
// Grab the view data and display in the right pane
getCall("ForerunnerDB.instances()[0].db('" + dbNode.fdb.id + "')." + moduleNode.fdb.moduleData.module + "('" + node.fdb.id + "').find()", function (result, isException) {
// Unlink any previous data-binding
db.view('dataView').unlink();
db.view('dataView').drop();
db.document('dataViewStatus').drop();
// Set the new data in the data view collection
db.collection('dataView').setData(result);
db.view('dataView').from(db.collection('dataView'));
db.view('dataView').queryData({}, {
$page: 0,
$limit: 10,
$orderBy: {
_id: 1
}
});
// Create document to wrap data in
var wrapperDoc = db.document('dataViewStatus')
.setData({
records: 0,
page: 1,
pages: 1
});
// Keep the record count up to date as changes occur to the view
db.view('dataView').on('change', function () {
var cursor = db.view('dataView').cursor();
if (cursor) {
wrapperDoc.update({}, {
records: cursor.records,
page: cursor.page + 1,
pages: cursor.pages
});
}
});
// Link the data view to collection data template
db.view('dataView').link('#dataView', '#dataViewTable', {
$wrap: 'items',
$wrapIn: wrapperDoc
});
});
break;
default:
tree.setExpandedState(node, true, {});
break;
}
}
}
});
var bodyElem = $('body');
// Handle pagination controls
bodyElem.on('click', '.pageFirst', function (e) {
e.stopPropagation();
db.view('dataView').pageFirst();
});
bodyElem.on('click', '.pagePrev', function (e) {
e.stopPropagation();
db.view('dataView').pageScan(-1);
});
bodyElem.on('click', '.pageNext', function (e) {
e.stopPropagation();
db.view('dataView').pageScan(1);
});
bodyElem.on('click', '.pageLast', function (e) {
e.stopPropagation();
db.view('dataView').pageLast();
});
// Traverse the tree and open previously expanded
// items
tree = $('#tree').data('treeview').tree;
expandNodes(tree, tree.getNode('Databases'));
};
for (i = 0; i < result.length; i++) {
tmpNode = {
fdb: {
type: 'database',
id: result[i].name,
children: result[i].children
},
nodeId: db.objectId(result[i].name),
text: result[i].name,
icon: 'glyphicon glyphicon-align-justify',
nodes: []
};
dbNodes.push(tmpNode);
if (self._expanded[tmpNode.nodeId]) {
// Add node to post-process array
postProcess.push(tmpNode);
totalCount++;
}
}
if (postProcess.length) {
processPostNodeChildRequest = function (tmpNode) {
nodeChildren(tmpNode, function (err, tmpNodeData) {
tmpNode.nodes = tmpNodeData;
processCount++;
if (processCount === totalCount) {
finishLoad(dbNodes);
}
});
};
while ((tmpNode = postProcess.shift())) {
processPostNodeChildRequest(tmpNode);
}
} else {
finishLoad(dbNodes);
}
});
} else {
$('#noInstances').show();
}
});
};
$(document).ready(function () {
// Get the forerunnerdb instance
getCall("typeof ForerunnerDB !== 'undefined'", function (result, isException) {
if (result) {
refreshDatabaseTree();
}
});
$('#refreshDatabaseTree').on('click', function (e) {
e.stopPropagation();
refreshDatabaseTree();
});
});
}());
;