FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
jquery.treeview.js
1 /*
2  * Treeview 1.4.1 - jQuery plugin to hide and show branches of a tree
3  *
4  * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
5  * http://docs.jquery.com/Plugins/Treeview
6  *
7  * Copyright (c) 2007 Jörn Zaefferer
8  *
9  * Dual licensed under the MIT and GPL licenses:
10  * http://www.opensource.org/licenses/mit-license.php
11  * http://www.gnu.org/licenses/gpl.html
12  *
13  * Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $
14  *
15  */
16 
17 ;(function($) {
18 
19  // TODO rewrite as a widget, removing all the extra plugins
20  $.extend($.fn, {
21  swapClass: function(c1, c2) {
22  var c1Elements = this.filter('.' + c1);
23  this.filter('.' + c2).removeClass(c2).addClass(c1);
24  c1Elements.removeClass(c1).addClass(c2);
25  return this;
26  },
27  replaceClass: function(c1, c2) {
28  return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
29  },
30  hoverClass: function(className) {
31  className = className || "hover";
32  return this.hover(function() {
33  $(this).addClass(className);
34  }, function() {
35  $(this).removeClass(className);
36  });
37  },
38  heightToggle: function(animated, callback) {
39  animated ?
40  this.animate({ height: "toggle" }, animated, callback) :
41  this.each(function(){
42  jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
43  if(callback) {
44  callback.apply(this, arguments);
45  }
46  });
47  },
48  heightHide: function(animated, callback) {
49  if (animated) {
50  this.animate({ height: "hide" }, animated, callback);
51  } else {
52  this.hide();
53  if (callback) {
54  this.each(callback);
55  }
56  }
57  },
58  prepareBranches: function(settings) {
59  if (!settings.prerendered) {
60  // mark last tree items
61  this.filter(":last-child:not(ul)").addClass(CLASSES.last);
62  // collapse whole tree, or only those marked as closed, anyway except those marked as open
63  this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
64  }
65  // return all items with sublists
66  return this.filter(":has(>ul)");
67  },
68  applyClasses: function(settings, toggler) {
69  // TODO use event delegation
70  this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
71  // don't handle click events on children, eg. checkboxes
72  if ( this == event.target ) {
73  toggler.apply($(this).next());
74  }
75  }).add( $("a", this) ).hoverClass();
76 
77  if (!settings.prerendered) {
78  // handle closed ones first
79  this.filter(":has(>ul:hidden)")
80  .addClass(CLASSES.expandable)
81  .replaceClass(CLASSES.last, CLASSES.lastExpandable);
82 
83  // handle open ones
84  this.not(":has(>ul:hidden)")
85  .addClass(CLASSES.collapsable)
86  .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
87 
88  // create hitarea if not present
89  var hitarea = this.find("div." + CLASSES.hitarea);
90  if (!hitarea.length) {
91  hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
92  }
93  hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
94  var classes = "";
95  $.each($(this).parent().attr("class").split(" "), function() {
96  classes += this + "-hitarea ";
97  });
98  $(this).addClass( classes );
99  })
100  }
101 
102  // apply event to hitarea
103  this.find("div." + CLASSES.hitarea).click( toggler );
104  },
105  treeview: function(settings) {
106 
107  settings = $.extend({
108  cookieId: "treeview"
109  }, settings);
110 
111  if ( settings.toggle ) {
112  var callback = settings.toggle;
113  settings.toggle = function() {
114  return callback.apply($(this).parent()[0], arguments);
115  };
116  }
117 
118  // factory for treecontroller
119  function treeController(tree, control) {
120  // factory for click handlers
121  function handler(filter) {
122  return function() {
123  // reuse toggle event handler, applying the elements to toggle
124  // start searching for all hitareas
125  toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
126  // for plain toggle, no filter is provided, otherwise we need to check the parent element
127  return filter ? $(this).parent("." + filter).length : true;
128  }) );
129  return false;
130  };
131  }
132  // click on first element to collapse tree
133  $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
134  // click on second to expand tree
135  $("a:eq(1)", control).click( handler(CLASSES.expandable) );
136  // click on third to toggle tree
137  $("a:eq(2)", control).click( handler() );
138  }
139 
140  // handle toggle event
141  function toggler() {
142  $(this)
143  .parent()
144  // swap classes for hitarea
145  .find(">.hitarea")
146  .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
147  .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
148  .end()
149  // swap classes for parent li
150  .swapClass( CLASSES.collapsable, CLASSES.expandable )
151  .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
152  // find child lists
153  .find( ">ul" )
154  // toggle them
155  .heightToggle( settings.animated, settings.toggle );
156  if ( settings.unique ) {
157  $(this).parent()
158  .siblings()
159  // swap classes for hitarea
160  .find(">.hitarea")
161  .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
162  .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
163  .end()
164  .replaceClass( CLASSES.collapsable, CLASSES.expandable )
165  .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
166  .find( ">ul" )
167  .heightHide( settings.animated, settings.toggle );
168  }
169  }
170  this.data("toggler", toggler);
171 
172  function serialize() {
173  function binary(arg) {
174  return arg ? 1 : 0;
175  }
176  var data = [];
177  branches.each(function(i, e) {
178  data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
179  });
180  $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
181  }
182 
183  function deserialize() {
184  var stored = $.cookie(settings.cookieId);
185  if ( stored ) {
186  var data = stored.split("");
187  branches.each(function(i, e) {
188  $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
189  });
190  }
191  }
192 
193  // add treeview class to activate styles
194  this.addClass("treeview");
195 
196  // prepare branches and find all tree items with child lists
197  var branches = this.find("li").prepareBranches(settings);
198 
199  switch(settings.persist) {
200  case "cookie":
201  var toggleCallback = settings.toggle;
202  settings.toggle = function() {
203  serialize();
204  if (toggleCallback) {
205  toggleCallback.apply(this, arguments);
206  }
207  };
208  deserialize();
209  break;
210  case "location":
211  var current = this.find("a").filter(function() {
212  return this.href.toLowerCase() == location.href.toLowerCase();
213  });
214  if ( current.length ) {
215  // TODO update the open/closed classes
216  var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
217  if (settings.prerendered) {
218  // if prerendered is on, replicate the basic class swapping
219  items.filter("li")
220  .swapClass( CLASSES.collapsable, CLASSES.expandable )
221  .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
222  .find(">.hitarea")
223  .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
224  .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
225  }
226  }
227  break;
228  }
229 
230  branches.applyClasses(settings, toggler);
231 
232  // if control option is set, create the treecontroller and show it
233  if ( settings.control ) {
234  treeController(this, settings.control);
235  $(settings.control).show();
236  }
237 
238  return this;
239  }
240  });
241 
242  // classes used by the plugin
243  // need to be styled via external stylesheet, see first example
244  $.treeview = {};
245  var CLASSES = ($.treeview.classes = {
246  open: "open",
247  closed: "closed",
248  expandable: "expandable",
249  expandableHitarea: "expandable-hitarea",
250  lastExpandableHitarea: "lastExpandable-hitarea",
251  collapsable: "collapsable",
252  collapsableHitarea: "collapsable-hitarea",
253  lastCollapsableHitarea: "lastCollapsable-hitarea",
254  lastCollapsable: "lastCollapsable",
255  lastExpandable: "lastExpandable",
256  last: "last",
257  hitarea: "hitarea"
258  });
259 
260 })(jQuery);