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