1/* 2 * Accordion 1.3 - jQuery menu widget 3 * 4 * Copyright (c) 2006 Jörn Zaefferer, Frank Marcia 5 * 6 * Dual licensed under the MIT and GPL licenses: 7 * http://www.opensource.org/licenses/mit-license.php 8 * http://www.gnu.org/licenses/gpl.html 9 * 10 * Revision: $Id: jquery.accordion.js 1524 2007-03-13 20:09:19Z joern $ 11 * 12 */ 13 14/** 15 * Make the selected elements Accordion widgets. 16 * 17 * Semantic requirements: 18 * 19 * If the structure of your container is flat with unique 20 * tags for header and content elements, eg. a definition list 21 * (dl > dt + dd), you don't have to specify any options at 22 * all. 23 * 24 * If your structure uses the same elements for header and 25 * content or uses some kind of nested structure, you have to 26 * specify the header elements, eg. via class, see the second example. 27 * 28 * Use activate(Number) to change the active content programmatically. 29 * 30 * A change event is triggered everytime the accordion changes. Apart from 31 * the event object, all arguments are jQuery objects. 32 * Arguments: event, newHeader, oldHeader, newContent, oldContent 33 * 34 * @example jQuery('#nav').Accordion(); 35 * @before <dl id="nav"> 36 * <dt>Header 1</dt> 37 * <dd>Content 1</dd> 38 * <dt>Header 2</dt> 39 * <dd>Content 2</dd> 40 * </dl> 41 * @desc Creates an Accordion from the given definition list 42 * 43 * @example jQuery('#nav').Accordion({ 44 * header: 'div.title' 45 * }); 46 * @before <div id="nav"> 47 * <div> 48 * <div class="title">Header 1</div> 49 * <div>Content 1</div> 50 * </div> 51 * <div> 52 * <div class="title">Header 2</div> 53 * <div>Content 2</div> 54 * </div> 55 * </div> 56 * @desc Creates an Accordion from the given div structure 57 * 58 * @example jQuery('#nav').Accordion({ 59 * header: 'a.head' 60 * }); 61 * @before <ul id="nav"> 62 * <li> 63 * <a class="head">Header 1</a> 64 * <ul> 65 * <li><a href="#">Link 1</a></li> 66 * <li><a href="#">Link 2></a></li> 67 * </ul> 68 * </li> 69 * <li> 70 * <a class="head">Header 2</a> 71 * <ul> 72 * <li><a href="#">Link 3</a></li> 73 * <li><a href="#">Link 4></a></li> 74 * </ul> 75 * </li> 76 * </ul> 77 * @desc Creates an Accordion from the given navigation list 78 * 79 * @example jQuery('#accordion').Accordion().change(function(event, newHeader, oldHeader, newContent, oldContent) { 80 * jQuery('#status').html(newHeader.text()); 81 * }); 82 * @desc Updates the element with id status with the text of the selected header every time the accordion changes 83 * 84 * @param Map options key/value pairs of optional settings. 85 * @option String|Element|jQuery|Boolean active Selector for the active element, default is the first child, set to false to display none at start 86 * @option String|Element|jQuery header Selector for the header element, eg. div.title, a.head, default is the first child's tagname 87 * @option String|Number showSpeed Speed for the slideIn, default is 'slow' (for numbers: smaller = faster) 88 * @option String|Number hideSpeed Speed for the slideOut, default is 'fast' (for numbers: smaller = faster) 89 * @option String selectedClass Class for active header elements, default is 'selected' 90 * @option Boolean alwaysOpen Whether there must be one content element open, default is true. 91 * @option Boolean animated Set to false to disable animations. Default: true 92 * @option String event The event on which to trigger the accordion, eg. "mouseover". Default: "click" 93 * 94 * @type jQuery 95 * @see activate(Number) 96 * @name Accordion 97 * @cat Plugins/Accordion 98 */ 99 100/** 101 * Activate a content part of the Accordion programmatically at the given zero-based index. 102 * 103 * If the index is not specified, it defaults to zero, if it is an invalid index, eg. a string, 104 * nothing happens. 105 * 106 * @example jQuery('#accordion').activate(1); 107 * @desc Activate the second content of the Accordion contained in <div id="accordion">. 108 * 109 * @example jQuery('#nav').activate(); 110 * @desc Activate the first content of the Accordion contained in <ul id="nav">. 111 * 112 * @param Number index (optional) An Integer specifying the zero-based index of the content to be 113 * activated. Default: 0 114 * 115 * @type jQuery 116 * @name activate 117 * @cat Plugins/Accordion 118 */ 119 120/** 121 * Override the default settings of the Accordion. Affects only following plugin calls. 122 * 123 * @example jQuery.Accordion.setDefaults({ 124 * showSpeed: 1000, 125 * hideSpeed: 150 126 * }); 127 * 128 * @param Map options key/value pairs of optional settings, see Accordion() for details 129 * 130 * @type jQuery 131 * @name setDefaults 132 * @cat Plugins/Accordion 133 */ 134 135jQuery.fn.extend({ 136 // nextUntil is necessary, would be nice to have this in jQuery core 137 nextUntil: function(expr) { 138 var match = []; 139 140 // We need to figure out which elements to push onto the array 141 this.each(function(){ 142 // Traverse through the sibling nodes 143 for( var i = this.nextSibling; i; i = i.nextSibling ) { 144 // Make sure that we're only dealing with elements 145 if ( i.nodeType != 1 ) continue; 146 147 // If we find a match then we need to stop
148 if (jQuery.filter(expr, [i]).length) break; 149 150 // Otherwise, add it on to the stack 151 match.push( i ); 152 } 153 }); 154 155 return this.pushStack( match ); 156 }, 157 // the plugin method itself 158 Accordion: function(settings) { 159 // setup configuration 160 settings = jQuery.extend({}, jQuery.Accordion.defaults, { 161 // define context defaults 162 header: jQuery(':first-child', this)[0].tagName // take first childs tagName as header 163 }, settings); 164 165 // calculate active if not specified, using the first header 166 var container = this, 167 active = settings.active 168 ? jQuery(settings.active, this) 169 : settings.active === false 170 ? jQuery("<div>") 171 : jQuery(settings.header, this).eq(0), 172 running = 0; 173 174 container.find(settings.header) 175 .not(active || "") 176 .nextUntil(settings.header) 177 .hide(); 178 active.addClass(settings.selectedClass); 179 180 function clickHandler(event) { 181 // get the click target 182 var clicked = jQuery(event.target); 183 184 // due to the event delegation model, we have to check if one 185 // of the parent elements is our actual header, and find that 186 if ( clicked.parents(settings.header).length ) { 187 while ( !clicked.is(settings.header) ) { 188 clicked = clicked.parent(); 189 } 190 } 191 192 var clickedActive = clicked[0] == active[0]; 193 194 // if animations are still active, or the active header is the target, ignore click 195 if(running || (settings.alwaysOpen && clickedActive) || !clicked.is(settings.header)) 196 return; 197 198 // switch classes 199 active.toggleClass(settings.selectedClass); 200 if ( !clickedActive ) { 201 clicked.addClass(settings.selectedClass); 202 } 203 204 // find elements to show and hide 205 var toShow = clicked.nextUntil(settings.header), 206 toHide = active.nextUntil(settings.header), 207 data = [clicked, active, toShow, toHide]; 208 active = clickedActive ? jQuery([]) : clicked; 209 // count elements to animate 210 running = toHide.size() + toShow.size(); 211 var finished = function(cancel) { 212 running = cancel ? 0 : --running; 213 if ( running ) 214 return; 215 216 // trigger custom change event 217 container.trigger("change", data); 218 }; 219 // TODO if hideSpeed is set to zero, animations are crappy 220 // workaround: use hide instead 221 // solution: animate should check for speed of 0 and do something about it 222 if ( settings.animated ) { 223 if ( !settings.alwaysOpen && clickedActive ) { 224 toShow.slideToggle(settings.showSpeed); 225 finished(true); 226 } else { 227 toHide.filter(":hidden").each(finished).end().filter(":visible").slideUp(settings.hideSpeed, finished); 228 toShow.slideDown(settings.showSpeed, finished); 229 } 230 } else { 231 if ( !settings.alwaysOpen && clickedActive ) { 232 toShow.toggle(); 233 } else { 234 toHide.hide(); 235 toShow.show(); 236 } 237 finished(true); 238 } 239 240 return false; 241 }; 242 function activateHandlder(event, index) { 243 // call clickHandler with custom event 244 clickHandler({ 245 target: jQuery(settings.header, this)[index] 246 }); 247 }; 248 249 return container 250 .bind(settings.event, clickHandler) 251 .bind("activate", activateHandlder); 252 }, 253 // programmatic triggering 254 activate: function(index) { 255 return this.trigger('activate', [index || 0]); 256 } 257}); 258 259jQuery.Accordion = {}; 260jQuery.extend(jQuery.Accordion, { 261 defaults: { 262 selectedClass: "selected", 263 showSpeed: 'slow', 264 hideSpeed: 'fast', 265 alwaysOpen: true, 266 animated: true, 267 event: "click" 268 }, 269 setDefaults: function(settings) { 270 jQuery.extend(jQuery.Accordion.defaults, settings); 271 } 272});
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.