JSFiddle - React, Tailwind, and code Playground
by tonyleeper
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<div class="container">
<ul class="treeview" data-bind="treeview: { rootNode: rootNode }" tabindex="0"></ul>
</div>
<div class="test" data-bind="text: selectedNodeId"></div>
CSS
.test {
position: absolute;
top: 0;
left: 300px;
border: 1px solid black;
width : 100px;
height: 100px;
}
html, body {
height: 100%;
}
* {
padding: 0;
margin: 0;
-webkit-user-select: none;
box-sizing: border-box;
font-family: arial;
font-size: 12px;
line-height: 25px;
}
.container {
width : 300px;
height: 100%;
overflow: auto;
}
.treeview {
cursor: default;
outline: 0;
position: relative;
padding: 3px 5px;
}
li {
position: relative;
text-indent: 20px;
margin: 2px 0;
}
.treeview label {
display: block;
height: 25px;
border: 1px solid transparent;
border-radius: 2px;
}
.treeview label:hover {
border: 1px solid #bed2f0;
background-color: #e9f0fa;
}
.treeview label span {
position: relative;
top: -2px;
text-shadow: 0 1px white;
}
li.selected > label {
border: 1px solid #cfcfcf;
background-color: #ddd;
}
.treeview:focus li.selected > label {
border: 1px solid #94b5e5;
background-color: #bed2f0;
}
ul:not(.treeview) {
display: none;
}
ul {
list-style: none;
}
.children {
display: none;
}
i {
display: inline-block;
background-repeat: no-repeat;
position: absolute;
}
i.folder {
background-image: url(http://s10.postimg.org/vr6k6n7r9/folder_closed_16.png);
width: 16px;
height: 16px;
top: 0px;
left: -20px;
}
i.open-closed-state {
background-image:...
JavaScript
/**
Treeview Mark-II
*/
ko.bindingHandlers.treeview = {
createTreeDOMNode: function(appendTo, treeNode, depth) {
depth = depth || 0;
var node = document.createElement("li");
node.setAttribute("data-id", treeNode.id);
node.setAttribute("data-type", treeNode.type);
node.setAttribute("style", "text-indent: " + ((depth + 2) * 19) + "px");
var label = document.createElement("label");
var span = document.createElement("span");
span.textContent = treeNode.displayName;
if (treeNode.children && treeNode.children.length > 0) {
var expandIcon = document.createElement("i");
expandIcon.setAttribute("class", "open-closed-state");
span.appendChild(expandIcon);
}
var folderIcon = document.createElement("i");
folderIcon.setAttribute("class", "folder");
span.appendChild(folderIcon);
label.appendChild(span);
node.appendChild(label);
if (treeNode.children && treeNode.children.length > 0) {
var children = document.createElement("ul");
for (var i = 0; i < treeNode.children.length; i++) {
ko.bindingHandlers.treeview.createTreeDOMNode(children, treeNode.children[i], depth + 1);
}
node.appendChild(children);
}
appendTo.appendChild(node);
},
scrollIntoView: function(node) {
// find the first scrollable element in the DOM heirarchy
var scrollableElement = node.parentNode;
while (scrollableElement.nodeName !== "BODY") {
if (scrollableElement.scrollHeight >...