Template:CollapsibleTree

Table of contents
No headers
// CollapsibleTree template, by neilw, 2009
// Versions
//    1.00    6/25/09    neilw
//    1.01    6/26/09    neilw    Fixed slide operation on sublists
//    1.02    6/26/09    neilw    Fixed very strange bug with body html
//    1.03    6/29/09    neilw    Set marker to display:none to avoid extra whitespace

//NOTE: This template requires the file "collapse_icons.gif" to be installed in the location
// specified below
var icons = "http://snstouch.com/@api/deki/files/172/=collapse_icons.gif";

// USAGE: template.collapsibleList(path, tree_depth, collapse_depth, slide)
//    "xml": if specified, then insert this list xml.  Doesn't matter if the list is wrapped
//        inside other elements.  Otherwise, find the next <UL> on the page just after the template
//        call.
//    "depth": number of tree levels to collapse (default: 99).  This is to avoid very lengthy
//        processing on very large trees.  However, the processing is on the client side, so it
//        won't bog down the wiki server either way.
//    "slide": if true, use "slide" effect to show/hide subtrees (default: false)

// Args
var xml = $0 ?? $xml;
var depth = $1 ?? $depth ?? 99;
var slide = $2 ?? $slide ?? false;

// Output
<html>
// Scripts go in the head
<head>
//
// First script element is unique to each template call, passing args to the common code
//
<script type="text/javascript">"
DekiWiki.$(document).ready(function($) {
    collapse_list($, " .. json.emit(@id) .. ", "..json.emit(depth)..","..json.emit(slide)..");
});
"</script>
//
// This script element is always the same, so only one copy will end up on the page even if the
// template is called multiple times
//
<script type="text/javascript">"
function collapse_list($, id, max_depth, slide) {
// Find the list
    var $list;
    var pid = 'p#' + id;
    var $nodes = $(pid).nextAll();
    for (var i = 0; i < $nodes.length; i++) {
        $list = $nodes.eq(i);
        if ($list.is('ul'))
            break;
        $list = $list.find('ul:first');
        if ($list.length > 0)
            break;
    }
// Make sure we found it
    if ($list.length == 0) {
	alert(\"ERROR: CollapsibleTree: can\'t find unordered list\"); 
	return;
    }
    $list.children('li').find('ul:first').hide();	// hide first level ASAP
    $(pid).next().show();
// Recursively traverse list
    if (max_depth > 0) collapse_list_recurse($, $list, 0, max_depth, slide);
}

var collapseIcon_hide = '0px -64px';
var collapseIcon_show = '0px -80px';

function collapse_list_recurse($, $list, depth, max_depth, slide) {
// Fail-safe
	if (depth >= max_depth) return;
// Make each list item collapsible
	$list.children('li').each(function () {
	// Get rid of bullet and insert icon in front of each list item
		$(this).css({'margin-left':'0', 'padding-left':'0', 'list-style-type':'none'}).prepend(
                '<img src=\"http://snstouch.com/@api/deki/files/172/=collapse_icons.gif\" style=\"background-image:url(\\\'".. icons .. "\\\')\" /> ');
	// Find and hide inner UL, if any
		var $ul  	= $(this).children('ul:first').hide();
		var $img	= $(this).children('img:first');
	// Set bullet to expand icon or appropriate UL bullet
		$img.css('background-position',
                ($ul.length ? collapseIcon_show : '0px -'+(16+16*(depth%3))+'px'));
	// If appropriate, link icon to toggle function and recurse
		if ($ul.length) {
			$img.css('cursor','pointer').click(function() {
				var display = $ul.css('display');
				if (display == 'none') {
					if (slide)	$ul.slideDown('fast');
					else		$ul.show();
					$(this).css('background-position',collapseIcon_hide);
				}
				else {
					if (slide)	$ul.slideUp('fast');
					else		$ul.hide();
					$(this).css('background-position',collapseIcon_show);
				}
				return(false);
			});
		// recurse
			if (depth+1 < max_depth) 
				collapse_list_recurse($, $ul, depth+1, max_depth, slide);
		}
	});
}
"</script>
</head>
// Content goes in the body
<body>
    <p id="{{@id}}" style="display:none;"/>  // This is a marker to help find the list that follows
    <div style="display:none"> xml </div>;
</body>
</html>

Tag page