1/*! 2 * jQuery UI Accordion 1.8.24 3 * 4 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) 5 * Dual licensed under the MIT or GPL Version 2 licenses. 6 * http://jquery.org/license 7 * 8 * http://docs.jquery.com/UI/Accordion 9 * 10 * Depends: 11 * jquery.ui.core.js 12 * jquery.ui.widget.js 13 */ 14(function( $, undefined ) { 15 16$.widget( "ui.accordion", { 17 options: { 18 active: 0, 19 animated: "slide", 20 autoHeight: true, 21 clearStyle: false, 22 collapsible: false, 23 event: "click", 24 fillSpace: false, 25 header: "> li > :first-child,> :not(li):even", 26 icons: { 27 header: "ui-icon-triangle-1-e", 28 headerSelected: "ui-icon-triangle-1-s" 29 }, 30 navigation: false, 31 navigationFilter: function() { 32 return this.href.toLowerCase() === location.href.toLowerCase(); 33 } 34 }, 35 36 _create: function() { 37 var self = this, 38 options = self.options; 39 40 self.running = 0; 41 42 self.element 43 .addClass( "ui-accordion ui-widget ui-helper-reset" ) 44 // in lack of child-selectors in CSS 45 // we need to mark top-LIs in a UL-accordion for some IE-fix 46 .children( "li" ) 47 .addClass( "ui-accordion-li-fix" ); 48 49 self.headers = self.element.find( options.header ) 50 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ) 51 .bind( "mouseenter.accordion", function() { 52 if ( options.disabled ) { 53 return; 54 } 55 $( this ).addClass( "ui-state-hover" ); 56 }) 57 .bind( "mouseleave.accordion", function() { 58 if ( options.disabled ) { 59 return; 60 } 61 $( this ).removeClass( "ui-state-hover" ); 62 }) 63 .bind( "focus.accordion", function() { 64 if ( options.disabled ) { 65 return; 66 } 67 $( this ).addClass( "ui-state-focus" ); 68 }) 69 .bind( "blur.accordion", function() { 70 if ( options.disabled ) { 71 return; 72 } 73 $( this ).removeClass( "ui-state-focus" ); 74 }); 75 76 self.headers.next() 77 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ); 78 79 if ( options.navigation ) { 80 var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 ); 81 if ( current.length ) { 82 var header = current.closest( ".ui-accordion-header" ); 83 if ( header.length ) { 84 // anchor within header 85 self.active = header; 86 } else { 87 // anchor within content 88 self.active = current.closest( ".ui-accordion-content" ).prev(); 89 } 90 } 91 } 92 93 self.active = self._findActive( self.active || options.active ) 94 .addClass( "ui-state-default ui-state-active" ) 95 .toggleClass( "ui-corner-all" ) 96 .toggleClass( "ui-corner-top" ); 97 self.active.next().addClass( "ui-accordion-content-active" ); 98 99 self._createIcons(); 100 self.resize(); 101 102 // ARIA 103 self.element.attr( "role", "tablist" ); 104 105 self.headers 106 .attr( "role", "tab" ) 107 .bind( "keydown.accordion", function( event ) { 108 return self._keydown( event ); 109 }) 110 .next() 111 .attr( "role", "tabpanel" ); 112 113 self.headers 114 .not( self.active || "" ) 115 .attr({ 116 "aria-expanded": "false", 117 "aria-selected": "false", 118 tabIndex: -1 119 }) 120 .next() 121 .hide(); 122 123 // make sure at least one header is in the tab order 124 if ( !self.active.length ) { 125 self.headers.eq( 0 ).attr( "tabIndex", 0 ); 126 } else { 127 self.active 128 .attr({ 129 "aria-expanded": "true", 130 "aria-selected": "true", 131 tabIndex: 0 132 }); 133 } 134 135 // only need links in tab order for Safari 136 if ( !$.browser.safari ) { 137 self.headers.find( "a" ).attr( "tabIndex", -1 ); 138 } 139 140 if ( options.event ) { 141 self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) { 142 self._clickHandler.call( self, event, this ); 143 event.preventDefault(); 144 }); 145 } 146 }, 147 148 _createIcons: function() { 149 var options = this.options; 150 if ( options.icons ) { 151 $( "<span></span>" ) 152 .addClass( "ui-icon " + options.icons.header ) 153 .prependTo( this.headers ); 154 this.active.children( ".ui-icon" ) 155 .toggleClass(options.icons.header) 156 .toggleClass(options.icons.headerSelected); 157 this.element.addClass( "ui-accordion-icons" ); 158 } 159 }, 160 161 _destroyIcons: function() { 162 this.headers.children( ".ui-icon" ).remove(); 163 this.element.removeClass( "ui-accordion-icons" ); 164 }, 165 166 destroy: function() { 167 var options = this.options; 168 169 this.element 170 .removeClass( "ui-accordion ui-widget ui-helper-reset" ) 171 .removeAttr( "role" ); 172 173 this.headers 174 .unbind( ".accordion" ) 175 .removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) 176 .removeAttr( "role" ) 177 .removeAttr( "aria-expanded" ) 178 .removeAttr( "aria-selected" ) 179 .removeAttr( "tabIndex" ); 180 181 this.headers.find( "a" ).removeAttr( "tabIndex" ); 182 this._destroyIcons(); 183 var contents = this.headers.next() 184 .css( "display", "" ) 185 .removeAttr( "role" ) 186 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" ); 187 if ( options.autoHeight || options.fillHeight ) { 188 contents.css( "height", "" ); 189 } 190 191 return $.Widget.prototype.destroy.call( this ); 192 }, 193 194 _setOption: function( key, value ) { 195 $.Widget.prototype._setOption.apply( this, arguments ); 196 197 if ( key == "active" ) { 198 this.activate( value ); 199 } 200 if ( key == "icons" ) { 201 this._destroyIcons(); 202 if ( value ) { 203 this._createIcons(); 204 } 205 } 206 // #5332 - opacity doesn't cascade to positioned elements in IE 207 // so we need to add the disabled class to the headers and panels 208 if ( key == "disabled" ) { 209 this.headers.add(this.headers.next()) 210 [ value ? "addClass" : "removeClass" ]( 211 "ui-accordion-disabled ui-state-disabled" ); 212 } 213 }, 214 215 _keydown: function( event ) { 216 if ( this.options.disabled || event.altKey || event.ctrlKey ) { 217 return; 218 } 219 220 var keyCode = $.ui.keyCode, 221 length = this.headers.length, 222 currentIndex = this.headers.index( event.target ), 223 toFocus = false;
224 225 switch ( event.keyCode ) { 226 case keyCode.RIGHT: 227 case keyCode.DOWN: 228 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 229 break; 230 case keyCode.LEFT: 231 case keyCode.UP: 232 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 233 break; 234 case keyCode.SPACE: 235 case keyCode.ENTER: 236 this._clickHandler( { target: event.target }, event.target ); 237 event.preventDefault(); 238 } 239 240 if ( toFocus ) { 241 $( event.target ).attr( "tabIndex", -1 ); 242 $( toFocus ).attr( "tabIndex", 0 ); 243 toFocus.focus(); 244 return false; 245 } 246 247 return true; 248 }, 249 250 resize: function() { 251 var options = this.options, 252 maxHeight; 253 254 if ( options.fillSpace ) { 255 if ( $.browser.msie ) { 256 var defOverflow = this.element.parent().css( "overflow" ); 257 this.element.parent().css( "overflow", "hidden"); 258 } 259 maxHeight = this.element.parent().height(); 260 if ($.browser.msie) { 261 this.element.parent().css( "overflow", defOverflow ); 262 } 263 264 this.headers.each(function() { 265 maxHeight -= $( this ).outerHeight( true ); 266 }); 267 268 this.headers.next() 269 .each(function() { 270 $( this ).height( Math.max( 0, maxHeight - 271 $( this ).innerHeight() + $( this ).height() ) ); 272 }) 273 .css( "overflow", "auto" ); 274 } else if ( options.autoHeight ) { 275 maxHeight = 0; 276 this.headers.next() 277 .each(function() { 278 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 279 }) 280 .height( maxHeight ); 281 } 282 283 return this; 284 }, 285 286 activate: function( index ) { 287 // TODO this gets called on init, changing the option without an explicit call for that 288 this.options.active = index; 289 // call clickHandler with custom event 290 var active = this._findActive( index )[ 0 ]; 291 this._clickHandler( { target: active }, active ); 292 293 return this; 294 }, 295 296 _findActive: function( selector ) { 297 return selector 298 ? typeof selector === "number" 299 ? this.headers.filter( ":eq(" + selector + ")" ) 300 : this.headers.not( this.headers.not( selector ) ) 301 : selector === false 302 ? $( [] ) 303 : this.headers.filter( ":eq(0)" ); 304 }, 305 306 // TODO isn't event.target enough? why the separate target argument? 307 _clickHandler: function( event, target ) { 308 var options = this.options; 309 if ( options.disabled ) { 310 return; 311 } 312 313 // called only when using activate(false) to close all parts programmatically 314 if ( !event.target ) { 315 if ( !options.collapsible ) { 316 return; 317 } 318 this.active 319 .removeClass( "ui-state-active ui-corner-top" ) 320 .addClass( "ui-state-default ui-corner-all" ) 321 .children( ".ui-icon" ) 322 .removeClass( options.icons.headerSelected ) 323 .addClass( options.icons.header ); 324 this.active.next().addClass( "ui-accordion-content-active" ); 325 var toHide = this.active.next(), 326 data = { 327 options: options, 328 newHeader: $( [] ), 329 oldHeader: options.active, 330 newContent: $( [] ), 331 oldContent: toHide 332 }, 333 toShow = ( this.active = $( [] ) ); 334 this._toggle( toShow, toHide, data ); 335 return; 336 } 337 338 // get the click target 339 var clicked = $( event.currentTarget || target ), 340 clickedIsActive = clicked[0] === this.active[0]; 341 342 // TODO the option is changed, is that correct? 343 // TODO if it is correct, shouldn't that happen after determining that the click is valid? 344 options.active = options.collapsible && clickedIsActive ? 345 false : 346 this.headers.index( clicked ); 347 348 // if animations are still active, or the active header is the target, ignore click 349 if ( this.running || ( !options.collapsible && clickedIsActive ) ) { 350 return; 351 } 352 353 // find elements to show and hide 354 var active = this.active, 355 toShow = clicked.next(), 356 toHide = this.active.next(), 357 data = { 358 options: options, 359 newHeader: clickedIsActive && options.collapsible ? $([]) : clicked, 360 oldHeader: this.active, 361 newContent: clickedIsActive && options.collapsible ? $([]) : toShow, 362 oldContent: toHide 363 }, 364 down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); 365 366 // when the call to ._toggle() comes after the class changes 367 // it causes a very odd bug in IE 8 (see #6720) 368 this.active = clickedIsActive ? $([]) : clicked; 369 this._toggle( toShow, toHide, data, clickedIsActive, down ); 370 371 // switch classes 372 active 373 .removeClass( "ui-state-active ui-corner-top" ) 374 .addClass( "ui-state-default ui-corner-all" ) 375 .children( ".ui-icon" ) 376 .removeClass( options.icons.headerSelected )
377 .addClass( options.icons.header ); 378 if ( !clickedIsActive ) { 379 clicked 380 .removeClass( "ui-state-default ui-corner-all" ) 381 .addClass( "ui-state-active ui-corner-top" ) 382 .children( ".ui-icon" ) 383 .removeClass( options.icons.header ) 384 .addClass( options.icons.headerSelected ); 385 clicked 386 .next() 387 .addClass( "ui-accordion-content-active" ); 388 } 389 390 return; 391 }, 392 393 _toggle: function( toShow, toHide, data, clickedIsActive, down ) { 394 var self = this, 395 options = self.options; 396 397 self.toShow = toShow; 398 self.toHide = toHide; 399 self.data = data; 400 401 var complete = function() { 402 if ( !self ) { 403 return; 404 } 405 return self._completed.apply( self, arguments ); 406 }; 407 408 // trigger changestart event 409 self._trigger( "changestart", null, self.data ); 410 411 // count elements to animate 412 self.running = toHide.size() === 0 ? toShow.size() : toHide.size(); 413 414 if ( options.animated ) { 415 var animOptions = {}; 416 417 if ( options.collapsible && clickedIsActive ) { 418 animOptions = { 419 toShow: $( [] ), 420 toHide: toHide, 421 complete: complete, 422 down: down, 423 autoHeight: options.autoHeight || options.fillSpace 424 }; 425 } else { 426 animOptions = { 427 toShow: toShow, 428 toHide: toHide, 429 complete: complete, 430 down: down, 431 autoHeight: options.autoHeight || options.fillSpace 432 }; 433 } 434 435 if ( !options.proxied ) { 436 options.proxied = options.animated; 437 } 438 439 if ( !options.proxiedDuration ) { 440 options.proxiedDuration = options.duration; 441 } 442 443 options.animated = $.isFunction( options.proxied ) ? 444 options.proxied( animOptions ) : 445 options.proxied; 446 447 options.duration = $.isFunction( options.proxiedDuration ) ? 448 options.proxiedDuration( animOptions ) : 449 options.proxiedDuration; 450 451 var animations = $.ui.accordion.animations, 452 duration = options.duration, 453 easing = options.animated; 454 455 if ( easing && !animations[ easing ] && !$.easing[ easing ] ) { 456 easing = "slide"; 457 } 458 if ( !animations[ easing ] ) { 459 animations[ easing ] = function( options ) { 460 this.slide( options, { 461 easing: easing, 462 duration: duration || 700 463 }); 464 }; 465 } 466 467 animations[ easing ]( animOptions ); 468 } else { 469 if ( options.collapsible && clickedIsActive ) { 470 toShow.toggle(); 471 } else { 472 toHide.hide(); 473 toShow.show(); 474 } 475 476 complete( true ); 477 } 478 479 // TODO assert that the blur and focus triggers are really necessary, remove otherwise 480 toHide.prev() 481 .attr({ 482 "aria-expanded": "false", 483 "aria-selected": "false", 484 tabIndex: -1 485 }) 486 .blur(); 487 toShow.prev() 488 .attr({ 489 "aria-expanded": "true", 490 "aria-selected": "true", 491 tabIndex: 0 492 }) 493 .focus(); 494 }, 495 496 _completed: function( cancel ) { 497 this.running = cancel ? 0 : --this.running; 498 if ( this.running ) { 499 return; 500 } 501 502 if ( this.options.clearStyle ) { 503 this.toShow.add( this.toHide ).css({ 504 height: "", 505 overflow: "" 506 }); 507 } 508 509 // other classes are removed before the animation; this one needs to stay until completed 510 this.toHide.removeClass( "ui-accordion-content-active" ); 511 // Work around for rendering bug in IE (#5421) 512 if ( this.toHide.length ) { 513 this.toHide.parent()[0].className = this.toHide.parent()[0].className; 514 } 515 516 this._trigger( "change", null, this.data ); 517 } 518}); 519 520$.extend( $.ui.accordion, { 521 version: "1.8.24", 522 animations: { 523 slide: function( options, additions ) { 524 options = $.extend({ 525 easing: "swing", 526 duration: 300 527 }, options, additions ); 528 if ( !options.toHide.size() ) { 529 options.toShow.animate({ 530 height: "show", 531 paddingTop: "show", 532 paddingBottom: "show" 533 }, options ); 534 return; 535 } 536 if ( !options.toShow.size() ) { 537 options.toHide.animate({ 538 height: "hide", 539 paddingTop: "hide", 540 paddingBottom: "hide" 541 }, options ); 542 return; 543 } 544 var overflow = options.toShow.css( "overflow" ), 545 percentDone = 0, 546 showProps = {}, 547 hideProps = {}, 548 fxAttrs = [ "height", "paddingTop", "paddingBottom" ], 549 originalWidth; 550 // fix width before calculating height of hidden element 551 var s = options.toShow; 552 originalWidth = s[0].style.width; 553 s.width( s.parent().width() 554 - parseFloat( s.css( "paddingLeft" ) ) 555 - parseFloat( s.css( "paddingRight" ) ) 556 - ( parseFloat( s.css( "borderLeftWidth" ) ) || 0 ) 557 - ( parseFloat( s.css( "borderRightWidth" ) ) || 0 ) ); 558 559 $.each( fxAttrs, function( i, prop ) { 560 hideProps[ prop ] = "hide"; 561 562 var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ ); 563 showProps[ prop ] = { 564 value: parts[ 1 ], 565 unit: parts[ 2 ] || "px" 566 }; 567 }); 568 options.toShow.css({ height: 0, overflow: "hidden" }).show(); 569 options.toHide 570 .filter( ":hidden" ) 571 .each( options.complete ) 572 .end() 573 .filter( ":visible" ) 574 .animate( hideProps, { 575 step: function( now, settings ) { 576 // only calculate the percent when animating height 577 // IE gets very inconsistent results when animating elements 578 // with small values, which is common for padding 579 if ( settings.prop == "height" ) { 580 percentDone = ( settings.end - settings.start === 0 ) ? 0 : 581 ( settings.now - settings.start ) / ( settings.end - settings.start ); 582 } 583 584 options.toShow[ 0 ].style[ settings.prop ] = 585 ( percentDone * showProps[ settings.prop ].value ) 586 + showProps[ settings.prop ].unit; 587 }, 588 duration: options.duration, 589 easing: options.easing, 590 complete: function() { 591 if ( !options.autoHeight ) { 592 options.toShow.css( "height", "" ); 593 } 594 options.toShow.css({ 595 width: originalWidth, 596 overflow: overflow 597 }); 598 options.complete(); 599 } 600 }); 601 }, 602 bounceslide: function( options ) { 603 this.slide( options, { 604 easing: options.down ? "easeOutBounce" : "swing", 605 duration: options.down ? 1000 : 200 606 }); 607 } 608 } 609}); 610 611})( 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.