Skip to content

Instantly share code, notes, and snippets.

@slawrence
Created November 20, 2012 20:44
Show Gist options
  • Save slawrence/4120949 to your computer and use it in GitHub Desktop.
Save slawrence/4120949 to your computer and use it in GitHub Desktop.
treeify.js
/*jslint browser: true*/
/*global pn: true, Tree: true */
pn = window.pn || {};
(function () {
if (pn.Tree) {
console.error('Tree is already defined!');
return;
}
/**
Creates a Tree object. If a delimiter is not provided it defaults to forwardslash ("/").
Basic example:
>>>
<script>
var tree = new pn.Tree();
tree.createBranch('/a/b/c');
tree.createBranch('/a/b/x/y');
tree.createBranch('/foo');
tree.createBranch('/bar/');
tree.createBranch('/research/papers/');
example.append($("<pre/>").append(JSON.stringify(tree.getRoot(), null, 4)));
</script>
<<<
Callbacks can be added so certain logic is executed on folder creation or document creation. Additional properties can be added to each node as well. The LocalStorage object uses the Tree folder and document callbacks to create entries in localStorage.
*/
pn.Tree = function (delim) {
var delimiter = delim || "/";
var root = { path: delimiter, children: [ ] };
var folder_fn = function (parent, node) { return node; };
var document_fn = function (parent, node) { return node; };
function createFolder(parent, piece) {
var node = {};
node.id = piece;
node.path = parent.path + piece + (isFolder(piece) ? "" : delimiter);
node.children = [ ];
node = folder_fn.call(null, parent, node);
if (node) {
parent.children.push(node);
}
return node;
}
function createDocument(parent, piece) {
var node = {};
node.id = piece;
node.path = parent.path + piece;
node = document_fn.call(null, parent, node);
if (node) {
parent.children.push(node);
}
return node;
}
function isFolder(path) {
var last_char = path.charAt(path.length - 1);
if (last_char === delimiter) {
return true;
}
return false;
}
function explode(string) {
var i,
pieces = string.split(delimiter);
//remove empty pieces
for (i = 0; i < pieces.length; i += 1) {
if (!pieces[i]) {
pieces.splice(i, 1);
i = i - 1;
}
}
//add delimiter back to last piece
//(specifies in branch creation whether the piece is a folder or document)
if (isFolder(string)) {
var last_index = pieces.length - 1;
pieces[last_index] = pieces[last_index].concat(delimiter);
}
return pieces;
}
function branch(folder, pieces) {
var i,
nodes,
current_piece = pieces.shift();
if (!folder) {
return;
}
nodes = folder.children;
for (i = 0; i < nodes.length; i += 1) {
if (nodes[i].id === current_piece) {
if (!nodes[i].children || !pieces.length) {
console.error("Contradictory or duplicate branch");
return;
}
return branch(nodes[i], pieces);
}
}
if (pieces.length) {
return branch(createFolder(folder, current_piece), pieces);
}
if (isFolder(current_piece)) {
return createFolder(folder, current_piece);
} else {
return createDocument(folder, current_piece);
}
}
function traverse(nodes, pieces) {
var i,
current_piece = pieces.shift();
for (i = 0; i < nodes.length; i += 1) {
if (nodes[i].id === current_piece) {
if (pieces.length) {
if (!nodes[i].children) {
return false;
}
return traverse(nodes[i].children, pieces);
}
return nodes[i];
}
}
return false;
}
this.createBranch = function (string) {
return branch(root, explode(string));
};
this.search = function (string) {
return traverse(root, explode(string));
};
this.getRoot = function () {
return root.children;
};
//callbacks setters
this.setDocumentCallback = function (fn) {
document_fn = fn;
};
this.setFolderCallback = function (fn) {
folder_fn = fn;
};
return this;
};
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment