JSFiddle - React, Tailwind, and code Playground
by Anov Siradj
HTML
<h3>Create dir tree: </h3>
<br />
<ul id='tree'>
<li>
<div class="line">
<input value='filename' />
<span class='controls'>
»
<a href='#' data-func='add-sibling' >+sibling</a> |
<a href='#' data-func='add-child'>+child</a> |
<a href='#' data-func='delete'>delete</a>
</span>
</div>
</li>
</ul>
<hr />
<h3>Output:</h3>
<br />
<pre id='out' cols='50' rows='20'></pre>
CSS
body {
padding: 10px;
}
input, .line:before, .line:after {
font-family: Courier New,monospace,serif;
letter-spacing: -0.02em;
}
input {
background: transparent;
border: none;
}
ul {
overflow: hidden;
}
.line:after {
content: '│';
position: absolute;
bottom: 0;
left: -1.42em;
transform: rotate(90deg);
-moz-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
}
li:last-child .line:before {
content: '│';
position: absolute;
bottom: -0.69em;
left: -2em;
transform: scaleY(100);
transform-origin: bottom;
-moz-transform: scaleY(100);
-moz-transform-origin: bottom;
-webkit-transform: scaleY(100);
-webkit-transform-origin: bottom;
}
li {
list-style-type: none;
padding-left: 2em;
}
.line {
position: relative;
display: inline-block;
}
.controls {
visibility: hidden;
}
.line:hover > .controls {
visibility: visible;
}
a:hover {
background-color: #ddd;
}
pre {
line-height: 1.15em;
font-family: Courier New,monospace,serif;
letter-spacing: -0.02em;
}
JavaScript
var prefix = "├── ",
prefix_last = "└── ",
spacer = "│ ",
spacer_e = " ",
ul_template = $('#tree'),
li_template = $('li', ul_template).first().clone();
var action = {
"add-sibling" : function(obj) {
li_template.clone().insertAfter(obj);
},
"add-child" : function(obj) {
var ul = obj.children('ul');
if (ul.length === 0) {
ul = $('<ul/>').appendTo(obj);
}
li_template.clone().appendTo(ul);
},
"delete" : function(obj) { obj.remove(); }
};
$(document).on('click', 'li .controls > a', function(e) {
e.preventDefault();
action[this.getAttribute('data-func')]($(this).closest('li'));
rebuild_tree();
});
function get_subdir_text(obj, pad) {
var padding = pad || "",
out = "",
items = obj.children("li"),
last = items.length - 1;
items.each(function(index) {
var $this = $(this);
out += padding
+ ((index == last) ? prefix_last : prefix)
+ $this.find("> .line input").val() + "\n";
var subdirs = $this.children("ul");
if (subdirs.length) {
out += get_subdir_text(subdirs,
padding + ((index == last) ? spacer_e : spacer ));
}
});
return out;
}
function rebuild_tree() {
$('#out').text(get_subdir_text($('#tree')));
}
$("[data-func='add-sibling'],[data-func='add-child']", '#tree').click();
$(document).on('keyup', '#tree input', function(e){
if (e.keyCode == '13') {
if (e.shiftKey) {
action['add-child']($(this).closest('li'));
} else {
action['add-sibling']($(this).closest('li'));
}
}
rebuild_tree();
});