Bug 20489 Configure illegal file characters https://bugzilla.wikimedia.org/show_bug...
[mediawiki.git] / js2 / mwEmbed / jquery / jquery.ui / ui / ui.accordion.js
blob0e94df1642f1b9e09e983115166dcd40240c5e8b
1 /*
2  * jQuery UI Accordion 1.7.1
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($) {
15 $.widget("ui.accordion", {
17         _init: function() {
19                 var o = this.options, self = this;
20                 this.running = 0;
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                 }
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                 }
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                 }
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'); });
55                 this.headers
56                         .next()
57                                 .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
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');
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);
66                 // IE7-/Win - Extra vertical space in lists fixed
67                 if ($.browser.msie) {
68                         this.element.find('a').css('zoom', '1');
69                 }
71                 this.resize();
73                 //ARIA
74                 this.element.attr('role','tablist');
76                 this.headers
77                         .attr('role','tab')
78                         .bind('keydown', function(event) { return self._keydown(event); })
79                         .next()
80                         .attr('role','tabpanel');
82                 this.headers
83                         .not(this.active || "")
84                         .attr('aria-expanded','false')
85                         .attr("tabIndex", "-1")
86                         .next()
87                         .hide();
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                 }
98                 // only need links in taborder for Safari
99                 if (!$.browser.safari)
100                         this.headers.find('a').attr('tabIndex','-1');
102                 if (o.event) {
103                         this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); });
104                 }
106         },
108         destroy: function() {
109                 var o = this.options;
111                 this.element
112                         .removeClass("ui-accordion ui-widget ui-helper-reset")
113                         .removeAttr("role")
114                         .unbind('.accordion')
115                         .removeData('accordion');
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");
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         },
135         _keydown: function(event) {
137                 var o = this.options, keyCode = $.ui.keyCode;
139                 if (o.disabled || event.altKey || event.ctrlKey)
140                         return;
142                 var length = this.headers.length;
143                 var currentIndex = this.headers.index(event.target);
144                 var toFocus = false;
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                 }
160                 if (toFocus) {
161                         $(event.target).attr('tabIndex','-1');
162                         $(toFocus).attr('tabIndex','0');
163                         toFocus.focus();
164                         return false;
165                 }
167                 return true;
169         },
171         resize: function() {
173                 var o = this.options, maxHeight;
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                         });
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');
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                 }
198         },
200         activate: function(index) {
201                 // call clickHandler with custom event
202                 var active = this._findActive(index)[0];
203                 this._clickHandler({ target: active }, active);
204         },
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         },
216         _clickHandler: function(event, target) {
218                 var o = this.options;
219                 if (o.disabled) return false;
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                 }
239                 // get the click target
240                 var clicked = $(event.currentTarget || target);
241                 var clickedIsActive = clicked[0] == this.active[0];
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                 }
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                 }
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] );
270                 this.active = clickedIsActive ? $([]) : clicked;
271                 this._toggle(toShow, toHide, data, clickedIsActive, down);
273                 return false;
275         },
277         _toggle: function(toShow, toHide, data, clickedIsActive, down) {
279                 var o = this.options, self = this;
281                 this.toShow = toShow;
282                 this.toHide = toHide;
283                 this.data = data;
285                 var complete = function() { if(!self) return; return self._completed.apply(self, arguments); };
287                 // trigger changestart event
288                 this._trigger("changestart", null, this.data);
290                 // count elements to animate
291                 this.running = toHide.size() === 0 ? toShow.size() : toHide.size();
293                 if (o.animated) {
295                         var animOptions = {};
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                         }
315                         if (!o.proxied) {
316                                 o.proxied = o.animated;
317                         }
319                         if (!o.proxiedDuration) {
320                                 o.proxiedDuration = o.duration;
321                         }
323                         o.animated = $.isFunction(o.proxied) ?
324                                 o.proxied(animOptions) : o.proxied;
326                         o.duration = $.isFunction(o.proxiedDuration) ?
327                                 o.proxiedDuration(animOptions) : o.proxiedDuration;
329                         var animations = $.ui.accordion.animations,
330                                 duration = o.duration,
331                                 easing = o.animated;
333                         if (!animations[easing]) {
334                                 animations[easing] = function(options) {
335                                         this.slide(options, {
336                                                 easing: easing,
337                                                 duration: duration || 700
338                                         });
339                                 };
340                         }
342                         animations[easing](animOptions);
344                 } else {
346                         if (o.collapsible && clickedIsActive) {
347                                 toShow.toggle();
348                         } else {
349                                 toHide.hide();
350                                 toShow.show();
351                         }
353                         complete(true);
355                 }
357                 toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur();
358                 toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus();
360         },
362         _completed: function(cancel) {
364                 var o = this.options;
366                 this.running = cancel ? 0 : --this.running;
367                 if (this.running) return;
369                 if (o.clearStyle) {
370                         this.toShow.add(this.toHide).css({
371                                 height: "",
372                                 overflow: ""
373                         });
374                 }
376                 this._trigger('change', null, this.data);
377         }
382 $.extend($.ui.accordion, {
383         version: "1.7.1",
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         }
477 })(jQuery);