Subversion Repositories Sites.obs-saisons.fr

Rev

Blame | Last modification | View Log | RSS feed

/*
 * jQuery UI Tabs 1.8.5
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Tabs
 *
 * Depends:
 *      jquery.ui.core.js
 *      jquery.ui.widget.js
 */
(function( $, undefined ) {

var tabId = 0,
        listId = 0;

function getNextTabId() {
        return ++tabId;
}

function getNextListId() {
        return ++listId;
}

$.widget( "ui.tabs", {
        options: {
                add: null,
                ajaxOptions: null,
                cache: false,
                cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
                collapsible: false,
                disable: null,
                disabled: [],
                enable: null,
                event: "click",
                fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
                idPrefix: "ui-tabs-",
                load: null,
                panelTemplate: "<div></div>",
                remove: null,
                select: null,
                show: null,
                spinner: "<em>Loading&#8230;</em>",
                tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
        },

        _create: function() {
                this._tabify( true );
        },

        _setOption: function( key, value ) {
                if ( key == "selected" ) {
                        if (this.options.collapsible && value == this.options.selected ) {
                                return;
                        }
                        this.select( value );
                } else {
                        this.options[ key ] = value;
                        this._tabify();
                }
        },

        _tabId: function( a ) {
                return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) ||
                        this.options.idPrefix + getNextTabId();
        },

        _sanitizeSelector: function( hash ) {
                // we need this because an id may contain a ":"
                return hash.replace( /:/g, "\\:" );
        },

        _cookie: function() {
                var cookie = this.cookie ||
                        ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() );
                return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) );
        },

        _ui: function( tab, panel ) {
                return {
                        tab: tab,
                        panel: panel,
                        index: this.anchors.index( tab )
                };
        },

        _cleanup: function() {
                // restore all former loading tabs labels
                this.lis.filter( ".ui-state-processing" )
                        .removeClass( "ui-state-processing" )
                        .find( "span:data(label.tabs)" )
                                .each(function() {
                                        var el = $( this );
                                        el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" );
                                });
        },

        _tabify: function( init ) {
                var self = this,
                        o = this.options,
                        fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash

                this.list = this.element.find( "ol,ul" ).eq( 0 );
                this.lis = $( " > li:has(a[href])", this.list );
                this.anchors = this.lis.map(function() {
                        return $( "a", this )[ 0 ];
                });
                this.panels = $( [] );

                this.anchors.each(function( i, a ) {
                        var href = $( a ).attr( "href" );
                        // For dynamically created HTML that contains a hash as href IE < 8 expands
                        // such href to the full page url with hash and then misinterprets tab as ajax.
                        // Same consideration applies for an added tab with a fragment identifier
                        // since a[href=#fragment-identifier] does unexpectedly not match.
                        // Thus normalize href attribute...
                        var hrefBase = href.split( "#" )[ 0 ],
                                baseEl;
                        if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] ||
                                        ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) {
                                href = a.hash;
                                a.href = href;
                        }

                        // inline tab
                        if ( fragmentId.test( href ) ) {
                                self.panels = self.panels.add( self._sanitizeSelector( href ) );
                        // remote tab
                        // prevent loading the page itself if href is just "#"
                        } else if ( href && href !== "#" ) {
                                // required for restore on destroy
                                $.data( a, "href.tabs", href );

                                // TODO until #3808 is fixed strip fragment identifier from url
                                // (IE fails to load from such url)
                                $.data( a, "load.tabs", href.replace( /#.*$/, "" ) );

                                var id = self._tabId( a );
                                a.href = "#" + id;
                                var $panel = $( "#" + id );
                                if ( !$panel.length ) {
                                        $panel = $( o.panelTemplate )
                                                .attr( "id", id )
                                                .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
                                                .insertAfter( self.panels[ i - 1 ] || self.list );
                                        $panel.data( "destroy.tabs", true );
                                }
                                self.panels = self.panels.add( $panel );
                        // invalid tab href
                        } else {
                                o.disabled.push( i );
                        }
                });

                // initialization from scratch
                if ( init ) {
                        // attach necessary classes for styling
                        this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" );
                        this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
                        this.lis.addClass( "ui-state-default ui-corner-top" );
                        this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" );

                        // Selected tab
                        // use "selected" option or try to retrieve:
                        // 1. from fragment identifier in url
                        // 2. from cookie
                        // 3. from selected class attribute on <li>
                        if ( o.selected === undefined ) {
                                if ( location.hash ) {
                                        this.anchors.each(function( i, a ) {
                                                if ( a.hash == location.hash ) {
                                                        o.selected = i;
                                                        return false;
                                                }
                                        });
                                }
                                if ( typeof o.selected !== "number" && o.cookie ) {
                                        o.selected = parseInt( self._cookie(), 10 );
                                }
                                if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) {
                                        o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
                                }
                                o.selected = o.selected || ( this.lis.length ? 0 : -1 );
                        } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release
                                o.selected = -1;
                        }

                        // sanity check - default to first tab...
                        o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 )
                                ? o.selected
                                : 0;

                        // Take disabling tabs via class attribute from HTML
                        // into account and update option properly.
                        // A selected tab cannot become disabled.
                        o.disabled = $.unique( o.disabled.concat(
                                $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) {
                                        return self.lis.index( n );
                                })
                        ) ).sort();

                        if ( $.inArray( o.selected, o.disabled ) != -1 ) {
                                o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 );
                        }

                        // highlight selected tab
                        this.panels.addClass( "ui-tabs-hide" );
                        this.lis.removeClass( "ui-tabs-selected ui-state-active" );
                        // check for length avoids error when initializing empty list
                        if ( o.selected >= 0 && this.anchors.length ) {
                                this.panels.eq( o.selected ).removeClass( "ui-tabs-hide" );
                                this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" );

                                // seems to be expected behavior that the show callback is fired
                                self.element.queue( "tabs", function() {
                                        self._trigger( "show", null,
                                                self._ui( self.anchors[ o.selected ], self.panels[ o.selected ] ) );
                                });

                                this.load( o.selected );
                        }

                        // clean up to avoid memory leaks in certain versions of IE 6
                        // TODO: namespace this event
                        $( window ).bind( "unload", function() {
                                self.lis.add( self.anchors ).unbind( ".tabs" );
                                self.lis = self.anchors = self.panels = null;
                        });
                // update selected after add/remove
                } else {
                        o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
                }

                // update collapsible
                // TODO: use .toggleClass()
                this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" );

                // set or update cookie after init and add/remove respectively
                if ( o.cookie ) {
                        this._cookie( o.selected, o.cookie );
                }

                // disable tabs
                for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
                        $( li )[ $.inArray( i, o.disabled ) != -1 &&
                                // TODO: use .toggleClass()
                                !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" );
                }

                // reset cache if switching from cached to not cached
                if ( o.cache === false ) {
                        this.anchors.removeData( "cache.tabs" );
                }

                // remove all handlers before, tabify may run on existing tabs after add or option change
                this.lis.add( this.anchors ).unbind( ".tabs" );

                if ( o.event !== "mouseover" ) {
                        var addState = function( state, el ) {
                                if ( el.is( ":not(.ui-state-disabled)" ) ) {
                                        el.addClass( "ui-state-" + state );
                                }
                        };
                        var removeState = function( state, el ) {
                                el.removeClass( "ui-state-" + state );
                        };
                        this.lis.bind( "mouseover.tabs" , function() {
                                addState( "hover", $( this ) );
                        });
                        this.lis.bind( "mouseout.tabs", function() {
                                removeState( "hover", $( this ) );
                        });
                        this.anchors.bind( "focus.tabs", function() {
                                addState( "focus", $( this ).closest( "li" ) );
                        });
                        this.anchors.bind( "blur.tabs", function() {
                                removeState( "focus", $( this ).closest( "li" ) );
                        });
                }

                // set up animations
                var hideFx, showFx;
                if ( o.fx ) {
                        if ( $.isArray( o.fx ) ) {
                                hideFx = o.fx[ 0 ];
                                showFx = o.fx[ 1 ];
                        } else {
                                hideFx = showFx = o.fx;
                        }
                }

                // Reset certain styles left over from animation
                // and prevent IE's ClearType bug...
                function resetStyle( $el, fx ) {
                        $el.css( "display", "" );
                        if ( !$.support.opacity && fx.opacity ) {
                                $el[ 0 ].style.removeAttribute( "filter" );
                        }
                }

                // Show a tab...
                var showTab = showFx
                        ? function( clicked, $show ) {
                                $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
                                $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way
                                        .animate( showFx, showFx.duration || "normal", function() {
                                                resetStyle( $show, showFx );
                                                self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
                                        });
                        }
                        : function( clicked, $show ) {
                                $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
                                $show.removeClass( "ui-tabs-hide" );
                                self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
                        };

                // Hide a tab, $show is optional...
                var hideTab = hideFx
                        ? function( clicked, $hide ) {
                                $hide.animate( hideFx, hideFx.duration || "normal", function() {
                                        self.lis.removeClass( "ui-tabs-selected ui-state-active" );
                                        $hide.addClass( "ui-tabs-hide" );
                                        resetStyle( $hide, hideFx );
                                        self.element.dequeue( "tabs" );
                                });
                        }
                        : function( clicked, $hide, $show ) {
                                self.lis.removeClass( "ui-tabs-selected ui-state-active" );
                                $hide.addClass( "ui-tabs-hide" );
                                self.element.dequeue( "tabs" );
                        };

                // attach tab event handler, unbind to avoid duplicates from former tabifying...
                this.anchors.bind( o.event + ".tabs", function() {
                        var el = this,
                                $li = $(el).closest( "li" ),
                                $hide = self.panels.filter( ":not(.ui-tabs-hide)" ),
                                $show = $( self._sanitizeSelector( el.hash ) );

                        // If tab is already selected and not collapsible or tab disabled or
                        // or is already loading or click callback returns false stop here.
                        // Check if click handler returns false last so that it is not executed
                        // for a disabled or loading tab!
                        if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) ||
                                $li.hasClass( "ui-state-disabled" ) ||
                                $li.hasClass( "ui-state-processing" ) ||
                                self.panels.filter( ":animated" ).length ||
                                self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) {
                                this.blur();
                                return false;
                        }

                        o.selected = self.anchors.index( this );

                        self.abort();

                        // if tab may be closed
                        if ( o.collapsible ) {
                                if ( $li.hasClass( "ui-tabs-selected" ) ) {
                                        o.selected = -1;

                                        if ( o.cookie ) {
                                                self._cookie( o.selected, o.cookie );
                                        }

                                        self.element.queue( "tabs", function() {
                                                hideTab( el, $hide );
                                        }).dequeue( "tabs" );

                                        this.blur();
                                        return false;
                                } else if ( !$hide.length ) {
                                        if ( o.cookie ) {
                                                self._cookie( o.selected, o.cookie );
                                        }

                                        self.element.queue( "tabs", function() {
                                                showTab( el, $show );
                                        });

                                        // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
                                        self.load( self.anchors.index( this ) );

                                        this.blur();
                                        return false;
                                }
                        }

                        if ( o.cookie ) {
                                self._cookie( o.selected, o.cookie );
                        }

                        // show new tab
                        if ( $show.length ) {
                                if ( $hide.length ) {
                                        self.element.queue( "tabs", function() {
                                                hideTab( el, $hide );
                                        });
                                }
                                self.element.queue( "tabs", function() {
                                        showTab( el, $show );
                                });

                                self.load( self.anchors.index( this ) );
                        } else {
                                throw "jQuery UI Tabs: Mismatching fragment identifier.";
                        }

                        // Prevent IE from keeping other link focussed when using the back button
                        // and remove dotted border from clicked link. This is controlled via CSS
                        // in modern browsers; blur() removes focus from address bar in Firefox
                        // which can become a usability and annoying problem with tabs('rotate').
                        if ( $.browser.msie ) {
                                this.blur();
                        }
                });

                // disable click in any case
                this.anchors.bind( "click.tabs", function(){
                        return false;
                });
        },

    _getIndex: function( index ) {
                // meta-function to give users option to provide a href string instead of a numerical index.
                // also sanitizes numerical indexes to valid values.
                if ( typeof index == "string" ) {
                        index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) );
                }

                return index;
        },

        destroy: function() {
                var o = this.options;

                this.abort();

                this.element
                        .unbind( ".tabs" )
                        .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" )
                        .removeData( "tabs" );

                this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );

                this.anchors.each(function() {
                        var href = $.data( this, "href.tabs" );
                        if ( href ) {
                                this.href = href;
                        }
                        var $this = $( this ).unbind( ".tabs" );
                        $.each( [ "href", "load", "cache" ], function( i, prefix ) {
                                $this.removeData( prefix + ".tabs" );
                        });
                });

                this.lis.unbind( ".tabs" ).add( this.panels ).each(function() {
                        if ( $.data( this, "destroy.tabs" ) ) {
                                $( this ).remove();
                        } else {
                                $( this ).removeClass([
                                        "ui-state-default",
                                        "ui-corner-top",
                                        "ui-tabs-selected",
                                        "ui-state-active",
                                        "ui-state-hover",
                                        "ui-state-focus",
                                        "ui-state-disabled",
                                        "ui-tabs-panel",
                                        "ui-widget-content",
                                        "ui-corner-bottom",
                                        "ui-tabs-hide"
                                ].join( " " ) );
                        }
                });

                if ( o.cookie ) {
                        this._cookie( null, o.cookie );
                }

                return this;
        },

        add: function( url, label, index ) {
                if ( index === undefined ) {
                        index = this.anchors.length;
                }

                var self = this,
                        o = this.options,
                        $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ),
                        id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] );

                $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );

                // try to find an existing element before creating a new one
                var $panel = $( "#" + id );
                if ( !$panel.length ) {
                        $panel = $( o.panelTemplate )
                                .attr( "id", id )
                                .data( "destroy.tabs", true );
                }
                $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" );

                if ( index >= this.lis.length ) {
                        $li.appendTo( this.list );
                        $panel.appendTo( this.list[ 0 ].parentNode );
                } else {
                        $li.insertBefore( this.lis[ index ] );
                        $panel.insertBefore( this.panels[ index ] );
                }

                o.disabled = $.map( o.disabled, function( n, i ) {
                        return n >= index ? ++n : n;
                });

                this._tabify();

                if ( this.anchors.length == 1 ) {
                        o.selected = 0;
                        $li.addClass( "ui-tabs-selected ui-state-active" );
                        $panel.removeClass( "ui-tabs-hide" );
                        this.element.queue( "tabs", function() {
                                self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) );
                        });

                        this.load( 0 );
                }

                this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
                return this;
        },

        remove: function( index ) {
                index = this._getIndex( index );
                var o = this.options,
                        $li = this.lis.eq( index ).remove(),
                        $panel = this.panels.eq( index ).remove();

                // If selected tab was removed focus tab to the right or
                // in case the last tab was removed the tab to the left.
                if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
                        this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
                }

                o.disabled = $.map(
                        $.grep( o.disabled, function(n, i) {
                                return n != index;
                        }),
                        function( n, i ) {
                                return n >= index ? --n : n;
                        });

                this._tabify();

                this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
                return this;
        },

        enable: function( index ) {
                index = this._getIndex( index );
                var o = this.options;
                if ( $.inArray( index, o.disabled ) == -1 ) {
                        return;
                }

                this.lis.eq( index ).removeClass( "ui-state-disabled" );
                o.disabled = $.grep( o.disabled, function( n, i ) {
                        return n != index;
                });

                this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
                return this;
        },

        disable: function( index ) {
                index = this._getIndex( index );
                var self = this, o = this.options;
                // cannot disable already selected tab
                if ( index != o.selected ) {
                        this.lis.eq( index ).addClass( "ui-state-disabled" );

                        o.disabled.push( index );
                        o.disabled.sort();

                        this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
                }

                return this;
        },

        select: function( index ) {
                index = this._getIndex( index );
                if ( index == -1 ) {
                        if ( this.options.collapsible && this.options.selected != -1 ) {
                                index = this.options.selected;
                        } else {
                                return this;
                        }
                }
                this.anchors.eq( index ).trigger( this.options.event + ".tabs" );
                return this;
        },

        load: function( index ) {
                index = this._getIndex( index );
                var self = this,
                        o = this.options,
                        a = this.anchors.eq( index )[ 0 ],
                        url = $.data( a, "load.tabs" );

                this.abort();

                // not remote or from cache
                if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) {
                        this.element.dequeue( "tabs" );
                        return;
                }

                // load remote from here on
                this.lis.eq( index ).addClass( "ui-state-processing" );

                if ( o.spinner ) {
                        var span = $( "span", a );
                        span.data( "label.tabs", span.html() ).html( o.spinner );
                }

                this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, {
                        url: url,
                        success: function( r, s ) {
                                $( self._sanitizeSelector( a.hash ) ).html( r );

                                // take care of tab labels
                                self._cleanup();

                                if ( o.cache ) {
                                        $.data( a, "cache.tabs", true );
                                }

                                self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
                                try {
                                        o.ajaxOptions.success( r, s );
                                }
                                catch ( e ) {}
                        },
                        error: function( xhr, s, e ) {
                                // take care of tab labels
                                self._cleanup();

                                self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
                                try {
                                        // Passing index avoid a race condition when this method is
                                        // called after the user has selected another tab.
                                        // Pass the anchor that initiated this request allows
                                        // loadError to manipulate the tab content panel via $(a.hash)
                                        o.ajaxOptions.error( xhr, s, index, a );
                                }
                                catch ( e ) {}
                        }
                } ) );

                // last, so that load event is fired before show...
                self.element.dequeue( "tabs" );

                return this;
        },

        abort: function() {
                // stop possibly running animations
                this.element.queue( [] );
                this.panels.stop( false, true );

                // "tabs" queue must not contain more than two elements,
                // which are the callbacks for the latest clicked tab...
                this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) );

                // terminate pending requests from other tabs
                if ( this.xhr ) {
                        this.xhr.abort();
                        delete this.xhr;
                }

                // take care of tab labels
                this._cleanup();
                return this;
        },

        url: function( index, url ) {
                this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url );
                return this;
        },

        length: function() {
                return this.anchors.length;
        }
});

