jquery.treeview.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Treeview 1.3 - jQuery plugin to hide and show branches of a tree
  3. *
  4. * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
  5. *
  6. * Copyright (c) 2006 Jörn Zaefferer, Myles Angell
  7. *
  8. * Dual licensed under the MIT and GPL licenses:
  9. * http://www.opensource.org/licenses/mit-license.php
  10. * http://www.gnu.org/licenses/gpl.html
  11. *
  12. * Revision: $Id: jquery.treeview.js 3506 2007-10-02 18:15:21Z joern.zaefferer $
  13. *
  14. */
  15. (function($) {
  16. // classes used by the plugin
  17. // need to be styled via external stylesheet, see first example
  18. var CLASSES = {
  19. open: "open",
  20. closed: "closed",
  21. expandable: "expandable",
  22. collapsable: "collapsable",
  23. lastCollapsable: "lastCollapsable",
  24. lastExpandable: "lastExpandable",
  25. last: "last",
  26. hitarea: "hitarea"
  27. };
  28. $.extend($.fn, {
  29. swapClass: function(c1, c2) {
  30. return this.each(function() {
  31. var $this = $(this);
  32. if ( $.className.has(this, c1) )
  33. $this.removeClass(c1).addClass(c2);
  34. else if ( $.className.has(this, c2) )
  35. $this.removeClass(c2).addClass(c1);
  36. });
  37. },
  38. replaceClass: function(c1, c2) {
  39. return this.each(function() {
  40. var $this = $(this);
  41. if ( $.className.has(this, c1) )
  42. $this.removeClass(c1).addClass(c2);
  43. });
  44. },
  45. hoverClass: function(className) {
  46. className = className || "hover";
  47. return this.hover(function() {
  48. $(this).addClass(className);
  49. }, function() {
  50. $(this).removeClass(className);
  51. });
  52. },
  53. heightToggle: function(animated, callback) {
  54. animated ?
  55. this.animate({ height: "toggle" }, animated, callback) :
  56. this.each(function(){
  57. jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
  58. if(callback)
  59. callback.apply(this, arguments);
  60. });
  61. },
  62. heightHide: function(animated, callback) {
  63. if (animated) {
  64. this.animate({ height: "hide" }, animated, callback)
  65. } else {
  66. this.hide();
  67. if (callback)
  68. this.each(callback);
  69. }
  70. },
  71. prepareBranches: function(settings) {
  72. // mark last tree items
  73. this.filter(":last-child").addClass(CLASSES.last);
  74. // collapse whole tree, or only those marked as closed, anyway except those marked as open
  75. this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
  76. // return all items with sublists
  77. return this.filter(":has(>ul)");
  78. },
  79. applyClasses: function(settings, toggler) {
  80. this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) {
  81. if ( this == event.target ) {
  82. toggler.apply($(this).next());
  83. }
  84. }).add( $("a", this) ).hoverClass();
  85. // handle closed ones first
  86. this.filter(":has(>ul:hidden)")
  87. .addClass(CLASSES.expandable)
  88. .replaceClass(CLASSES.last, CLASSES.lastExpandable);
  89. // handle open ones
  90. this.not(":has(>ul:hidden)")
  91. .addClass(CLASSES.collapsable)
  92. .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
  93. // create hitarea
  94. this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>")
  95. .find("div." + CLASSES.hitarea).click( toggler )
  96. },
  97. treeview: function(settings) {
  98. // currently no defaults necessary, all implicit
  99. settings = $.extend({}, settings);
  100. if (settings.add) {
  101. return this.trigger("add", [settings.add]);
  102. }
  103. if (settings.toggle ) {
  104. var callback = settings.toggle;
  105. settings.toggle = function() {
  106. return callback.apply($(this).parent()[0], arguments);
  107. }
  108. }
  109. // factory for treecontroller
  110. function treeController(tree, control) {
  111. // factory for click handlers
  112. function handler(filter) {
  113. return function() {
  114. // reuse toggle event handler, applying the elements to toggle
  115. // start searching for all hitareas
  116. toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
  117. // for plain toggle, no filter is provided, otherwise we need to check the parent element
  118. return filter ? $(this).parent("." + filter).length : true;
  119. }) );
  120. return false;
  121. }
  122. }
  123. // click on first element to collapse tree
  124. $(":eq(0)", control).click( handler(CLASSES.collapsable) );
  125. // click on second to expand tree
  126. $(":eq(1)", control).click( handler(CLASSES.expandable) );
  127. // click on third to toggle tree
  128. $(":eq(2)", control).click( handler() );
  129. }
  130. // handle toggle event
  131. function toggler() {
  132. // this refers to hitareas, we need to find the parent lis first
  133. $(this).parent()
  134. // swap classes
  135. .swapClass( CLASSES.collapsable, CLASSES.expandable )
  136. .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
  137. // find child lists
  138. .find( ">ul" )
  139. // toggle them
  140. .heightToggle( settings.animated, settings.toggle );
  141. if ( settings.unique ) {
  142. $(this).parent()
  143. .siblings()
  144. .replaceClass( CLASSES.collapsable, CLASSES.expandable )
  145. .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
  146. .find( ">ul" )
  147. .heightHide( settings.animated, settings.toggle );
  148. }
  149. }
  150. function serialize() {
  151. function binary(arg) {
  152. return arg ? 1 : 0;
  153. }
  154. var data = [];
  155. branches.each(function(i, e) {
  156. data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
  157. });
  158. $.cookie("treeview", data.join("") );
  159. }
  160. function deserialize() {
  161. var stored = $.cookie("treeview");
  162. if ( stored ) {
  163. var data = stored.split("");
  164. branches.each(function(i, e) {
  165. $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
  166. });
  167. }
  168. }
  169. // add treeview class to activate styles
  170. this.addClass("treeview");
  171. // prepare branches and find all tree items with child lists
  172. var branches = this.find("li").prepareBranches(settings);
  173. switch(settings.persist) {
  174. case "cookie":
  175. var toggleCallback = settings.toggle;
  176. settings.toggle = function() {
  177. serialize();
  178. if (toggleCallback) {
  179. toggleCallback.apply(this, arguments);
  180. }
  181. };
  182. deserialize();
  183. break;
  184. case "location":
  185. var current = this.find("a").filter(function() { return this.href == location.href; });
  186. if ( current.length ) {
  187. current.addClass("selected").parents("ul, li").add( current.next() ).show();
  188. }
  189. break;
  190. }
  191. branches.applyClasses(settings, toggler);
  192. // if control option is set, create the treecontroller
  193. if ( settings.control )
  194. treeController(this, settings.control);
  195. return this.bind("add", function(event, branches) {
  196. $(branches).prev().removeClass(CLASSES.last).removeClass(CLASSES.lastCollapsable).removeClass(CLASSES.lastExpandable);
  197. $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler);
  198. });
  199. }
  200. });
  201. // provide backwards compability
  202. $.fn.Treeview = $.fn.treeview;
  203. })(jQuery);