JSFiddle - React, Tailwind, and code Playground

by Paulo Silva

HTML

<div id="content">
    <div class="listTree"></div>
    <button class="btn btn-success">Check All</button>
    <button class="btn btn-danger">Un-Check All</button>
    <button class="btn btn-info">Expand All</button>
    <button class="btn btn-warning">Collapse All</button>
    <button class="btn btn-inverse">Change Data</button>
 
    <br /><br />
    
    <h4>Selection JSON:</h4>
    <pre id="selectionJson"></pre>
    <button class="btn btn-primary">Get JSON for selected nodes</button>
</div>

CSS

/*
 * Copyright 2012 Clay Walker
 * Licensed under GPLv2 ONLY
 */
.listTree {
    margin-bottom: 18px;
}
 
.listTree i {
    float: right;
    margin-right: 15px;
}
 
.listTree ul {
    margin: 0;
}
 
.listTree li {
    list-style-type: none;
    cursor: pointer;
}
 
.listTree > ul > li {
    background-color: #eee;
    border-width: 1px 1px 0 1px;
    border-style: solid;
    border-color: #ddd;
}
 
.listTree > ul > li:first-child {
    border-width: 1px 1px 0 1px;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
}
 
.listTree > ul > li:last-child {
    border-width: 1px;
    border-bottom-left-radius: 3px;
    border-bottom-right-radius: 3px;
}
 
.listTree > ul > li:last-child > ul > li:last-child {
    border-bottom-left-radius: 3px;
    border-bottom-right-radius: 3px;
}
 
.listTree span {
    display: inline-block;
    width: 100%;
    padding: 5px;
}
 
.listTree > ul > li > span {
    font-weight: bold;
}
 
.listTree > ul > li > ul > li {
    background-color: #fff;
    border-width: 1px 0 0 0;
    border-style: solid;
    border-color: #ddd;
    padding-left: 10px;
}
 
.listTree > ul > li > ul > li:first-child {
    border-width: 1px 0 0 0;
}
 
.listTree > ul > li > ul > li:last-child {
    border-width: 1px 0 0 0;
}
 
.listTree input[type="checkbox"] {
    margin-top: 0;
}

JavaScript

/*
 * Copyright 2012 Clay Walker
 * Licensed under GPLv2 ONLY
 */
;(function($) {
    var template = '\
        <ul>\
            <% _.each(context, function(parent, index) { %>\
            <li>\
                <span><input type="checkbox" \
                <% var ps; %>\
                <% if ( !_.isUndefined(ps = _.find(options.selected, function(elem) { return elem.key === this.key; }, parent)) ) { %>\
                checked="checked"\
                <% } %> value="<%= parent.key %>" /> <%= parent.key %><i class="icon-chevron-up icon-black"></i></span>\
                <% if (options.startCollapsed) { %>\
                <ul style="display: none;">\
                <% } else { %>\
                <ul>\
                <% } %>\
                    <% _.each(parent.values, function(child, index) { %>\
                    <li>\
                        <span><input type="checkbox" \
                        <% if ( !_.isUndefined(this) && !_.isUndefined(_.find(this.values, function(elem) { return elem.key === this.key; }, child)) ) { %>\
                        checked="checked"\
                        <% } %> value="<%= child.key %>" /> <%= child.key %></span>\
                    </li>\
                    <% }, ps); %>\
                </ul>\
            </li>\
            <% }); %>\
        </ul>';
    
    /** Check all child checkboxes.
     * @param jQElement The parent <li>.
     */
    function _selectAllChildren(jQElement) {
        jQElement.find('ul > li > span > input[type="checkbox"]')
            .each(function() {
                $(this).prop('checked', true);
            });
    }
    
    /** Uncheck all child checkboxes.
     * @param jQElement The parent <li>.
     */
    function _deselectAllChildren(jQElement) {
        jQElement.find('ul > li > span > input[type="checkbox"]')
            .each(function() {
                $(this).prop('checked', false);
            });
    }
    
    /** Toggle all checkboxes.
     * @param[in] jQElement...