2 * Treeview 1.4.2 - jQuery plugin to hide and show branches of a tree
4 * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
6 * Copyright Jörn Zaefferer
7 * Released under the MIT license:
8 * http://www.opensource.org/licenses/mit-license.php
13 // TODO rewrite as a widget, removing all the extra plugins
15 swapClass: function(c1, c2) {
16 var c1Elements = this.filter('.' + c1);
17 this.filter('.' + c2).removeClass(c2).addClass(c1);
18 c1Elements.removeClass(c1).addClass(c2);
21 replaceClass: function(c1, c2) {
22 return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
24 hoverClass: function(className) {
25 className = className || "hover";
26 return this.hover(function() {
27 $(this).addClass(className);
29 $(this).removeClass(className);
32 heightToggle: function(animated, callback) {
34 this.animate({ height: "toggle" }, animated, callback) :
36 jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
38 callback.apply(this, arguments);
41 heightHide: function(animated, callback) {
43 this.animate({ height: "hide" }, animated, callback);
50 prepareBranches: function(settings) {
51 if (!settings.prerendered) {
52 // mark last tree items
53 this.filter(":last-child:not(ul)").addClass(CLASSES.last);
54 // collapse whole tree, or only those marked as closed, anyway except those marked as open
55 this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
57 // return all items with sublists
58 return this.filter(":has(>ul)");
60 applyClasses: function(settings, toggler) {
61 // TODO use event delegation
62 this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
63 // don't handle click events on children, eg. checkboxes
64 if ( this == event.target )
65 toggler.apply($(this).next());
66 }).add( $("a", this) ).hoverClass();
68 if (!settings.prerendered) {
69 // handle closed ones first
70 this.filter(":has(>ul:hidden)")
71 .addClass(CLASSES.expandable)
72 .replaceClass(CLASSES.last, CLASSES.lastExpandable);
75 this.not(":has(>ul:hidden)")
76 .addClass(CLASSES.collapsable)
77 .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
79 // create hitarea if not present
80 var hitarea = this.find("div." + CLASSES.hitarea);
82 hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
83 hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
85 $.each($(this).parent().attr("class").split(" "), function() {
86 classes += this + "-hitarea ";
88 $(this).addClass( classes );
92 // apply event to hitarea
93 this.find("div." + CLASSES.hitarea).click( toggler );
95 treeview: function(settings) {
101 if ( settings.toggle ) {
102 var callback = settings.toggle;
103 settings.toggle = function() {
104 return callback.apply($(this).parent()[0], arguments);
108 // factory for treecontroller
109 function treeController(tree, control) {
110 // factory for click handlers
111 function handler(filter) {
113 // reuse toggle event handler, applying the elements to toggle
114 // start searching for all hitareas
115 toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
116 // for plain toggle, no filter is provided, otherwise we need to check the parent element
117 return filter ? $(this).parent("." + filter).length : true;
122 // click on first element to collapse tree
123 $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
124 // click on second to expand tree
125 $("a:eq(1)", control).click( handler(CLASSES.expandable) );
126 // click on third to toggle tree
127 $("a:eq(2)", control).click( handler() );
130 // handle toggle event
134 // swap classes for hitarea
136 .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
137 .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
139 // swap classes for parent li
140 .swapClass( CLASSES.collapsable, CLASSES.expandable )
141 .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
145 .heightToggle( settings.animated, settings.toggle );
146 if ( settings.unique ) {
149 // swap classes for hitarea
151 .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
152 .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
154 .replaceClass( CLASSES.collapsable, CLASSES.expandable )
155 .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
157 .heightHide( settings.animated, settings.toggle );
160 this.data("toggler", toggler);
162 function serialize() {
163 function binary(arg) {
167 branches.each(function(i, e) {
168 data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
170 $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
173 function deserialize() {
174 var stored = $.cookie(settings.cookieId);
176 var data = stored.split("");
177 branches.each(function(i, e) {
178 $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
183 // add treeview class to activate styles
184 this.addClass("treeview");
186 // prepare branches and find all tree items with child lists
187 var branches = this.find("li").prepareBranches(settings);
189 switch(settings.persist) {
191 var toggleCallback = settings.toggle;
192 settings.toggle = function() {
194 if (toggleCallback) {
195 toggleCallback.apply(this, arguments);
201 var current = this.find("a").filter(function() {
202 return location.href.toLowerCase().indexOf(this.href.toLowerCase()) == 0;
204 if ( current.length ) {
205 // TODO update the open/closed classes
206 var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
207 if (settings.prerendered) {
208 // if prerendered is on, replicate the basic class swapping
210 .swapClass( CLASSES.collapsable, CLASSES.expandable )
211 .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
213 .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
214 .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
220 branches.applyClasses(settings, toggler);
222 // if control option is set, create the treecontroller and show it
223 if ( settings.control ) {
224 treeController(this, settings.control);
225 $(settings.control).show();
232 // classes used by the plugin
233 // need to be styled via external stylesheet, see first example
235 var CLASSES = ($.treeview.classes = {
238 expandable: "expandable",
239 expandableHitarea: "expandable-hitarea",
240 lastExpandableHitarea: "lastExpandable-hitarea",
241 collapsable: "collapsable",
242 collapsableHitarea: "collapsable-hitarea",
243 lastCollapsableHitarea: "lastCollapsable-hitarea",
244 lastCollapsable: "lastCollapsable",
245 lastExpandable: "lastExpandable",