Skip to content

Commit

Permalink
Merge branch 'abstract-tree'
Browse files Browse the repository at this point in the history
  • Loading branch information
plequang committed May 12, 2017
2 parents e6d69c4 + 1b977d9 commit e1709ae
Show file tree
Hide file tree
Showing 7 changed files with 516 additions and 123 deletions.
156 changes: 156 additions & 0 deletions cosmoz-default-tree.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<link rel="import" href="cosmoz-tree.html">
<script>
'use strict';

window.Cosmoz = window.Cosmoz || {};

function _objectValues(obj) {
return Object.keys(obj).map(function (key) {
return obj[key];
});
}

/**
* Cosmoz.DefaultTree
*
* @constructor
*/
Cosmoz.DefaultTree = function (treeData) {
Cosmoz.Tree.apply(this, arguments);
this._treeData = treeData;
this._roots = _objectValues(treeData);
};

Cosmoz.DefaultTree.prototype = Object.create(Cosmoz.Tree.prototype);

Cosmoz.DefaultTree.prototype.getNodeByProperty = function (propertyName, propertyValue) {
if (propertyName === undefined || propertyValue === undefined) {
return;
}

if (propertyName === 'pathLocator') {
return this._getNodeByPathLocator(propertyValue);
}

return this._searchAllRoots(propertyName, propertyValue);
};

Cosmoz.DefaultTree.prototype.getPath = function (node) {
if (node === undefined) {
return;
}
return this._getPathByPathLocator(node.pathLocator);
};

Cosmoz.DefaultTree.prototype.getPathByProperty = function (propertyName, propertyValue) {
if (propertyName === undefined || propertyValue === undefined) {
return;
}

if (propertyName === 'pathLocator') {
return this._getPathByPathLocator(propertyValue);
}

var node = this._searchAllRoots(propertyName, propertyValue);
if (node !== undefined) {
return this._getPathByPathLocator(node.pathLocator);
}
};

Cosmoz.DefaultTree.prototype.getChildren = function (node) {
if (node === undefined) {
return;
}
return _objectValues(node.children);
};

Cosmoz.DefaultTree.prototype.getProperty = function (node, propertyName) {
if (node === undefined || propertyName === undefined) {
return;
}

return node[propertyName];
};

Cosmoz.DefaultTree.prototype._searchAllRoots = function (propertyName, propertyValue) {
var i,
node;

for (i = 0; i < this._roots.length; i+=1) {
node = this.search(this._roots[i], propertyName, propertyValue);
if (node !== undefined) {
return node;
}
}
};

Cosmoz.DefaultTree.prototype._getNodeByPathLocator = function (pathLocator) {
var node,
path,
i;

for (i = 0; i < this._roots.length; i+=1) {
node = this._roots[i];
if (node.pathLocator === pathLocator) {
return node;
}

if (pathLocator.indexOf(node.pathLocator + '.') === 0) {
path = pathLocator.slice(node.pathLocator.length + 1).split('.');
for (i = 0; i < path.length; i+=1) {
if (node.children) {
node = node.children[path[i]];
} else {
node = null;
}
if (node === undefined || node === null) {
break;
}
}

if (node !== undefined && node !== null) {
return node;
}
}
}
};

Cosmoz.DefaultTree.prototype._getPathByPathLocator = function (pathLocator) {
var node,
path,
subPath,
i;

for (i = 0; i < this._roots.length; i+=1) {
node = this._roots[i];
path = [node];

if (node.pathLocator === pathLocator) {
return path;
}

if (pathLocator.indexOf(node.pathLocator + '.') === 0) {
subPath = pathLocator.slice(node.pathLocator.length + 1).split('.');
for (i = 0; i < subPath.length; i+=1) {
if (node.children) {
node = node.children[subPath[i]];
} else {
node = null;
}
if (node === undefined || node === null) {
path = null;
break;
} else {
path.push(node);
}
}

if (path !== null) {
return path;
}
}
}
};


</script>
134 changes: 44 additions & 90 deletions cosmoz-tree.html
Original file line number Diff line number Diff line change
@@ -1,123 +1,77 @@
<script>
'use strict';

