treeview.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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. //add by bin.gu 09-05-20 start
  194. var container = $(this);
  195. this.find("a").each(function() {
  196. $(this).click(function() {
  197. container.find('a.selected').each(
  198. function() {
  199. $(this).removeClass('selected');
  200. });
  201. $(this).addClass('selected');
  202. });
  203. });
  204. //end
  205. branches.applyClasses(settings, toggler);
  206. // if control option is set, create the treecontroller and show it
  207. if ( settings.control ) {
  208. treeController(this, settings.control);
  209. $(settings.control).show();
  210. }
  211. return this.bind("add", function(event, branches) {
  212. $(branches).prev()
  213. .removeClass(CLASSES.last)
  214. .removeClass(CLASSES.lastCollapsable)
  215. .removeClass(CLASSES.lastExpandable)
  216. .find(">.hitarea")
  217. .removeClass(CLASSES.lastCollapsableHitarea)
  218. .removeClass(CLASSES.lastExpandableHitarea);
  219. $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler);
  220. });
  221. }
  222. });
  223. // classes used by the plugin
  224. // need to be styled via external stylesheet, see first example
  225. var CLASSES = $.fn.treeview.classes = {
  226. open: "open",
  227. closed: "closed",
  228. expandable: "expandable",
  229. expandableHitarea: "expandable-hitarea",
  230. lastExpandableHitarea: "lastExpandable-hitarea",
  231. collapsable: "collapsable",
  232. collapsableHitarea: "collapsable-hitarea",
  233. lastCollapsableHitarea: "lastCollapsable-hitarea",
  234. lastCollapsable: "lastCollapsable",
  235. lastExpandable: "lastExpandable",
  236. last: "last",
  237. hitarea: "hitarea"
  238. };
  239. // provide backwards compability
  240. $.fn.Treeview = $.fn.treeview;
  241. })(jQuery);
  242. (function($) {
  243. function load(settings, child, container,asyncSpan) {
  244. $.ajax({
  245. url : settings.url,
  246. cache : false,
  247. dataType : 'json',
  248. type:'post',
  249. data : settings.params,
  250. success : function(response) {
  251. function createNode(parent) {
  252. var current = $("<li/>").attr("id", this.id || "")
  253. .html("<span><a>" + this.text + "</a></span>")
  254. .appendTo(parent);
  255. if (this.classes) {
  256. current.children("span").addClass(this.classes);
  257. } else {
  258. current.children("span").addClass('file');
  259. }
  260. if (this.expanded) {
  261. current.addClass("open");
  262. }
  263. var node = {
  264. "id" : this.id,
  265. "text" : this.text,
  266. "link" : this.link,
  267. "hasChildren" : this.hasChildren
  268. };
  269. $("a", current).click(function(e) {
  270. if(settings.processNode){
  271. settings.processNode(node);
  272. container.find('a').each(function(){
  273. $(this).removeClass('nodeSelected');
  274. }) ;
  275. $(this).addClass('nodeSelected');
  276. }
  277. }).hoverClass();
  278. if (this.hasChildren || this.children
  279. && this.children.length) {
  280. $(">li>span",parent).removeClass('file').addClass('folder')
  281. var branch = $("<ul/>").appendTo(current);
  282. if (this.hasChildren) {
  283. current.addClass("hasChildren");
  284. createNode.call({
  285. text : "placeholder",
  286. id : "placeholder",
  287. children : []
  288. }, branch);
  289. }
  290. if (this.children && this.children.length) {
  291. $.each(this.children, createNode, [branch])
  292. }
  293. }
  294. }
  295. if (response != "") {
  296. $.each(response, createNode, [child]);
  297. $(container).treeview({
  298. add : child
  299. });
  300. }
  301. //change bin.gu 09-04-21
  302. if (asyncSpan) {
  303. asyncSpan.replaceClass('loading', 'folder');
  304. }
  305. },
  306. error:function(response){
  307. alert('出现异常');
  308. }
  309. });
  310. }
  311. var proxied = $.fn.treeview;
  312. $.fn.ajaxTree = function(settings) {
  313. if(!settings.params){
  314. settings.params=[];
  315. }
  316. if (!settings.url) {
  317. return proxied.apply(this, arguments);
  318. }
  319. var container = this;
  320. load(settings, this, container);
  321. var userToggle = settings.toggle;
  322. return proxied.call(this, $.extend({}, settings, {
  323. collapsed: true,
  324. toggle: function() {
  325. var $this = $(this);
  326. if ($this.hasClass("hasChildren")) {
  327. var asyncSpan = $(">span",$(this));
  328. asyncSpan.replaceClass('folder', 'loading');
  329. var childList = $this.removeClass("hasChildren").find("ul");
  330. childList.empty();
  331. if(settings.async){
  332. if (settings.asyncData) {
  333. var params = settings.asyncData($this.attr('id'),
  334. $this.text());
  335. /**
  336. for (var pi = 0; pi < params.length; pi++) {
  337. settings.params[settings.params.length] = params[pi];
  338. }
  339. **/
  340. settings.params = params ;
  341. }
  342. }
  343. load(settings, childList, container,asyncSpan);
  344. }
  345. if (userToggle) {
  346. userToggle.apply(this, arguments);
  347. }
  348. }
  349. }));
  350. };
  351. $.fn.selectedTreeMenu = function(menuName){
  352. var container = $(this);
  353. $(this).find("a").each(function() {
  354. var text = $(this).text();
  355. if(text==menuName){
  356. $(this).addClass('selected');
  357. }else{
  358. $(this).removeClass('selected');
  359. }
  360. });
  361. }
  362. $.fn.findTreeById = function(id){
  363. var findLi ;
  364. $(this).find('li').each(function(){
  365. var treeLi =$(this) ;
  366. var liId = treeLi.attr('id');
  367. if(liId == id){
  368. findLi = treeLi ;
  369. return;
  370. }
  371. });
  372. return findLi ;
  373. }
  374. })(jQuery);