source: trunk/themes/default/js/ui/jquery.ui.tabs.js @ 20824

Last change on this file since 20824 was 20824, checked in by rvelices, 11 years ago

upgraded jquery ui from 1.9.0 to 1.10.1

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