source: trunk/themes/default/js/ui/jquery.ui.accordion.js @ 18630

Last change on this file since 18630 was 18630, checked in by rvelices, 12 years ago

feature 2771: upgrade jquery from 1.7.2 to 1.8.2 and jquery.ui from 1.8.16 to 1.9.0
Attention plugins: jquery ui effect script ids change when using combine_script because file names changed ...

File size: 18.8 KB
Line 
1/*!
2 * jQuery UI Accordion 1.9.0
3 * http://jqueryui.com
4 *
5 * Copyright 2012 jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
8 *
9 * http://api.jqueryui.com/accordion/
10 *
11 * Depends:
12 *      jquery.ui.core.js
13 *      jquery.ui.widget.js
14 */
15(function( $, undefined ) {
16
17var uid = 0,
18        hideProps = {},
19        showProps = {};
20
21hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
22        hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
23showProps.height = showProps.paddingTop = showProps.paddingBottom =
24        showProps.borderTopWidth = showProps.borderBottomWidth = "show";
25
26$.widget( "ui.accordion", {
27        version: "1.9.0",
28        options: {
29                active: 0,
30                animate: {},
31                collapsible: false,
32                event: "click",
33                header: "> li > :first-child,> :not(li):even",
34                heightStyle: "auto",
35                icons: {
36                        activeHeader: "ui-icon-triangle-1-s",
37                        header: "ui-icon-triangle-1-e"
38                },
39
40                // callbacks
41                activate: null,
42                beforeActivate: null
43        },
44
45        _create: function() {
46                var accordionId = this.accordionId = "ui-accordion-" +
47                                (this.element.attr( "id" ) || ++uid),
48                        options = this.options;
49
50                this.prevShow = this.prevHide = $();
51                this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );
52
53                this.headers = this.element.find( options.header )
54                        .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
55                this._hoverable( this.headers );
56                this._focusable( this.headers );
57
58                this.headers.next()
59                        .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
60                        .hide();
61
62                // don't allow collapsible: false and active: false
63                if ( !options.collapsible && options.active === false ) {
64                        options.active = 0;
65                }
66                // handle negative values
67                if ( options.active < 0 ) {
68                        options.active += this.headers.length;
69                }
70                this.active = this._findActive( options.active )
71                        .addClass( "ui-accordion-header-active ui-state-active" )
72                        .toggleClass( "ui-corner-all ui-corner-top" );
73                this.active.next()
74                        .addClass( "ui-accordion-content-active" )
75                        .show();
76
77                this._createIcons();
78                this.originalHeight = this.element[0].style.height;
79                this.refresh();
80
81                // ARIA
82                this.element.attr( "role", "tablist" );
83
84                this.headers
85                        .attr( "role", "tab" )
86                        .each(function( i ) {
87                                var header = $( this ),
88                                        headerId = header.attr( "id" ),
89                                        panel = header.next(),
90                                        panelId = panel.attr( "id" );
91                                if ( !headerId ) {
92                                        headerId = accordionId + "-header-" + i;
93                                        header.attr( "id", headerId );
94                                }
95                                if ( !panelId ) {
96                                        panelId = accordionId + "-panel-" + i;
97                                        panel.attr( "id", panelId );
98                                }
99                                header.attr( "aria-controls", panelId );
100                                panel.attr( "aria-labelledby", headerId );
101                        })
102                        .next()
103                                .attr( "role", "tabpanel" );
104
105                this.headers
106                        .not( this.active )
107                        .attr({
108                                "aria-selected": "false",
109                                tabIndex: -1
110                        })
111                        .next()
112                                .attr({
113                                        "aria-expanded": "false",
114                                        "aria-hidden": "true"
115                                })
116                                .hide();
117
118                // make sure at least one header is in the tab order
119                if ( !this.active.length ) {
120                        this.headers.eq( 0 ).attr( "tabIndex", 0 );
121                } else {
122                        this.active.attr({
123                                "aria-selected": "true",
124                                tabIndex: 0
125                        })
126                        .next()
127                                .attr({
128                                        "aria-expanded": "true",
129                                        "aria-hidden": "false"
130                                });
131                }
132
133                this._on( this.headers, { keydown: "_keydown" });
134                this._on( this.headers.next(), { keydown: "_panelKeyDown" });
135                this._setupEvents( options.event );
136        },
137
138        _getCreateEventData: function() {
139                return {
140                        header: this.active,
141                        content: !this.active.length ? $() : this.active.next()
142                };
143        },
144
145        _createIcons: function() {
146                var icons = this.options.icons;
147                if ( icons ) {
148                        $( "<span>" )
149                                .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
150                                .prependTo( this.headers );
151                        this.active.children( ".ui-accordion-header-icon" )
152                                .removeClass( icons.header )
153                                .addClass( icons.activeHeader );
154                        this.headers.addClass( "ui-accordion-icons" );
155                }
156        },
157
158        _destroyIcons: function() {
159                this.headers
160                        .removeClass( "ui-accordion-icons" )
161                        .children( ".ui-accordion-header-icon" )
162                                .remove();
163        },
164
165        _destroy: function() {
166                var contents;
167
168                // clean up main element
169                this.element
170                        .removeClass( "ui-accordion ui-widget ui-helper-reset" )
171                        .removeAttr( "role" );
172
173                // clean up headers
174                this.headers
175                        .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
176                        .removeAttr( "role" )
177                        .removeAttr( "aria-selected" )
178                        .removeAttr( "aria-controls" )
179                        .removeAttr( "tabIndex" )
180                        .each(function() {
181                                if ( /^ui-accordion/.test( this.id ) ) {
182                                        this.removeAttribute( "id" );
183                                }
184                        });
185                this._destroyIcons();
186
187                // clean up content panels
188                contents = this.headers.next()
189                        .css( "display", "" )
190                        .removeAttr( "role" )
191                        .removeAttr( "aria-expanded" )
192                        .removeAttr( "aria-hidden" )
193                        .removeAttr( "aria-labelledby" )
194                        .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
195                        .each(function() {
196                                if ( /^ui-accordion/.test( this.id ) ) {
197                                        this.removeAttribute( "id" );
198                                }
199                        });
200                if ( this.options.heightStyle !== "content" ) {
201                        this.element.css( "height", this.originalHeight );
202                        contents.css( "height", "" );
203                }
204        },
205
206        _setOption: function( key, value ) {
207                if ( key === "active" ) {
208                        // _activate() will handle invalid values and update this.options
209                        this._activate( value );
210                        return;
211                }
212
213                if ( key === "event" ) {
214                        if ( this.options.event ) {
215                                this._off( this.headers, this.options.event );
216                        }
217                        this._setupEvents( value );
218                }
219
220                this._super( key, value );
221
222                // setting collapsible: false while collapsed; open first panel
223                if ( key === "collapsible" && !value && this.options.active === false ) {
224                        this._activate( 0 );
225                }
226
227                if ( key === "icons" ) {
228                        this._destroyIcons();
229                        if ( value ) {
230                                this._createIcons();
231                        }
232                }
233
234                // #5332 - opacity doesn't cascade to positioned elements in IE
235                // so we need to add the disabled class to the headers and panels
236                if ( key === "disabled" ) {
237                        this.headers.add( this.headers.next() )
238                                .toggleClass( "ui-state-disabled", !!value );
239                }
240        },
241
242        _keydown: function( event ) {
243                if ( event.altKey || event.ctrlKey ) {
244                        return;
245                }
246
247                var keyCode = $.ui.keyCode,
248                        length = this.headers.length,
249                        currentIndex = this.headers.index( event.target ),
250                        toFocus = false;
251
252                switch ( event.keyCode ) {
253                        case keyCode.RIGHT:
254                        case keyCode.DOWN:
255                                toFocus = this.headers[ ( currentIndex + 1 ) % length ];
256                                break;
257                        case keyCode.LEFT:
258                        case keyCode.UP:
259                                toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
260                                break;
261                        case keyCode.SPACE:
262                        case keyCode.ENTER:
263                                this._eventHandler( event );
264                                break;
265                        case keyCode.HOME:
266                                toFocus = this.headers[ 0 ];
267                                break;
268                        case keyCode.END:
269                                toFocus = this.headers[ length - 1 ];
270                                break;
271                }
272
273                if ( toFocus ) {
274                        $( event.target ).attr( "tabIndex", -1 );
275                        $( toFocus ).attr( "tabIndex", 0 );
276                        toFocus.focus();
277                        event.preventDefault();
278                }
279        },
280
281        _panelKeyDown : function( event ) {
282                if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
283                        $( event.currentTarget ).prev().focus();
284                }
285        },
286
287        refresh: function() {
288                var maxHeight, overflow,
289                        heightStyle = this.options.heightStyle,
290                        parent = this.element.parent();
291
292                this.element.css( "height", this.originalHeight );
293
294                if ( heightStyle === "fill" ) {
295                        // IE 6 treats height like minHeight, so we need to turn off overflow
296                        // in order to get a reliable height
297                        // we use the minHeight support test because we assume that only
298                        // browsers that don't support minHeight will treat height as minHeight
299                        if ( !$.support.minHeight ) {
300                                overflow = parent.css( "overflow" );
301                                parent.css( "overflow", "hidden");
302                        }
303                        maxHeight = parent.height();
304                        this.element.siblings( ":visible" ).each(function() {
305                                var elem = $( this ),
306                                        position = elem.css( "position" );
307
308                                if ( position === "absolute" || position === "fixed" ) {
309                                        return;
310                                }
311                                maxHeight -= elem.outerHeight( true );
312                        });
313                        if ( overflow ) {
314                                parent.css( "overflow", overflow );
315                        }
316
317                        this.headers.each(function() {
318                                maxHeight -= $( this ).outerHeight( true );
319                        });
320
321                        this.headers.next()
322                                .each(function() {
323                                        $( this ).height( Math.max( 0, maxHeight -
324                                                $( this ).innerHeight() + $( this ).height() ) );
325                                })
326                                .css( "overflow", "auto" );
327                } else if ( heightStyle === "auto" ) {
328                        maxHeight = 0;
329                        this.headers.next()
330                                .each(function() {
331                                        maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
332                                })
333                                .height( maxHeight );
334                }
335
336                if ( heightStyle !== "content" ) {
337                        this.element.height( this.element.height() );
338                }
339        },
340
341        _activate: function( index ) {
342                var active = this._findActive( index )[ 0 ];
343
344                // trying to activate the already active panel
345                if ( active === this.active[ 0 ] ) {
346                        return;
347                }
348
349                // trying to collapse, simulate a click on the currently active header
350                active = active || this.active[ 0 ];
351
352                this._eventHandler({
353                        target: active,
354                        currentTarget: active,
355                        preventDefault: $.noop
356                });
357        },
358
359        _findActive: function( selector ) {
360                return typeof selector === "number" ? this.headers.eq( selector ) : $();
361        },
362
363        _setupEvents: function( event ) {
364                var events = {};
365                if ( !event ) {
366                        return;
367                }
368                $.each( event.split(" "), function( index, eventName ) {
369                        events[ eventName ] = "_eventHandler";
370                });
371                this._on( this.headers, events );
372        },
373
374        _eventHandler: function( event ) {
375                var options = this.options,
376                        active = this.active,
377                        clicked = $( event.currentTarget ),
378                        clickedIsActive = clicked[ 0 ] === active[ 0 ],
379                        collapsing = clickedIsActive && options.collapsible,
380                        toShow = collapsing ? $() : clicked.next(),
381                        toHide = active.next(),
382                        eventData = {
383                                oldHeader: active,
384                                oldPanel: toHide,
385                                newHeader: collapsing ? $() : clicked,
386                                newPanel: toShow
387                        };
388
389                event.preventDefault();
390
391                if (
392                                // click on active header, but not collapsible
393                                ( clickedIsActive && !options.collapsible ) ||
394                                // allow canceling activation
395                                ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
396                        return;
397                }
398
399                options.active = collapsing ? false : this.headers.index( clicked );
400
401                // when the call to ._toggle() comes after the class changes
402                // it causes a very odd bug in IE 8 (see #6720)
403                this.active = clickedIsActive ? $() : clicked;
404                this._toggle( eventData );
405
406                // switch classes
407                // corner classes on the previously active header stay after the animation
408                active.removeClass( "ui-accordion-header-active ui-state-active" );
409                if ( options.icons ) {
410                        active.children( ".ui-accordion-header-icon" )
411                                .removeClass( options.icons.activeHeader )
412                                .addClass( options.icons.header );
413                }
414
415                if ( !clickedIsActive ) {
416                        clicked
417                                .removeClass( "ui-corner-all" )
418                                .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
419                        if ( options.icons ) {
420                                clicked.children( ".ui-accordion-header-icon" )
421                                        .removeClass( options.icons.header )
422                                        .addClass( options.icons.activeHeader );
423                        }
424
425                        clicked
426                                .next()
427                                .addClass( "ui-accordion-content-active" );
428                }
429        },
430
431        _toggle: function( data ) {
432                var toShow = data.newPanel,
433                        toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
434
435                // handle activating a panel during the animation for another activation
436                this.prevShow.add( this.prevHide ).stop( true, true );
437                this.prevShow = toShow;
438                this.prevHide = toHide;
439
440                if ( this.options.animate ) {
441                        this._animate( toShow, toHide, data );
442                } else {
443                        toHide.hide();
444                        toShow.show();
445                        this._toggleComplete( data );
446                }
447
448                toHide.attr({
449                        "aria-expanded": "false",
450                        "aria-hidden": "true"
451                });
452                toHide.prev().attr( "aria-selected", "false" );
453                // if we're switching panels, remove the old header from the tab order
454                // if we're opening from collapsed state, remove the previous header from the tab order
455                // if we're collapsing, then keep the collapsing header in the tab order
456                if ( toShow.length && toHide.length ) {
457                        toHide.prev().attr( "tabIndex", -1 );
458                } else if ( toShow.length ) {
459                        this.headers.filter(function() {
460                                return $( this ).attr( "tabIndex" ) === 0;
461                        })
462                        .attr( "tabIndex", -1 );
463                }
464
465                toShow
466                        .attr({
467                                "aria-expanded": "true",
468                                "aria-hidden": "false"
469                        })
470                        .prev()
471                                .attr({
472                                        "aria-selected": "true",
473                                        tabIndex: 0
474                                });
475        },
476
477        _animate: function( toShow, toHide, data ) {
478                var total, easing, duration,
479                        that = this,
480                        adjust = 0,
481                        down = toShow.length &&
482                                ( !toHide.length || ( toShow.index() < toHide.index() ) ),
483                        animate = this.options.animate || {},
484                        options = down && animate.down || animate,
485                        complete = function() {
486                                that._toggleComplete( data );
487                        };
488
489                if ( typeof options === "number" ) {
490                        duration = options;
491                }
492                if ( typeof options === "string" ) {
493                        easing = options;
494                }
495                // fall back from options to animation in case of partial down settings
496                easing = easing || options.easing || animate.easing;
497                duration = duration || options.duration || animate.duration;
498
499                if ( !toHide.length ) {
500                        return toShow.animate( showProps, duration, easing, complete );
501                }
502                if ( !toShow.length ) {
503                        return toHide.animate( hideProps, duration, easing, complete );
504                }
505
506                total = toShow.show().outerHeight();
507                toHide.animate( hideProps, {
508                        duration: duration,
509                        easing: easing,
510                        step: function( now, fx ) {
511                                fx.now = Math.round( now );
512                        }
513                });
514                toShow
515                        .hide()
516                        .animate( showProps, {
517                                duration: duration,
518                                easing: easing,
519                                complete: complete,
520                                step: function( now, fx ) {
521                                        fx.now = Math.round( now );
522                                        if ( fx.prop !== "height" ) {
523                                                adjust += fx.now;
524                                        } else if ( that.options.heightStyle !== "content" ) {
525                                                fx.now = Math.round( total - toHide.outerHeight() - adjust );
526                                                adjust = 0;
527                                        }
528                                }
529                        });
530        },
531
532        _toggleComplete: function( data ) {
533                var toHide = data.oldPanel;
534
535                toHide
536                        .removeClass( "ui-accordion-content-active" )
537                        .prev()
538                                .removeClass( "ui-corner-top" )
539                                .addClass( "ui-corner-all" );
540
541                // Work around for rendering bug in IE (#5421)
542                if ( toHide.length ) {
543                        toHide.parent()[0].className = toHide.parent()[0].className;
544                }
545
546                this._trigger( "activate", null, data );
547        }
548});
549
550
551
552// DEPRECATED
553if ( $.uiBackCompat !== false ) {
554        // navigation options
555        (function( $, prototype ) {
556                $.extend( prototype.options, {
557                        navigation: false,
558                        navigationFilter: function() {
559                                return this.href.toLowerCase() === location.href.toLowerCase();
560                        }
561                });
562
563                var _create = prototype._create;
564                prototype._create = function() {
565                        if ( this.options.navigation ) {
566                                var that = this,
567                                        headers = this.element.find( this.options.header ),
568                                        content = headers.next(),
569                                        current = headers.add( content )
570                                                .find( "a" )
571                                                .filter( this.options.navigationFilter )
572                                                [ 0 ];
573                                if ( current ) {
574                                        headers.add( content ).each( function( index ) {
575                                                if ( $.contains( this, current ) ) {
576                                                        that.options.active = Math.floor( index / 2 );
577                                                        return false;
578                                                }
579                                        });
580                                }
581                        }
582                        _create.call( this );
583                };
584        }( jQuery, jQuery.ui.accordion.prototype ) );
585
586        // height options
587        (function( $, prototype ) {
588                $.extend( prototype.options, {
589                        heightStyle: null, // remove default so we fall back to old values
590                        autoHeight: true, // use heightStyle: "auto"
591                        clearStyle: false, // use heightStyle: "content"
592                        fillSpace: false // use heightStyle: "fill"
593                });
594
595                var _create = prototype._create,
596                        _setOption = prototype._setOption;
597
598                $.extend( prototype, {
599                        _create: function() {
600                                this.options.heightStyle = this.options.heightStyle ||
601                                        this._mergeHeightStyle();
602
603                                _create.call( this );
604                        },
605
606                        _setOption: function( key, value ) {
607                                if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) {
608                                        this.options.heightStyle = this._mergeHeightStyle();
609                                }
610                                _setOption.apply( this, arguments );
611                        },
612
613                        _mergeHeightStyle: function() {
614                                var options = this.options;
615
616                                if ( options.fillSpace ) {
617                                        return "fill";
618                                }
619
620                                if ( options.clearStyle ) {
621                                        return "content";
622                                }
623
624                                if ( options.autoHeight ) {
625                                        return "auto";
626                                }
627                        }
628                });
629        }( jQuery, jQuery.ui.accordion.prototype ) );
630
631        // icon options
632        (function( $, prototype ) {
633                $.extend( prototype.options.icons, {
634                        activeHeader: null, // remove default so we fall back to old values
635                        headerSelected: "ui-icon-triangle-1-s"
636                });
637
638                var _createIcons = prototype._createIcons;
639                prototype._createIcons = function() {
640                        if ( this.options.icons ) {
641                                this.options.icons.activeHeader = this.options.icons.activeHeader ||
642                                        this.options.icons.headerSelected;
643                        }
644                        _createIcons.call( this );
645                };
646        }( jQuery, jQuery.ui.accordion.prototype ) );
647
648        // expanded active option, activate method
649        (function( $, prototype ) {
650                prototype.activate = prototype._activate;
651
652                var _findActive = prototype._findActive;
653                prototype._findActive = function( index ) {
654                        if ( index === -1 ) {
655                                index = false;
656                        }
657                        if ( index && typeof index !== "number" ) {
658                                index = this.headers.index( this.headers.filter( index ) );
659                                if ( index === -1 ) {
660                                        index = false;
661                                }
662                        }
663                        return _findActive.call( this, index );
664                };
665        }( jQuery, jQuery.ui.accordion.prototype ) );
666
667        // resize method
668        jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh;
669
670        // change events
671        (function( $, prototype ) {
672                $.extend( prototype.options, {
673                        change: null,
674                        changestart: null
675                });
676
677                var _trigger = prototype._trigger;
678                prototype._trigger = function( type, event, data ) {
679                        var ret = _trigger.apply( this, arguments );
680                        if ( !ret ) {
681                                return false;
682                        }
683
684                        if ( type === "beforeActivate" ) {
685                                ret = _trigger.call( this, "changestart", event, {
686                                        oldHeader: data.oldHeader,
687                                        oldContent: data.oldPanel,
688                                        newHeader: data.newHeader,
689                                        newContent: data.newPanel
690                                });
691                        } else if ( type === "activate" ) {
692                                ret = _trigger.call( this, "change", event, {
693                                        oldHeader: data.oldHeader,
694                                        oldContent: data.oldPanel,
695                                        newHeader: data.newHeader,
696                                        newContent: data.newPanel
697                                });
698                        }
699                        return ret;
700                };
701        }( jQuery, jQuery.ui.accordion.prototype ) );
702
703        // animated option
704        // NOTE: this only provides support for "slide", "bounceslide", and easings
705        // not the full $.ui.accordion.animations API
706        (function( $, prototype ) {
707                $.extend( prototype.options, {
708                        animate: null,
709                        animated: "slide"
710                });
711
712                var _create = prototype._create;
713                prototype._create = function() {
714                        var options = this.options;
715                        if ( options.animate === null ) {
716                                if ( !options.animated ) {
717                                        options.animate = false;
718                                } else if ( options.animated === "slide" ) {
719                                        options.animate = 300;
720                                } else if ( options.animated === "bounceslide" ) {
721                                        options.animate = {
722                                                duration: 200,
723                                                down: {
724                                                        easing: "easeOutBounce",
725                                                        duration: 1000
726                                                }
727                                        };
728                                } else {
729                                        options.animate = options.animated;
730                                }
731                        }
732
733                        _create.call( this );
734                };
735        }( jQuery, jQuery.ui.accordion.prototype ) );
736}
737
738})( jQuery );
Note: See TracBrowser for help on using the repository browser.