tree using knockout and tmpl

by pabloski

HTML

<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
<script src="http://knockoutjs.com/js/knockout-1.2.0.js"></script>
<script id="folderTmpl" type="text/x-jquery-tmpl">
    <li class="toggle">
        <span class="expand">${expanderSymbol($item)}</span>
        <span>${name}</span>
    </li>
    {{if expanded}}
        <li>
            <ul>{{tmpl(getFolderItems($item)) "#itemTmpl"}}</ul>
            <ul>{{tmpl(getSubFolders($item)) "#folderTmpl"}}</ul>
        </li>
    {{/if}}
</script>

<script id="itemTmpl" type="text/x-jquery-tmpl">
    <li class="folderItem">${name}</li>
</script>

<ul id="samplesList" class="treeView"><li></li></ul>

CSS

.treeView li li {margin-left:18px;} 
.expand {
    vertical-align:middle;
    margin-right:7px;
    display:inline-block;
    border:1px solid #555;
    text-align:center;
    height:12px;
    width:12px;
    line-height:11px;
    background-color:#f8f8f8;
    color:Blue;
} 
.treeView, .treeView ul {padding:0;margin:0;} 
.treeView li {
    margin-left:8px;
    list-style-type:none;
    padding:2px;
    cursor:pointer;
} 
.treeView li.folderItem {
    color:Blue;
    text-decoration:underline;
    font-style:italic;
    margin-bottom:4px;
}

JavaScript

/* Hierarchy of named folders */ 
var folders = {
    name: "Samples",
    folders: [
        { name: "API", folders: [
            { name: ".tmpl()"}
        ]},
        { name: "Template markup", folders: [
            { name: "Tags", folders: [
                { name: "{{wrap}}"}
            ]},
        ]},
    ]
};

/* Array for the folder items. Each item can show up in one or more folders */
var samples = [
    { name: "Template in script block", 
        folders: [ ".tmpl()" ], 
        description: "Rendering a template declared in script block" },
    { name: "Template as string", 
        folders: [ ".tmpl()" ], 
        description:"Rendering a template passed as a string" },
    { name: "Render remote data", 
        folders: [ "API" ], 
        description: "Rendering remote data using templates" },
    { name: "Tab View", 
        folders: [ "{{wrap}}", ".tmpl()" ], 
        description: "A tab view, using {{wrap}}" }
];

/* Declare the functions for getting the items and subfolders, etc. 
   These could be simple global functions. 
   (Here we are adding them to the window object, which is equivalent). */
$.extend( window, { 
    getFolderItems: function( tmplItem ) {
        return $.map( samples, function( sample ) {
            return $.inArray( tmplItem.data.name, sample.folders ) > -1 ? sample : null;
        });
    }, 
    getSubFolders: function( tmplItem ) {
        return tmplItem.data.folders || [];
    }, 
    expanderSymbol: function( tmplItem ) {
        return tmplItem.data.expanded ? "-" : "+";
    }
});

$( "#folderTmpl" ).tmpl( folders ).appendTo( "#samplesList" );

$( "#samplesList" )
    .delegate( ".toggle", "click", function() {
        /* Toggle expanded property on data, then update rendering */
        var tmplItem = $.tmplItem( this );
        tmplItem.data.expanded = !tmplItem.data.expanded;
        tmplItem.update();
    })
    .delegate( ".folderItem", "click", function() {
        alert( $.tmplItem( this...