if (typeof Cosmoz === 'undefined') {
var Cosmoz = {};
}
window.Cosmoz = window.Cosmoz || {};


/* eslint-disable no-unused-vars */

/**
* Cosmoz.Tree
*
* @constructor
*/
Cosmoz.Tree = function (node) {
this._node = node;
this._flattenedTree = this._flattenTree(node);
this._pathLocatorSeparator = '.';
Cosmoz.Tree = function () {
if (this.constructor === Cosmoz.Tree) {
throw new Error('abstract');
}
};

Cosmoz.Tree.prototype = {

constructor: Cosmoz.Tree,

findNodeById: function (id) {
return this._flattenedTree[id];
getNodeByProperty: function (propertyName, propertyValue) {
throw new Error('Must be implemented in derived object');
},

findNodeByPathLocator: function (pathLocator) {
if (!pathLocator) {
return;
}
return pathLocator
.split(this._pathLocatorSeparator)
.reduce(function (node, part) {
if (node.children) {
node = node.children;
}
if (node[part]) {
node = node[part];
}
return node;
}, this._node);
getPath: function (node) {
throw new Error('Must be implemented in derived object');
},

getPath: function (keyId) {
if (this.isGuid(keyId)) {
return this.getPathByNodeId(keyId);
}
return this.getPathByLocator(keyId);
getPathByProperty: function (propertyName, propertyValue) {
throw new Error('Must be implemented in derived object');
},

getPathByNode: function (node) {
if (!node || !node.pathLocator) {
return;
}
var currentNode = this._node;
return node.pathLocator
.split(this._pathLocatorSeparator)
.map(function (part) {
var ret = currentNode;
if (currentNode.children && currentNode.children[part]) {
currentNode = currentNode.children[part];
}
if (currentNode[part]) {
currentNode = currentNode[part];
}
if (ret === currentNode) {
return;
}
return currentNode;
})
.filter(function (part) {
return part !== undefined;
});
getChildren: function (node) {
throw new Error('Must be implemented in derived object');
},

getPathByNodeId: function (nodeId) {
var node = this.findNodeById(nodeId);
return this.getPathByNode(node);
getProperty: function (node, propertyName) {
throw new Error('Must be implemented in derived object');
},

getPathByLocator: function (locator) {
var node = this.findNodeByPathLocator(locator);
return this.getPathByNode(node);
getPathString: function (node, textPropertyName, separator) {
var path = this.getPath(node);
return path.map(function (n) {
return this.getProperty(n, textPropertyName);
}, this).join(separator);
},

getPathString: function (path, separator) {
if (!path || !Array.isArray(path) || path.length < 1) {
return;
getPathStringByProperty: function (propertyName, propertyValue, textPropertyName, separator) {
var node = this.getNodeByProperty(propertyName, propertyValue);
if (node !== undefined) {
return this.getPathString(node, textPropertyName, separator);
}
return path.map(function (part) {
return part.name;
}).join(separator);
},

isGuid: function (input) { // FIXME: GUID Check
return input && input.length === 36;
},

/**
* Utility function to flatten the tree to ease node lookup.
* Basic search for a node by one of its property
*/
_flattenTree: function (tree, flattened) {
if (!flattened) {
flattened = {};
}

if (tree === undefined) {
return flattened;
search: function (node, propertyName, propertyValue) {
if (this.getProperty(node, propertyName) === propertyValue) {
return node;
}

Object.keys(tree).forEach(function (key) {
var node = tree[key];
flattened[node.id] = node;
var children = this.getChildren(node),
i = 0,
n;

if (node.children && Object.keys(node.children).length > 0) {
this._flattenTree(node.children, flattened);
if (children) {
for (i = 0; i < children.length; i+=1) {
n = this.search(children[i], propertyName, propertyValue);
if (n !== undefined) {
return n;
}
}

}, this);

return flattened;
},
}
}
};
</script>
</script>
Loading

0 comments on commit e1709ae

Please sign in to comment.