| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 | /* * 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,v 1.1 2009/10/01 17:59:38 ccheng Exp $ * */;(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) {			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.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);
 |