source: Dev/branches/jQueryUI/client/js/jquery/ui/jquery.ui.tabs.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

File size: 20.7 KB
Line 
1/*
2 * jQuery UI Tabs 1.8.17
3 *
4 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
7 *
8 * http://docs.jquery.com/UI/Tabs
9 *
10 * Depends:
11 *      jquery.ui.core.js
12 *      jquery.ui.widget.js
13 */
14(function( $, undefined ) {
15
16var tabId = 0,
17        listId = 0;
18
19function getNextTabId() {
20        return ++tabId;
21}
22
23function getNextListId() {
24        return ++listId;
25}
26
27$.widget( "ui.tabs", {
28        options: {
29                add: null,
30                ajaxOptions: null,
31                cache: false,
32                cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
33                collapsible: false,
34                disable: null,
35                disabled: [],
36                enable: null,
37                event: "click",
38                fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
39                idPrefix: "ui-tabs-",
40                load: null,
41                panelTemplate: "<div></div>",
42                remove: null,
43                select: null,
44                show: null,
45                spinner: "<em>Loading&#8230;</em>",
46                tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
47        },
48
49        _create: function() {
50                this._tabify( true );
51        },
52
53        _setOption: function( key, value ) {
54                if ( key == "selected" ) {
55                        if (this.options.collapsible && value == this.options.selected ) {
56                                return;
57                        }
58                        this.select( value );
59                } else {
60                        this.options[ key ] = value;
61                        this._tabify();
62                }
63        },
64
65        _tabId: function( a ) {
66                return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) ||
67                        this.options.idPrefix + getNextTabId();
68        },
69
70        _sanitizeSelector: function( hash ) {
71                // we need this because an id may contain a ":"
72                return hash.replace( /:/g, "\\:" );
73        },
74
75        _cookie: function() {
76                var cookie = this.cookie ||
77                        ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() );
78                return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) );
79        },
80
81        _ui: function( tab, panel ) {
82                return {
83                        tab: tab,
84                        panel: panel,
85                        index: this.anchors.index( tab )
86                };
87        },
88
89        _cleanup: function() {
90                // restore all former loading tabs labels
91                this.lis.filter( ".ui-state-processing" )
92                        .removeClass( "ui-state-processing" )
93                        .find( "span:data(label.tabs)" )
94                                .each(function() {
95                                        var el = $( this );
96                                        el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" );
97                                });
98        },
99
100        _tabify: function( init ) {
101                var self = this,
102                        o = this.options,
103                        fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
104
105                this.list = this.element.find( "ol,ul" ).eq( 0 );
106                this.lis = $( " > li:has(a[href])", this.list );
107                this.anchors = this.lis.map(function() {
108                        return $( "a", this )[ 0 ];
109                });
110                this.panels = $( [] );
111
112                this.anchors.each(function( i, a ) {
113                        var href = $( a ).attr( "href" );
114                        // For dynamically created HTML that contains a hash as href IE < 8 expands
115                        // such href to the full page url with hash and then misinterprets tab as ajax.
116                        // Same consideration applies for an added tab with a fragment identifier
117                        // since a[href=#fragment-identifier] does unexpectedly not match.
118                        // Thus normalize href attribute...
119                        var hrefBase = href.split( "#" )[ 0 ],
120                                baseEl;
121                        if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] ||
122                                        ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) {
123                                href = a.hash;
124                                a.href = href;
125                        }
126
127                        // inline tab
128                        if ( fragmentId.test( href ) ) {
129                                self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) );
130                        // remote tab
131                        // prevent loading the page itself if href is just "#"
132                        } else if ( href && href !== "#" ) {
133                                // required for restore on destroy
134                                $.data( a, "href.tabs", href );
135
136                                // TODO until #3808 is fixed strip fragment identifier from url
137                                // (IE fails to load from such url)
138                                $.data( a, "load.tabs", href.replace( /#.*$/, "" ) );
139
140                                var id = self._tabId( a );
141                                a.href = "#" + id;
142                                var $panel = self.element.find( "#" + id );
143                                if ( !$panel.length ) {
144                                        $panel = $( o.panelTemplate )
145                                                .attr( "id", id )
146                                                .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
147                                                .insertAfter( self.panels[ i - 1 ] || self.list );
148                                        $panel.data( "destroy.tabs", true );
149                                }
150                                self.panels = self.panels.add( $panel );
151                        // invalid tab href
152                        } else {
153                                o.disabled.push( i );
154                        }
155                });
156
157                // initialization from scratch
158                if ( init ) {
159                        // attach necessary classes for styling
160                        this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" );
161                        this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
162                        this.lis.addClass( "ui-state-default ui-corner-top" );
163                        this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" );
164
165                        // Selected tab
166                        // use "selected" option or try to retrieve:
167                        // 1. from fragment identifier in url
168                        // 2. from cookie
169                        // 3. from selected class attribute on <li>
170                        if ( o.selected === undefined ) {
171                                if ( location.hash ) {
172                                        this.anchors.each(function( i, a ) {
173                                                if ( a.hash == location.hash ) {
174                                                        o.selected = i;
175                                                        return false;
176                                                }
177                                        });
178                                }
179                                if ( typeof o.selected !== "number" && o.cookie ) {
180                                        o.selected = parseInt( self._cookie(), 10 );
181                                }
182                                if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) {
183                                        o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
184                                }
185                                o.selected = o.selected || ( this.lis.length ? 0 : -1 );
186                        } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release
187                                o.selected = -1;
188                        }
189
190                        // sanity check - default to first tab...
191                        o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 )
192                                ? o.selected
193                                : 0;
194
195                        // Take disabling tabs via class attribute from HTML
196                        // into account and update option properly.
197                        // A selected tab cannot become disabled.
198                        o.disabled = $.unique( o.disabled.concat(
199                                $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) {
200                                        return self.lis.index( n );
201                                })
202                        ) ).sort();
203
204                        if ( $.inArray( o.selected, o.disabled ) != -1 ) {
205                                o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 );
206                        }
207
208                        // highlight selected tab
209                        this.panels.addClass( "ui-tabs-hide" );
210                        this.lis.removeClass( "ui-tabs-selected ui-state-active" );
211                        // check for length avoids error when initializing empty list
212                        if ( o.selected >= 0 && this.anchors.length ) {
213                                self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" );
214                                this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" );
215
216                                // seems to be expected behavior that the show callback is fired
217                                self.element.queue( "tabs", function() {
218                                        self._trigger( "show", null,
219                                                self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) );
220                                });
221
222                                this.load( o.selected );
223                        }
224
225                        // clean up to avoid memory leaks in certain versions of IE 6
226                        // TODO: namespace this event
227                        $( window ).bind( "unload", function() {
228                                self.lis.add( self.anchors ).unbind( ".tabs" );
229                                self.lis = self.anchors = self.panels = null;
230                        });
231                // update selected after add/remove
232                } else {
233                        o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
234                }
235
236                // update collapsible
237                // TODO: use .toggleClass()
238                this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" );
239
240                // set or update cookie after init and add/remove respectively
241                if ( o.cookie ) {
242                        this._cookie( o.selected, o.cookie );
243                }
244
245                // disable tabs
246                for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
247                        $( li )[ $.inArray( i, o.disabled ) != -1 &&
248                                // TODO: use .toggleClass()
249                                !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" );
250                }
251
252                // reset cache if switching from cached to not cached
253                if ( o.cache === false ) {
254                        this.anchors.removeData( "cache.tabs" );
255                }
256
257                // remove all handlers before, tabify may run on existing tabs after add or option change
258                this.lis.add( this.anchors ).unbind( ".tabs" );
259
260                if ( o.event !== "mouseover" ) {
261                        var addState = function( state, el ) {
262                                if ( el.is( ":not(.ui-state-disabled)" ) ) {
263                                        el.addClass( "ui-state-" + state );
264                                }
265                        };
266                        var removeState = function( state, el ) {
267                                el.removeClass( "ui-state-" + state );
268                        };
269                        this.lis.bind( "mouseover.tabs" , function() {
270                                addState( "hover", $( this ) );
271                        });
272                        this.lis.bind( "mouseout.tabs", function() {
273                                removeState( "hover", $( this ) );
274                        });
275                        this.anchors.bind( "focus.tabs", function() {
276                                addState( "focus", $( this ).closest( "li" ) );
277                        });
278                        this.anchors.bind( "blur.tabs", function() {
279                                removeState( "focus", $( this ).closest( "li" ) );
280                        });
281                }
282
283                // set up animations
284                var hideFx, showFx;
285                if ( o.fx ) {
286                        if ( $.isArray( o.fx ) ) {
287                                hideFx = o.fx[ 0 ];
288                                showFx = o.fx[ 1 ];
289                        } else {
290                                hideFx = showFx = o.fx;
291                        }
292                }
293
294                // Reset certain styles left over from animation
295                // and prevent IE's ClearType bug...
296                function resetStyle( $el, fx ) {
297                        $el.css( "display", "" );
298                        if ( !$.support.opacity && fx.opacity ) {
299                                $el[ 0 ].style.removeAttribute( "filter" );
300                        }
301                }
302
303                // Show a tab...
304                var showTab = showFx
305                        ? function( clicked, $show ) {
306                                $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
307                                $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way
308                                        .animate( showFx, showFx.duration || "normal", function() {
309                                                resetStyle( $show, showFx );
310                                                self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
311                                        });
312                        }
313                        : function( clicked, $show ) {
314                                $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
315                                $show.removeClass( "ui-tabs-hide" );
316                                self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
317                        };
318
319                // Hide a tab, $show is optional...
320                var hideTab = hideFx
321                        ? function( clicked, $hide ) {
322                                $hide.animate( hideFx, hideFx.duration || "normal", function() {
323                                        self.lis.removeClass( "ui-tabs-selected ui-state-active" );
324                                        $hide.addClass( "ui-tabs-hide" );
325                                        resetStyle( $hide, hideFx );
326                                        self.element.dequeue( "tabs" );
327                                });
328                        }
329                        : function( clicked, $hide, $show ) {
330                                self.lis.removeClass( "ui-tabs-selected ui-state-active" );
331                                $hide.addClass( "ui-tabs-hide" );
332                                self.element.dequeue( "tabs" );
333                        };
334
335                // attach tab event handler, unbind to avoid duplicates from former tabifying...
336                this.anchors.bind( o.event + ".tabs", function() {
337                        var el = this,
338                                $li = $(el).closest( "li" ),
339                                $hide = self.panels.filter( ":not(.ui-tabs-hide)" ),
340                                $show = self.element.find( self._sanitizeSelector( el.hash ) );
341
342                        // If tab is already selected and not collapsible or tab disabled or
343                        // or is already loading or click callback returns false stop here.
344                        // Check if click handler returns false last so that it is not executed
345                        // for a disabled or loading tab!
346                        if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) ||
347                                $li.hasClass( "ui-state-disabled" ) ||
348                                $li.hasClass( "ui-state-processing" ) ||
349                                self.panels.filter( ":animated" ).length ||
350                                self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) {
351                                this.blur();
352                                return false;
353                        }
354
355                        o.selected = self.anchors.index( this );
356
357                        self.abort();
358
359                        // if tab may be closed
360                        if ( o.collapsible ) {
361                                if ( $li.hasClass( "ui-tabs-selected" ) ) {
362                                        o.selected = -1;
363
364                                        if ( o.cookie ) {
365                                                self._cookie( o.selected, o.cookie );
366                                        }
367
368                                        self.element.queue( "tabs", function() {
369                                                hideTab( el, $hide );
370                                        }).dequeue( "tabs" );
371
372                                        this.blur();
373                                        return false;
374                                } else if ( !$hide.length ) {
375                                        if ( o.cookie ) {
376                                                self._cookie( o.selected, o.cookie );
377                                        }
378
379                                        self.element.queue( "tabs", function() {
380                                                showTab( el, $show );
381                                        });
382
383                                        // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
384                                        self.load( self.anchors.index( this ) );
385
386                                        this.blur();
387                                        return false;
388                                }
389                        }
390
391                        if ( o.cookie ) {
392                                self._cookie( o.selected, o.cookie );
393                        }
394
395                        // show new tab
396                        if ( $show.length ) {
397                                if ( $hide.length ) {
398                                        self.element.queue( "tabs", function() {
399                                                hideTab( el, $hide );
400                                        });
401                                }
402                                self.element.queue( "tabs", function() {
403                                        showTab( el, $show );
404                                });
405
406                                self.load( self.anchors.index( this ) );
407                        } else {
408                                throw "jQuery UI Tabs: Mismatching fragment identifier.";
409                        }
410
411                        // Prevent IE from keeping other link focussed when using the back button
412                        // and remove dotted border from clicked link. This is controlled via CSS
413                        // in modern browsers; blur() removes focus from address bar in Firefox
414                        // which can become a usability and annoying problem with tabs('rotate').
415                        if ( $.browser.msie ) {
416                                this.blur();
417                        }
418                });
419
420                // disable click in any case
421                this.anchors.bind( "click.tabs", function(){
422                        return false;
423                });
424        },
425
426    _getIndex: function( index ) {
427                // meta-function to give users option to provide a href string instead of a numerical index.
428                // also sanitizes numerical indexes to valid values.
429                if ( typeof index == "string" ) {
430                        index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) );
431                }
432
433                return index;
434        },
435
436        destroy: function() {
437                var o = this.options;
438
439                this.abort();
440
441                this.element
442                        .unbind( ".tabs" )
443                        .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" )
444                        .removeData( "tabs" );
445
446                this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
447
448                this.anchors.each(function() {
449                        var href = $.data( this, "href.tabs" );
450                        if ( href ) {
451                                this.href = href;
452                        }
453                        var $this = $( this ).unbind( ".tabs" );
454                        $.each( [ "href", "load", "cache" ], function( i, prefix ) {
455                                $this.removeData( prefix + ".tabs" );
456                        });
457                });
458
459                this.lis.unbind( ".tabs" ).add( this.panels ).each(function() {
460                        if ( $.data( this, "destroy.tabs" ) ) {
461                                $( this ).remove();
462                        } else {
463                                $( this ).removeClass([
464                                        "ui-state-default",
465                                        "ui-corner-top",
466                                        "ui-tabs-selected",
467                                        "ui-state-active",
468                                        "ui-state-hover",
469                                        "ui-state-focus",
470                                        "ui-state-disabled",
471                                        "ui-tabs-panel",
472                                        "ui-widget-content",
473                                        "ui-corner-bottom",
474                                        "ui-tabs-hide"
475                                ].join( " " ) );
476                        }
477                });
478
479                if ( o.cookie ) {
480                        this._cookie( null, o.cookie );
481                }
482
483                return this;
484        },
485
486        add: function( url, label, index ) {
487                if ( index === undefined ) {
488                        index = this.anchors.length;
489                }
490
491                var self = this,
492                        o = this.options,
493                        $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ),
494                        id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] );
495
496                $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );
497
498                // try to find an existing element before creating a new one
499                var $panel = self.element.find( "#" + id );
500                if ( !$panel.length ) {
501                        $panel = $( o.panelTemplate )
502                                .attr( "id", id )
503                                .data( "destroy.tabs", true );
504                }
505                $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" );
506
507                if ( index >= this.lis.length ) {
508                        $li.appendTo( this.list );
509                        $panel.appendTo( this.list[ 0 ].parentNode );
510                } else {
511                        $li.insertBefore( this.lis[ index ] );
512                        $panel.insertBefore( this.panels[ index ] );
513                }
514
515                o.disabled = $.map( o.disabled, function( n, i ) {
516                        return n >= index ? ++n : n;
517                });
518
519                this._tabify();
520
521                if ( this.anchors.length == 1 ) {
522                        o.selected = 0;
523                        $li.addClass( "ui-tabs-selected ui-state-active" );
524                        $panel.removeClass( "ui-tabs-hide" );
525                        this.element.queue( "tabs", function() {
526                                self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) );
527                        });
528
529                        this.load( 0 );
530                }
531
532                this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
533                return this;
534        },
535
536        remove: function( index ) {
537                index = this._getIndex( index );
538                var o = this.options,
539                        $li = this.lis.eq( index ).remove(),
540                        $panel = this.panels.eq( index ).remove();
541
542                // If selected tab was removed focus tab to the right or
543                // in case the last tab was removed the tab to the left.
544                if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
545                        this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
546                }
547
548                o.disabled = $.map(
549                        $.grep( o.disabled, function(n, i) {
550                                return n != index;
551                        }),
552                        function( n, i ) {
553                                return n >= index ? --n : n;
554                        });
555
556                this._tabify();
557
558                this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
559                return this;
560        },
561
562        enable: function( index ) {
563                index = this._getIndex( index );
564                var o = this.options;
565                if ( $.inArray( index, o.disabled ) == -1 ) {
566                        return;
567                }
568
569                this.lis.eq( index ).removeClass( "ui-state-disabled" );
570                o.disabled = $.grep( o.disabled, function( n, i ) {
571                        return n != index;
572                });
573
574                this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
575                return this;
576        },
577
578        disable: function( index ) {
579                index = this._getIndex( index );
580                var self = this, o = this.options;
581                // cannot disable already selected tab
582                if ( index != o.selected ) {
583                        this.lis.eq( index ).addClass( "ui-state-disabled" );
584
585                        o.disabled.push( index );
586                        o.disabled.sort();
587
588                        this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
589                }
590
591                return this;
592        },
593
594        select: function( index ) {
595                index = this._getIndex( index );
596                if ( index == -1 ) {
597                        if ( this.options.collapsible && this.options.selected != -1 ) {
598                                index = this.options.selected;
599                        } else {
600                                return this;
601                        }
602                }
603                this.anchors.eq( index ).trigger( this.options.event + ".tabs" );
604                return this;
605        },
606
607        load: function( index ) {
608                index = this._getIndex( index );
609                var self = this,
610                        o = this.options,
611                        a = this.anchors.eq( index )[ 0 ],
612                        url = $.data( a, "load.tabs" );
613
614                this.abort();
615
616                // not remote or from cache
617                if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) {
618                        this.element.dequeue( "tabs" );
619                        return;
620                }
621
622                // load remote from here on
623                this.lis.eq( index ).addClass( "ui-state-processing" );
624
625                if ( o.spinner ) {
626                        var span = $( "span", a );
627                        span.data( "label.tabs", span.html() ).html( o.spinner );
628                }
629
630                this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, {
631                        url: url,
632                        success: function( r, s ) {
633                                self.element.find( self._sanitizeSelector( a.hash ) ).html( r );
634
635                                // take care of tab labels
636                                self._cleanup();
637
638                                if ( o.cache ) {
639                                        $.data( a, "cache.tabs", true );
640                                }
641
642                                self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
643                                try {
644                                        o.ajaxOptions.success( r, s );
645                                }
646                                catch ( e ) {}
647                        },
648                        error: function( xhr, s, e ) {
649                                // take care of tab labels
650                                self._cleanup();
651
652                                self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
653                                try {
654                                        // Passing index avoid a race condition when this method is
655                                        // called after the user has selected another tab.
656                                        // Pass the anchor that initiated this request allows
657                                        // loadError to manipulate the tab content panel via $(a.hash)
658                                        o.ajaxOptions.error( xhr, s, index, a );
659                                }
660                                catch ( e ) {}
661                        }
662                } ) );
663
664                // last, so that load event is fired before show...
665                self.element.dequeue( "tabs" );
666
667                return this;
668        },
669
670        abort: function() {
671                // stop possibly running animations
672                this.element.queue( [] );
673                this.panels.stop( false, true );
674
675                // "tabs" queue must not contain more than two elements,
676                // which are the callbacks for the latest clicked tab...
677                this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) );
678
679                // terminate pending requests from other tabs
680                if ( this.xhr ) {
681                        this.xhr.abort();
682                        delete this.xhr;
683                }
684
685                // take care of tab labels
686                this._cleanup();
687                return this;
688        },
689
690        url: function( index, url ) {
691                this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url );
692                return this;
693        },
694
695        length: function() {
696                return this.anchors.length;
697        }
698});
699
700$.extend( $.ui.tabs, {
701        version: "1.8.17"
702});
703
704/*
705 * Tabs Extensions
706 */
707
708/*
709 * Rotate
710 */
711$.extend( $.ui.tabs.prototype, {
712        rotation: null,
713        rotate: function( ms, continuing ) {
714                var self = this,
715                        o = this.options;
716
717                var rotate = self._rotate || ( self._rotate = function( e ) {
718                        clearTimeout( self.rotation );
719                        self.rotation = setTimeout(function() {
720                                var t = o.selected;
721                                self.select( ++t < self.anchors.length ? t : 0 );
722                        }, ms );
723                       
724                        if ( e ) {
725                                e.stopPropagation();
726                        }
727                });
728
729                var stop = self._unrotate || ( self._unrotate = !continuing
730                        ? function(e) {
731                                if (e.clientX) { // in case of a true click
732                                        self.rotate(null);
733                                }
734                        }
735                        : function( e ) {
736                                t = o.selected;
737                                rotate();
738                        });
739
740                // start rotation
741                if ( ms ) {
742                        this.element.bind( "tabsshow", rotate );
743                        this.anchors.bind( o.event + ".tabs", stop );
744                        rotate();
745                // stop rotation
746                } else {
747                        clearTimeout( self.rotation );
748                        this.element.unbind( "tabsshow", rotate );
749                        this.anchors.unbind( o.event + ".tabs", stop );
750                        delete this._rotate;
751                        delete this._unrotate;
752                }
753
754                return this;
755        }
756});
757
758})( jQuery );
Note: See TracBrowser for help on using the repository browser.