









































































/*
 * Treeview 1.0 - jQuery plugin to hide and show branches of a tree
 *
 * Copyright (c) 2006 Jörn Zaefferer, Myles Angell
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.treeview.js 1195 2007-01-25 12:33:29Z joern $
 *
 */

/**
 * Takes an unordered list and makes all branches collapsable.
 *
 * The "treeview" class is added if not already present.
 *
 * To hide branches on first display, mark their li elements with
 * the class "closed". If the "collapsed" option is used, mark intially open
 * branches with class "open".
 *
 * @example .treeview, .treeview ul { 
 * 	padding: 0;
 * 	margin: 0;
 * 	list-style: none;
 * }	
 * 
 * .treeview li { 
 * 	position: relative;
 * 	margin: 0;
 * 	padding: 4px 0 3px 20px;
 * 	z-index: 10;
 * }
 * 
 * .treeview li { background: url(images/tv-item.gif) 0 0 no-repeat; }
 * .treeview .collapsable { background-image: url(images/tv-collapsable.gif); }
 * .treeview .expandable { background-image: url(images/tv-expandable.gif); }
 * .treeview .last { background-image: url(images/tv-item-last.gif); }
 * .treeview .lastCollapsable { background-image: url(images/tv-collapsable-last.gif); }
 * .treeview .lastExpandable { background-image: url(images/tv-expandable-last.gif); }
 * @desc The following styles are necessary in your stylesheet. There is an alternative set of images available.
 *
 * @example $("ul").Treeview();
 * @before <ul>
 *   <li>Item 1
 *     <ul>
 *       <li>Item 1.1</li>
 *     </ul>
 *   </li>
 *   <li class="closed">Item 2 (starts closed)
 *     <ul>
 *       <li>Item 2.1
 *         <ul>
 *           <li>Item 2.1.1</li>
 *           <li>Item 2.1.2</li>
 *         </ul>
 *       </li>
 *       <li>Item 2.2</li>
 *     </ul>
 *   </li>
 *   <li>Item 3</li>
 * </ul>
 * @desc Basic usage example
 *
 * @example $("ul").Treeview({ speed: "fast", collapsed: true});
 * @before <ul>
 *   <li class="open">Item 1 (starts open)
 *     <ul>
 *       <li>Item 1.1</li>
 *     </ul>
 *   </li>
 *   <li>Item 2
 *     <ul>
 *       <li>Item 2.1</li>
 *       <li>Item 2.2</li>
 *     </ul>
 *   </li>
 * </ul>
 * @desc Create a treeview that starts collapsed. Toggling branches is animated.
 *
 * @example $("ul").Treeview({ control: #treecontrol });
 * @before <div id="treecontrol">
 *   <a href="#">Collapse All</a>
 *   <a href="#">Expand All</a>
 *   <a href="#">Toggle All</a>
 * </div>
 * @desc Creates a treeview that can be controlled with a few links.
 * Very likely to be changed/improved in future versions.
 *
 * @param Map options Optional settings to configure treeview
 * @option String|Number speed Speed of animation, see animate() for details. Default: none, no animation
 * @option Boolean collapsed Start with all branches collapsed. Default: none, all expanded
 * @option <Content> control Container for a treecontrol, see last example.
 * @type jQuery
 * @name Treeview
 * @cat Plugins/Treeview
 */

Element.addMethods( {
	// necessary helper method
	swapClass: function(element, c1,c2) {
		element = $(element);
		////console.log("this: "+ element);
		if ( element.hasClassName(c1) )
			element.removeClassName(c1).addClassName(c2);
		else if ( element.hasClassName(c2) )
			element.removeClassName(c2).addClassName(c1);
		return element;
	},
});

