Accordion plugin
As I don't use jQuery (because I just have fun with Chrome and iOS/Android) and I prefer to write my own functions, I decided to write a simple Accordion function some time ago:
- Short code
- High performance
- Latest JS CSS3 HTML5 technologies
I don't want to add many classes and ids, and many eventhandlers. (My iPad 1 is very sensitive with too many eventhandlers and they are also a pain to delete if needed)
This function adds no ids, no extra classes and uses only one eventhandler.
Single Accordion:
Code for single Accordions (you can apply this function to more elements but you can't put accordions inside accordions.):
function acsf(e) {
var Accordion = e.target.parentNode;
if (Accordion.parentNode == this && Accordion.firstChild == e.target) {
if (this.CurrentAccordion == Accordion) {
this.CurrentAccordion.style.height = '';
delete this.CurrentAccordion
} else {
!this.CurrentAccordion || (this.CurrentAccordion.style.height = '');
this.CurrentAccordion = Accordion;
this.CurrentAccordion.style.height =
(Accordion.firstChild.offsetHeight +
this.CurrentAccordion.childNodes[1].offsetHeight) + 'px'
}
}
}
Structure (no new lines or spaces between <>
):
<div class="accordion">
<div>
<div>Title</div>
<div>Content</div>
</div>
<div>
<div>Title</div>
<div>Content</div>
</div>
</div>
Usage:
document.getElementsByClassName('accordion')[0].addEventListener('click',acsf,false);
The above code works perfectly.
But I want to create a plugin that adds this function to every element with the accordion class and include it as a script:
(function() {
function acsf() {
//the code above
}
function init(){
var acs = D.getElementsByClassName('accordion'),
acsl = acs.length;
while(acsl--){
acs[acsl].addEventListener('click',acsf,false);
}
window.removeEventListener('load',init,false);
}
window.addEventListener('load',init,false);
})()
Is this correct, or are the better ways to do that?
Should this remove the possibility of creating problems with other variable or function names?
I also want to be able to put accordions inside accordions, so I wrote this next script, but there is a delay and I totally don't know how to remove that.
I also don't want to use settimeout. That was just the only way I knew to get it work vs webkitAnimationEnd
which just needs a little more code. But I need to get the next height before the animation or timeout ends.
(function (D) {
function acsf(e) {
var a = e.target.parentNode,
h;
if (a.parentNode == this && a.firstChild == e.target) {
h = a.firstChild.offsetHeight;
!this.c || (this.c.style.height = h + 'px');
this.c != a ?
(this.c = a, this.c.style.height = (h + this.c.childNodes[1].offsetHeight) + 'px') :
(this.c.style.height = h + 'px', delete this.c);
setTimeout(acscf.bind(this), 350);
}
}
function acscf(x) {
x = this;
if (x.parentNode && x.parentNode.parentNode &&
x.parentNode.parentNode.parentNode &&
x.parentNode.parentNode.parentNode.classList) {
var y = x.parentNode.parentNode.parentNode;
if (y.classList.contains('accordion')) {
console.log(x.offsetHeight);
y.c.style.height = (48 + (x.offsetHeight)) + 'px';
setTimeout(acscf.bind(y), 350);
}
}
}
function acsinit() {
var acs = D.getElementsByClassName('accordion'),
acsl = acs.length;
while (acsl--) {
acs[acsl].addEventListener('click', acsf, false);
}
window.removeEventListener('load', acsinit, false);
}
window.addEventListener('load', acsinit, false);
})(document)
Example to play with:
^ the latest accordion title contains other 2 accordions
And now to make things difficult I'm trying to find a way to interact with the closed function outside of it. So basically toggle elements with another function created inside another script.
To resume the questions:
- Create a plugin to include that does not create problems with other scripts. (I'm totally new to JS classes)
- Remove the delay
- I want to be able to toggle the elements outside with a function outside of the plugin.
EDIT
I just found out that I could use try
catch
vs the long check on the parentNode
s.
if(x.parentNode &&
x.parentNode.parentNode &&
x.parentNode.parentNode.parentNode &&
x.parentNode.parentNode.parentNode.classList..
to
try{
y=x.parentNode.parentNode.parentNode.classList.contains('accordion')
}catch(e){
y=false
}
But what about performance?