source: trunk/template-common/lib/ui/ui.accordion.js @ 3282

Last change on this file since 3282 was 3282, checked in by plg, 15 years ago

change: according to topic:15067, svn:keywords property was removed

  • Property svn:eol-style set to LF
File size: 7.8 KB
Line 
1/*
2 * jQuery UI Accordion
3 *
4 * Copyright (c) 2007, 2008 Jörn Zaefferer
5 * Dual licensed under the MIT (MIT-LICENSE.txt)
6 * and GPL (GPL-LICENSE.txt) licenses.
7 *
8 * http://docs.jquery.com/UI/Accordion
9 *
10 * Depends:
11 *      ui.core.js
12 */
13(function($) {
14
15$.widget("ui.accordion", {
16        init: function() {
17                var options = this.options;
18               
19                if ( options.navigation ) {
20                        var current = this.element.find("a").filter(options.navigationFilter);
21                        if ( current.length ) {
22                                if ( current.filter(options.header).length ) {
23                                        options.active = current;
24                                } else {
25                                        options.active = current.parent().parent().prev();
26                                        current.addClass("current");
27                                }
28                        }
29                }
30               
31                // calculate active if not specified, using the first header
32                options.headers = this.element.find(options.header);
33                options.active = findActive(options.headers, options.active);
34               
35                // IE7-/Win - Extra vertical space in Lists fixed
36                if ($.browser.msie) {
37                        this.element.find('a').css('zoom', '1');
38                }
39               
40                if (!this.element.hasClass("ui-accordion")) {
41                        this.element.addClass("ui-accordion");
42                        $("<span class='ui-accordion-left'/>").insertBefore(options.headers);
43                        $("<span class='ui-accordion-right'/>").appendTo(options.headers);
44                        options.headers.addClass("ui-accordion-header").attr("tabindex", "0");
45                }
46               
47                var maxHeight;
48                if ( options.fillSpace ) {
49                        maxHeight = this.element.parent().height();
50                        options.headers.each(function() {
51                                maxHeight -= $(this).outerHeight();
52                        });
53                        var maxPadding = 0;
54                        options.headers.next().each(function() {
55                                maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
56                        }).height(maxHeight - maxPadding);
57                } else if ( options.autoHeight ) {
58                        maxHeight = 0;
59                        options.headers.next().each(function() {
60                                maxHeight = Math.max(maxHeight, $(this).outerHeight());
61                        }).height(maxHeight);
62                }
63       
64                options.headers
65                        .not(options.active || "")
66                        .next()
67                        .hide();
68                options.active.parent().andSelf().addClass(options.selectedClass);
69               
70                if (options.event) {
71                        this.element.bind((options.event) + ".accordion", clickHandler);
72                }
73        },
74        activate: function(index) {
75                // call clickHandler with custom event
76                clickHandler.call(this.element[0], {
77                        target: findActive( this.options.headers, index )[0]
78                });
79        },
80        destroy: function() {
81                this.options.headers.next().css("display", "");
82                if ( this.options.fillSpace || this.options.autoHeight ) {
83                        this.options.headers.next().css("height", "");
84                }
85                $.removeData(this.element[0], "accordion");
86                this.element.removeClass("ui-accordion").unbind(".accordion");
87        }
88});
89
90function scopeCallback(callback, scope) {
91        return function() {
92                return callback.apply(scope, arguments);
93        };
94};
95
96function completed(cancel) {
97        // if removed while animated data can be empty
98        if (!$.data(this, "accordion")) {
99                return;
100        }
101       
102        var instance = $.data(this, "accordion");
103        var options = instance.options;
104        options.running = cancel ? 0 : --options.running;
105        if ( options.running ) {
106                return;
107        }
108        if ( options.clearStyle ) {
109                options.toShow.add(options.toHide).css({
110                        height: "",
111                        overflow: ""
112                });
113        }
114        $(this).triggerHandler("accordionchange", [$.event.fix({type: 'accordionchange', target: instance.element[0]}), options.data], options.change);
115}
116
117function toggle(toShow, toHide, data, clickedActive, down) {
118        var options = $.data(this, "accordion").options;
119        options.toShow = toShow;
120        options.toHide = toHide;
121        options.data = data;
122        var complete = scopeCallback(completed, this);
123       
124        // count elements to animate
125        options.running = toHide.size() === 0 ? toShow.size() : toHide.size();
126       
127        if ( options.animated ) {
128                if ( !options.alwaysOpen && clickedActive ) {
129                        $.ui.accordion.animations[options.animated]({
130                                toShow: jQuery([]),
131                                toHide: toHide,
132                                complete: complete,
133                                down: down,
134                                autoHeight: options.autoHeight
135                        });
136                } else {
137                        $.ui.accordion.animations[options.animated]({
138                                toShow: toShow,
139                                toHide: toHide,
140                                complete: complete,
141                                down: down,
142                                autoHeight: options.autoHeight
143                        });
144                }
145        } else {
146                if ( !options.alwaysOpen && clickedActive ) {
147                        toShow.toggle();
148                } else {
149                        toHide.hide();
150                        toShow.show();
151                }
152                complete(true);
153        }
154}
155
156function clickHandler(event) {
157        var options = $.data(this, "accordion").options;
158        if (options.disabled) {
159                return false;
160        }
161       
162        // called only when using activate(false) to close all parts programmatically
163        if ( !event.target && !options.alwaysOpen ) {
164                options.active.parent().andSelf().toggleClass(options.selectedClass);
165                var toHide = options.active.next(),
166                        data = {
167                                options: options,
168                                newHeader: jQuery([]),
169                                oldHeader: options.active,
170                                newContent: jQuery([]),
171                                oldContent: toHide
172                        },
173                        toShow = (options.active = $([]));
174                toggle.call(this, toShow, toHide, data );
175                return false;
176        }
177        // get the click target
178        var clicked = $(event.target);
179       
180        // due to the event delegation model, we have to check if one
181        // of the parent elements is our actual header, and find that
182        // otherwise stick with the initial target
183        clicked = $( clicked.parents(options.header)[0] || clicked );
184       
185        var clickedActive = clicked[0] == options.active[0];
186       
187        // if animations are still active, or the active header is the target, ignore click
188        if (options.running || (options.alwaysOpen && clickedActive)) {
189                return false;
190        }
191        if (!clicked.is(options.header)) {
192                return;
193        }
194       
195        // switch classes
196        options.active.parent().andSelf().toggleClass(options.selectedClass);
197        if ( !clickedActive ) {
198                clicked.parent().andSelf().addClass(options.selectedClass);
199        }
200       
201        // find elements to show and hide
202        var toShow = clicked.next(),
203                toHide = options.active.next(),
204                //data = [clicked, options.active, toShow, toHide],
205                data = {
206                        options: options,
207                        newHeader: clicked,
208                        oldHeader: options.active,
209                        newContent: toShow,
210                        oldContent: toHide
211                },
212                down = options.headers.index( options.active[0] ) > options.headers.index( clicked[0] );
213       
214        options.active = clickedActive ? $([]) : clicked;
215        toggle.call(this, toShow, toHide, data, clickedActive, down );
216
217        return false;
218};
219
220function findActive(headers, selector) {
221        return selector != undefined
222                ? typeof selector == "number"
223                        ? headers.filter(":eq(" + selector + ")")
224                        : headers.not(headers.not(selector))
225                : selector === false
226                        ? $([])
227                        : headers.filter(":eq(0)");
228}
229
230$.extend($.ui.accordion, {
231        defaults: {
232                selectedClass: "selected",
233                alwaysOpen: true,
234                animated: 'slide',
235                event: "click",
236                header: "a",
237                autoHeight: true,
238                running: 0,
239                navigationFilter: function() {
240                        return this.href.toLowerCase() == location.href.toLowerCase();
241                }
242        },
243        animations: {
244                slide: function(options, additions) {
245                        options = $.extend({
246                                easing: "swing",
247                                duration: 300
248                        }, options, additions);
249                        if ( !options.toHide.size() ) {
250                                options.toShow.animate({height: "show"}, options);
251                                return;
252                        }
253                        var hideHeight = options.toHide.height(),
254                                showHeight = options.toShow.height(),
255                                difference = showHeight / hideHeight;
256                        options.toShow.css({ height: 0, overflow: 'hidden' }).show();
257                        options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate({height:"hide"},{
258                                step: function(now) {
259                                        var current = (hideHeight - now) * difference;
260                                        if ($.browser.msie || $.browser.opera) {
261                                                current = Math.ceil(current);
262                                        }
263                                        options.toShow.height( current );
264                                },
265                                duration: options.duration,
266                                easing: options.easing,
267                                complete: function() {
268                                        if ( !options.autoHeight ) {
269                                                options.toShow.css("height", "auto");
270                                        }
271                                        options.complete();
272                                }
273                        });
274                },
275                bounceslide: function(options) {
276                        this.slide(options, {
277                                easing: options.down ? "bounceout" : "swing",
278                                duration: options.down ? 1000 : 200
279                        });
280                },
281                easeslide: function(options) {
282                        this.slide(options, {
283                                easing: "easeinout",
284                                duration: 700
285                        });
286                }
287        }
288});
289
290// deprecated, use accordion("activate", index) instead
291$.fn.activate = function(index) {
292        return this.accordion("activate", index);
293};
294
295})(jQuery);
Note: See TracBrowser for help on using the repository browser.