tree list

by JakobJingleheimer

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0/handlebars.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0-rc.3/handlebars.min.js"></script>

    <script id="partial-template" type="text/x-handlebars-template">
        <ul>
        {{#each nodes}} 
            <li{{#if this.nodes}} class="branch"{{/if}}>
                 <span class="four"><label>{{Name}}</label><i class="icon-plus" alt="add"></i></span>
            {{#if this.nodes}}{{> partial}}{{/if}}
            </li>
        {{/each}}
        </ul>
        
    </script>

    <!-- The template for rendering the source object -->
    <script id="main-template" type="text/x-handlebars-template">
        <h1>{{title}}</h1>
        <ul class="tree twelve">
            <li class="branch">
                {{#each nodes}}
                    <span class="four"><label>{{Name}}</label><i class="icon-plus" alt="add"></i></span>
                    {{> partial}}
                {{/each}}
            </li>
        </ul>
    </script>

CSS

html, body {
    display: block;
    height:  100%;
    width:   100%;
}

.twelve {
    width:100%;
}

.four {
    width: 33.334%;
}

ul.tree {
}

ul.tree li {
    margin-bottom: 0.1em;
}
ul.tree li > span > * {
    display: table-cell;
}

ul.tree li input {
    border: none;
    height: 100%;
    margin: 0;
    max-width: 100%;
}

ul.tree li.branch label:before {
    content: '–';
    margin-right: 0.5em;
}
ul.tree li.branch {
    background-color: rgba(125,125,125,0.2);
}

ul.tree li.branch.collapsed label:before {
    content: '+';
}
ul.tree li > ul {
    transition: all 1s;
}
ul.tree li.branch.collapsed > ul {
    height:0;
    opacity: 0;
}

ul.tree ul {
    padding-left: 16.667%;
}

ul.tree li > span {
    background-color: rgba(125,125,125,0.2);
    display: table-row;
}
ul.tree li > span > label {
    padding-left: 1.5em;
    padding: 0.5em;
}
i[class*="icon-"] {
    cursor: pointer;
    padding: 0.5em;
    text-align: center;
    width: 1em;
}
i[class*="icon-"]:before {
    color: white;
}
i.icon-plus {
    background-color: green;
}
i.icon-plus:before {
    content: '+';
}
i.icon-remove {
    background-color: red;
}
i.icon-remove:before {
    content: 'x';
}

ul.tree li.branch > span,
ul.tree li.branch > span > label {
    cursor: pointer;
}

JavaScript

$(document).ready(function () {
            //Handlebars.compile($("#partial-template").html());
            Handlebars.registerPartial("partial", $("#partial-template").html());

            var template = Handlebars.compile($("#main-template").html());

            var source = {
                "title":"Subnet Group Tree",
                "nodes":[
                    {
                        "Name": "Canada",

                        "nodes":[
                            {
                                "Name": "Alberta",
                                
                                "nodes":[
                                    {
                                        "Name": "Edmonton"
                                    },
                                    {
                                        "Name": "Calgary"
                                    }
                                ]
                            },
                            {
                                "Name": "BC"
                            }
                        ]
                    }
                ]
            };

            $("body").html(template(source));
});

$('li.branch').find('label').on('click', function(event)
{
    $(this).parent().parent().toggleClass('collapsed');
    event.stopPropagation();
});
$('i.icon-plus').on('click', function(event)
{
    console.log('clicked');
    var $newLI = $( document.createElement('li') )
        .html('<span class="four"><label><input placeholder="New leaf" /></label><i class="icon-remove" alt="add"></i></span>');
        $newLI.find('i.icon-remove').on('click', function(event)
    {
        $(this).parent().parent().remove();
    });
    $(this).closest('ul').append( $newLI );
});