/*
	Sliding Labels 3.2 + djjeck patches
	
	This is the official plugin version of Sliding Labels.
	It is open source code by Tim Wright of CSSKarma.com
	Use as you see fit, I'd like it if you kept this in 
	the code, but basically share it and don't be a jerk.
	
	Support:
	http://www.csskarma.com/blog/sliding-labels-plugin
	
	Version: 2 - added textarea functionality
	Version: 3 - added axis parameter
	           - added speed parameter
	           - removed color parameter, as it should be define in the CSS
	           - added position:relative to wrapping element
	           - coverted to jQuery plugin
	Version: 3.1 - changed "children" to "find" so it works a little better with UL & fieldsets
	Version: 3.2 - Added a "className" option so you don't have to use ".slider" as the wrapper
	
	djjeck patches
		- enhanced automatic positioning of label
		- bugfix for absolutely positioned labels
		- optimized execution speed (bugfix for too many event handlers)
		- optimized memory consumption (less scopes and less variables used)
		
		// TODO change time according to distance to slide, so that speed is constant (for x axis, it depends on label varying sizes, for y axis it depends on input paddings or such)
		// TODO automatically add the wrapper
		// TODO select support
		// TODO nested label-input support
		// TODO investigate on supporting automatic label positioning when elements are not displayed (might be not possible. if so, add a recalculate method, or something, to be called when form get displayed)
*/
(function($){
	$.fn.slidinglabels = function(options){
		options = $.extend({
			className    : 'form-slider', // <- new to version 3.2
			topPosition  : undefined,
			leftPosition : undefined,
			axis         : 'x',
			speed        : 'fast'
		}, options);
		
		var placeLabel = function(input, slided, animate) {
			input = $(input); // wrap it in $
			var label = input.prev('label'); // rediscovered each time, so labels can be replaced
			
			var getInt = function(string) { return (parseInt(string, 10)) ? parseInt(string, 10) : 0; } // normalizes values: removes units (px, em, ...), discards values like 'auto'
			
			var css = // calculate the position of the label
				$.extend({
						// position if not slided = inside the input - values are taken from options, or calculated
						left:
							options.leftPosition != undefined ? // if an option is set
								options.leftPosition : // use option
								// otherwise calculate
								input.position().left + // position of input
								getInt(input.css('marginLeft')) + // margin
								getInt(input.css('borderLeftWidth')) + // border
								getInt(input.css('paddingLeft')) // padding
						,
						top:
							options.topPosition != undefined ? // if an option is set
								options.topPosition : // use option
								// otherwise calculate
								input.position().top + // position of input
								getInt(input.css('marginTop')) + // margin
								getInt(input.css('borderTopWidth')) + // border
								getInt(input.css('paddingTop')) + // padding
								(input.is('textarea')?0:parseInt((input.height() - label.height()) / 2)) // difference in sizes - if not textarea, vertically center
					}, 
					// slided = outside the input - values depend on label size
					(slided && options.axis == 'x') ? { left: ( input.position().left - label.outerWidth(true) - 5) + 'px' } : // XXX magic number: 5
					(slided && options.axis == 'y') ? { top: ( input.position().top - label.outerHeight(true) )+ 'px' } :
					{}
				);
			label.stop().animate(css, // set the position
				animate ? options.speed : 0 // if not animate, set animation duration to 0 milliseconds
			);
		};
		
		
		this.
		// INITIALIZE CONTAINER CSS
		find('.'+options.className).css({position: 'relative'}). // position the container: labels must be positioned relatively to their containers
		// INITIALIZE INPUT CSS
		find('input, textarea, select').
		// PLACE THE LABELS
		each(function(){
			$(this).prev('label').css({
				position : 'absolute',
				display  : 'inline', // safe, but not necessary
				zIndex   : 99 // safe, but not necessary
			});
			placeLabel(
				this, // the input
				($.trim($(this).val()) != ''), // if the input is full -> slided (outside the input); if the input is empty -> not slided (inside the input) 
				false // not animated
			);
		}).
		// SET FOCUS HANDLER
		focus(function(){
			// on focus, slide the label
			placeLabel(
				this, // the input
				true, // slided = outside the input
				($.trim($(this).val()) == '') // if the input is empty -> animate; otherwise: label should already be outside, so avoid the animation and move that label already
					// note: this animation check is included for safe programming.
					// there is still an open issue when slidinglabels method is called when the inputs and/or labels are not shown yet on the page.
					// this causes an error on the calculated label position, which can be recovered when the user focuses the input for the first time.
			);
		}).
		// SET BLUR HANDLER
		blur(function(){
			// if the input is empty on blur, move it back
			placeLabel(
				this, // the input
				($.trim($(this).val()) != ''), // if the input is full -> slided (outside the input); if the input is empty -> not slided (inside the input) 
				true // animate
			);
		});
	}; // End function
})(jQuery); // End jQuery
