[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/resources/lib/jquery.ui/ -> jquery.ui.accordion.js (source)

   1  /*!
   2   * jQuery UI Accordion 1.9.2
   3   * http://jqueryui.com
   4   *
   5   * Copyright 2012 jQuery Foundation and other contributors
   6   * Released under the MIT license.
   7   * http://jquery.org/license
   8   *
   9   * http://api.jqueryui.com/accordion/
  10   *
  11   * Depends:
  12   *    jquery.ui.core.js
  13   *    jquery.ui.widget.js
  14   */
  15  (function( $, undefined ) {
  16  
  17  var uid = 0,
  18      hideProps = {},
  19      showProps = {};
  20  
  21  hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
  22      hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
  23  showProps.height = showProps.paddingTop = showProps.paddingBottom =
  24      showProps.borderTopWidth = showProps.borderBottomWidth = "show";
  25  
  26  $.widget( "ui.accordion", {
  27      version: "1.9.2",
  28      options: {
  29          active: 0,
  30          animate: {},
  31          collapsible: false,
  32          event: "click",
  33          header: "> li > :first-child,> :not(li):even",
  34          heightStyle: "auto",
  35          icons: {
  36              activeHeader: "ui-icon-triangle-1-s",
  37              header: "ui-icon-triangle-1-e"
  38          },
  39  
  40          // callbacks
  41          activate: null,
  42          beforeActivate: null
  43      },
  44  
  45      _create: function() {
  46          var accordionId = this.accordionId = "ui-accordion-" +
  47                  (this.element.attr( "id" ) || ++uid),
  48              options = this.options;
  49  
  50          this.prevShow = this.prevHide = $();
  51          this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
  52  
  53          this.headers = this.element.find( options.header )
  54              .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
  55          this._hoverable( this.headers );
  56          this._focusable( this.headers );
  57  
  58          this.headers.next()
  59              .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
  60              .hide();
  61  
  62          // don't allow collapsible: false and active: false / null
  63          if ( !options.collapsible && (options.active === false || options.active == null) ) {
  64              options.active = 0;
  65          }
  66          // handle negative values
  67          if ( options.active < 0 ) {
  68              options.active += this.headers.length;
  69          }
  70          this.active = this._findActive( options.active )
  71              .addClass( "ui-accordion-header-active ui-state-active" )
  72              .toggleClass( "ui-corner-all ui-corner-top" );
  73          this.active.next()
  74              .addClass( "ui-accordion-content-active" )
  75              .show();
  76  
  77          this._createIcons();
  78          this.refresh();
  79  
  80          // ARIA
  81          this.element.attr( "role", "tablist" );
  82  
  83          this.headers
  84              .attr( "role", "tab" )
  85              .each(function( i ) {
  86                  var header = $( this ),
  87                      headerId = header.attr( "id" ),
  88                      panel = header.next(),
  89                      panelId = panel.attr( "id" );
  90                  if ( !headerId ) {
  91                      headerId = accordionId + "-header-" + i;
  92                      header.attr( "id", headerId );
  93                  }
  94                  if ( !panelId ) {
  95                      panelId = accordionId + "-panel-" + i;
  96                      panel.attr( "id", panelId );
  97                  }
  98                  header.attr( "aria-controls", panelId );
  99                  panel.attr( "aria-labelledby", headerId );
 100              })
 101              .next()
 102                  .attr( "role", "tabpanel" );
 103  
 104          this.headers
 105              .not( this.active )
 106              .attr({
 107                  "aria-selected": "false",
 108                  tabIndex: -1
 109              })
 110              .next()
 111                  .attr({
 112                      "aria-expanded": "false",
 113                      "aria-hidden": "true"
 114                  })
 115                  .hide();
 116  
 117          // make sure at least one header is in the tab order
 118          if ( !this.active.length ) {
 119              this.headers.eq( 0 ).attr( "tabIndex", 0 );
 120          } else {
 121              this.active.attr({
 122                  "aria-selected": "true",
 123                  tabIndex: 0
 124              })
 125              .next()
 126                  .attr({
 127                      "aria-expanded": "true",
 128                      "aria-hidden": "false"
 129                  });
 130          }
 131  
 132          this._on( this.headers, { keydown: "_keydown" });
 133          this._on( this.headers.next(), { keydown: "_panelKeyDown" });
 134          this._setupEvents( options.event );
 135      },
 136  
 137      _getCreateEventData: function() {
 138          return {
 139              header: this.active,
 140              content: !this.active.length ? $() : this.active.next()
 141          };
 142      },
 143  
 144      _createIcons: function() {
 145          var icons = this.options.icons;
 146          if ( icons ) {
 147              $( "<span>" )
 148                  .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
 149                  .prependTo( this.headers );
 150              this.active.children( ".ui-accordion-header-icon" )
 151                  .removeClass( icons.header )
 152                  .addClass( icons.activeHeader );
 153              this.headers.addClass( "ui-accordion-icons" );
 154          }
 155      },
 156  
 157      _destroyIcons: function() {
 158          this.headers
 159              .removeClass( "ui-accordion-icons" )
 160              .children( ".ui-accordion-header-icon" )
 161                  .remove();
 162      },
 163  
 164      _destroy: function() {
 165          var contents;
 166  
 167          // clean up main element
 168          this.element
 169              .removeClass( "ui-accordion ui-widget ui-helper-reset" )
 170              .removeAttr( "role" );
 171  
 172          // clean up headers
 173          this.headers
 174              .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
 175              .removeAttr( "role" )
 176              .removeAttr( "aria-selected" )
 177              .removeAttr( "aria-controls" )
 178              .removeAttr( "tabIndex" )
 179              .each(function() {
 180                  if ( /^ui-accordion/.test( this.id ) ) {
 181                      this.removeAttribute( "id" );
 182                  }
 183              });
 184          this._destroyIcons();
 185  
 186          // clean up content panels
 187          contents = this.headers.next()
 188              .css( "display", "" )
 189              .removeAttr( "role" )
 190              .removeAttr( "aria-expanded" )
 191              .removeAttr( "aria-hidden" )
 192              .removeAttr( "aria-labelledby" )
 193              .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
 194              .each(function() {
 195                  if ( /^ui-accordion/.test( this.id ) ) {
 196                      this.removeAttribute( "id" );
 197                  }
 198              });
 199          if ( this.options.heightStyle !== "content" ) {
 200              contents.css( "height", "" );
 201          }
 202      },
 203  
 204      _setOption: function( key, value ) {
 205          if ( key === "active" ) {
 206              // _activate() will handle invalid values and update this.options
 207              this._activate( value );
 208              return;
 209          }
 210  
 211          if ( key === "event" ) {
 212              if ( this.options.event ) {
 213                  this._off( this.headers, this.options.event );
 214              }
 215              this._setupEvents( value );
 216          }
 217  
 218          this._super( key, value );
 219  
 220          // setting collapsible: false while collapsed; open first panel
 221          if ( key === "collapsible" && !value && this.options.active === false ) {
 222              this._activate( 0 );
 223          }
 224  
 225          if ( key === "icons" ) {
 226              this._destroyIcons();
 227              if ( value ) {
 228                  this._createIcons();
 229              }
 230          }
 231  
 232          // #5332 - opacity doesn't cascade to positioned elements in IE
 233          // so we need to add the disabled class to the headers and panels
 234          if ( key === "disabled" ) {
 235              this.headers.add( this.headers.next() )
 236                  .toggleClass( "ui-state-disabled", !!value );
 237          }
 238      },
 239  
 240      _keydown: function( event ) {
 241          if ( event.altKey || event.ctrlKey ) {
 242              return;
 243          }
 244  
 245          var keyCode = $.ui.keyCode,
 246              length = this.headers.length,
 247              currentIndex = this.headers.index( event.target ),
 248              toFocus = false;
 249  
 250          switch ( event.keyCode ) {
 251              case keyCode.RIGHT:
 252              case keyCode.DOWN:
 253                  toFocus = this.headers[ ( currentIndex + 1 ) % length ];
 254                  break;
 255              case keyCode.LEFT:
 256              case keyCode.UP:
 257                  toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
 258                  break;
 259              case keyCode.SPACE:
 260              case keyCode.ENTER:
 261                  this._eventHandler( event );
 262                  break;
 263              case keyCode.HOME:
 264                  toFocus = this.headers[ 0 ];
 265                  break;
 266              case keyCode.END:
 267                  toFocus = this.headers[ length - 1 ];
 268                  break;
 269          }
 270  
 271          if ( toFocus ) {
 272              $( event.target ).attr( "tabIndex", -1 );
 273              $( toFocus ).attr( "tabIndex", 0 );
 274              toFocus.focus();
 275              event.preventDefault();
 276          }
 277      },
 278  
 279      _panelKeyDown : function( event ) {
 280          if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
 281              $( event.currentTarget ).prev().focus();
 282          }
 283      },
 284  
 285      refresh: function() {
 286          var maxHeight, overflow,
 287              heightStyle = this.options.heightStyle,
 288              parent = this.element.parent();
 289  
 290  
 291          if ( heightStyle === "fill" ) {
 292              // IE 6 treats height like minHeight, so we need to turn off overflow
 293              // in order to get a reliable height
 294              // we use the minHeight support test because we assume that only
 295              // browsers that don't support minHeight will treat height as minHeight
 296              if ( !$.support.minHeight ) {
 297                  overflow = parent.css( "overflow" );
 298                  parent.css( "overflow", "hidden");
 299              }
 300              maxHeight = parent.height();
 301              this.element.siblings( ":visible" ).each(function() {
 302                  var elem = $( this ),
 303                      position = elem.css( "position" );
 304  
 305                  if ( position === "absolute" || position === "fixed" ) {
 306                      return;
 307                  }
 308                  maxHeight -= elem.outerHeight( true );
 309              });
 310              if ( overflow ) {
 311                  parent.css( "overflow", overflow );
 312              }
 313  
 314              this.headers.each(function() {
 315                  maxHeight -= $( this ).outerHeight( true );
 316              });
 317  
 318              this.headers.next()
 319                  .each(function() {
 320                      $( this ).height( Math.max( 0, maxHeight -
 321                          $( this ).innerHeight() + $( this ).height() ) );
 322                  })
 323                  .css( "overflow", "auto" );
 324          } else if ( heightStyle === "auto" ) {
 325              maxHeight = 0;
 326              this.headers.next()
 327                  .each(function() {
 328                      maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
 329                  })
 330                  .height( maxHeight );
 331          }
 332      },
 333  
 334      _activate: function( index ) {
 335          var active = this._findActive( index )[ 0 ];
 336  
 337          // trying to activate the already active panel
 338          if ( active === this.active[ 0 ] ) {
 339              return;
 340          }
 341  
 342          // trying to collapse, simulate a click on the currently active header
 343          active = active || this.active[ 0 ];
 344  
 345          this._eventHandler({
 346              target: active,
 347              currentTarget: active,
 348              preventDefault: $.noop
 349          });
 350      },
 351  
 352      _findActive: function( selector ) {
 353          return typeof selector === "number" ? this.headers.eq( selector ) : $();
 354      },
 355  
 356      _setupEvents: function( event ) {
 357          var events = {};
 358          if ( !event ) {
 359              return;
 360          }
 361          $.each( event.split(" "), function( index, eventName ) {
 362              events[ eventName ] = "_eventHandler";
 363          });
 364          this._on( this.headers, events );
 365      },
 366  
 367      _eventHandler: function( event ) {
 368          var options = this.options,
 369              active = this.active,
 370              clicked = $( event.currentTarget ),
 371              clickedIsActive = clicked[ 0 ] === active[ 0 ],
 372              collapsing = clickedIsActive && options.collapsible,
 373              toShow = collapsing ? $() : clicked.next(),
 374              toHide = active.next(),
 375              eventData = {
 376                  oldHeader: active,
 377                  oldPanel: toHide,
 378                  newHeader: collapsing ? $() : clicked,
 379                  newPanel: toShow
 380              };
 381  
 382          event.preventDefault();
 383  
 384          if (
 385                  // click on active header, but not collapsible
 386                  ( clickedIsActive && !options.collapsible ) ||
 387                  // allow canceling activation
 388                  ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
 389              return;
 390          }
 391  
 392          options.active = collapsing ? false : this.headers.index( clicked );
 393  
 394          // when the call to ._toggle() comes after the class changes
 395          // it causes a very odd bug in IE 8 (see #6720)
 396          this.active = clickedIsActive ? $() : clicked;
 397          this._toggle( eventData );
 398  
 399          // switch classes
 400          // corner classes on the previously active header stay after the animation
 401          active.removeClass( "ui-accordion-header-active ui-state-active" );
 402          if ( options.icons ) {
 403              active.children( ".ui-accordion-header-icon" )
 404                  .removeClass( options.icons.activeHeader )
 405                  .addClass( options.icons.header );
 406          }
 407  
 408          if ( !clickedIsActive ) {
 409              clicked
 410                  .removeClass( "ui-corner-all" )
 411                  .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
 412              if ( options.icons ) {
 413                  clicked.children( ".ui-accordion-header-icon" )
 414                      .removeClass( options.icons.header )
 415                      .addClass( options.icons.activeHeader );
 416              }
 417  
 418              clicked
 419                  .next()
 420                  .addClass( "ui-accordion-content-active" );
 421          }
 422      },
 423  
 424      _toggle: function( data ) {
 425          var toShow = data.newPanel,
 426              toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
 427  
 428          // handle activating a panel during the animation for another activation
 429          this.prevShow.add( this.prevHide ).stop( true, true );
 430          this.prevShow = toShow;
 431          this.prevHide = toHide;
 432  
 433          if ( this.options.animate ) {
 434              this._animate( toShow, toHide, data );
 435          } else {
 436              toHide.hide();
 437              toShow.show();
 438              this._toggleComplete( data );
 439          }
 440  
 441          toHide.attr({
 442              "aria-expanded": "false",
 443              "aria-hidden": "true"
 444          });
 445          toHide.prev().attr( "aria-selected", "false" );
 446          // if we're switching panels, remove the old header from the tab order
 447          // if we're opening from collapsed state, remove the previous header from the tab order
 448          // if we're collapsing, then keep the collapsing header in the tab order
 449          if ( toShow.length && toHide.length ) {
 450              toHide.prev().attr( "tabIndex", -1 );
 451          } else if ( toShow.length ) {
 452              this.headers.filter(function() {
 453                  return $( this ).attr( "tabIndex" ) === 0;
 454              })
 455              .attr( "tabIndex", -1 );
 456          }
 457  
 458          toShow
 459              .attr({
 460                  "aria-expanded": "true",
 461                  "aria-hidden": "false"
 462              })
 463              .prev()
 464                  .attr({
 465                      "aria-selected": "true",
 466                      tabIndex: 0
 467                  });
 468      },
 469  
 470      _animate: function( toShow, toHide, data ) {
 471          var total, easing, duration,
 472              that = this,
 473              adjust = 0,
 474              down = toShow.length &&
 475                  ( !toHide.length || ( toShow.index() < toHide.index() ) ),
 476              animate = this.options.animate || {},
 477              options = down && animate.down || animate,
 478              complete = function() {
 479                  that._toggleComplete( data );
 480              };
 481  
 482          if ( typeof options === "number" ) {
 483              duration = options;
 484          }
 485          if ( typeof options === "string" ) {
 486              easing = options;
 487          }
 488          // fall back from options to animation in case of partial down settings
 489          easing = easing || options.easing || animate.easing;
 490          duration = duration || options.duration || animate.duration;
 491  
 492          if ( !toHide.length ) {
 493              return toShow.animate( showProps, duration, easing, complete );
 494          }
 495          if ( !toShow.length ) {
 496              return toHide.animate( hideProps, duration, easing, complete );
 497          }
 498  
 499          total = toShow.show().outerHeight();
 500          toHide.animate( hideProps, {
 501              duration: duration,
 502              easing: easing,
 503              step: function( now, fx ) {
 504                  fx.now = Math.round( now );
 505              }
 506          });
 507          toShow
 508              .hide()
 509              .animate( showProps, {
 510                  duration: duration,
 511                  easing: easing,
 512                  complete: complete,
 513                  step: function( now, fx ) {
 514                      fx.now = Math.round( now );
 515                      if ( fx.prop !== "height" ) {
 516                          adjust += fx.now;
 517                      } else if ( that.options.heightStyle !== "content" ) {
 518                          fx.now = Math.round( total - toHide.outerHeight() - adjust );
 519                          adjust = 0;
 520                      }
 521                  }
 522              });
 523      },
 524  
 525      _toggleComplete: function( data ) {
 526          var toHide = data.oldPanel;
 527  
 528          toHide
 529              .removeClass( "ui-accordion-content-active" )
 530              .prev()
 531                  .removeClass( "ui-corner-top" )
 532                  .addClass( "ui-corner-all" );
 533  
 534          // Work around for rendering bug in IE (#5421)
 535          if ( toHide.length ) {
 536              toHide.parent()[0].className = toHide.parent()[0].className;
 537          }
 538  
 539          this._trigger( "activate", null, data );
 540      }
 541  });
 542  
 543  
 544  
 545  // DEPRECATED
 546  if ( $.uiBackCompat !== false ) {
 547      // navigation options
 548      (function( $, prototype ) {
 549          $.extend( prototype.options, {
 550              navigation: false,
 551              navigationFilter: function() {
 552                  return this.href.toLowerCase() === location.href.toLowerCase();
 553              }
 554          });
 555  
 556          var _create = prototype._create;
 557          prototype._create = function() {
 558              if ( this.options.navigation ) {
 559                  var that = this,
 560                      headers = this.element.find( this.options.header ),
 561                      content = headers.next(),
 562                      current = headers.add( content )
 563                          .find( "a" )
 564                          .filter( this.options.navigationFilter )
 565                          [ 0 ];
 566                  if ( current ) {
 567                      headers.add( content ).each( function( index ) {
 568                          if ( $.contains( this, current ) ) {
 569                              that.options.active = Math.floor( index / 2 );
 570                              return false;
 571                          }
 572                      });
 573                  }
 574              }
 575              _create.call( this );
 576          };
 577      }( jQuery, jQuery.ui.accordion.prototype ) );
 578  
 579      // height options
 580      (function( $, prototype ) {
 581          $.extend( prototype.options, {
 582              heightStyle: null, // remove default so we fall back to old values
 583              autoHeight: true, // use heightStyle: "auto"
 584              clearStyle: false, // use heightStyle: "content"
 585              fillSpace: false // use heightStyle: "fill"
 586          });
 587  
 588          var _create = prototype._create,
 589              _setOption = prototype._setOption;
 590  
 591          $.extend( prototype, {
 592              _create: function() {
 593                  this.options.heightStyle = this.options.heightStyle ||
 594                      this._mergeHeightStyle();
 595  
 596                  _create.call( this );
 597              },
 598  
 599              _setOption: function( key ) {
 600                  if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
 601                      this.options.heightStyle = this._mergeHeightStyle();
 602                  }
 603                  _setOption.apply( this, arguments );
 604              },
 605  
 606              _mergeHeightStyle: function() {
 607                  var options = this.options;
 608  
 609                  if ( options.fillSpace ) {
 610                      return "fill";
 611                  }
 612  
 613                  if ( options.clearStyle ) {
 614                      return "content";
 615                  }
 616  
 617                  if ( options.autoHeight ) {
 618                      return "auto";
 619                  }
 620              }
 621          });
 622      }( jQuery, jQuery.ui.accordion.prototype ) );
 623  
 624      // icon options
 625      (function( $, prototype ) {
 626          $.extend( prototype.options.icons, {
 627              activeHeader: null, // remove default so we fall back to old values
 628              headerSelected: "ui-icon-triangle-1-s"
 629          });
 630  
 631          var _createIcons = prototype._createIcons;
 632          prototype._createIcons = function() {
 633              if ( this.options.icons ) {
 634                  this.options.icons.activeHeader = this.options.icons.activeHeader ||
 635                      this.options.icons.headerSelected;
 636              }
 637              _createIcons.call( this );
 638          };
 639      }( jQuery, jQuery.ui.accordion.prototype ) );
 640  
 641      // expanded active option, activate method
 642      (function( $, prototype ) {
 643          prototype.activate = prototype._activate;
 644  
 645          var _findActive = prototype._findActive;
 646          prototype._findActive = function( index ) {
 647              if ( index === -1 ) {
 648                  index = false;
 649              }
 650              if ( index && typeof index !== "number" ) {
 651                  index = this.headers.index( this.headers.filter( index ) );
 652                  if ( index === -1 ) {
 653                      index = false;
 654                  }
 655              }
 656              return _findActive.call( this, index );
 657          };
 658      }( jQuery, jQuery.ui.accordion.prototype ) );
 659  
 660      // resize method
 661      jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
 662  
 663      // change events
 664      (function( $, prototype ) {
 665          $.extend( prototype.options, {
 666              change: null,
 667              changestart: null
 668          });
 669  
 670          var _trigger = prototype._trigger;
 671          prototype._trigger = function( type, event, data ) {
 672              var ret = _trigger.apply( this, arguments );
 673              if ( !ret ) {
 674                  return false;
 675              }
 676  
 677              if ( type === "beforeActivate" ) {
 678                  ret = _trigger.call( this, "changestart", event, {
 679                      oldHeader: data.oldHeader,
 680                      oldContent: data.oldPanel,
 681                      newHeader: data.newHeader,
 682                      newContent: data.newPanel
 683                  });
 684              } else if ( type === "activate" ) {
 685                  ret = _trigger.call( this, "change", event, {
 686                      oldHeader: data.oldHeader,
 687                      oldContent: data.oldPanel,
 688                      newHeader: data.newHeader,
 689                      newContent: data.newPanel
 690                  });
 691              }
 692              return ret;
 693          };
 694      }( jQuery, jQuery.ui.accordion.prototype ) );
 695  
 696      // animated option
 697      // NOTE: this only provides support for "slide", "bounceslide", and easings
 698      // not the full $.ui.accordion.animations API
 699      (function( $, prototype ) {
 700          $.extend( prototype.options, {
 701              animate: null,
 702              animated: "slide"
 703          });
 704  
 705          var _create = prototype._create;
 706          prototype._create = function() {
 707              var options = this.options;
 708              if ( options.animate === null ) {
 709                  if ( !options.animated ) {
 710                      options.animate = false;
 711                  } else if ( options.animated === "slide" ) {
 712                      options.animate = 300;
 713                  } else if ( options.animated === "bounceslide" ) {
 714                      options.animate = {
 715                          duration: 200,
 716                          down: {
 717                              easing: "easeOutBounce",
 718                              duration: 1000
 719                          }
 720                      };
 721                  } else {
 722                      options.animate = options.animated;
 723                  }
 724              }
 725  
 726              _create.call( this );
 727          };
 728      }( jQuery, jQuery.ui.accordion.prototype ) );
 729  }
 730  
 731  })( jQuery );


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1