$.extend( $.ui.tabs, {
        version: "1.8.5"
});

/*
 * Tabs Extensions
 */

/*
 * Rotate
 */
$.extend( $.ui.tabs.prototype, {
        rotation: null,
        rotate: function( ms, continuing ) {
                var self = this,
                        o = this.options;

                var rotate = self._rotate || ( self._rotate = function( e ) {
                        clearTimeout( self.rotation );
                        self.rotation = setTimeout(function() {
                                var t = o.selected;
                                self.select( ++t < self.anchors.length ? t : 0 );
                        }, ms );
                        
                        if ( e ) {
                                e.stopPropagation();
                        }
                });

                var stop = self._unrotate || ( self._unrotate = !continuing
                        ? function(e) {
                                if (e.clientX) { // in case of a true click
                                        self.rotate(null);
                                }
                        }
                        : function( e ) {
                                t = o.selected;
                                rotate();
                        });

                // start rotation
                if ( ms ) {
                        this.element.bind( "tabsshow", rotate );
                        this.anchors.bind( o.event + ".tabs", stop );
                        rotate();
                // stop rotation
                } else {
                        clearTimeout( self.rotation );
                        this.element.unbind( "tabsshow", rotate );
                        this.anchors.unbind( o.event + ".tabs", stop );
                        delete this._rotate;
                        delete this._unrotate;
                }

                return this;
        }
});

})( jQuery );