/*
 * When included, this file will replace all definition lists with classname "ztabslider"
 * with a nifty sliding JavaScript thingie. It allows you to cram a lot of UI components
 * into a small area of real estate. They work sort of like they tab view things in
 * Outlook.
 *
 * To use, include prototype.js, effects.js, and ztabslider.js, in that order.
 * Also include ztabslider_style.css, and alter it to your liking.
 *
 * Graceful degradation -- if the user has JavaScript disabled in their browser, then
 * they will just see the list in its exploded view -- not necessarily pretty, but
 * still accessible.
 *
 * This code is quite ugly and could use a refactoring.
 *
 * You can specify an area as being open by default by giving the <dt> element
 * a class name of "opened".
 *
 *
 *
 * This tool requires version 1.4.0 of the prototype.js library.
 *                    version 1.5.1 of the builder.js library.
 *
 *
 * @author Nicholas Piasecki nick@zincastle.com
 */


/*
 * The aSliders global array is provided in case, for whatever reason, you'd
 * like to access the applied editor objects.
 */
var aSliders = $A( Array() );

/*
 * On window load, this function creates editors for each of the textareas on
 * the page that have the replace-with-zeditor class applied. (They'll also
 * size themselves to the dimension of the textarea, so if you have a specific
 * size in mind, set your textarea to it beforehand.
 */
Event.observe
( 
	window,
	'load',
	function() 
	{
		document.getElementsByClassName( 'replace-with-ztabslider', 'DIV' ).each
		( 
			function( oValue, iIdx ) 
			{
				aSliders.push
				( 
					new ZTabSlider( oValue )
				);
			} 
		);
	},
	false
);

var ZTabSlider = Class.create();

ZTabSlider.prototype =
{
	initialize: function( oSlider )
	{
		this.oSlider = oSlider;
		
		var iDtHeight = 0;
		// Get height of the dts
		$A( this.oSlider.childNodes ).each
		(
			function( oValue, iIdx )
			{
				if ( oValue.tagName && oValue.tagName.match( /dt/i ) )
				{
					iDtHeight += oValue.offsetHeight;
					var iDtIdx = iIdx;
					while ( !oSlider.childNodes[iDtIdx].tagName ||
						      !oSlider.childNodes[iDtIdx].tagName.match( /dd/i ) )
					{
						iDtIdx += 1;
					}
					oValue.oPanel = oSlider.childNodes[iDtIdx];
					if ( Element.hasClassName( oValue, 'opened' ) )
					{
						Element.show( oValue.oPanel );
						oValue.bOpened = true;
					}
					else
					{
						Element.hide( oValue.oPanel );
						oValue.bOpened = false;
					}
				}
			}
		);
		// Hide all of the panels
		$A( this.oSlider.childNodes ).each
		(
			function( oValue, iIdx )
			{
				if ( oValue.tagName && oValue.tagName.match( /dd/i ) )
				{
					oValue.style.height = oSlider.offsetHeight - iDtHeight + 'px';
				}
			}
		);
		
		// Register event listeners to tabs
		$A( this.oSlider.childNodes ).each
		(
			function( oValue, iIdx )
			{
				if ( oValue.tagName && oValue.tagName.match( /dt/i ) )
				{
					var iDtIdx = iIdx;
					while ( !oSlider.childNodes[iDtIdx].tagName ||
						      !oSlider.childNodes[iDtIdx].tagName.match( /dd/i ) )
					{
						iDtIdx += 1;
					}
					oValue.oPanel = oSlider.childNodes[iDtIdx];
					Event.observe
					(
						oValue,
						'click',
						function( oEvent )
						{
							var oToRemove;
							$A( this.parentNode.childNodes ).each
							(
								function( oValue, iIdx )
								{
									if ( oValue.tagName && oValue.tagName.match( /dt/i ) && oValue.bOpened && !oValue.bClosing )
									{
										oToRemove = oValue;
									}
								}
							);
							if ( !this.bOpened && !this.parentNode.bOpening )
							{
								var aEffects = $A( Array() );
								aEffects.push( new Effect.Appear( this.oPanel, { sync: true } ) );
								aEffects.push( new Effect.BlindDown( this.oPanel, { sync: true } ) );
								if ( oToRemove )
								{
									aEffects.push( new Effect.BlindUp( oToRemove.oPanel, { sync: true } ) );
									aEffects.push( new Effect.Fade( oToRemove.oPanel, { sync: true } ) );
								}
								new Effect.Parallel
								(
									aEffects,
									{
										duration: 2.0,
										beforeStart: function( effect )
										{
											if ( oToRemove )
											{
												oToRemove.bClosing = true;
												Element.removeClassName( oToRemove, 'opened' );
												Element.addClassName( oToRemove, 'closed' );
											}
											this.parentNode.bOpening = true;
											Element.addClassName( this, 'opened' );
											Element.removeClassName( oToRemove, 'closed' );
										}.bindAsEventListener( oValue ),
										
										afterFinish: function( effect )
										{
											if ( oToRemove )
											{
												oToRemove.bOpened = false;
												oToRemove.bClosing = false;
											}
											this.bOpened = true;
											this.parentNode.bOpening = false;
										}.bindAsEventListener( oValue )
									}
								);
							}
						}.bindAsEventListener( oValue ),
						false
					);
				}
			}
		);
	}
}