Treeview = {
	CLASSES: {
		open: "open",
		closed: "closed",
		expandable: "expandable",
		collapsable: "collapsable",
		lastCollapsable: "lastCollapsable",
		lastExpandable: "lastExpandable",
		last: "last",
		hitarea: "hitarea"
	},
	
	create: function(element, options) {
		
		element = $(element);
		if (!element) {
			////console.debug("Treeview: couldn't find element '"+element+"'");
			return null;
		}
		
		// currently no defaults necessary, all implicit
		options = Object.extend({
				expandableItems: false,
				classNameExpandableItemControl: 'title', // class name that will be used to control expandable items
				classNameExpandableItemSource: 'content', // class name of the expandable item content
			}, options);
		
		// styles for hitareas
		var hitareaCSS = {
			height: 15,
			width: 15,
			marginLeft: "-15px",
			float: "left",
			cursor: "pointer"
		};
		
		// classes used by the plugin
		// need to be styled via external stylesheet, see first example

		// ie specific styles for hitareas
		if( Prototype.Browser.IE )
			Object.extend( hitareaCSS, {
				background: "#fff",
				filter: "alpha(opacity=0)",
				left: -21
			});
		
		////console.debug("element: " + element);	
	
		// add treeview class to activate styles
		element.addClassName("treeview");
		
		// mark last tree items
		//$("li:last-child", this).addClass(CLASSES.last);
		element.getElementsBySelector("li").each( function(li) {
			// this is the last item if we don't have any further siblings
			if ( !li.next() ) {
				//console.debug("adding className to last list item", li, li.next() );
				li.addClassName(Treeview.CLASSES.last);
			}
		});
		
		
		// collapse whole tree, or only those marked as closed, anyway except those marked as open
		//$( (options.collapsed ? "li" : "li." + CLASSES.closed) + ":not(." + CLASSES.open + ") > ul", this).hide();
		
		// find all tree items with child lists
		element.getElementsBySelector("li").each( function(li) {
			if (! li.getElementsBySelector("ul")) {
				//console.debug("li doesn't have any ul", li);
				return;
			}
			
			// li should only have one direct child ul
			li.childElements().each( function( node ) {
        
        //console.debug('li.child', node, node.tagName);
        
        if (node.tagName == 'UL') {
            var ul = node;
            // handle open ones
            if (ul.visible) {
                //console.debug("adding classname to li for open ul", li, ul);
                li.addClassName(Treeview.CLASSES.collapsable);
                li.swapClass(Treeview.CLASSES.last, Treeview.CLASSES.lastCollapsable);
            }
            // handle closed ones
            else {
                //console.debug("adding classname to li for closed ul", li, ul);
                li.addClassName(Treeview.CLASSES.expandable);
                li.swapClass(Treeview.CLASSES.last, Treeview.CLASSES.lastExpandable);
            }
        }
			});
			
		  if( li.select("ul").first() ) {
		  
        // append hitarea
        //console.debug("appending hitarea to li", li, li.select("ul") );
        new Insertion.Top(li, "<div class=\"" + Treeview.CLASSES.hitarea + "\">");
        
        // find hitarea
        li.getElementsBySelector("div." + Treeview.CLASSES.hitarea).each( function(div) {
            //console.debug("adding styles to hitarea", div);
            // apply styles to hitarea
            div.setStyle(hitareaCSS);
            // apply click event to hitarea
            //console.debug("adding 'click' observer to hitarea div", div);
            div.observe('click', function (event) {
                var hitarea = Event.element(event);
                //console.debug("onClickEvent", event);
                // this refers to hitareas, we need to find the parent lis first
                hitarea.up()
                // swap classes
                .swapClass(Treeview.CLASSES.collapsable, Treeview.CLASSES.expandable)
                .swapClass(Treeview.CLASSES.lastCollapsable, Treeview.CLASSES.lastExpandable)
                // find child lists
                .getElementsBySelector("ul").each( function(ul) {
                    // toggle them
                    ul.toggle();
                });
            });
        });
		  }
			//console.debug("after observe");
		});
		
		if (options.expandableItems) {
				//console.debug("making items expandable");
				
				// go through each li and get the text content
				//console.debug("getting expandable item control: ", options.classNameExpandableItemControl);
				element.getElementsBySelector("."+options.classNameExpandableItemControl).each( function(divControl) {
					//console.debug("divControl", divControl);
					var divSource = divControl.up().getElementsBySelector("." + options.classNameExpandableItemSource).first();
					divControl.setStyle({cursor: 'pointer'});
					if (divSource) {
						divControl.observe('click', function (event) {
							$(divSource).toggle();
						});
					}
				});
				
		}

		
		return this;
	},
};

