Collapsable effects with Script.aculo.us
Want to get that cool effect as demonstrated on this website from when a user clicks on the code block and it slides up and fades out? Well, assuming you’re interested anyway - I’ll show you just how I accomplished that by only using Prototype and Script.aculo.us. That’s right, I won’t be forcing you to grab from that common library. We’ll be using all the tools provided from these two libraries as needed such as the Event.observer, the Element object, even the getElementsByClassName prototype so you won’t need to use my own custom function for that matter.
The Object Game
As you might have guessed, this will of course be in my favorite syntax of object notation taking the form of an object literal to speed up the process.
So first off, let’s get a little sample of what we’re actually producing here. If you’re not reading this article through an RSS reader - go ahead and click on the head of the following code block:
Click Here for Demonstration
/* Sample CSS code */
h3.code,pre {
color:#444;
font:12px/1.1em 'courier new',courier,monospace;
width:90%;
}
h3.code {
background:#e3c78b;
text-align:right;
padding:2px 3px;
}
pre {
padding:10px;
overflow:hidden;
}
Great, so now that we know what we’re doing here, let’s see exactly what we need to do.
First things first
Like any other Prototype/Script.aculo.us tutorial - the first thing you’ll always see is that you need to do the following:
Reference your JavaScript
<head>
...
<script type='text/javascript' src='/js/prototype.js'></script>
<script type='text/javascript' src='/js/scriptaculous.js'></script>
...
</head>
With that done, now we can get right down to business. This is going to be short and sweet, so pay attention.
Building up the cd object
var cd = {
codes : Array,
init : function() {
cd.codes = document.getElementsByClassName('code','contentBody');
cd.attach();
},
attach : function() {
var i;
for ( i=0;i<cd.codes.length;i++ ) {
Event.observe(cd.codes[i],'click',cd.collapse,false);
Element.cleanWhitespace(cd.codes[i].parentNode);
}
},
getEventSrc : function (e) {
if (!e) e = window.event;
if (e.originalTarget)
return e.originalTarget;
else if (e.srcElement)
return e.srcElement;
},
collapse : function(e) {
var el = cd.getEventSrc(e).nextSibling;
if ( Element.hasClassName(el,'closed') ) {
new Effect.Parallel(
[
new Effect.SlideDown(el,{sync:true}),
new Effect.Appear(el,{sync:true})
],
{
duration:1.0,
fps:40
}
);
Element.removeClassName(el,'closed');
} else {
new Effect.Parallel(
[
new Effect.SlideUp(el,{sync:true}),
new Effect.Fade(el,{sync:true})
],
{
duration:1.0,
fps:40
}
);
Element.addClassName(el,'closed')
}
}
};
Event.observe(window,'load',cd.init,false);
That’s it! Simple as that. Of course we wouldn’t learn anything if there was no explanation. So let’s look at it step by step.
- We can see that first this whole thing is named ‘cd’. Just a simple way to keep the object name nice and short for anytime we need to reference it.
- The bottom of this snippet of code reveals that we’re adding
cd.init()to run upon the window ‘load’ event using the Event.observe method provided by Prototype. - Now we declare
codesas an array which eventually becomes a reference to all our header elements with a className of ‘code’. - Next we fire the attach method of the cd object which assigns the
collapsemethod to fire on the ‘click’ event for all of the element headers. - Simutaneously while looping through the
codeheaders we run theElement.cleanWhitespacemethod on it’s parent node so we can properly access ourpreelement a bit later on. - Upon getting fired, the
collapsemethod checks to see where it’s ‘click’ came from with thecd.getEventSrcmethod. - Then we do a check to see if the element has a className of ‘closed’ - if it does, then we open up our code blocks using the
Effect.SlideDownandEffect.Appearmethods. - If the code block does not have the className we checked for, then we close it up by running the
Effect.SlideUpandEffect.Fademethods on thepreelement and assign it a className of ‘closed’ appropriately.
All done. Pretty cool eh?
Todays question and book information
The winner of today’s contest will receive a copy of JavaScript: The Complete Reference by Thomas Powell and Fritz Schneider.
Put together an “Ode to my underwear” in exactly four lines. (Yours, not mine)
Please remember to put your answers encapsulated within a <blockquote> element, and the regular discussion as normal.














