1/* ------------------------------------------------------------------------------ 2 3 2. Treeview 1.4.2 4 5 * Treeview 1.4.2 - jQuery plugin to hide and show branches of a tree 6 * 7 * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/ 8 * 9 * Copyright Jörn Zaefferer 10 * Released under the MIT license: 11 * http://www.opensource.org/licenses/mit-license.php 12------------------------------------------------------------------------------- */ 13 14;(function($) { 15 16 // TODO rewrite as a widget, removing all the extra plugins 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 // TODO use event delegation 65 this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) { 66 // don't handle click events on children, eg. checkboxes 67 if ( this == event.target ) 68 toggler.apply($(this).next()); 69 }).add( $("a", this) ).hoverClass(); 70 71 if (!settings.prerendered) { 72 // handle closed ones first 73 this.filter(":has(>ul:hidden)") 74 .addClass(CLASSES.expandable) 75 .replaceClass(CLASSES.last, CLASSES.lastExpandable); 76 77 // handle open ones 78 this.not(":has(>ul:hidden)") 79 .addClass(CLASSES.collapsable) 80 .replaceClass(CLASSES.last, CLASSES.lastCollapsable); 81 82 // create hitarea if not present 83 var hitarea = this.find("div." + CLASSES.hitarea); 84 if (!hitarea.length) 85 hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea); 86 hitarea.removeClass().addClass(CLASSES.hitarea).each(function() { 87 var classes = ""; 88 $.each($(this).parent().attr("class").split(" "), function() { 89 classes += this + "-hitarea "; 90 }); 91 $(this).addClass( classes ); 92 }) 93 } 94 95 // apply event to hitarea 96 this.find("div." + CLASSES.hitarea).click( toggler ); 97 }, 98 treeview: function(settings) { 99 100 settings = $.extend({ 101 cookieId: "treeview" 102 }, settings); 103 104 if ( settings.toggle ) { 105 var callback = settings.toggle; 106 settings.toggle = function() { 107 return callback.apply($(this).parent()[0], arguments); 108 }; 109 } 110 111 // factory for treecontroller
112 function treeController(tree, control) { 113 // factory for click handlers 114 function handler(filter) { 115 return function() { 116 // reuse toggle event handler, applying the elements to toggle 117 // start searching for all hitareas 118 toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() { 119 // for plain toggle, no filter is provided, otherwise we need to check the parent element 120 return filter ? $(this).parent("." + filter).length : true; 121 }) ); 122 return false; 123 }; 124 } 125 // click on first element to collapse tree 126 $("a:eq(0)", control).click( handler(CLASSES.collapsable) ); 127 // click on second to expand tree 128 $("a:eq(1)", control).click( handler(CLASSES.expandable) ); 129 // click on third to toggle tree 130 $("a:eq(2)", control).click( handler() ); 131 } 132 133 // handle toggle event 134 function toggler() { 135 $(this) 136 .parent() 137 // swap classes for hitarea 138 .find(">.hitarea") 139 .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) 140 .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) 141 .end() 142 // swap classes for parent li 143 .swapClass( CLASSES.collapsable, CLASSES.expandable ) 144 .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) 145 // find child lists 146 .find( ">ul" ) 147 // toggle them 148 .heightToggle( settings.animated, settings.toggle ); 149 if ( settings.unique ) { 150 $(this).parent() 151 .siblings() 152 // swap classes for hitarea 153 .find(">.hitarea") 154 .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) 155 .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ) 156 .end() 157 .replaceClass( CLASSES.collapsable, CLASSES.expandable ) 158 .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) 159 .find( ">ul" ) 160 .heightHide( settings.animated, settings.toggle ); 161 } 162 } 163 this.data("toggler", toggler); 164 165 function serialize() { 166 function binary(arg) { 167 return arg ? 1 : 0; 168 } 169 var data = []; 170 branches.each(function(i, e) { 171 data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0; 172 }); 173 $.cookie(settings.cookieId, data.join(""), settings.cookieOptions ); 174 } 175 176 function deserialize() { 177 var stored = $.cookie(settings.cookieId); 178 if ( stored ) { 179 var data = stored.split(""); 180 branches.each(function(i, e) { 181 $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ](); 182 }); 183 } 184 } 185 186 // add treeview class to activate styles 187 this.addClass("treeview"); 188 189 // prepare branches and find all tree items with child lists 190 var branches = this.find("li").prepareBranches(settings); 191 192 switch(settings.persist) { 193 case "cookie": 194 var toggleCallback = settings.toggle; 195 settings.toggle = function() { 196 serialize(); 197 if (toggleCallback) { 198 toggleCallback.apply(this, arguments); 199 } 200 }; 201 deserialize(); 202 break; 203 case "location": 204 var current = this.find("a").filter(function() { 205 return location.href.toLowerCase().indexOf(this.href.toLowerCase()) == 0;
206 }); 207 if ( current.length ) { 208 // TODO update the open/closed classes 209 var items = current.addClass("selected").parents("ul, li").add( current.next() ).show(); 210 if (settings.prerendered) { 211 // if prerendered is on, replicate the basic class swapping 212 items.filter("li") 213 .swapClass( CLASSES.collapsable, CLASSES.expandable ) 214 .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable ) 215 .find(">.hitarea") 216 .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea ) 217 .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea ); 218 } 219 } 220 break; 221 } 222 223 branches.applyClasses(settings, toggler); 224 225 // if control option is set, create the treecontroller and show it 226 if ( settings.control ) { 227 treeController(this, settings.control); 228 $(settings.control).show(); 229 } 230 231 return this; 232 } 233 }); 234 235 // classes used by the plugin 236 // need to be styled via external stylesheet, see first example 237 $.treeview = {}; 238 var CLASSES = ($.treeview.classes = { 239 open: "open", 240 closed: "closed", 241 expandable: "expandable", 242 expandableHitarea: "expandable-hitarea", 243 lastExpandableHitarea: "lastExpandable-hitarea", 244 collapsable: "collapsable", 245 collapsableHitarea: "collapsable-hitarea", 246 lastCollapsableHitarea: "lastCollapsable-hitarea", 247 lastCollapsable: "lastCollapsable", 248 lastExpandable: "lastExpandable", 249 last: "last", 250 hitarea: "hitarea" 251 }); 252 253})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.