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);