5689e83244a6e3d1209324af261a5ef62f8c7f01
[atutor.git] / mods / photo_album / fluid / component-templates / js / jquery.ui-1.0 / ui.accordion.js
1 /*\r
2  * Accordion 1.5 - jQuery menu widget\r
3  *\r
4  * Copyright (c) 2007 Jörn Zaefferer, Frank Marcia\r
5  *\r
6  * http://bassistance.de/jquery-plugins/jquery-plugin-accordion/\r
7  *\r
8  * Dual licensed under the MIT and GPL licenses:\r
9  *   http://www.opensource.org/licenses/mit-license.php\r
10  *   http://www.gnu.org/licenses/gpl.html\r
11  *\r
12  * Revision: $Id: jquery.accordion.js 2951 2007-08-28 07:21:13Z joern.zaefferer $\r
13  *\r
14  */\r
15 \r
16 (function($) {\r
17 \r
18 $.ui = $.ui || {}\r
19 \r
20 $.ui.accordion = {};\r
21 $.extend($.ui.accordion, {\r
22         defaults: {\r
23                 selectedClass: "selected",\r
24                 alwaysOpen: true,\r
25                 animated: 'slide',\r
26                 event: "click",\r
27                 header: "a"\r
28         },\r
29         animations: {\r
30                 slide: function(settings, additions) {\r
31                         settings = $.extend({\r
32                                 easing: "swing",\r
33                                 duration: 300\r
34                         }, settings, additions);\r
35                         if ( !settings.toHide.size() ) {\r
36                                 settings.toShow.animate({height: "show"}, {\r
37                                         duration: settings.duration,\r
38                                         easing: settings.easing,\r
39                                         complete: settings.finished\r
40                                 });\r
41                                 return;\r
42                         }\r
43                         var hideHeight = settings.toHide.height(),\r
44                                 showHeight = settings.toShow.height(),\r
45                                 difference = showHeight / hideHeight;\r
46                         settings.toShow.css({ height: 0, overflow: 'hidden' }).show();\r
47                         settings.toHide.filter(":hidden").each(settings.finished).end().filter(":visible").animate({height:"hide"},{\r
48                                 step: function(n){\r
49                                         settings.toShow.height(Math.ceil( (hideHeight - (n)) * difference ));\r
50                                 },\r
51                                 duration: settings.duration,\r
52                                 easing: settings.easing,\r
53                                 complete: settings.finished\r
54                         });\r
55                 },\r
56                 bounceslide: function(settings) {\r
57                         this.slide(settings, {\r
58                                 easing: settings.down ? "bounceout" : "swing",\r
59                                 duration: settings.down ? 1000 : 200\r
60                         });\r
61                 },\r
62                 easeslide: function(settings) {\r
63                         this.slide(settings, {\r
64                                 easing: "easeinout",\r
65                                 duration: 700\r
66                         })\r
67                 }\r
68         }\r
69 });\r
70 \r
71 $.fn.extend({\r
72         nextUntil: function(expr) {\r
73             var match = [];\r
74         \r
75             // We need to figure out which elements to push onto the array\r
76             this.each(function(){\r
77                 // Traverse through the sibling nodes\r
78                 for( var i = this.nextSibling; i; i = i.nextSibling ) {\r
79                     // Make sure that we're only dealing with elements\r
80                     if ( i.nodeType != 1 ) continue;\r
81         \r
82                     // If we find a match then we need to stop\r
83                     if ( $.filter( expr, [i] ).r.length ) break;\r
84         \r
85                     // Otherwise, add it on to the stack\r
86                     match.push( i );\r
87                 }\r
88             });\r
89         \r
90             return this.pushStack( match );\r
91         },\r
92         // the plugin method itself\r
93         accordion: function(settings) {\r
94                 if ( !this.length )\r
95                         return this;\r
96         \r
97                 // setup configuration\r
98                 settings = $.extend({}, $.ui.accordion.defaults, settings);\r
99                 \r
100                 if ( settings.navigation ) {\r
101                         var current = this.find("a").filter(function() { return this.href == location.href; });\r
102                         if ( current.length ) {\r
103                                 if ( current.filter(settings.header).length ) {\r
104                                         settings.active = current;\r
105                                 } else {\r
106                                         settings.active = current.parent().parent().prev();\r
107                                         current.addClass("current");\r
108                                 }\r
109                         }\r
110                 }\r
111                 \r
112                 // calculate active if not specified, using the first header\r
113                 var container = this,\r
114                         headers = container.find(settings.header),\r
115                         active = findActive(settings.active),\r
116                         running = 0;\r
117 \r
118                 if ( settings.fillSpace ) {\r
119                         var maxHeight = this.parent().height();\r
120                         headers.each(function() {\r
121                                 maxHeight -= $(this).outerHeight();\r
122                         });\r
123                         var maxPadding = 0;\r
124                         headers.nextUntil(settings.header).each(function() {\r
125                                 maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());\r
126                         }).height(maxHeight - maxPadding);\r
127                 } else if ( settings.autoheight ) {\r
128                         var maxHeight = 0;\r
129                         headers.nextUntil(settings.header).each(function() {\r
130                                 maxHeight = Math.max(maxHeight, $(this).height());\r
131                         }).height(maxHeight);\r
132                 }\r
133 \r
134                 headers\r
135                         .not(active || "")\r
136                         .nextUntil(settings.header)\r
137                         .hide();\r
138                 active.parent().andSelf().addClass(settings.selectedClass);\r
139                 \r
140                 \r
141                 function findActive(selector) {\r
142                         return selector != undefined\r
143                                 ? typeof selector == "number"\r
144                                         ? headers.filter(":eq(" + selector + ")")\r
145                                         : headers.not(headers.not(selector))\r
146                                 : selector === false\r
147                                         ? $("<div>")\r
148                                         : headers.filter(":eq(0)");\r
149                 }\r
150                 \r
151                 function toggle(toShow, toHide, data, clickedActive, down) {\r
152                         var finished = function(cancel) {\r
153                                 running = cancel ? 0 : --running;\r
154                                 if ( running )\r
155                                         return;\r
156                                 // trigger custom change event\r
157                                 container.trigger("change", data);\r
158                         };\r
159                         \r
160                         // count elements to animate\r
161                         running = toHide.size() == 0 ? toShow.size() : toHide.size();\r
162                         \r
163                         if ( settings.animated ) {\r
164                                 if ( !settings.alwaysOpen && clickedActive ) {\r
165                                         toShow.slideToggle(settings.animated);\r
166                                         finished(true);\r
167                                 } else {\r
168                                         $.ui.accordion.animations[settings.animated]({\r
169                                                 toShow: toShow,\r
170                                                 toHide: toHide,\r
171                                                 finished: finished,\r
172                                                 down: down\r
173                                         });\r
174                                 }\r
175                         } else {\r
176                                 if ( !settings.alwaysOpen && clickedActive ) {\r
177                                         toShow.toggle();\r
178                                 } else {\r
179                                         toHide.hide();\r
180                                         toShow.show();\r
181                                 }\r
182                                 finished(true);\r
183                         }\r
184                 }\r
185                 \r
186                 function clickHandler(event) {\r
187                         // called only when using activate(false) to close all parts programmatically\r
188                         if ( !event.target && !settings.alwaysOpen ) {\r
189                                 active.toggleClass(settings.selectedClass);\r
190                                 var toHide = active.nextUntil(settings.header);\r
191                                 var toShow = active = $([]);\r
192                                 toggle( toShow, toHide );\r
193                                 return;\r
194                         }\r
195                         // get the click target\r
196                         var clicked = $(event.target);\r
197                         \r
198                         // due to the event delegation model, we have to check if one\r
199                         // of the parent elements is our actual header, and find that\r
200                         if ( clicked.parents(settings.header).length )\r
201                                 while ( !clicked.is(settings.header) )\r
202                                         clicked = clicked.parent();\r
203                         \r
204                         var clickedActive = clicked[0] == active[0];\r
205                         \r
206                         // if animations are still active, or the active header is the target, ignore click\r
207                         if(running || (settings.alwaysOpen && clickedActive) || !clicked.is(settings.header))\r
208                                 return;\r
209 \r
210                         // switch classes\r
211                         active.parent().andSelf().toggleClass(settings.selectedClass);\r
212                         if ( !clickedActive ) {\r
213                                 clicked.parent().andSelf().addClass(settings.selectedClass);\r
214                         }\r
215 \r
216                         // find elements to show and hide\r
217                         var toShow = clicked.nextUntil(settings.header),\r
218                                 toHide = active.nextUntil(settings.header),\r
219                                 data = [clicked, active, toShow, toHide],\r
220                                 down = headers.index( active[0] ) > headers.index( clicked[0] );\r
221                         \r
222                         active = clickedActive ? $([]) : clicked;\r
223                         toggle( toShow, toHide, data, clickedActive, down );\r
224 \r
225                         return !toShow.length;\r
226                 };\r
227                 function activateHandler(event, index) {\r
228                         // IE manages to call activateHandler on normal clicks\r
229                         if ( arguments.length == 1 )\r
230                                 return;\r
231                         // call clickHandler with custom event\r
232                         clickHandler({\r
233                                 target: findActive(index)[0]\r
234                         });\r
235                 };\r
236 \r
237                 return container\r
238                         .bind(settings.event, clickHandler)\r
239                         .bind("activate", activateHandler);\r
240         },\r
241         activate: function(index) {\r
242                 return this.trigger('activate', [index]);\r
243         }\r
244 });\r
245 \r
246 })(jQuery);