An Fx.Elements extension which allows you to easily create accordion type controls.
Fx.Accordion = new Class({
Extends: Fx.Elements,
options: {/*
onActive: function(toggler, section){},
onBackground: function(toggler, section){},*/
fixedHeight: false,
fixedWidth: false,
display: 0,
show: false,
height: true,
width: false,
opacity: true,
alwaysHide: false,
trigger: 'click',
initialDisplayFx: true,
returnHeightToAuto: true
},
initialize: function(){
var defined = function(obj){
return obj != null;
};
var params = Array.link(arguments, {
'container': Type.isElement, //deprecated
'options': Type.isObject,
'togglers': defined,
'elements': defined
});
this.parent(params.elements, params.options);
this.togglers = $$(params.togglers);
this.previous = -1;
this.internalChain = new Chain();
if (this.options.alwaysHide) this.options.wait = true;
if (this.options.show || this.options.show === 0){
this.options.display = false;
this.previous = this.options.show;
}
if (this.options.start){
this.options.display = false;
this.options.show = false;
}
this.effects = {};
if (this.options.opacity) this.effects.opacity = 'fullOpacity';
if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
this.elements.each(function(el, i){
if (this.options.show === i){
this.fireEvent('active', [this.togglers[i], el]);
} else {
for (var fx in this.effects) el.setStyle(fx, 0);
}
}, this);
if (this.options.display || this.options.display === 0 || this.options.initialDisplayFx === false){
this.display(this.options.display, this.options.initialDisplayFx);
}
if (this.options.fixedHeight !== false) this.options.returnHeightToAuto = false;
this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain));
},
addSection: function(toggler, element){
toggler = document.id(toggler);
element = document.id(element);
this.togglers.include(toggler);
this.elements.include(element);
var test = this.togglers.contains(toggler);
var idx = this.togglers.indexOf(toggler);
var displayer = this.display.bind(this, idx);
toggler.store('accordion:display', displayer)
.addEvent(this.options.trigger, displayer);
if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
element.fullOpacity = 1;
if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
element.setStyle('overflow', 'hidden');
if (!test){
for (var fx in this.effects) element.setStyle(fx, 0);
}
return this;
},
removeSection: function(toggler, displayIndex){
var idx = this.togglers.indexOf(toggler);
var element = this.elements[idx];
var remover = function(){
this.togglers.erase(toggler);
this.elements.erase(element);
this.detach(toggler);
}.bind(this);
if (this.now == idx || displayIndex != null){
this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover);
} else {
remover();
}
return this;
},
detach: function(toggler){
var remove = function(toggler){
toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display'));
}.bind(this);
if (!toggler) this.togglers.each(remove);
else remove(toggler);
return this;
},
display: function(index, useFx){
if (!this.check(index, useFx)) return this;
useFx = useFx != null ? useFx : true;
index = (typeOf(index) == 'element') ? this.elements.indexOf(index) : index;
if (index == this.previous) return this;
if (this.options.returnHeightToAuto){
var prev = this.elements[this.previous];
if (prev && !this.selfHidden){
for (var fx in this.effects){
prev.setStyle(fx, prev[this.effects[fx]]);
}
}
}
if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
this.previous = index;
var obj = {};
this.elements.each(function(el, i){
obj[i] = {};
var hide;
if (i != index){
hide = true;
} else if (this.options.alwaysHide && ((el.offsetHeight > 0 && this.options.height) || el.offsetWidth > 0 && this.options.width)){
hide = true;
this.selfHidden = true;
}
this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
}, this);
this.internalChain.clearChain();
this.internalChain.chain(function(){
if (this.options.returnHeightToAuto && !this.selfHidden){
var el = this.elements[index];
if (el) el.setStyle('height', 'auto');
};
}.bind(this));
return useFx ? this.start(obj) : this.set(obj);
}
});
<1.2compat>
Compatibility with 1.2.0
var Accordion = new Class({
Extends: Fx.Accordion,
initialize: function(){
this.parent.apply(this, arguments);
var params = Array.link(arguments, {'container': Type.isElement});
this.container = params.container;
},
addSection: function(toggler, element, pos){
toggler = document.id(toggler);
element = document.id(element);
var test = this.togglers.contains(toggler);
var len = this.togglers.length;
if (len && (!test || pos)){
pos = pos != null ? pos : len - 1;
toggler.inject(this.togglers[pos], 'before');
element.inject(toggler, 'after');
} else if (this.container && !test){
toggler.inject(this.container);
element.inject(this.container);
}
return this.parent.apply(this, arguments);
}
});
</1.2compat>