[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/jquery/ui/ -> tabs.js (source)

   1  /*!
   2   * jQuery UI Tabs 1.13.2
   3   * http://jqueryui.com
   4   *
   5   * Copyright jQuery Foundation and other contributors
   6   * Released under the MIT license.
   7   * http://jquery.org/license
   8   */
   9  
  10  //>>label: Tabs
  11  //>>group: Widgets
  12  //>>description: Transforms a set of container elements into a tab structure.
  13  //>>docs: http://api.jqueryui.com/tabs/
  14  //>>demos: http://jqueryui.com/tabs/
  15  //>>css.structure: ../../themes/base/core.css
  16  //>>css.structure: ../../themes/base/tabs.css
  17  //>>css.theme: ../../themes/base/theme.css
  18  
  19  ( function( factory ) {
  20      "use strict";
  21  
  22      if ( typeof define === "function" && define.amd ) {
  23  
  24          // AMD. Register as an anonymous module.
  25          define( [
  26              "jquery",
  27              "./core"
  28          ], factory );
  29      } else {
  30  
  31          // Browser globals
  32          factory( jQuery );
  33      }
  34  } )( function( $ ) {
  35  "use strict";
  36  
  37  $.widget( "ui.tabs", {
  38      version: "1.13.2",
  39      delay: 300,
  40      options: {
  41          active: null,
  42          classes: {
  43              "ui-tabs": "ui-corner-all",
  44              "ui-tabs-nav": "ui-corner-all",
  45              "ui-tabs-panel": "ui-corner-bottom",
  46              "ui-tabs-tab": "ui-corner-top"
  47          },
  48          collapsible: false,
  49          event: "click",
  50          heightStyle: "content",
  51          hide: null,
  52          show: null,
  53  
  54          // Callbacks
  55          activate: null,
  56          beforeActivate: null,
  57          beforeLoad: null,
  58          load: null
  59      },
  60  
  61      _isLocal: ( function() {
  62          var rhash = /#.*$/;
  63  
  64          return function( anchor ) {
  65              var anchorUrl, locationUrl;
  66  
  67              anchorUrl = anchor.href.replace( rhash, "" );
  68              locationUrl = location.href.replace( rhash, "" );
  69  
  70              // Decoding may throw an error if the URL isn't UTF-8 (#9518)
  71              try {
  72                  anchorUrl = decodeURIComponent( anchorUrl );
  73              } catch ( error ) {}
  74              try {
  75                  locationUrl = decodeURIComponent( locationUrl );
  76              } catch ( error ) {}
  77  
  78              return anchor.hash.length > 1 && anchorUrl === locationUrl;
  79          };
  80      } )(),
  81  
  82      _create: function() {
  83          var that = this,
  84              options = this.options;
  85  
  86          this.running = false;
  87  
  88          this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
  89          this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
  90  
  91          this._processTabs();
  92          options.active = this._initialActive();
  93  
  94          // Take disabling tabs via class attribute from HTML
  95          // into account and update option properly.
  96          if ( Array.isArray( options.disabled ) ) {
  97              options.disabled = $.uniqueSort( options.disabled.concat(
  98                  $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
  99                      return that.tabs.index( li );
 100                  } )
 101              ) ).sort();
 102          }
 103  
 104          // Check for length avoids error when initializing empty list
 105          if ( this.options.active !== false && this.anchors.length ) {
 106              this.active = this._findActive( options.active );
 107          } else {
 108              this.active = $();
 109          }
 110  
 111          this._refresh();
 112  
 113          if ( this.active.length ) {
 114              this.load( options.active );
 115          }
 116      },
 117  
 118      _initialActive: function() {
 119          var active = this.options.active,
 120              collapsible = this.options.collapsible,
 121              locationHash = location.hash.substring( 1 );
 122  
 123          if ( active === null ) {
 124  
 125              // check the fragment identifier in the URL
 126              if ( locationHash ) {
 127                  this.tabs.each( function( i, tab ) {
 128                      if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
 129                          active = i;
 130                          return false;
 131                      }
 132                  } );
 133              }
 134  
 135              // Check for a tab marked active via a class
 136              if ( active === null ) {
 137                  active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
 138              }
 139  
 140              // No active tab, set to false
 141              if ( active === null || active === -1 ) {
 142                  active = this.tabs.length ? 0 : false;
 143              }
 144          }
 145  
 146          // Handle numbers: negative, out of range
 147          if ( active !== false ) {
 148              active = this.tabs.index( this.tabs.eq( active ) );
 149              if ( active === -1 ) {
 150                  active = collapsible ? false : 0;
 151              }
 152          }
 153  
 154          // Don't allow collapsible: false and active: false
 155          if ( !collapsible && active === false && this.anchors.length ) {
 156              active = 0;
 157          }
 158  
 159          return active;
 160      },
 161  
 162      _getCreateEventData: function() {
 163          return {
 164              tab: this.active,
 165              panel: !this.active.length ? $() : this._getPanelForTab( this.active )
 166          };
 167      },
 168  
 169      _tabKeydown: function( event ) {
 170          var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
 171              selectedIndex = this.tabs.index( focusedTab ),
 172              goingForward = true;
 173  
 174          if ( this._handlePageNav( event ) ) {
 175              return;
 176          }
 177  
 178          switch ( event.keyCode ) {
 179          case $.ui.keyCode.RIGHT:
 180          case $.ui.keyCode.DOWN:
 181              selectedIndex++;
 182              break;
 183          case $.ui.keyCode.UP:
 184          case $.ui.keyCode.LEFT:
 185              goingForward = false;
 186              selectedIndex--;
 187              break;
 188          case $.ui.keyCode.END:
 189              selectedIndex = this.anchors.length - 1;
 190              break;
 191          case $.ui.keyCode.HOME:
 192              selectedIndex = 0;
 193              break;
 194          case $.ui.keyCode.SPACE:
 195  
 196              // Activate only, no collapsing
 197              event.preventDefault();
 198              clearTimeout( this.activating );
 199              this._activate( selectedIndex );
 200              return;
 201          case $.ui.keyCode.ENTER:
 202  
 203              // Toggle (cancel delayed activation, allow collapsing)
 204              event.preventDefault();
 205              clearTimeout( this.activating );
 206  
 207              // Determine if we should collapse or activate
 208              this._activate( selectedIndex === this.options.active ? false : selectedIndex );
 209              return;
 210          default:
 211              return;
 212          }
 213  
 214          // Focus the appropriate tab, based on which key was pressed
 215          event.preventDefault();
 216          clearTimeout( this.activating );
 217          selectedIndex = this._focusNextTab( selectedIndex, goingForward );
 218  
 219          // Navigating with control/command key will prevent automatic activation
 220          if ( !event.ctrlKey && !event.metaKey ) {
 221  
 222              // Update aria-selected immediately so that AT think the tab is already selected.
 223              // Otherwise AT may confuse the user by stating that they need to activate the tab,
 224              // but the tab will already be activated by the time the announcement finishes.
 225              focusedTab.attr( "aria-selected", "false" );
 226              this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
 227  
 228              this.activating = this._delay( function() {
 229                  this.option( "active", selectedIndex );
 230              }, this.delay );
 231          }
 232      },
 233  
 234      _panelKeydown: function( event ) {
 235          if ( this._handlePageNav( event ) ) {
 236              return;
 237          }
 238  
 239          // Ctrl+up moves focus to the current tab
 240          if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
 241              event.preventDefault();
 242              this.active.trigger( "focus" );
 243          }
 244      },
 245  
 246      // Alt+page up/down moves focus to the previous/next tab (and activates)
 247      _handlePageNav: function( event ) {
 248          if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
 249              this._activate( this._focusNextTab( this.options.active - 1, false ) );
 250              return true;
 251          }
 252          if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
 253              this._activate( this._focusNextTab( this.options.active + 1, true ) );
 254              return true;
 255          }
 256      },
 257  
 258      _findNextTab: function( index, goingForward ) {
 259          var lastTabIndex = this.tabs.length - 1;
 260  
 261  		function constrain() {
 262              if ( index > lastTabIndex ) {
 263                  index = 0;
 264              }
 265              if ( index < 0 ) {
 266                  index = lastTabIndex;
 267              }
 268              return index;
 269          }
 270  
 271          while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
 272              index = goingForward ? index + 1 : index - 1;
 273          }
 274  
 275          return index;
 276      },
 277  
 278      _focusNextTab: function( index, goingForward ) {
 279          index = this._findNextTab( index, goingForward );
 280          this.tabs.eq( index ).trigger( "focus" );
 281          return index;
 282      },
 283  
 284      _setOption: function( key, value ) {
 285          if ( key === "active" ) {
 286  
 287              // _activate() will handle invalid values and update this.options
 288              this._activate( value );
 289              return;
 290          }
 291  
 292          this._super( key, value );
 293  
 294          if ( key === "collapsible" ) {
 295              this._toggleClass( "ui-tabs-collapsible", null, value );
 296  
 297              // Setting collapsible: false while collapsed; open first panel
 298              if ( !value && this.options.active === false ) {
 299                  this._activate( 0 );
 300              }
 301          }
 302  
 303          if ( key === "event" ) {
 304              this._setupEvents( value );
 305          }
 306  
 307          if ( key === "heightStyle" ) {
 308              this._setupHeightStyle( value );
 309          }
 310      },
 311  
 312      _sanitizeSelector: function( hash ) {
 313          return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
 314      },
 315  
 316      refresh: function() {
 317          var options = this.options,
 318              lis = this.tablist.children( ":has(a[href])" );
 319  
 320          // Get disabled tabs from class attribute from HTML
 321          // this will get converted to a boolean if needed in _refresh()
 322          options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
 323              return lis.index( tab );
 324          } );
 325  
 326          this._processTabs();
 327  
 328          // Was collapsed or no tabs
 329          if ( options.active === false || !this.anchors.length ) {
 330              options.active = false;
 331              this.active = $();
 332  
 333          // was active, but active tab is gone
 334          } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
 335  
 336              // all remaining tabs are disabled
 337              if ( this.tabs.length === options.disabled.length ) {
 338                  options.active = false;
 339                  this.active = $();
 340  
 341              // activate previous tab
 342              } else {
 343                  this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
 344              }
 345  
 346          // was active, active tab still exists
 347          } else {
 348  
 349              // make sure active index is correct
 350              options.active = this.tabs.index( this.active );
 351          }
 352  
 353          this._refresh();
 354      },
 355  
 356      _refresh: function() {
 357          this._setOptionDisabled( this.options.disabled );
 358          this._setupEvents( this.options.event );
 359          this._setupHeightStyle( this.options.heightStyle );
 360  
 361          this.tabs.not( this.active ).attr( {
 362              "aria-selected": "false",
 363              "aria-expanded": "false",
 364              tabIndex: -1
 365          } );
 366          this.panels.not( this._getPanelForTab( this.active ) )
 367              .hide()
 368              .attr( {
 369                  "aria-hidden": "true"
 370              } );
 371  
 372          // Make sure one tab is in the tab order
 373          if ( !this.active.length ) {
 374              this.tabs.eq( 0 ).attr( "tabIndex", 0 );
 375          } else {
 376              this.active
 377                  .attr( {
 378                      "aria-selected": "true",
 379                      "aria-expanded": "true",
 380                      tabIndex: 0
 381                  } );
 382              this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
 383              this._getPanelForTab( this.active )
 384                  .show()
 385                  .attr( {
 386                      "aria-hidden": "false"
 387                  } );
 388          }
 389      },
 390  
 391      _processTabs: function() {
 392          var that = this,
 393              prevTabs = this.tabs,
 394              prevAnchors = this.anchors,
 395              prevPanels = this.panels;
 396  
 397          this.tablist = this._getList().attr( "role", "tablist" );
 398          this._addClass( this.tablist, "ui-tabs-nav",
 399              "ui-helper-reset ui-helper-clearfix ui-widget-header" );
 400  
 401          // Prevent users from focusing disabled tabs via click
 402          this.tablist
 403              .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
 404                  if ( $( this ).is( ".ui-state-disabled" ) ) {
 405                      event.preventDefault();
 406                  }
 407              } )
 408  
 409              // Support: IE <9
 410              // Preventing the default action in mousedown doesn't prevent IE
 411              // from focusing the element, so if the anchor gets focused, blur.
 412              // We don't have to worry about focusing the previously focused
 413              // element since clicking on a non-focusable element should focus
 414              // the body anyway.
 415              .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
 416                  if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
 417                      this.blur();
 418                  }
 419              } );
 420  
 421          this.tabs = this.tablist.find( "> li:has(a[href])" )
 422              .attr( {
 423                  role: "tab",
 424                  tabIndex: -1
 425              } );
 426          this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
 427  
 428          this.anchors = this.tabs.map( function() {
 429              return $( "a", this )[ 0 ];
 430          } )
 431              .attr( {
 432                  tabIndex: -1
 433              } );
 434          this._addClass( this.anchors, "ui-tabs-anchor" );
 435  
 436          this.panels = $();
 437  
 438          this.anchors.each( function( i, anchor ) {
 439              var selector, panel, panelId,
 440                  anchorId = $( anchor ).uniqueId().attr( "id" ),
 441                  tab = $( anchor ).closest( "li" ),
 442                  originalAriaControls = tab.attr( "aria-controls" );
 443  
 444              // Inline tab
 445              if ( that._isLocal( anchor ) ) {
 446                  selector = anchor.hash;
 447                  panelId = selector.substring( 1 );
 448                  panel = that.element.find( that._sanitizeSelector( selector ) );
 449  
 450              // remote tab
 451              } else {
 452  
 453                  // If the tab doesn't already have aria-controls,
 454                  // generate an id by using a throw-away element
 455                  panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
 456                  selector = "#" + panelId;
 457                  panel = that.element.find( selector );
 458                  if ( !panel.length ) {
 459                      panel = that._createPanel( panelId );
 460                      panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
 461                  }
 462                  panel.attr( "aria-live", "polite" );
 463              }
 464  
 465              if ( panel.length ) {
 466                  that.panels = that.panels.add( panel );
 467              }
 468              if ( originalAriaControls ) {
 469                  tab.data( "ui-tabs-aria-controls", originalAriaControls );
 470              }
 471              tab.attr( {
 472                  "aria-controls": panelId,
 473                  "aria-labelledby": anchorId
 474              } );
 475              panel.attr( "aria-labelledby", anchorId );
 476          } );
 477  
 478          this.panels.attr( "role", "tabpanel" );
 479          this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
 480  
 481          // Avoid memory leaks (#10056)
 482          if ( prevTabs ) {
 483              this._off( prevTabs.not( this.tabs ) );
 484              this._off( prevAnchors.not( this.anchors ) );
 485              this._off( prevPanels.not( this.panels ) );
 486          }
 487      },
 488  
 489      // Allow overriding how to find the list for rare usage scenarios (#7715)
 490      _getList: function() {
 491          return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
 492      },
 493  
 494      _createPanel: function( id ) {
 495          return $( "<div>" )
 496              .attr( "id", id )
 497              .data( "ui-tabs-destroy", true );
 498      },
 499  
 500      _setOptionDisabled: function( disabled ) {
 501          var currentItem, li, i;
 502  
 503          if ( Array.isArray( disabled ) ) {
 504              if ( !disabled.length ) {
 505                  disabled = false;
 506              } else if ( disabled.length === this.anchors.length ) {
 507                  disabled = true;
 508              }
 509          }
 510  
 511          // Disable tabs
 512          for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
 513              currentItem = $( li );
 514              if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
 515                  currentItem.attr( "aria-disabled", "true" );
 516                  this._addClass( currentItem, null, "ui-state-disabled" );
 517              } else {
 518                  currentItem.removeAttr( "aria-disabled" );
 519                  this._removeClass( currentItem, null, "ui-state-disabled" );
 520              }
 521          }
 522  
 523          this.options.disabled = disabled;
 524  
 525          this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
 526              disabled === true );
 527      },
 528  
 529      _setupEvents: function( event ) {
 530          var events = {};
 531          if ( event ) {
 532              $.each( event.split( " " ), function( index, eventName ) {
 533                  events[ eventName ] = "_eventHandler";
 534              } );
 535          }
 536  
 537          this._off( this.anchors.add( this.tabs ).add( this.panels ) );
 538  
 539          // Always prevent the default action, even when disabled
 540          this._on( true, this.anchors, {
 541              click: function( event ) {
 542                  event.preventDefault();
 543              }
 544          } );
 545          this._on( this.anchors, events );
 546          this._on( this.tabs, { keydown: "_tabKeydown" } );
 547          this._on( this.panels, { keydown: "_panelKeydown" } );
 548  
 549          this._focusable( this.tabs );
 550          this._hoverable( this.tabs );
 551      },
 552  
 553      _setupHeightStyle: function( heightStyle ) {
 554          var maxHeight,
 555              parent = this.element.parent();
 556  
 557          if ( heightStyle === "fill" ) {
 558              maxHeight = parent.height();
 559              maxHeight -= this.element.outerHeight() - this.element.height();
 560  
 561              this.element.siblings( ":visible" ).each( function() {
 562                  var elem = $( this ),
 563                      position = elem.css( "position" );
 564  
 565                  if ( position === "absolute" || position === "fixed" ) {
 566                      return;
 567                  }
 568                  maxHeight -= elem.outerHeight( true );
 569              } );
 570  
 571              this.element.children().not( this.panels ).each( function() {
 572                  maxHeight -= $( this ).outerHeight( true );
 573              } );
 574  
 575              this.panels.each( function() {
 576                  $( this ).height( Math.max( 0, maxHeight -
 577                      $( this ).innerHeight() + $( this ).height() ) );
 578              } )
 579                  .css( "overflow", "auto" );
 580          } else if ( heightStyle === "auto" ) {
 581              maxHeight = 0;
 582              this.panels.each( function() {
 583                  maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
 584              } ).height( maxHeight );
 585          }
 586      },
 587  
 588      _eventHandler: function( event ) {
 589          var options = this.options,
 590              active = this.active,
 591              anchor = $( event.currentTarget ),
 592              tab = anchor.closest( "li" ),
 593              clickedIsActive = tab[ 0 ] === active[ 0 ],
 594              collapsing = clickedIsActive && options.collapsible,
 595              toShow = collapsing ? $() : this._getPanelForTab( tab ),
 596              toHide = !active.length ? $() : this._getPanelForTab( active ),
 597              eventData = {
 598                  oldTab: active,
 599                  oldPanel: toHide,
 600                  newTab: collapsing ? $() : tab,
 601                  newPanel: toShow
 602              };
 603  
 604          event.preventDefault();
 605  
 606          if ( tab.hasClass( "ui-state-disabled" ) ||
 607  
 608                  // tab is already loading
 609                  tab.hasClass( "ui-tabs-loading" ) ||
 610  
 611                  // can't switch durning an animation
 612                  this.running ||
 613  
 614                  // click on active header, but not collapsible
 615                  ( clickedIsActive && !options.collapsible ) ||
 616  
 617                  // allow canceling activation
 618                  ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
 619              return;
 620          }
 621  
 622          options.active = collapsing ? false : this.tabs.index( tab );
 623  
 624          this.active = clickedIsActive ? $() : tab;
 625          if ( this.xhr ) {
 626              this.xhr.abort();
 627          }
 628  
 629          if ( !toHide.length && !toShow.length ) {
 630              $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
 631          }
 632  
 633          if ( toShow.length ) {
 634              this.load( this.tabs.index( tab ), event );
 635          }
 636          this._toggle( event, eventData );
 637      },
 638  
 639      // Handles show/hide for selecting tabs
 640      _toggle: function( event, eventData ) {
 641          var that = this,
 642              toShow = eventData.newPanel,
 643              toHide = eventData.oldPanel;
 644  
 645          this.running = true;
 646  
 647  		function complete() {
 648              that.running = false;
 649              that._trigger( "activate", event, eventData );
 650          }
 651  
 652  		function show() {
 653              that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
 654  
 655              if ( toShow.length && that.options.show ) {
 656                  that._show( toShow, that.options.show, complete );
 657              } else {
 658                  toShow.show();
 659                  complete();
 660              }
 661          }
 662  
 663          // Start out by hiding, then showing, then completing
 664          if ( toHide.length && this.options.hide ) {
 665              this._hide( toHide, this.options.hide, function() {
 666                  that._removeClass( eventData.oldTab.closest( "li" ),
 667                      "ui-tabs-active", "ui-state-active" );
 668                  show();
 669              } );
 670          } else {
 671              this._removeClass( eventData.oldTab.closest( "li" ),
 672                  "ui-tabs-active", "ui-state-active" );
 673              toHide.hide();
 674              show();
 675          }
 676  
 677          toHide.attr( "aria-hidden", "true" );
 678          eventData.oldTab.attr( {
 679              "aria-selected": "false",
 680              "aria-expanded": "false"
 681          } );
 682  
 683          // If we're switching tabs, remove the old tab from the tab order.
 684          // If we're opening from collapsed state, remove the previous tab from the tab order.
 685          // If we're collapsing, then keep the collapsing tab in the tab order.
 686          if ( toShow.length && toHide.length ) {
 687              eventData.oldTab.attr( "tabIndex", -1 );
 688          } else if ( toShow.length ) {
 689              this.tabs.filter( function() {
 690                  return $( this ).attr( "tabIndex" ) === 0;
 691              } )
 692                  .attr( "tabIndex", -1 );
 693          }
 694  
 695          toShow.attr( "aria-hidden", "false" );
 696          eventData.newTab.attr( {
 697              "aria-selected": "true",
 698              "aria-expanded": "true",
 699              tabIndex: 0
 700          } );
 701      },
 702  
 703      _activate: function( index ) {
 704          var anchor,
 705              active = this._findActive( index );
 706  
 707          // Trying to activate the already active panel
 708          if ( active[ 0 ] === this.active[ 0 ] ) {
 709              return;
 710          }
 711  
 712          // Trying to collapse, simulate a click on the current active header
 713          if ( !active.length ) {
 714              active = this.active;
 715          }
 716  
 717          anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
 718          this._eventHandler( {
 719              target: anchor,
 720              currentTarget: anchor,
 721              preventDefault: $.noop
 722          } );
 723      },
 724  
 725      _findActive: function( index ) {
 726          return index === false ? $() : this.tabs.eq( index );
 727      },
 728  
 729      _getIndex: function( index ) {
 730  
 731          // meta-function to give users option to provide a href string instead of a numerical index.
 732          if ( typeof index === "string" ) {
 733              index = this.anchors.index( this.anchors.filter( "[href$='" +
 734                  $.escapeSelector( index ) + "']" ) );
 735          }
 736  
 737          return index;
 738      },
 739  
 740      _destroy: function() {
 741          if ( this.xhr ) {
 742              this.xhr.abort();
 743          }
 744  
 745          this.tablist
 746              .removeAttr( "role" )
 747              .off( this.eventNamespace );
 748  
 749          this.anchors
 750              .removeAttr( "role tabIndex" )
 751              .removeUniqueId();
 752  
 753          this.tabs.add( this.panels ).each( function() {
 754              if ( $.data( this, "ui-tabs-destroy" ) ) {
 755                  $( this ).remove();
 756              } else {
 757                  $( this ).removeAttr( "role tabIndex " +
 758                      "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
 759              }
 760          } );
 761  
 762          this.tabs.each( function() {
 763              var li = $( this ),
 764                  prev = li.data( "ui-tabs-aria-controls" );
 765              if ( prev ) {
 766                  li
 767                      .attr( "aria-controls", prev )
 768                      .removeData( "ui-tabs-aria-controls" );
 769              } else {
 770                  li.removeAttr( "aria-controls" );
 771              }
 772          } );
 773  
 774          this.panels.show();
 775  
 776          if ( this.options.heightStyle !== "content" ) {
 777              this.panels.css( "height", "" );
 778          }
 779      },
 780  
 781      enable: function( index ) {
 782          var disabled = this.options.disabled;
 783          if ( disabled === false ) {
 784              return;
 785          }
 786  
 787          if ( index === undefined ) {
 788              disabled = false;
 789          } else {
 790              index = this._getIndex( index );
 791              if ( Array.isArray( disabled ) ) {
 792                  disabled = $.map( disabled, function( num ) {
 793                      return num !== index ? num : null;
 794                  } );
 795              } else {
 796                  disabled = $.map( this.tabs, function( li, num ) {
 797                      return num !== index ? num : null;
 798                  } );
 799              }
 800          }
 801          this._setOptionDisabled( disabled );
 802      },
 803  
 804      disable: function( index ) {
 805          var disabled = this.options.disabled;
 806          if ( disabled === true ) {
 807              return;
 808          }
 809  
 810          if ( index === undefined ) {
 811              disabled = true;
 812          } else {
 813              index = this._getIndex( index );
 814              if ( $.inArray( index, disabled ) !== -1 ) {
 815                  return;
 816              }
 817              if ( Array.isArray( disabled ) ) {
 818                  disabled = $.merge( [ index ], disabled ).sort();
 819              } else {
 820                  disabled = [ index ];
 821              }
 822          }
 823          this._setOptionDisabled( disabled );
 824      },
 825  
 826      load: function( index, event ) {
 827          index = this._getIndex( index );
 828          var that = this,
 829              tab = this.tabs.eq( index ),
 830              anchor = tab.find( ".ui-tabs-anchor" ),
 831              panel = this._getPanelForTab( tab ),
 832              eventData = {
 833                  tab: tab,
 834                  panel: panel
 835              },
 836              complete = function( jqXHR, status ) {
 837                  if ( status === "abort" ) {
 838                      that.panels.stop( false, true );
 839                  }
 840  
 841                  that._removeClass( tab, "ui-tabs-loading" );
 842                  panel.removeAttr( "aria-busy" );
 843  
 844                  if ( jqXHR === that.xhr ) {
 845                      delete that.xhr;
 846                  }
 847              };
 848  
 849          // Not remote
 850          if ( this._isLocal( anchor[ 0 ] ) ) {
 851              return;
 852          }
 853  
 854          this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
 855  
 856          // Support: jQuery <1.8
 857          // jQuery <1.8 returns false if the request is canceled in beforeSend,
 858          // but as of 1.8, $.ajax() always returns a jqXHR object.
 859          if ( this.xhr && this.xhr.statusText !== "canceled" ) {
 860              this._addClass( tab, "ui-tabs-loading" );
 861              panel.attr( "aria-busy", "true" );
 862  
 863              this.xhr
 864                  .done( function( response, status, jqXHR ) {
 865  
 866                      // support: jQuery <1.8
 867                      // http://bugs.jquery.com/ticket/11778
 868                      setTimeout( function() {
 869                          panel.html( response );
 870                          that._trigger( "load", event, eventData );
 871  
 872                          complete( jqXHR, status );
 873                      }, 1 );
 874                  } )
 875                  .fail( function( jqXHR, status ) {
 876  
 877                      // support: jQuery <1.8
 878                      // http://bugs.jquery.com/ticket/11778
 879                      setTimeout( function() {
 880                          complete( jqXHR, status );
 881                      }, 1 );
 882                  } );
 883          }
 884      },
 885  
 886      _ajaxSettings: function( anchor, event, eventData ) {
 887          var that = this;
 888          return {
 889  
 890              // Support: IE <11 only
 891              // Strip any hash that exists to prevent errors with the Ajax request
 892              url: anchor.attr( "href" ).replace( /#.*$/, "" ),
 893              beforeSend: function( jqXHR, settings ) {
 894                  return that._trigger( "beforeLoad", event,
 895                      $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
 896              }
 897          };
 898      },
 899  
 900      _getPanelForTab: function( tab ) {
 901          var id = $( tab ).attr( "aria-controls" );
 902          return this.element.find( this._sanitizeSelector( "#" + id ) );
 903      }
 904  } );
 905  
 906  // DEPRECATED
 907  // TODO: Switch return back to widget declaration at top of file when this is removed
 908  if ( $.uiBackCompat !== false ) {
 909  
 910      // Backcompat for ui-tab class (now ui-tabs-tab)
 911      $.widget( "ui.tabs", $.ui.tabs, {
 912          _processTabs: function() {
 913              this._superApply( arguments );
 914              this._addClass( this.tabs, "ui-tab" );
 915          }
 916      } );
 917  }
 918  
 919  return $.ui.tabs;
 920  
 921  } );


Generated : Sat Apr 20 08:20:01 2024 Cross-referenced by PHPXref