3dbe056bcf85dde8c33c762eca4b2e27d12aad14.svn-base 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * Treeview 1.4 - 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 4684 2008-02-07 19:08:06Z joern.zaefferer $
  14. *
  15. */
  16. ;(function($) {
  17. $.extend($.fn, {
  18. swapClass: function(c1, c2) {
  19. var c1Elements = this.filter('.' + c1);
  20. this.filter('.' + c2).removeClass(c2).addClass(c1);
  21. c1Elements.removeClass(c1).addClass(c2);
  22. return this;
  23. },
  24. replaceClass: function(c1, c2) {
  25. return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
  26. },
  27. hoverClass: function(className) {
  28. className = className || "hover";
  29. return this.hover(function() {
  30. $(this).addClass(className);
  31. }, function() {
  32. $(this).removeClass(className);
  33. });
  34. },
  35. heightToggle: function(animated, callback) {
  36. animated ?
  37. this.animate({ height: "toggle" }, animated, callback) :
  38. this.each(function(){
  39. jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
  40. if(callback)
  41. callback.apply(this, arguments);
  42. });
  43. },
  44. heightHide: function(animated, callback) {
  45. if (animated) {
  46. this.animate({ height: "hide" }, animated, callback);
  47. } else {
  48. this.hide();
  49. if (callback)
  50. this.each(callback);
  51. }
  52. },
  53. prepareBranches: function(settings) {
  54. if (!settings.prerendered) {
  55. // mark last tree items
  56. this.filter(":last-child:not(ul)").addClass(CLASSES.last);
  57. // collapse whole tree, or only those marked as closed, anyway except those marked as open
  58. this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
  59. }
  60. // return all items with sublists
  61. return this.filter(":has(>ul)");
  62. },
  63. applyClasses: function(settings, toggler) {
  64. this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) {
  65. toggler.apply($(this).next());
  66. }).add( $("a", this) ).hoverClass();
  67. if (!settings.prerendered) {
  68. // handle closed ones first
  69. this.filter(":has(>ul:hidden)")
  70. .addClass(CLASSES.expandable)
  71. .replaceClass(CLASSES.last, CLASSES.lastExpandable);
  72. // handle open ones
  73. this.not(":has(>ul:hidden)")
  74. .addClass(CLASSES.collapsable)
  75. .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
  76. // create hitarea
  77. this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea).each(function() {
  78. var classes = "";
  79. $.each($(this).parent().attr("class").split(" "), function() {
  80. classes += this + "-hitarea ";
  81. });
  82. $(this).addClass( classes );
  83. });
  84. }
  85. // apply event to hitarea
  86. this.find("div." + CLASSES.hitarea).click( toggler );
  87. },
  88. treeview: function(settings) {
  89. settings = $.extend({
  90. cookieId: "treeview"
  91. }, settings);
  92. if (settings.add) {
  93. return this.trigger("add", [settings.add]);
  94. }
  95. if ( settings.toggle ) {
  96. var callback = settings.toggle;
  97. settings.toggle = function() {
  98. return callback.apply($(this).parent()[0], arguments);
  99. };
  100. }
  101. // factory for treecontroller
  102. function treeController(tree, control) {
  103. // factory for click handlers
  104. function handler(filter) {
  105. return function() {
  106. // reuse toggle event handler, applying the elements to toggle
  107. // start searching for all hitareas
  108. toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
  109. // for plain toggle, no filter is provided, otherwise we need to check the parent element
  110. return filter ? $(this).parent("." + filter).length : true;
  111. }) );
  112. return false;
  113. };
  114. }
  115. // click on first element to collapse tree
  116. $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
  117. // click on second to expand tree
  118. $("a:eq(1)", control).click( handler(CLASSES.expandable) );
  119. // click on third to toggle tree
  120. $("a:eq(2)", control).click( handler() );
  121. }
  122. // handle toggle event
  123. function toggler() {
  124. $(this)
  125. .parent()
  126. // swap classes for hitarea
  127. .find(">.hitarea")
  128. .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
  129. .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
  130. .end()
  131. // swap classes for parent li
  132. .swapClass( CLASSES.collapsable, CLASSES.expandable )
  133. .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
  134. // find child lists
  135. .find( ">ul" )
  136. // toggle them
  137. .heightToggle( settings.animated, settings.toggle );
  138. if ( settings.unique ) {
  139. $(this).parent()
  140. .siblings()
  141. // swap classes for hitarea
  142. .find(">.hitarea")
  143. .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
  144. .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
  145. .end()
  146. .replaceClass( CLASSES.collapsable, CLASSES.expandable )
  147. .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
  148. .find( ">ul" )
  149. .heightHide( settings.animated, settings.toggle );
  150. }
  151. }
  152. function serialize() {
  153. function binary(arg) {
  154. return arg ? 1 : 0;
  155. }
  156. var data = [];
  157. branches.each(function(i, e) {
  158. data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
  159. });
  160. $.cookie(settings.cookieId, data.join("") );
  161. }
  162. function deserialize() {
  163. var stored = $.cookie(settings.cookieId);
  164. if ( stored ) {
  165. var data = stored.split("");
  166. branches.each(function(i, e) {
  167. $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
  168. });
  169. }
  170. }
  171. // add treeview class to activate styles
  172. this.addClass("treeview");
  173. // prepare branches and find all tree items with child lists
  174. var branches = this.find("li").prepareBranches(settings);
  175. switch(settings.persist) {
  176. case "cookie":
  177. var toggleCallback = settings.toggle;
  178. settings.toggle = function() {
  179. serialize();
  180. if (toggleCallback) {
  181. toggleCallback.apply(this, arguments);
  182. }
  183. };
  184. deserialize();
  185. break;
  186. case "location":
  187. var current = this.find("a").filter(function() { return this.href.toLowerCase() == location.href.toLowerCase(); });
  188. if ( current.length ) {
  189. current.addClass("selected").parents("ul, li").add( current.next() ).show();
  190. }
  191. break;
  192. }
  193. branches.applyClasses(settings, toggler);
  194. // if control option is set, create the treecontroller and show it
  195. if ( settings.control ) {
  196. treeController(this, settings.control);
  197. $(settings.control).show();
  198. }
  199. return this.bind("add", function(event, branches) {
  200. $(branches).prev()
  201. .removeClass(CLASSES.last)
  202. .removeClass(CLASSES.lastCollapsable)
  203. .removeClass(CLASSES.lastExpandable)
  204. .find(">.hitarea")
  205. .removeClass(CLASSES.lastCollapsableHitarea)
  206. .removeClass(CLASSES.lastExpandableHitarea);
  207. $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler);
  208. });
  209. }
  210. });
  211. // classes used by the plugin
  212. // need to be styled via external stylesheet, see first example
  213. var CLASSES = $.fn.treeview.classes = {
  214. open: "open",
  215. closed: "closed",
  216. expandable: "expandable",
  217. expandableHitarea: "expandable-hitarea",
  218. lastExpandableHitarea: "lastExpandable-hitarea",
  219. collapsable: "collapsable",
  220. collapsableHitarea: "collapsable-hitarea",
  221. lastCollapsableHitarea: "lastCollapsable-hitarea",
  222. lastCollapsable: "lastCollapsable",
  223. lastExpandable: "lastExpandable",
  224. last: "last",
  225. hitarea: "hitarea"
  226. };
  227. // provide backwards compability
  228. $.fn.Treeview = $.fn.treeview;
  229. })(jQuery);