github.com/april1989/origin-go-tools@v0.0.32/godoc/static/jquery.treeview.js (about)

     1  /*
     2   * Treeview 1.4.2 - jQuery plugin to hide and show branches of a tree
     3   *
     4   * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
     5   *
     6   * Copyright Jörn Zaefferer
     7   * Released under the MIT license:
     8   *   http://www.opensource.org/licenses/mit-license.php
     9   */
    10  
    11  ;(function($) {
    12  
    13  	// TODO rewrite as a widget, removing all the extra plugins
    14  	$.extend($.fn, {
    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);
    19  			return this;
    20  		},
    21  		replaceClass: function(c1, c2) {
    22  			return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
    23  		},
    24  		hoverClass: function(className) {
    25  			className = className || "hover";
    26  			return this.hover(function() {
    27  				$(this).addClass(className);
    28  			}, function() {
    29  				$(this).removeClass(className);
    30  			});
    31  		},
    32  		heightToggle: function(animated, callback) {
    33  			animated ?
    34  				this.animate({ height: "toggle" }, animated, callback) :
    35  				this.each(function(){
    36  					jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
    37  					if(callback)
    38  						callback.apply(this, arguments);
    39  				});
    40  		},
    41  		heightHide: function(animated, callback) {
    42  			if (animated) {
    43  				this.animate({ height: "hide" }, animated, callback);
    44  			} else {
    45  				this.hide();
    46  				if (callback)
    47  					this.each(callback);
    48  			}
    49  		},
    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();
    56  			}
    57  			// return all items with sublists
    58  			return this.filter(":has(>ul)");
    59  		},
    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();
    67  
    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);
    73  
    74  				// handle open ones
    75  				this.not(":has(>ul:hidden)")
    76  						.addClass(CLASSES.collapsable)
    77  						.replaceClass(CLASSES.last, CLASSES.lastCollapsable);
    78  
    79  	            // create hitarea if not present
    80  				var hitarea = this.find("div." + CLASSES.hitarea);
    81  				if (!hitarea.length)
    82  					hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
    83  				hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
    84  					var classes = "";
    85  					$.each($(this).parent().attr("class").split(" "), function() {
    86  						classes += this + "-hitarea ";
    87  					});
    88  					$(this).addClass( classes );
    89  				})
    90  			}
    91  
    92  			// apply event to hitarea
    93  			this.find("div." + CLASSES.hitarea).click( toggler );
    94  		},
    95  		treeview: function(settings) {
    96  
    97  			settings = $.extend({
    98  				cookieId: "treeview"
    99  			}, settings);
   100  
   101  			if ( settings.toggle ) {
   102  				var callback = settings.toggle;
   103  				settings.toggle = function() {
   104  					return callback.apply($(this).parent()[0], arguments);
   105  				};
   106  			}
   107  
   108  			// factory for treecontroller
   109  			function treeController(tree, control) {
   110  				// factory for click handlers
   111  				function handler(filter) {
   112  					return function() {
   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;
   118  						}) );
   119  						return false;
   120  					};
   121  				}
   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() );
   128  			}
   129  
   130  			// handle toggle event
   131  			function toggler() {
   132  				$(this)
   133  					.parent()
   134  					// swap classes for hitarea
   135  					.find(">.hitarea")
   136  						.swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
   137  						.swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
   138  					.end()
   139  					// swap classes for parent li
   140  					.swapClass( CLASSES.collapsable, CLASSES.expandable )
   141  					.swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
   142  					// find child lists
   143  					.find( ">ul" )
   144  					// toggle them
   145  					.heightToggle( settings.animated, settings.toggle );
   146  				if ( settings.unique ) {
   147  					$(this).parent()
   148  						.siblings()
   149  						// swap classes for hitarea
   150  						.find(">.hitarea")
   151  							.replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
   152  							.replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
   153  						.end()
   154  						.replaceClass( CLASSES.collapsable, CLASSES.expandable )
   155  						.replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
   156  						.find( ">ul" )
   157  						.heightHide( settings.animated, settings.toggle );
   158  				}
   159  			}
   160  			this.data("toggler", toggler);
   161  
   162  			function serialize() {
   163  				function binary(arg) {
   164  					return arg ? 1 : 0;
   165  				}
   166  				var data = [];
   167  				branches.each(function(i, e) {
   168  					data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
   169  				});
   170  				$.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
   171  			}
   172  
   173  			function deserialize() {
   174  				var stored = $.cookie(settings.cookieId);
   175  				if ( stored ) {
   176  					var data = stored.split("");
   177  					branches.each(function(i, e) {
   178  						$(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
   179  					});
   180  				}
   181  			}
   182  
   183  			// add treeview class to activate styles
   184  			this.addClass("treeview");
   185  
   186  			// prepare branches and find all tree items with child lists
   187  			var branches = this.find("li").prepareBranches(settings);
   188  
   189  			switch(settings.persist) {
   190  			case "cookie":
   191  				var toggleCallback = settings.toggle;
   192  				settings.toggle = function() {
   193  					serialize();
   194  					if (toggleCallback) {
   195  						toggleCallback.apply(this, arguments);
   196  					}
   197  				};
   198  				deserialize();
   199  				break;
   200  			case "location":
   201  				var current = this.find("a").filter(function() {
   202  					return location.href.toLowerCase().indexOf(this.href.toLowerCase()) == 0;
   203  				});
   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
   209  						items.filter("li")
   210  							.swapClass( CLASSES.collapsable, CLASSES.expandable )
   211  							.swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
   212  							.find(">.hitarea")
   213  								.swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
   214  								.swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
   215  					}
   216  				}
   217  				break;
   218  			}
   219  
   220  			branches.applyClasses(settings, toggler);
   221  
   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();
   226  			}
   227  
   228  			return this;
   229  		}
   230  	});
   231  
   232  	// classes used by the plugin
   233  	// need to be styled via external stylesheet, see first example
   234  	$.treeview = {};
   235  	var CLASSES = ($.treeview.classes = {
   236  		open: "open",
   237  		closed: "closed",
   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",
   246  		last: "last",
   247  		hitarea: "hitarea"
   248  	});
   249  
   250  })(jQuery);