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