[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Thu Dec 3 01:00:04 2020 Cross-referenced by PHPXref 0.7.1