1 | /* |
---|
2 | * jQuery UI Accordion 1.7.2 |
---|
3 | * |
---|
4 | * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) |
---|
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 | |
---|
17 | _init: function() { |
---|
18 | |
---|
19 | var o = this.options, self = this; |
---|
20 | this.running = 0; |
---|
21 | |
---|
22 | // if the user set the alwaysOpen option on init |
---|
23 | // then we need to set the collapsible option |
---|
24 | // if they set both on init, collapsible will take priority |
---|
25 | if (o.collapsible == $.ui.accordion.defaults.collapsible && |
---|
26 | o.alwaysOpen != $.ui.accordion.defaults.alwaysOpen) { |
---|
27 | o.collapsible = !o.alwaysOpen; |
---|
28 | } |
---|
29 | |
---|
30 | if ( o.navigation ) { |
---|
31 | var current = this.element.find("a").filter(o.navigationFilter); |
---|
32 | if ( current.length ) { |
---|
33 | if ( current.filter(o.header).length ) { |
---|
34 | this.active = current; |
---|
35 | } else { |
---|
36 | this.active = current.parent().parent().prev(); |
---|
37 | current.addClass("ui-accordion-content-active"); |
---|
38 | } |
---|
39 | } |
---|
40 | } |
---|
41 | |
---|
42 | this.element.addClass("ui-accordion ui-widget ui-helper-reset"); |
---|
43 | |
---|
44 | // in lack of child-selectors in CSS we need to mark top-LIs in a UL-accordion for some IE-fix |
---|
45 | if (this.element[0].nodeName == "UL") { |
---|
46 | this.element.children("li").addClass("ui-accordion-li-fix"); |
---|
47 | } |
---|
48 | |
---|
49 | this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all") |
---|
50 | .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); }) |
---|
51 | .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); }) |
---|
52 | .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); }) |
---|
53 | .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); }); |
---|
54 | |
---|
55 | this.headers |
---|
56 | .next() |
---|
57 | .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); |
---|
58 | |
---|
59 | this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"); |
---|
60 | this.active.next().addClass('ui-accordion-content-active'); |
---|
61 | |
---|
62 | //Append icon elements |
---|
63 | $("<span/>").addClass("ui-icon " + o.icons.header).prependTo(this.headers); |
---|
64 | this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected); |
---|
65 | |
---|
66 | // IE7-/Win - Extra vertical space in lists fixed |
---|
67 | if ($.browser.msie) { |
---|
68 | this.element.find('a').css('zoom', '1'); |
---|
69 | } |
---|
70 | |
---|
71 | this.resize(); |
---|
72 | |
---|
73 | //ARIA |
---|
74 | this.element.attr('role','tablist'); |
---|
75 | |
---|
76 | this.headers |
---|
77 | .attr('role','tab') |
---|
78 | .bind('keydown', function(event) { return self._keydown(event); }) |
---|
79 | .next() |
---|
80 | .attr('role','tabpanel'); |
---|
81 | |
---|
82 | this.headers |
---|
83 | .not(this.active || "") |
---|
84 | .attr('aria-expanded','false') |
---|
85 | .attr("tabIndex", "-1") |
---|
86 | .next() |
---|
87 | .hide(); |
---|
88 | |
---|
89 | // make sure at least one header is in the tab order |
---|
90 | if (!this.active.length) { |
---|
91 | this.headers.eq(0).attr('tabIndex','0'); |
---|
92 | } else { |
---|
93 | this.active |
---|
94 | .attr('aria-expanded','true') |
---|
95 | .attr('tabIndex', '0'); |
---|
96 | } |
---|
97 | |
---|
98 | // only need links in taborder for Safari |
---|
99 | if (!$.browser.safari) |
---|
100 | this.headers.find('a').attr('tabIndex','-1'); |
---|
101 | |
---|
102 | if (o.event) { |
---|
103 | this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); }); |
---|
104 | } |
---|
105 | |
---|
106 | }, |
---|
107 | |
---|
108 | destroy: function() { |
---|
109 | var o = this.options; |
---|
110 | |
---|
111 | this.element |
---|
112 | .removeClass("ui-accordion ui-widget ui-helper-reset") |
---|
113 | .removeAttr("role") |
---|
114 | .unbind('.accordion') |
---|
115 | .removeData('accordion'); |
---|
116 | |
---|
117 | this.headers |
---|
118 | .unbind(".accordion") |
---|
119 | .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top") |
---|
120 | .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex"); |
---|
121 | |
---|
122 | this.headers.find("a").removeAttr("tabindex"); |
---|
123 | this.headers.children(".ui-icon").remove(); |
---|
124 | var contents = this.headers.next().css("display", "").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active"); |
---|
125 | if (o.autoHeight || o.fillHeight) { |
---|
126 | contents.css("height", ""); |
---|
127 | } |
---|
128 | }, |
---|
129 | |
---|
130 | _setData: function(key, value) { |
---|
131 | if(key == 'alwaysOpen') { key = 'collapsible'; value = !value; } |
---|
132 | $.widget.prototype._setData.apply(this, arguments); |
---|
133 | }, |
---|
134 | |
---|
135 | _keydown: function(event) { |
---|
136 | |
---|
137 | var o = this.options, keyCode = $.ui.keyCode; |
---|
138 | |
---|
139 | if (o.disabled || event.altKey || event.ctrlKey) |
---|
140 | return; |
---|
141 | |
---|
142 | var length = this.headers.length; |
---|
143 | var currentIndex = this.headers.index(event.target); |
---|
144 | var toFocus = false; |
---|
145 | |
---|
146 | switch(event.keyCode) { |
---|
147 | case keyCode.RIGHT: |
---|
148 | case keyCode.DOWN: |
---|
149 | toFocus = this.headers[(currentIndex + 1) % length]; |
---|
150 | break; |
---|
151 | case keyCode.LEFT: |
---|
152 | case keyCode.UP: |
---|
153 | toFocus = this.headers[(currentIndex - 1 + length) % length]; |
---|
154 | break; |
---|
155 | case keyCode.SPACE: |
---|
156 | case keyCode.ENTER: |
---|
157 | return this._clickHandler({ target: event.target }, event.target); |
---|
158 | } |
---|
159 | |
---|
160 | if (toFocus) { |
---|
161 | $(event.target).attr('tabIndex','-1'); |
---|
162 | $(toFocus).attr('tabIndex','0'); |
---|
163 | toFocus.focus(); |
---|
164 | return false; |
---|
165 | } |
---|
166 | |
---|
167 | return true; |
---|
168 | |
---|
169 | }, |
---|
170 | |
---|
171 | resize: function() { |
---|
172 | |
---|
173 | var o = this.options, maxHeight; |
---|
174 | |
---|
175 | if (o.fillSpace) { |
---|
176 | |
---|
177 | if($.browser.msie) { var defOverflow = this.element.parent().css('overflow'); this.element.parent().css('overflow', 'hidden'); } |
---|
178 | maxHeight = this.element.parent().height(); |
---|
179 | if($.browser.msie) { this.element.parent().css('overflow', defOverflow); } |
---|
180 | |
---|
181 | this.headers.each(function() { |
---|
182 | maxHeight -= $(this).outerHeight(); |
---|
183 | }); |
---|
184 | |
---|
185 | var maxPadding = 0; |
---|
186 | this.headers.next().each(function() { |
---|
187 | maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height()); |
---|
188 | }).height(Math.max(0, maxHeight - maxPadding)) |
---|
189 | .css('overflow', 'auto'); |
---|
190 | |
---|
191 | } else if ( o.autoHeight ) { |
---|
192 | maxHeight = 0; |
---|
193 | this.headers.next().each(function() { |
---|
194 | maxHeight = Math.max(maxHeight, $(this).outerHeight()); |
---|
195 | }).height(maxHeight); |
---|
196 | } |
---|
197 | |
---|
198 | }, |
---|
199 | |
---|
200 | activate: function(index) { |
---|
201 | // call clickHandler with custom event |
---|
202 | var active = this._findActive(index)[0]; |
---|
203 | this._clickHandler({ target: active }, active); |
---|
204 | }, |
---|
205 | |
---|
206 | _findActive: function(selector) { |
---|
207 | return selector |
---|
208 | ? typeof selector == "number" |
---|
209 | ? this.headers.filter(":eq(" + selector + ")") |
---|
210 | : this.headers.not(this.headers.not(selector)) |
---|
211 | : selector === false |
---|
212 | ? $([]) |
---|
213 | : this.headers.filter(":eq(0)"); |
---|
214 | }, |
---|
215 | |
---|
216 | _clickHandler: function(event, target) { |
---|
217 | |
---|
218 | var o = this.options; |
---|
219 | if (o.disabled) return false; |
---|
220 | |
---|
221 | // called only when using activate(false) to close all parts programmatically |
---|
222 | if (!event.target && o.collapsible) { |
---|
223 | this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") |
---|
224 | .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); |
---|
225 | this.active.next().addClass('ui-accordion-content-active'); |
---|
226 | var toHide = this.active.next(), |
---|
227 | data = { |
---|
228 | options: o, |
---|
229 | newHeader: $([]), |
---|
230 | oldHeader: o.active, |
---|
231 | newContent: $([]), |
---|
232 | oldContent: toHide |
---|
233 | }, |
---|
234 | toShow = (this.active = $([])); |
---|
235 | this._toggle(toShow, toHide, data); |
---|
236 | return false; |
---|
237 | } |
---|
238 | |
---|
239 | // get the click target |
---|
240 | var clicked = $(event.currentTarget || target); |
---|
241 | var clickedIsActive = clicked[0] == this.active[0]; |
---|
242 | |
---|
243 | // if animations are still active, or the active header is the target, ignore click |
---|
244 | if (this.running || (!o.collapsible && clickedIsActive)) { |
---|
245 | return false; |
---|
246 | } |
---|
247 | |
---|
248 | // switch classes |
---|
249 | this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") |
---|
250 | .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); |
---|
251 | this.active.next().addClass('ui-accordion-content-active'); |
---|
252 | if (!clickedIsActive) { |
---|
253 | clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top") |
---|
254 | .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected); |
---|
255 | clicked.next().addClass('ui-accordion-content-active'); |
---|
256 | } |
---|
257 | |
---|
258 | // find elements to show and hide |
---|
259 | var toShow = clicked.next(), |
---|
260 | toHide = this.active.next(), |
---|
261 | data = { |
---|
262 | options: o, |
---|
263 | newHeader: clickedIsActive && o.collapsible ? $([]) : clicked, |
---|
264 | oldHeader: this.active, |
---|
265 | newContent: clickedIsActive && o.collapsible ? $([]) : toShow.find('> *'), |
---|
266 | oldContent: toHide.find('> *') |
---|
267 | }, |
---|
268 | down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); |
---|
269 | |
---|
270 | this.active = clickedIsActive ? $([]) : clicked; |
---|
271 | this._toggle(toShow, toHide, data, clickedIsActive, down); |
---|
272 | |
---|
273 | return false; |
---|
274 | |
---|
275 | }, |
---|
276 | |
---|
277 | _toggle: function(toShow, toHide, data, clickedIsActive, down) { |
---|
278 | |
---|
279 | var o = this.options, self = this; |
---|
280 | |
---|
281 | this.toShow = toShow; |
---|
282 | this.toHide = toHide; |
---|
283 | this.data = data; |
---|
284 | |
---|
285 | var complete = function() { if(!self) return; return self._completed.apply(self, arguments); }; |
---|
286 | |
---|
287 | // trigger changestart event |
---|
288 | this._trigger("changestart", null, this.data); |
---|
289 | |
---|
290 | // count elements to animate |
---|
291 | this.running = toHide.size() === 0 ? toShow.size() : toHide.size(); |
---|
292 | |
---|
293 | if (o.animated) { |
---|
294 | |
---|
295 | var animOptions = {}; |
---|
296 | |
---|
297 | if ( o.collapsible && clickedIsActive ) { |
---|
298 | animOptions = { |
---|
299 | toShow: $([]), |
---|
300 | toHide: toHide, |
---|
301 | complete: complete, |
---|
302 | down: down, |
---|
303 | autoHeight: o.autoHeight || o.fillSpace |
---|
304 | }; |
---|
305 | } else { |
---|
306 | animOptions = { |
---|
307 | toShow: toShow, |
---|
308 | toHide: toHide, |
---|
309 | complete: complete, |
---|
310 | down: down, |
---|
311 | autoHeight: o.autoHeight || o.fillSpace |
---|
312 | }; |
---|
313 | } |
---|
314 | |
---|
315 | if (!o.proxied) { |
---|
316 | o.proxied = o.animated; |
---|
317 | } |
---|
318 | |
---|
319 | if (!o.proxiedDuration) { |
---|
320 | o.proxiedDuration = o.duration; |
---|
321 | } |
---|
322 | |
---|
323 | o.animated = $.isFunction(o.proxied) ? |
---|
324 | o.proxied(animOptions) : o.proxied; |
---|
325 | |
---|
326 | o.duration = $.isFunction(o.proxiedDuration) ? |
---|
327 | o.proxiedDuration(animOptions) : o.proxiedDuration; |
---|
328 | |
---|
329 | var animations = $.ui.accordion.animations, |
---|
330 | duration = o.duration, |
---|
331 | easing = o.animated; |
---|
332 | |
---|
333 | if (!animations[easing]) { |
---|
334 | animations[easing] = function(options) { |
---|
335 | this.slide(options, { |
---|
336 | easing: easing, |
---|
337 | duration: duration || 700 |
---|
338 | }); |
---|
339 | }; |
---|
340 | } |
---|
341 | |
---|
342 | animations[easing](animOptions); |
---|
343 | |
---|
344 | } else { |
---|
345 | |
---|
346 | if (o.collapsible && clickedIsActive) { |
---|
347 | toShow.toggle(); |
---|
348 | } else { |
---|
349 | toHide.hide(); |
---|
350 | toShow.show(); |
---|
351 | } |
---|
352 | |
---|
353 | complete(true); |
---|
354 | |
---|
355 | } |
---|
356 | |
---|
357 | toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur(); |
---|
358 | toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus(); |
---|
359 | |
---|
360 | }, |
---|
361 | |
---|
362 | _completed: function(cancel) { |
---|
363 | |
---|
364 | var o = this.options; |
---|
365 | |
---|
366 | this.running = cancel ? 0 : --this.running; |
---|
367 | if (this.running) return; |
---|
368 | |
---|
369 | if (o.clearStyle) { |
---|
370 | this.toShow.add(this.toHide).css({ |
---|
371 | height: "", |
---|
372 | overflow: "" |
---|
373 | }); |
---|
374 | } |
---|
375 | |
---|
376 | this._trigger('change', null, this.data); |
---|
377 | } |
---|
378 | |
---|
379 | }); |
---|
380 | |
---|
381 | |
---|
382 | $.extend($.ui.accordion, { |
---|
383 | version: "1.7.2", |
---|
384 | defaults: { |
---|
385 | active: null, |
---|
386 | alwaysOpen: true, //deprecated, use collapsible |
---|
387 | animated: 'slide', |
---|
388 | autoHeight: true, |
---|
389 | clearStyle: false, |
---|
390 | collapsible: false, |
---|
391 | event: "click", |
---|
392 | fillSpace: false, |
---|
393 | header: "> li > :first-child,> :not(li):even", |
---|
394 | icons: { |
---|
395 | header: "ui-icon-triangle-1-e", |
---|
396 | headerSelected: "ui-icon-triangle-1-s" |
---|
397 | }, |
---|
398 | navigation: false, |
---|
399 | navigationFilter: function() { |
---|
400 | return this.href.toLowerCase() == location.href.toLowerCase(); |
---|
401 | } |
---|
402 | }, |
---|
403 | animations: { |
---|
404 | slide: function(options, additions) { |
---|
405 | options = $.extend({ |
---|
406 | easing: "swing", |
---|
407 | duration: 300 |
---|
408 | }, options, additions); |
---|
409 | if ( !options.toHide.size() ) { |
---|
410 | options.toShow.animate({height: "show"}, options); |
---|
411 | return; |
---|
412 | } |
---|
413 | if ( !options.toShow.size() ) { |
---|
414 | options.toHide.animate({height: "hide"}, options); |
---|
415 | return; |
---|
416 | } |
---|
417 | var overflow = options.toShow.css('overflow'), |
---|
418 | percentDone, |
---|
419 | showProps = {}, |
---|
420 | hideProps = {}, |
---|
421 | fxAttrs = [ "height", "paddingTop", "paddingBottom" ], |
---|
422 | originalWidth; |
---|
423 | // fix width before calculating height of hidden element |
---|
424 | var s = options.toShow; |
---|
425 | originalWidth = s[0].style.width; |
---|
426 | s.width( parseInt(s.parent().width(),10) - parseInt(s.css("paddingLeft"),10) - parseInt(s.css("paddingRight"),10) - (parseInt(s.css("borderLeftWidth"),10) || 0) - (parseInt(s.css("borderRightWidth"),10) || 0) ); |
---|
427 | |
---|
428 | $.each(fxAttrs, function(i, prop) { |
---|
429 | hideProps[prop] = 'hide'; |
---|
430 | |
---|
431 | var parts = ('' + $.css(options.toShow[0], prop)).match(/^([\d+-.]+)(.*)$/); |
---|
432 | showProps[prop] = { |
---|
433 | value: parts[1], |
---|
434 | unit: parts[2] || 'px' |
---|
435 | }; |
---|
436 | }); |
---|
437 | options.toShow.css({ height: 0, overflow: 'hidden' }).show(); |
---|
438 | options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{ |
---|
439 | step: function(now, settings) { |
---|
440 | // only calculate the percent when animating height |
---|
441 | // IE gets very inconsistent results when animating elements |
---|
442 | // with small values, which is common for padding |
---|
443 | if (settings.prop == 'height') { |
---|
444 | percentDone = (settings.now - settings.start) / (settings.end - settings.start); |
---|
445 | } |
---|
446 | |
---|
447 | options.toShow[0].style[settings.prop] = |
---|
448 | (percentDone * showProps[settings.prop].value) + showProps[settings.prop].unit; |
---|
449 | }, |
---|
450 | duration: options.duration, |
---|
451 | easing: options.easing, |
---|
452 | complete: function() { |
---|
453 | if ( !options.autoHeight ) { |
---|
454 | options.toShow.css("height", ""); |
---|
455 | } |
---|
456 | options.toShow.css("width", originalWidth); |
---|
457 | options.toShow.css({overflow: overflow}); |
---|
458 | options.complete(); |
---|
459 | } |
---|
460 | }); |
---|
461 | }, |
---|
462 | bounceslide: function(options) { |
---|
463 | this.slide(options, { |
---|
464 | easing: options.down ? "easeOutBounce" : "swing", |
---|
465 | duration: options.down ? 1000 : 200 |
---|
466 | }); |
---|
467 | }, |
---|
468 | easeslide: function(options) { |
---|
469 | this.slide(options, { |
---|
470 | easing: "easeinout", |
---|
471 | duration: 700 |
---|
472 | }); |
---|
473 | } |
---|
474 | } |
---|
475 | }); |
---|
476 | |
---|
477 | })(jQuery); |
---|