/* * 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) { 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("
").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);