December 31st, 2005 at 2:57 pm
http://moofx.mad4milk.net
IMHO, I think the small size of the MooFX library makes it ideal for doing effects like this (if all you’re going for is effects). However, I think having the libraries is awesome if you need the extended power.
Anyways, on to my entry :)
December 31st, 2005 at 3:14 pm
This is a really cool effect Dustin. Thanks for the tutorial! I dont know much about Java but I am interested in learning. Do you have some direction for me to enhance my skills?
December 31st, 2005 at 3:20 pm
December 31st, 2005 at 3:31 pm
Haha. I can just tell these entries are going to be great!
@Nate: The Moo.fx library is very cool indeed as I’ve toyed around with that one for a bit too. But I’d still keep the prototype library around for this.
@Dennis: I’m not much of a Java guy, but if you are in fact inquiring about “JavaScript” - then I’d recommend any of the books about JavaScript all found in my Books section
December 31st, 2005 at 3:44 pm
Argh, I tried scriptaculous a while back and gave up in disgust. It’s just too bulky and it would not work, plus I had to add extra markup. moo.fx isn’t much better, though I do enjoy their moo.ajax framework.
December 31st, 2005 at 3:50 pm
December 31st, 2005 at 5:25 pm
The way JavaScript has advanced in the last year is amazing. From the retarded sibling to a truly helpful tool.
December 31st, 2005 at 7:28 pm
Raanan, JavaScript has always been a powerful tool. It just took dynamic HTTP Requests to prove it to everyone.
December 31st, 2005 at 8:38 pm
Hi Dustin,
When does the contest end?
Jane
January 1st, 2006 at 4:43 am
@Dante: You are indeed correct. JS was more like the abused older brother whose siblings finally grew up and understood him. JS has been abused by web “masters” for years. Combine that with the lack of CSS in the early years, and the non-standard versions of HTML; and you had a powerful tool that looked weak and useless.
With real developers actually getting hold of JS now and using it in a way that actually enhances pages where available, and doesn’t break them when it’s not; and CSS and HTML “growing up”; we are finaly seeing the true gracefulness and power that is JS.
January 1st, 2006 at 11:16 pm
January 6th, 2006 at 9:40 am
Not entering the contest… just wanted to let you know that all the code in your code blocks on your site runs off the right side (when deeply nested) and gets clipped, therefore I cannot read much of the code on this page. IE 6. 1600×1200 res.
January 6th, 2006 at 11:00 am
Ryan,
You’re seeing the result of ‘overflow:hidden’ which was done on purpose. Otherwise the code would be flying off the page which really makes things look yucky.
If you want to really check out the code, you can copy and paste the lines you want, and surely enough, it will all be happily waiting for you on your clip board :)
January 23rd, 2006 at 4:40 pm
Hi,
Great example! I’m trying to get it working on my dev server. I copied your source code and ofcourse I have the Prototype and Script.aculo.us libraries installed. Now when I attempt to run the example, I get the following:
Error: Enumerable is not defined
Source File: http://fc4dev/sandbox/scriptaculous-js-1.5.1/src/effects.js
Line: 182
Any idea how to fix that? What am I doing wrong?
Thanks,
AC
January 23rd, 2006 at 5:07 pm
Haha….I should have waited another couple of minutes. I had a mismatch between the Prototype and Script.aculo.us libraries. Either way, great site Dustin. I’ll be sure to come back regularly.
February 7th, 2006 at 2:25 am
OK, so it’s a bit late - and it’s not four lines. But it was written when I was eight, and it’s one of the three poems I can actually remember.
Blowing in the breezes
is a pair of underwear.
They are drying there.
My humble haiku, for you.
July 31st, 2006 at 10:13 am
Hmm, I’m sure this is great, but right now it’s not working at all. Does it use an outdated version of prototype?
October 31st, 2006 at 3:29 pm
[…] Collapsable effects with Script.aculo.us (tags: javascript scriptaculous animation effects prototype) […]
November 15th, 2006 at 12:59 am
Hi Dustin,
Sorry for bumping this old post. But firstly, thanks for sharing this awesome code. It helped me to clear up lots of unwanted spaces taken up by codes.
I’ve experimented with the code you’ve provided, and I found out that it only works for the “pre” “code” elements, and not others, for example, “div” or “span”. Why is this so? Is there any workaround, because I wish to implement this script for my sidebar to make it collapsable, which is made up of “div” tags only… since I do not want to include my sidebar contents in the “pre” and “code” tags.
Thank you!
March 5th, 2007 at 8:13 pm
Hi Dustin - thanks a ton for posting this tutorial. I’m completely ignorant about js. Is there a way to modify the .js so the window is collapsed by default, and “opens” when clicked?
Again, thanks so much.
September 10th, 2007 at 12:09 am
sorry, Dustin was here and there but looked real busy to me, so I’m replying to your questions:
Re:Michael;
Yes, there are ways, as Dusting has explained clearly at the end, you can classify your TAGs as ‘closed’ so browser chooses your way at the 1st IF crossroadds.
You can also trigger the method at the body onload
Re:teddY;
ah ted, the getElementsByClassName is for this sort of work.. see the ‘code’ there? replace it with someother (not necessarily but) block-level elements.
Re:jim;
Boy, you do have some problems - hey dustin, this site requires some attention :-) anyways - I’ll keep looking for more examples
-k.
======= anyways
November 26th, 2007 at 4:16 pm
The explanation for implementation is unclear and unusable for me. The source code for this page varies greatly from your example as well. Can you explain what some of the unexplained items like “contentBody” refer to? How about a simple, working downloadable sample?