Hacking the Accordion
My day-to-day work as a web developer, means that I like to use tools that simplify things for me, but which allow me enough freedom to customize as required, as all of the projects I work on are custom built.
There are, however, times when I use a stock library to perform some form of function, and these days I find that I’m using the SPRY Framework more and more often.
It all started with the form validation widgets, along with their integration into Dreamweaver CS3, mean that I only occassionally have to delve into code to make minor modifications. To be honest, I haven’t really played with the other widgets that much, until now…
The first of the Widgets I’ve been playing with is the SPRY Accordion.
Now, taking into account, that I’ve upgraded my SPRY installation into CS3 using the freely available extension from Adobe Labs, I’ve been delving under the hood a little.
One of the things I like about the Accordion widget is that it’s easy to implement, but I hit a snag with a project I’m currently working on, as the client will be using IE6. Not that much of a problem, really, until you put an IFRAME into a Conent Panel. Under IE6 it looks awful. Not when it’s rendered, that’s fine, it’s the transition that leaves a lot to be desired, as it flashes, and does all sorts of nasty stuff… so the way around it?
The standard methods don’t allow me to trigger the Opening or Closing of the panels, so that left me stuck, as I thought that I could hide (set the css display property to ‘none’), during the closing transition… but there was no way to trap that…. well… until now
Note: This requires modification to the base file, and while it won’t have any lasting effects, it’s recommended that you make a copy of this file, prior to changing it, and then name it something else. The file I refer to, of course, is SpryAccordion.js
Right, so first things first… hunting through the source, I discovered that there’s a line referring to an onComplete method, though this isn’t implemented… it’s simply presented as:-
this.onComplete = null;
Well that’s no good, throughout the code there are references to this method, if it’s not null, then call the function name that it contains… so…
Search for the Spry.Widget.Accordion.PanelAnimator method, and a few lines down you’ll see:-
this.onComplete = null;
Change it to:-
this.onComplete = accordion.onComplete;
Now that you’ve done that, why not add one for the start? So just above the line I’ve mentioned previously, add the following:-
this.onStart = accordion.onStart;
This is all well and good, but there’s no trigger… we’ve passed a reference but it doesn’t get called at any time. To make sure it’s called find the Spry.Widget.Accordion.PanelAnimator.prototype.start method, and just before the setTimeout line add the following:-
if (this.onStart) this.onStart();
And that’s pretty much all there is to it! So how do we use it?
When you’re instantiating the Accordion object, you now have 2 additional parameters that you can send to it. In my case, the original line instantiating the Accordion was:-
var Accordion1 = new Spry.Widget.Accordion(”Accordion1″);
However, it now reads:-
var Accordion1 = new Spry.Widget.Accordion(”Accordion1″, { onStart: hideMe, onComplete: showMe });
The values hideMe and showMe are references to functions within my page that handle the hiding of the iFRAMEs… For completeness, here are those functions too:-
function toggleIframe(theState) {
// First let’s find which panel is open
var acc = document.getElementById(”Accordion1″);
var divs = acc.getElementsByTagName(”div”);
for (k=0; k < divs.length; k++) {
if (divs[k].className == “AccordionPanel AccordionPanelOpen”) {
var ifr = divs[k].getElementsByTagName(”iframe”);
for (i=0; i < ifr.length; i++) {
ifr[i].style.display = (theState != “show”) ? “block” : “none”;
}
} else {
var ifr = divs[k].getElementsByTagName(”iframe”);
for (i=0; i < ifr.length; i++) {
ifr[i].style.display = (theState != “show”) ? “none” : “block”;
}
}
}
}
function hideMe() {
toggleIframe(”hide”);
}
function showMe() {
toggleIframe(”show”);
}
Both hideMe and showMe call the same piece of code, but with different parameters (note: I didn’t look for ways of passing parameters to the callback function, but then, I didn’t need to)… and in this way, when a panel containing an IFRAME is closed, the IFRAME is hidden first. When the panel is opened and the transition is complete, the IFRAME is shown.
Now, this worked, but there was a delay, because the default speed of the animation is quite slow (60fps taking 500ms… no, I didn’t work this out, it’s in the code). So, I decided I wanted to control the speed of the animation, speed it up a bit, and cause the hide/show iframe element to become less noticeable.
All of this is handled in the Spry.Widget.Accordion.PanelAnimator method. Look for the line that says:-
this.fps = 60;
And change this to:-
this.fps = (accordion.fps) ? accordion.fps : 60;
So when the fps parameter is set, that value us used, otherwise the default value is used instead. Just under that line is another one:-
this.duration = 500;
So perform a similar modification to this line too:-
this.duration = (accordion.duration) ? accordion.duration : 500;
In this way, we now have control over the speed, and the length of the transition (open/close) of each panel. To use these new parameters, you can instantiate the Accordion like this:-
var Accordion1 = new Spry.Widget.Accordion(”Accordion1″, { onStart: hideMe, onComplete: showMe, enableAnimation: true, fps: 120, duration: 125 });
Which if you look at it, makes the transition run at twice the speed for a quarter of the length of the time, and bingo! You no longer notice the hide/show of the iframe.
For now, I’m not putting a working example of this online. The site where I’ve used this is a closed CRM, so no public access… but anyway, I hope this is of use.






Activity