/* 
  * Treeview 1.4 - jQuery plugin to hide and show branches of a tree 
  * 
  * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ 
  * http://docs.jquery.com/Plugins/Treeview 
  * 
  * Copyright (c) 2007 Jörn Zaefferer 
  * 
  * 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 4684 2008-02-07 19:08:06Z joern.zaefferer $ 
  * 
  */ 
  
 ;(function($) { 
  
         $.extend($.fn, { 
                 swapClass: function(c1, c2) { 
                         var c1Elements = this.filter('.' + c1); 
                         this.filter('.' + c2).removeClass(c2).addClass(c1); 
                         c1Elements.removeClass(c1).addClass(c2); 
                         return this; 
                 }, 
                 replaceClass: function(c1, c2) { 
                         return this.filter('.' + c1).removeClass(c1).addClass(c2).end(); 
                 }, 
                 hoverClass: function(className) { 
                         className = className || "hover"; 
                         return this.hover(function() { 
                                 $(this).addClass(className); 
                         }, function() { 
                                 $(this).removeClass(className); 
                         }); 
                 }, 
                 heightToggle: function(animated, callback) { 
                         animated ? 
                                 this.animate({ height: "toggle" }, animated, callback) : 
                                 this.each(function(){ 
                                         jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); 
                                         if(callback) 
                                                 callback.apply(this, arguments); 
                                 }); 
                 }, 
                 heightHide: function(animated, callback) { 
                         if (animated) { 
                                 this.animate({ height: "hide" }, animated, callback); 
                         } else { 
                                 this.hide(); 
                                 if (callback) 
                                         this.each(callback); 
                         } 
                 }, 
                 prepareBranches: function(settings) { 
                         if (!settings.prerendered) { 
                                 // mark last tree items 
                                 this.filter(":last-child:not(ul)").addClass(CLASSES.last); 
                                 // collapse whole tree, or only those marked as closed, anyway except those marked as open 
                                 this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide(); 
                         } 
                         // return all items with sublists 
                         return this.filter(":has(>ul)"); 
                 }, 
                 applyClasses: function(settings, toggler) { 
                         if (settings.link_unfold_onclick) { 
                                 this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) { 
                                         toggler.apply($(this).next()); 
                                 }).add( $("a", this) ).hoverClass(); 
                         } 
  
                         if (!settings.prerendered) { 
                                 // handle closed ones first 
                                 this.filter(":has(>ul:hidden)") 
                                                 .addClass(CLASSES.expandable) 
                                                 .replaceClass(CLASSES.last, CLASSES.lastExpandable); 
  
                                 // handle open ones 
                                 this.not(":has(>ul:hidden)") 
                                                 .addClass(CLASSES.collapsable) 
                                                 .replaceClass(CLASSES.last, CLASSES.lastCollapsable); 
  
                     // create hitarea 
                                 this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea).each(function() { 
                                         var classes = ""; 
                                         $.each($(this).parent().attr("class").split(" "), function() { 
                                                 classes += this + "-hitarea "; 
                                         }); 
                                         $(this).addClass( classes ); 
                                 }); 
                         } 
  
                         // apply event to hitarea 
                         this.find("div." + CLASSES.hitarea).click( toggler ); 
                 }, 
                 treeview: function(settings) { 
  
                         settings = $.extend({ 
                                 cookieId: "treeview" 
                         }, settings); 
  
                         if (settings.add) { 
                                 return this.trigger("add", [settings.add]); 
                         } 
  
                         if ( settings.toggle ) { 
                                 var callback = settings.toggle; 
                                 settings.toggle = function() { 
                                         return callback.apply($(this).parent()[0], arguments); 
                                 }; 
                         } 
  
                         // factory for treecontroller 
                         function treeController(tree, control) { 
                                 // factory for click handlers 
                                 function handler(filter) { 
                                         return function() { 
                                                 // reuse toggle event handler, applying the elements to toggle 
                                                 // start searching for all hitareas 
                                                 toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { 
                                                         // for plain toggle, no filter is provided, otherwise we need to check the parent element 
                                                         return filter ? $(this).parent("." + filter).length : true; 
                                                 }) ); 
                                                 return false; 
                                         }; 
                                 } 
                                 // click on first element to collapse tree 
                                 $("a:eq(0)", control).click( handler(CLASSES.collapsable) ); 
                                 // click on second to expand tree 
                                 $("a:eq(1)", control).click( handler(CLASSES.expandable) ); 
                                 // click on third to toggle tree 
                                 $("a:eq(2)", control).click( handler() ); 
                         } 
  
                         // handle toggle event 
                         function toggler() { 
                                 $(this) 
                                         .parent() 
                                         // swap classes for hitarea 
                                         .find(">.hitarea") 
                                                 .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) 
                                                 .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) 
                                         .end() 
                                         // swap classes for parent li 
                                         .swapClass( CLASSES.collapsable, CLASSES.expandable ) 
                                         .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) 
                                         // find child lists 
                                         .find( ">ul" ) 
                                         // toggle them 
                                         .heightToggle( settings.animated, settings.toggle ); 
                                 if ( settings.unique ) { 
                                         $(this).parent() 
                                                 .siblings() 
                                                 // swap classes for hitarea 
                                                 .find(">.hitarea") 
                                                         .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) 
                                                         .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) 
                                                 .end() 
                                                 .replaceClass( CLASSES.collapsable, CLASSES.expandable ) 
                                                 .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) 
                                                 .find( ">ul" ) 
                                                 .heightHide( settings.animated, settings.toggle ); 
                                 } 
                         } 
  
                         function serialize() { 
                                 function binary(arg) { 
                                         return arg ? 1 : 0; 
                                 } 
                                 var data = []; 
                                 branches.each(function(i, e) { 
                                         data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0; 
                                 }); 
                                 $.cookie(settings.cookieId, data.join("") ); 
                         } 
  
                         function deserialize() { 
                                 var stored = $.cookie(settings.cookieId); 
                                 if ( stored ) { 
                                         var data = stored.split(""); 
                                         branches.each(function(i, e) { 
                                                 $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ](); 
                                         }); 
                                 } 
                         } 
  
                         // add treeview class to activate styles 
                         this.addClass("treeview"); 
  
                         // prepare branches and find all tree items with child lists 
                         var branches = this.find("li").prepareBranches(settings); 
  
                         switch(settings.persist) { 
                         case "cookie": 
                                 var toggleCallback = settings.toggle; 
                                 settings.toggle = function() { 
                                         serialize(); 
                                         if (toggleCallback) { 
                                                 toggleCallback.apply(this, arguments); 
                                         } 
                                 }; 
                                 deserialize(); 
                                 break; 
                         case "location": 
                                 var current = this.find("a").filter(function() { return this.href.toLowerCase() == location.href.toLowerCase(); }); 
                                 if ( current.length ) { 
                                         current.addClass("selected").parents("ul, li").add( current.parent().next() ).show(); 
                                 } 
                                 break; 
                         } 
  
  
                         branches.applyClasses(settings, toggler); 
  
                         // if control option is set, create the treecontroller and show it 
                         if ( settings.control ) { 
                                 treeController(this, settings.control); 
                                 $(settings.control).show(); 
                         } 
  
                         return this.bind("add", function(event, branches) { 
                                 $(branches).prev() 
                                         .removeClass(CLASSES.last) 
                                         .removeClass(CLASSES.lastCollapsable) 
                                         .removeClass(CLASSES.lastExpandable) 
                                 .find(">.hitarea") 
                                         .removeClass(CLASSES.lastCollapsableHitarea) 
                                         .removeClass(CLASSES.lastExpandableHitarea); 
                                 $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler); 
                         }); 
                 } 
         }); 
  
         // classes used by the plugin 
         // need to be styled via external stylesheet, see first example 
         var CLASSES = $.fn.treeview.classes = { 
                 open: "open", 
                 closed: "closed", 
                 expandable: "expandable", 
                 expandableHitarea: "expandable-hitarea", 
                 lastExpandableHitarea: "lastExpandable-hitarea", 
                 collapsable: "collapsable", 
                 collapsableHitarea: "collapsable-hitarea", 
                 lastCollapsableHitarea: "lastCollapsable-hitarea", 
                 lastCollapsable: "lastCollapsable", 
                 lastExpandable: "lastExpandable", 
                 last: "last", 
                 hitarea: "hitarea" 
         }; 
  
         // provide backwards compability 
         $.fn.Treeview = $.fn.treeview; 
  
 })(jQuery); 
 
