Template:AjaxWikiTree

    Documentation

    This box includes basic usage information for this template.  When calling the template, this documentation will not appear.  Functional template code should be placed outside the dotted box.

    Summary

    Template Description

    This template produces a collapsible wiki tree.  Rather than pre-fetching the entire tree, it dynamically fetches only as much as necessary via AJAX and the Mindtouch API.  This means it loads quickly even if the full tree is very large, and makes it suitable for implementing a navigation tree for an entire wiki site.

    If you're not working with a large tree and therefore performance isn't an issue, you can also look at the non-AJAX version, "CollapsibleTree".

    This template was originally implemented by Blake Harms based on the CollapsibleTree template, and currently maintained by Neil Weinstock.

    Requirements
    Documentation URL http://developer.mindtouch.com/App_Catalog/AJAX_collapsible_wiki_tree
    Discussion URL http://forums.developer.mindtouch.com/showthread.php?5972-NEW-AJAX-Collapsible-Wiki.Tree

    Version History

    Place newest version at the top of the table.

    Version Date Author Description
    1.8.1 12-May-2011 Neil Weinstock Fixed alphabetization error for top-level list.
    1.8 11-May-2011 Neil Weinstock
    • Replaced wiki.tree() to speed things up a bit
    • Now require image files to be attached to template page
    • other minor clean-up
    1.7 30-Sep-2009 Neil Weinstock Converted to use page IDs as links, to fix all character encoding and URL escaping issues
    1.6 4-Sep-2009 Blake Harms Fixes for German language - Thanks Baum!
    1.5.1 10-Jul-2009 Blake Harms Removed click function from pages that do not have subpages
    1.5 10-Jul-2009 Blake Harms Added Ajax checks for subpage #s and added depth to the bullets
    1.3 10-Jul-2009 Blake Harms Fixed XML parsing for all major browsers
    1.2 9-Jul-2009 Blake Harms Fixed a MAJOR bug where IE didn't read XML properly
    1.0 9-Jul-2009 Blake Harms First version posted to App Catalog

    Template Parameters

    Name Type Default Description
    path str? page.path Path to the root of the tree
    slide bool? false Use "slide" effect to collapse and expand sub-trees

    Template Code

    UNSAFECONTENT Permission check

    var thisTemplate = wiki.inclusions()[-1];
    if (!wiki.pagepermissions(thisTemplate.id, thisTemplate.author.id).unsafecontent)
      <div style="color:red; width:75%; padding:5px; border:1px solid red;">
        "WARNING: The page '"..thisTemplate.path.."' must be re-saved by a user with UNSAFECONTENT permission in order to work correctly. ";
        <a href="http://developer.mindtouch.com/en/kb/Using_templates_which_require_UNSAFECONTENT_permission"> "See this" </a>;
        " for more info."; 
      </div>;
    

    Main Code Block

    // Deki AJAX API extension required!
    dekiapi();
    
    // Image files "collapse_icons.gif" and "loadinfo.net.gif" must be attached to this template!
    var iconsIMG  = thisTemplate.files["collapse_icons.gif"].uri;
    var loaderIMG = thisTemplate.files["loadinfo.net.gif"  ].uri;
    
    // USAGE: template.collapsibleList(path, slide)
    //    "path": Path for wiki.tree to load.
    //    "slide": if true, use "slide" effect to show/hide subtrees (default: false)
    
    // Args
    var path = $0 ?? $path ?? page.path;
    var slide = $1 ?? $slide ?? false;
    
    // Output
    <html>
    <head>
    
    //
    // First script element is unique to each template call, passing args to the common code
    //
    <script type="text/javascript">"
    DekiWiki.$(document).ready(function($) {
    	ajax_collapse_list(Deki.$('#" .. @id .. "').find('ul'),0, "..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">"
    var collapseIcon_hide = '0px -64px';
    var collapseIcon_show = '0px -80px';
    
    function readXML(str){
        var xml;
        if ($.browser.msie && typeof str == 'string') {
            xml = new ActiveXObject('Microsoft.XMLDOM');
            xml.async = false;
            xml.loadXML(str);
        } else {
            var parser = new DOMParser();
            xml = parser.parseFromString(str, 'text/xml');
        }
        return xml;
    }
    
    function ajax_collapse_list(ul, depth, slide){
        Deki.$(ul).children().each(function(){
            var $child = Deki.$(this).css({'margin-left':'0', 'padding-left':'0', 'list-style-type':'none'}).prepend(
                '<img src=\"/skins/common/icons/icon-trans.gif\" style=\"background-image:url(".. iconsIMG .. ")\" /> ');
            var $img	= $child.children('img:first');
            var child_id = $child.children('a:first').attr('pageid');
             // Check each item for subpages, if they have them, add the + button, if not, set depth.
            Deki.$.ajax({
    	    url: '/@api/deki/pages/'+child_id+'/subpages',
    	    type: 'GET',
                data: {
                    limit:0
                },
                dataType: ($.browser.msie) ? 'text' : 'xml',
    	    complete: function(data) {
                    var xml = readXML(data.responseText);
                    var count = Deki.$('subpages',xml).attr('totalcount');
                    if(count > 0 ){
                        $img.css('background-position', collapseIcon_show);
                    }
                    else {
                        $img.css('background-position', '0px -'+(16+16*(depth%3))+'px')
                            .css('cursor','auto')
                            .unbind('click');
                    }
    	    }
    	});
    	// Take action when expand or collapse icon is clicked
    	$img.css('background-position', collapseIcon_show)
                .css('cursor','pointer')
                .click(function(){
                    $self= Deki.$(this);
                    $parent = $self.parent();
                    var subpages = $parent.children('ul:first');
                    if(subpages.css('display') == 'none'){        // subpages is hidden
                        //show sublist
                        if(slide)            subpages.slideDown('fast');
    		    else                 subpages.show();
                        $self.css('background-position',collapseIcon_hide);
                    }
                    else if(subpages.html() && subpages.html().length > 0){        // subpages is not hidden
                        //hide sublist
                        if(slide)            subpages.slideUp('fast');
    		    else                 subpages.hide();
    		    $self.css('background-position',collapseIcon_show);
                    }
                    else {    // the hard part...
                        // loader icon.
                        $self.css('background-image','url("..loaderIMG..")');
                        //strip all empty uls
                        $parent.find('ul').each(function(){
                            if(! subpages.html() || subpages.html().length <= 0){
                                Deki.$(this).remove();
                            }
                        });
    		    // collect parent's page id.
    		    var link = $parent.find('a');
    		    var pageid = link.attr('pageid');
                        // load list with ajax
                        // create and immediately hide the list
    		    subpages = Deki.$('<ul></ul>').css('display','none');
    		    Deki.$.ajax({
    		        url: '/@api/deki/pages/'+pageid+'/subpages',
    			type: 'GET',
                            dataType: ($.browser.msie) ? 'text' : 'xml',
    			complete: function(data) {
                                var xml = readXML(data.responseText);
                                var titles = Deki.$('title',xml);
                                var paths  = Deki.$('path', xml);
                                if(titles.length > 0 ){
                                // Pre-populate list
                                    for(var i=0; i< titles.length;i++){
                                        var pageid = Deki.$(titles[i]).parent().attr('id');
                                        var $child = Deki.$('<li></li>')
                                            .append(Deki.$('<a></a>')
                                                .text(Deki.$(titles[i]).text())
                                            // This link method uses a backdoor mechanism, but it seems safe
                                                .attr({'href':'/index.php?title=_&curid='+pageid, 'pageid':pageid }))
                                            .appendTo(subpages);
                                    }
                                    $self.css('background-image','url("..iconsIMG..")')
                                         .css('background-position', collapseIcon_hide);
                                    $parent.append(subpages);
                                    if(slide)    subpages.slideDown('fast')
                                    else         subpages.show();
    			        ajax_collapse_list(subpages, depth+1, slide);
                                }
                                else {
                                    $self.css('background-image','url("..iconsIMG..")')
                                         .css('background-position', '0px -'+(16+16*(depth%3))+'px');
                                }
    			}
    		    });
                    }
                });
        });
    }
    "</script>;
    
    </head>
    // Content goes in the body
    <body>
            <div id=(@id)>
                <ul> foreach (var p in list.sort(map.values(wiki.getpage(path).subpages),"title"))
                    <li> <a href=(p.uri) title=(p.title) pageid=(p.id)> p.title </a> </li>;
                </ul>;
            </div>;
    </body>
    </html>
    
    Tag page

    Files 2

    FileVersionSizeModified 
    You must login to post a comment.

    Copyright © 2011 MindTouch, Inc. Powered by