i am dustin diaz

a JavaScriptr...

boosh.

don't worry about it.

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.
  1. 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.
  2. 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.
  3. Now we declare codes as an array which eventually becomes a reference to all our header elements with a className of 'code'.
  4. Next we fire the attach method of the cd object which assigns the collapse method to fire on the 'click' event for all of the element headers.
  5. Simutaneously while looping through the code headers we run the Element.cleanWhitespace method on it's parent node so we can properly access our pre element a bit later on.
  6. Upon getting fired, the collapse method checks to see where it's 'click' came from with the cd.getEventSrc method.
  7. 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.SlideDown and Effect.Appear methods.
  8. If the code block does not have the className we checked for, then we close it up by running the Effect.SlideUp and Effect.Fade methods on the pre element and assign it a className of 'closed' appropriately.
All done. Pretty cool eh?

Todays question and book information

JavaScript complete reference
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.

this is who i am

Hi, my name is Dustin Diaz and I'm an Engineer @ObviousCorp. Previously @Twitter, @Google, and @Yahoo, author of Strobist® Info co-author of JavaScript Design Patterns, co-creator of the Ender JavaScript Framework, a Photographer, and an amateur Mixologist. This is my website. Welcome!

On this site I write about JavaScript. You can also follow along with my open-source work on Github.

This site is optimized and works best in Microsoft Internet Explorer 6.