/*
	jsComponents v1.5
*/
var js = {
	
	/*
		Comprueva si el navegador es Internet Explorer
	*/
	IE : (window.attachEvent && navigator.userAgent.indexOf('Opera') === -1),
	/*
		Configuracion del server
	*/
	imageResizerScript : 'img_resizer.php',
	imageInfoScript : 'img_info.php',
	varNameForImageSource : 'url',
	varNameForSquareImage : 'lado',
	
	squareThumbnail : function(imgSource,sideSize)
		{
		return encodeURI(this.imageResizerScript+'?'+this.varNameForImageSource+'='+imgSource+'&'+this.varNameForSquareImage+'='+sideSize);
		},
		
	imageInfoUrl : function(images)
		{
		return encodeURI(js.imageInfoScript+'?'+js.varNameForImageSource+'='+images);
		},
	/*
		Se le pasa un id de elemento y se obtiene el elemento correspondiente
		o false si no existe un elemento con ese id;
	*/
	stringToObject : function(obj)
		{
		if(typeof(obj) == "string")
			{
			try
				{
				obj = document.getElementById(obj);
				}
			catch(e)
				{
				return false;
				}
			}
		return obj;
		},
	
	/*
		Crea un elemento del DOM cuyo tagName se pasa como parametro.
		Si la bandera text es true entonces se asume que se quiere
		crear un text node
	*/
	create : function(tag,text)
	{
		if(text)
			return $(document.createTextNode(tag));
		else
			return $(document.createElement(tag));
	},
	
	intervalFunctions : [],
	intervalFunc : function(func)
		{
		return (this.intervalFunctions.push(func) - 1);
		},
	
	_onReady : false,
	toExeOnReady : [],
	/*
		Almacena en un array la funcion pasada como parametro.
		Una vez la pagina haya sido cargada dispara una funcion que ejecuta
		todas las funciones almacenadas en el array.
		
		La funcion encargada de esto es _exeOnReady
	*/
	onReady : function(func)
	{
		this.toExeOnReady.push(func);
		
		if(!this._onReady)
		{
			this.respondsToEvent({
				'element' : window,
				'type' : "load",
				'func' : function(){js._exeOnReady();}
			});
			this._onReady = true;
		}
	},
	
	_exeOnReady : function()
	{
		for(var i=0;i<this.toExeOnReady.length;i++)
		{
			this.toExeOnReady[i]();	
		}
	},
	
	/*
		Añade un manejador de evento al objeto indicado
		Parametros
		{
			element : 'Elemento al que se aplica',
			type : 'tipo de evento',
			func : funcion que se disparará
		}
	*/
	respondsToEvent : function(P)
	{
		if(this.IE)
		{	
			P.type = "on" + P.type;
			js$(P.element).attachEvent(P.type,P.func);
		}
		else
			Event.observe(js$(P.element),P.type,P.func);
	}
};

var interfaces = {
	setMargin : function(margin)
		{
		var N = this;
		if(N.rootDiv)N = N.rootDiv;
		if(typeof(margin) == "number")margin += "px";
		if(typeof(margin) == "string")
			{
			js$(N).style.margin = margin;
			return;
			}
		if(margin.top)N.style.marginTop = margin.top+"px";
		if(margin.bottom)N.style.marginBottom = margin.bottom+"px";
		if(margin.left)N.style.marginLeft = margin.left+"px";
		if(margin.right)N.style.marginRight = margin.right+"px";
		},
		
	setPadding : function(padding)
		{
		js$(this).style.padding = padding+"px";
		},
		
	setPosition : function(P)
		{
		var N = this.rootDiv || js$(this);
		if(P.position)N.style.position = P.position;
		if(P.top)N.style.top = P.top;
		if(P.bottom)N.style.bottom = P.bottom;
		if(P.left)N.style.left = P.left;
		if(P.right)N.style.right = P.right;
		},
	
	appendTo : function(N)
		{
		jsAppendTo(N,this);
		},
		
	appendToMe : function(N)
	{
		jsAppendTo(this,N);
		},

	destroyNodes : function()
		{
		this.nodes().each(function(node)
			{
			node.remove();
			});
		},
		
	respondsToEvent : function(P)
		{
		Event.observe(js$(this),P.type,P.func);
		}
	};
/*
	js$
*/
function js$(N)
	{
	if(N.contDiv)return N.contDiv;
	if(N.rootDiv)return N.rootDiv;
	if(N.span)return N.span;
	if(N.paragraph)return N.paragraph;
	if(N.img)return N.img;
	return js.stringToObject(N);
	}

function jsAppendTo(A,B)
	{
	js$(A).appendChild((B.rootDiv || js$(B)));
	}
	
function jsInsertBefore(A,B,before)
	{
	js$(A).insertBefore((B.rootDiv || js$(B)),js$(before));	
	}
	
function removeChilds(N)
	{
	while(js$(N).hasChildNodes())js$(N).removeChild(js$(N).firstChild);
	}
	
function appendInPosition(N,A,position)
	{
	var AChildNodes = js$(A).childElements();
	if(AChildNodes.length == 0)
		{
		jsAppendTo(A,N);
		return;
		}
	else
		{
		if(position > (AChildNodes.length - 1))
			{
			jsAppendTo(A,N);
			return;
			}
		else
			{
			jsInsertBefore(A,N,AChildNodes[position]);
			return;
			}
		}
	}
/*
	Responder
	Crea un objeto listo para pasarlo como argumento a
	la interfaz respondsToEvent
*/
function Responder(func,type,capture)
	{
	this.type = type || "click";
	this.func = func;
	this.capture = capture || false;
	}
/*
	goToURL
	envia la ventena a una URL
*/
function goToURL(url)
	{
	window.location = encodeURI(url);
	}
/*
	Paragraph
*/
function jsParagraph(P)
	{
	if(!P)var P={};
	this.paragraph = js.create("p");
	this.paragraph.className = "js-paragraph";
	this.Text = function(newText)
		{
		if(newText)
			{
			removeChilds(this.paragraph);
			this.text = js.create(newText,true);
			jsAppendTo(this,this.text);
			}
		return this.text.nodeValue;
		}
	/*
		Interfaces
	*/
	this.appendTo = interfaces.appendTo;
	this.appendToMe = interfaces.appendToMe;
	/*
		Configuracion en instancia
	*/
	if(P.text)this.Text(P.text);
	if(P.appendTo)this.appendTo(P.appendTo);
	}
/*
	jsNotice
*/
function jsNotice(P)
	{
	this.jsBox = new jsBox({
		style : "simple"
		});
	this.rootDiv = this.jsBox.rootDiv;
	this.contDiv = this.jsBox.contDiv;
	this.rootDiv.style.margin = "3px";
	
	/*
		Establece un titulo
	*/
	this.setTitle = function(title)
		{
		if(!this.titleDiv)
			{
			this.titleDiv = js.create("div");
			this.titleDiv.className = "js-notice-title";
			appendInPosition(this.titleDiv,this.contDiv,0);
			}
		removeChilds(this.titleDiv);
		this.titleDiv.appendChild(js.create(title,true));
		}
	/*
		Establece un subtitulo
	*/
	this.setSubTitle = function(subTitle)
		{
		if(!this.subTitleDiv)
			{
			this.subTitleDiv = js.create("div");
			this.subTitleDiv.className = "js-notice-subTitle";
			appendInPosition(this.subTitleDiv,this.contDiv,1);
			}
		removeChilds(this.subTitleDiv);
		this.subTitleDiv.appendChild(js.create(subTitle,true));
		}
	/*
		Establece una fecha
	*/
	this.setNoticeDate = function(date)
		{
		if(!this.dateDiv)
			{
			this.dateDiv = js.create("div");
			this.dateDiv.className = "js-notice-date";
			appendInPosition(this.dateDiv,this.contDiv,3);
			}
		removeChilds(this.dateDiv);
		this.dateDiv.appendChild(js.create(date,true));
		}
	this.setContent = function(text)
		{
		if(!this.paragraph)
			{
			this.paragraph = new jsParagraph();
			appendInPosition(this.paragraph,this.contDiv,2);
			}
		this.paragraph.Text(text);
		}
	/*
		Interfaces
	*/
	this.appendTo = interfaces.appendTo;
	
	/*
		Configuracion en instancia
	*/
	if(P.title)this.setTitle(P.title);
	if(P.subTitle)this.setSubTitle(P.subTitle);
	if(P.date)this.setNoticeDate(P.date);
	if(P.text)this.setContent(P.text);
	if(P.appendTo)this.appendTo(P.appendTo);
	}
/*
	jsBox
*/
function jsBox(P)
	{
	if(!P)var P={};
	this.rootDiv = js.create("div");
	this.contDiv = js.create("div");
	this.rootDiv.appendChild(this.contDiv);
	
	/*
		Interfaces
	*/
	this.addControl = interfaces.appendToMe;
	this.appendTo = interfaces.appendTo;
	this.setMargin = interfaces.setMargin;
	this.setPadding = interfaces.setPadding;
	this.setPosition = interfaces.setPosition;
	if(P.resizable)this.resizer = new jsResizer({applyTo : this});
	
	switch(P.style)
		{
		case 'double':
			this.rootDiv.className = "js-box-double-root";
			this.contDiv.className = "js-box-double-cont";
			break;
		case 'simple':
			this.rootDiv.className = "js-box-simple-root";
			this.contDiv.className = "js-box-simple-cont";
			break;
		}
		
	/*
		Configuracion en instancia
	*/
	if(P.setPosition)this.setPosition(P.setPosition);
	if(P.className)this.contDiv.addClassName(P.className);
	if(P.setMargin)this.setMargin(P.setMargin);
	if(P.setPadding)this.setPadding(P.setPadding);
	if(P.Scroll)this.contDiv.style.overflow = P.Scroll;
	if(P.width)this.rootDiv.style.width = P.width+"px";
	if(P.height)this.rootDiv.style.height = P.height+"px";
	if(P.borderWidth)this.rootDiv.style.padding = P.borderWidth+"px";
	if(P.appendTo)this.appendTo(P.appendTo);
	}
/*
	Delay
*/
function Delay(P)
	{
	this.delay = P.delay;
	if(typeof(P.func.jsFuncIndex) == "number")
		this.jsFuncIndex = P.func.jsFuncIndex;
	else
		this.jsFuncIndex = (typeof(P.func) == "number")?P.func:js.intervalFunc(P.func);
	this.exec = P.exec;
	this.start = function()
		{
		this.interval = setTimeout("js.intervalFunctions["+this.jsFuncIndex+"]."+this.exec+"()",this.delay);
		}
	this.clear = function()
		{
		clearTimeout(this.interval);
		delete this.interval;
		}
	}
/*
	jsIcon
	Crea un icono
*/
function jsIcon(P)
	{
	this.rootDiv = js.create("div");
	this.imgDiv = js.create("div");
	this.textDiv = js.create("div");
	this.img = js.create("img");
	this.textNode = js.create(P.text,true);
	/*
		Configuracion del icono
	*/
	this.rootDiv.className = "js-ico-rootDiv js-pointer";
	this.img.src = P.img;
	this.img.alt = P.imgAlt || "";
	
	this.textDiv.appendChild(this.textNode);
	this.imgDiv.appendChild(this.img);
	this.rootDiv.appendChild(this.imgDiv);
	this.rootDiv.appendChild(this.textDiv);
	/*
		interfaces
	*/
	this.appendTo = interfaces.appendTo;
	this.respondsToEvent = interfaces.respondsToEvent;
	
	if(P.respondsToEvent)this.respondsToEvent(P.respondsToEvent);
	if(P.appendTo)this.appendTo(P.appendTo);
	}
/*
	jsIconGrid
	Crea una serie de iconos
*/
function jsIconGrid(P)
	{
	var iconArray = [];
	for(var i=0;i<P.icons.length;i++)
		{
		var temp = {};
		temp.img = P.icons[i].img;
		temp.text = P.icons[i].text;
		if(P.icons[i].imgAlt)temp.imgAlt = P.icons[i].imgAlt;
		if(P.appendTo)temp.appendTo = P.appendTo;
		if(P.icons[i].respondsToEvent)temp.respondsToEvent = P.icons[i].respondsToEvent;
		iconArray.push(new jsIcon(temp));
		}
	return iconArray;
	}
/*
	jsButton
*/
function jsButton(P)
	{
	this.rootDiv = js.create("div");
	this.leftDiv = js.create("div");
	this.rightDiv = js.create("div");
	this.bgDiv = js.create("div");
	
	this.rootDiv.className = "jsButton-rootDiv js-pointer";
	this.leftDiv.className = "jsButton-leftDiv";
	this.bgDiv.className = "jsButton-bgDiv";
	this.rightDiv.className = "jsButton-rightDiv";

	this.rootDiv.appendChild(this.leftDiv);
	this.rootDiv.appendChild(this.bgDiv);
	this.rootDiv.appendChild(this.rightDiv);
	
	/*
		Interfaces
	*/
	this.appendTo = interfaces.appendTo;
	this.respondsToEvent = interfaces.respondsToEvent;
	this.setMargin = interfaces.setMargin;
	
	this.Value = function(text)
	{
		removeChilds(this.bgDiv);
		var span = js.create("span");
		text = js.create(text,true);
		span.className = "jsText-white js-relativize";
		span.style.top = "6px";
		span.appendChild(text);
		this.bgDiv.appendChild(span);
	}
	
	this.setColor = function(color)
	{
		if(!color)color == "blue";
		if(this.color)
		{
			this.leftDiv.removeClassName("jsButton-"+this.color+"-left");
			this.rightDiv.removeClassName("jsButton-"+this.color+"-right");
			this.bgDiv.removeClassName("jsButton-"+this.color+"-bg");
		}
		this.leftDiv.addClassName("jsButton-"+color+"-left");
		this.rightDiv.addClassName("jsButton-"+color+"-right");
		this.bgDiv.addClassName("jsButton-"+color+"-bg");
		this.color = color;
	}
	/*
		Configuracion en instancia
	*/
	this.Value(P.value || "Button");
	this.setColor(P.color || "blue");
	if(P.setMargin)this.setMargin(P.setMargin);
	if(P.appendTo)this.appendTo(P.appendTo);
	if(P.respondsToEvent)this.respondsToEvent(P.respondsToEvent);
} 

/*
	HTMLInput
*/
function HTMLInput(P)
	{
	if(!P)P={};
	var input = js.create("input");
	/*
		Configuramos el elemento
	*/
	if(P.accept)	input.accept 	= P.accept;
	if(P.accesskey)	input.accesskey	= P.accesskey;
	if(P.alt)		input.alt		= P.alt;
	if(P.checked)	input.checked	= P.checked;
	if(P.disabled)	input.disabled	= P.disabled;
	if(P.maxlength)	input.maxlength	= P.maxlength;
	if(P.name)		input.name		= P.name;
	if(P.id)		input.id		= P.id;
	if(P.readonly)	input.readonly	= P.readonly;
	if(P.size)		input.size		= P.size;
	if(P.src)		input.src		= P.src;
	if(P.tabindex)	input.tabindex	= P.tabindex;
	if(P.value)		input.value		= P.value;
	if(P.className)	input.className	= P.className;
	input.type = P.type || "text" ;
	/*
		Interfaces
	*/
	input.appendTo = interfaces.appendTo;
	input.respondsToEvent = interfaces.respondsToEvent;
	
	if(P.respondsToEvent)input.respondsToEvent(P.respondsToEvent);
	if(P.appendTo)input.appendTo(P.appendTo);
	return input;
	}
	
/*
			Clase jsFormManager v1.0
			NECESITA REVICION
			
		Programada por flasbak@xaicom.es
			
	Esta clase define un objeto que controlara un formulario.
	
	Al hacer una instancia de la misma generara un elemento form
	y lo aÃ±adira al nodo indicado.
	
	CONSTRUCTOR
	
		jsFormManager
		
	PARAMETROS
	
		Recibe un objeto literal como parametro. Este objeto deve
		tener las siguientes propiedades.
		
		{
			//Obligatorias
			'id'		: Id que se le asignara al formulario
			
			//Opcionales (El valor de los mismos es como si asignaramos atributos directamente al formulario)
			'appendTo'	: Id o elemento en el que se isertarÃ¡ el formulario,
			'method'	: Metdo que se usara para el envio de datos,
			'name'		: Nombre del formulario,
			'action'	: URL del script que recibirÃ¡ los datos,
			'enctype'	: Tipo de codificacion
		}
		
	METODOS
	
		addInput
		
			AÃ±ade un elemento input al formulario. Recibe un objeto como parÃ¡metro.
			Las propiedades de este objeto y su valor indicaran los atributos que tendrÃ¡
			el elemento input. Todas las propiedades e incluso el objeto parametro son
			opcionales. Se podria llamar a addInput asÃ­:
			
				formManagerInstance.addInput();
				
			Este metodo implementa los grupos de formulario. Los grupos sirven para agrupar
			elementos input de manera que al incertar un nuevo input no deve ser necesariamente
			al final del forulario sino que indicando el nombre de grupo s incertarÃ¡ al final de
			este.
			Los grupos se crean por orden asÃ­ que si creamos "grupo_1" y "grupo_2", los elementos
			incertados en "grupo_1" apareceran por encima de los incertados en el "grupo_2"
				
			Propiedades objeto parametro.
			
			formManagerInstance.addInput({
				/
					Puede recibir cualquiera de las propiedades de un elemento input
					tal como si las aplicaramos sobre el mismo elemto.
					NO admite style, pero si className
				/
				'id'			: Id del elemento,
				'name'			: Nombre del elemento,
				'size'			: Longitud del elemento,
				'checked'		: Si estarÃ¡ checkeado o no,
				// ...
				'text'			: seÃ±ala un texto que que acompaÃ±arÃ¡ al input,
				'textPosition'	: Posicion del texto. Admite cuatro valores: 'left','right','below','above'. "Above se aplicarÃ¡ por defecto",
				'textClassName'	: Clase CSS que se le aplicarÃ¡ al texto,
				'group'			: grupo en el que se incluirÃ¡ el input. Si el grupo que se indica no existe se crea con ese nombre, si existe
								se aÃ±adirÃ¡ a ese grupo. Si no se indica se crearÃ¡ un nuevo grupo con el nombre "group_x", donde x es el numero
								de grupo.
			});
*/
function jsFormManager(p)
	{
	this.rootDiv = js.create("div");
	this.form = js.create("form");
	this.rootDiv.appendChild(this.form);
	this.inputsNumber = 0;
	this.inputs = [];
	/*
		Configuracion del formulario
	*/
	this.form.id = p.id;
	if(p.method)this.form.method = p.method;
	if(p.name)this.form.name = p.name;
	if(p.action)this.form.action = p.action;
	if(p.enctype)this.form.enctype = p.enctype;
	/*
		Interfaces
	*/
	this.appendTo = interfaces.appendTo;
	
	/*
		Configuracion de la instancia
	*/
	if(p.appendTo)this.appendTo(p.appendTo);
	/*
		Propiedades
	*/
	this.groups = [];
	/*
		Metodos
	*/
	this.groupExist = function(gId)
		{
		for(var i=0;i<this.groups.length;i++)
			{
			if(this.groups[i].id == gId)return i;
			}
		return false;
		}
	
	this.createGroup = function(id)
		{
		var groupDiv = document.createElement("div");
		groupDiv.id = (id) ? id : 'group_'+this.groups.length;
		this.groups.push(groupDiv);
		this.form.appendChild(groupDiv);
		return (this.groups.length - 1);
		}
	
	this.appendToGroup = function(group,div)
		{
		var gIndex = this.groupExist(group);
		if(typeof(gIndex) == "number")
			{
			this.groups[gIndex].appendChild(div);
			}
		else
			{
			gIndex = this.createGroup(group);
			this.groups[gIndex].appendChild(div);
			}
		return gIndex;
		}
		
	this.addInput = function(p)
		{
		if(!p)p = {};
		var div = js.create("div");
		var input = HTMLInput(p);
		div.appendChild(input);
		/*
			Si se ha especificado un texto que acompaÃ±e al input lo creamos e insertamos
		*/
		if(p.text)
			{
			var span = js.create("span");
			var text = js.create(p.text,true);
			if(p.textClassName)span.className = p.textClassName;
			span.style.verticalAlign = "top";
			span.appendChild(text);
			switch(p.textPosition)
				{
				case 'left':
					div.insertBefore(span,input);
					break;
				case 'right':
					div.appendChild(span,input);
					break;
				case 'below':
					var textDiv = js.create("div");
					textDiv.appendChild(span);
					div.appendChild(textDiv,input);
					break;
				default:
					var textDiv = js.create("div");
					textDiv.appendChild(span);
					div.insertBefore(textDiv,input);
					break;
				}
			}
		
		var gIndex = this.appendToGroup(p.group,div);
		return {
			'input'		: input,
			'div'		: div,
			'group'		: this.groups[gIndex],
			'remove'	: function()
				{
				this.group.removeChild(div);
				}
			};
		}
	}
	
/************************************************************************************************************************
			clase formValidador v1.3
			
			validador de formularios
			
				por flasbak (flasbak@xaicom.es)
					
	Por favor, documenta cualquier cambio, metodo que hagas y no olvides firmarlo.
			
	Esta clase valida un formulario cuyo nombre se le pasa como unico parametro al instanciar el objeto.
		
		Ej: var validador = new formValidador("nombre_formulario");
		
-DEPENDENCIAS-

	Aunque en principio esta clase depende del metodo js.stringToObject en el objeto js, la llamada
	a este metodo se produce en la primera instruccion del constructor (formValidador), por lo que
	se puede cambiar

-PROPIEDADES-

	Existen dos propiedades interesantes para el programador. Estas son invalidClass y checkboxInvalidClass.
	 - La primera contiene la clase CSS que se aplicara a los elementos del formulario tales como inputs tipo texto
	   o textareas que sean declaradas como invalidas.
	 - La segunda contiene una clase CSS que se aplicara a todas las etiquetas <label> relacionadas con un checkbox
	   de manera que seÃ±ale que ese checkbox a sido declarado invalido.
	   
	   Resulta obvio que la etiqueta label deve estar relacionada con el checkbox usando su atributo for:
	   
	  	<input name="checkbox" type="checkbox" id="acepto@" />
		
		<label for="acepto@" id="etiqueta">
			Marque esta casilla
		</label>
		
		Ej:  validador.invalidClass			= "invalid-input";
		Ej:  validador.checkboxInvalidClass	= "invalid-checkbox";
	
	De esta manera se resaltaran los campos que sean delcarados invalidos.
	
	La forma en la que se le indica al objeto como se deven validar los elementos input es mediante los mismos
	atributos id de los input.
		
		Ej: <input type="text" class="input" name="nombre" id="nombre@@text" />
		
	Esto le indicara al objeto que para este input se requiere contenido de tipo texto.
	Las dos '@' le indican al metodo que ese campo es obligatorio. Es digamos, el modo estricto,
	aparte de validar requiere contenido para el campo.
	Para ser un poco mas flexibles podriamos utilizar.
	
		Ej: <input type="text" class="input" name="nombre" id="nombre@text" />
		
	De esta forma dara como valido el campo tambien si esta vacio.
	
	
-METODO-

	El unico metodo disponible para el programador es validateForm. Este metodo repasa todos los elementos input
	del formulario comparando su contenido con unas expresiones regulares predefinidas en la clase.
		
		Uso:  validador.validateForm();
	
	Este metodo devolvera false si un campo se ha declarado como invalido y true si todos cumplian
	las normas de validacion.

	
	Ejemplos de validaciones:
		
		id-string@			-> Se requiere alfanumerico(INPUT), contenido(TEXTAREA) o checked = true(CHECKBOX)
		id-string@@text		-> Texto obligatorio
		id-string@phone		-> Numeros de telefono o vacio
		id-string@@email	-> Direccion e-mail obligatoria
		
	Las validaciones disponibles en un pricipio son:
		
		@			-> Campo requerido
		@text		-> Texto opcional
		@@text		-> Texto obligatorio
		@phone		-> Telefono opcional
		@@phone		-> Telefono requerido
		@number		-> Numero opcional
		@@number	-> Numero requerido
		@dni		-> DNI opcional
		@@dni		-> DNI requerido
		@Entero		-> (Solo password) Valido si longitud del campo es mayor o igual a Entero.
		
	
	AÃ±adir mas formas de validacion resultaria sencillo. Esto se haria aÃ±adiendo apartados "case"
	en la sentencia "switch" del metodo validaExpre.

*************************************************************************************************************************/
function formValidador(formId)
	{
	//Almacena el formualrio a validar
	this.formInputs = js.stringToObject(formId).elements;
	
	//Alamcena la clase que se aplicara a un campo cuando sea declarado invalido
	this.invalidClass = null;
	//Alamcena la clase que se aplicara a un texto label relacionado a un checkbox
	this.checkboxInvalidClass = null;
	
	this.fieldsPreClases = new Array();
	
	this.invalidField = function(field,estilo)
		{
		if(field.className != estilo)
			{
			if(field.className)
				{
				this.fieldsPreClases.push([field.id,field.className]);
				}
			else
				{
				this.fieldsPreClases.push([field.id,'']);
				}
			}
		field.className = estilo;
		}
		
	this.validField = function(field)
		{
		for(i=0;i<this.fieldsPreClases.length;i++)
			{
			if(this.fieldsPreClases[i][0] == field.id)
				{
				field.className = this.fieldsPreClases[i][1];
				this.fieldsPreClases.splice(i,1);
				}
			}
		}
		
	//Comprueba formato del elemento
	this.validaExpre = function(elemento)
		{
		var expre = new RegExp();
		/*
		Seleccionamos una expresion regular dependiendo del tipo de validacion requerida
		*/
		switch(elemento.id.substring(elemento.id.indexOf('@')))
			{
			//Campos obligatorios
			case '@@text':	//TEXTO
				expre = /^[a-zA-Z\.\,\s]+$/;
				break;
			case '@@phone':	//TELEFONO
				expre = /^([0-9\s\+\-])+$/;
				break;
			case '@@email':	//E-MAIL
				expre = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4})+$/;
				break;
			case '@@number'://NUMERICO
				expre = /^([0-9])+$/;
				break;
			case '@@dni':	//DNI
				expre = /^([0-9]{8})(\-*)([a-zA-Z]{1})+$/;
				break;
			case '@@':		//CONTENIDO
				expre = /^([\w\W\s])+$/;
				break;
			
			//Campos no obligatorios
			case '@text':	//TEXTO
				expre = /^[a-zA-Z\.\,\s]*$/;
				break;
			case '@phone':	//TELEFONO
				expre = /^([0-9\s\+\-])*$/;
				break;
			case '@email':	//E-MAIL
				expre = /^(\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4}))*$/;
				break;
			case '@number':	//NUMERICO
				expre = /^([0-9])*$/;
				break;
			case '@dni':	//DNI
				expre = /^(([0-9]{8})(\-*)([a-zA-Z]{1}))*$/;
				break;
			case '@':		//CONTENIDO
				expre = /^([\w\W\s])*$/;
				break;
			}
		
		// comprobamos la validez del campo actual
		if(expre.test(elemento.value))
			{
			return true;
			}
		else
			{
			return false;
			}
		}
		
	//Comprueba la longitud de un campo
	this.validaLongitud = function(elemento,longitud)
		{
		if(elemento.value.length >= parseInt(longitud))
			{
			return true;
			}
		else
			{
			return false;
			}
		}
	
	//valida el formulario
	this.validateForm = function()
		{
		var validez = true;
		for(x=0;x<this.formInputs.length;x++)
			{
			//comprueba que el campo requiera validacion
			if(this.formInputs[x].id.indexOf('@') == -1)
				{
				continue;
				}
// INPUT TEXT
			else if(this.formInputs[x].tagName == 'INPUT' && this.formInputs[x].type == 'text')
				{
				var cadena_sub_id = this.formInputs[x].id.substring(this.formInputs[x].id.lastIndexOf('@')+1);
				if(isNaN(cadena_sub_id) || cadena_sub_id == '')
					{
					if(this.validaExpre(this.formInputs[x]))
						{
						this.validField(this.formInputs[x]);
						}
					else
						{
						validez = false;
						this.invalidField(this.formInputs[x],this.invalidClass);
						}
					}
				else
					{
					if(this.validaLongitud(this.formInputs[x],cadena_sub_id))
						{
						this.validField(this.formInputs[x]);
						}
					else
						{
						validez = false;
						this.invalidField(this.formInputs[x],this.invalidClass);
						}
					}
				}
// TEXTAREA
			else if(this.formInputs[x].tagName == 'TEXTAREA')
				{
				if(this.formInputs[x].value != '')
					{
					this.validField(this.formInputs[x]);
					}
				else
					{
					validez = false;
					this.invalidField(this.formInputs[x],this.invalidClass);
					}
				}
// CHECKBOX
			else if(this.formInputs[x].tagName == 'INPUT' && this.formInputs[x].type == 'checkbox')
				{
				if(!this.formInputs[x].checked)validez = false;

				var etiquetas = document.getElementsByTagName('LABEL');
				for(e = 0;e<etiquetas.length;e++)
					{						
					if(etiquetas[e].htmlFor == this.formInputs[x].id)
						{
						if(this.formInputs[x].checked)
							{
							this.validField(etiquetas[e]);
							}
						else
							{
							this.invalidField(etiquetas[e],this.checkboxInvalidClass);
							}
						}
					}
				}
// PASSWORD
			else if(this.formInputs[x].tagName == 'INPUT' && this.formInputs[x].type == 'password')
				{
				var cadena_sub_id = this.formInputs[x].id.substring(this.formInputs[x].id.lastIndexOf('@')+1);
				if(this.validaLongitud(this.formInputs[x],cadena_sub_id))
					{
					this.validField(this.formInputs[x]);
					}
				else
					{
					validez = false;
					this.invalidField(this.formInputs[x],this.invalidClass);
					}
				}
			else
				{
				continue;
				}
			}	
		return validez;
		};
	}


/*----------------------------------------------------

	CON EFECTOS

----------------------------------------------------*/
/*
	Muestra el contenido de una capa como si se desliara desde arriba
*/
function jsTopSlider(P)
{
	this.applyTo = js$(P.applyTo);
	this.contentDiv = this.applyTo.firstDescendant();
	this.jumpSize = P.jumpSize || 5;
	this.time = P.time || 15;
	this.minHeight = P.minHeight || 0;
	this.sliderStatus = P.status || "close";
	this.Working = function()
	{
		if(this.interval)
			return true;
		else
			return false;
	}
		
	var slider = this;
	if(P.closeControl)
	{
		P.closeControl.respondsToEvent(new Responder(function(){slider.Switch();},"click"));
	}
	
	//Propiedades privadas
	this.jsFuncIndex = js.intervalFunc(this);
	this.tempHeight = this.applyTo.offsetHeight;
	
	this.Open = function()
	{
		if(this.Working())return false;
		if(this.tempHeight >= this.expandSize)return false;
		this.expandSize = this.contentDiv.offsetHeight;
		this.interval = setInterval("js.intervalFunctions["+this.jsFuncIndex+"].Opn()",this.time);
		this.sliderStatus = "open";
	}
		
	this.Close = function()
	{
		if(this.Working())return false;
		if(this.tempHeight <= this.minHeight)return false;
		this.expandSize = this.contentDiv.offsetHeight;
		this.interval = setInterval("js.intervalFunctions["+this.jsFuncIndex+"].Cls()",this.time);
		this.sliderStatus = "close";
	}
		
	this.Switch = function()
	{
		if(this.sliderStatus == "close")
			this.Open(E);
		else
			this.Close(E);
	}
		
	/*
		Metodos privados
	*/
	this.Opn = function()
	{
		this.tempHeight += this.jumpSize;
		if(this.tempHeight >= this.expandSize)
		{
			clearInterval(this.interval);
			delete this.interval;
			this.applyTo.style.height = this.expandSize+"px";
			this.tempHeight = this.expandSize;
			return;
		}
		this.applyTo.style.height = this.tempHeight+"px";
	}

	this.Cls = function()
	{
		this.tempHeight -= this.jumpSize;
		if(this.tempHeight <= this.minHeight)
		{
			clearInterval(this.interval);
			delete this.interval;
			this.applyTo.style.height = this.minHeight+"px";
			this.tempHeight = this.minHeight;
			return;
		}
		this.applyTo.style.height = this.tempHeight+"px";
	}
}
/*
	slideMenuBar
*/
function jsSlideMenuBar(P)
	{
	this.rootDiv = js.create("div");
	this.contDiv = js.create("div");
	this.rootDiv.className = "js-sliderMenu-rootDiv";
	this.contDiv.className = "js-sliderMenu-contDiv";
	if(P.closeHeight)this.rootDiv.style.height = P.closeHeight+"px";
	this.rootDiv.appendChild(this.contDiv);
	
	this.controls = [];
	
	this.sliderControl = new jsTopSlider({
		applyTo : this.rootDiv,
		minHeight : P.closeHeight || 10,
		jumpSize : P.jumpSize || 7
		});
	this.delay = new Delay({
		func : this.sliderControl,
		exec : "Open",
		delay : 250
		});
	
	var sliderControl = this.sliderControl;
	var delay = this.delay;
	
	if(P.openOnMouseOver)
		{
		this.rootDiv.addEventListener("mouseover",function()
			{
			if(sliderControl.sliderStatus == "open")return;
			delay.start();
			},false);
		this.rootDiv.addEventListener("mouseout",function()
			{
			if(sliderControl.sliderStatus == "open")return;
			delay.clear();
			},false);
		}
	
	if(P.selfCloseControl)
		{
		this.rootDiv.addEventListener("click",function()
			{
			sliderControl.Close();
			},false);
		}
	if(P.closeControl)
		{
		js$(P.closeControl).addEventListener("click",function()
			{
			sliderControl.Switch();
			},false);
		}
	this.addControl = interfaces.appendToMe;
	if(P.appendTo)js$(P.appendTo).appendChild(this.rootDiv);
	}
/*
	jsLoadBar
*/
function jsProgressBar(P)
	{
	this.rootDiv = js.create("div");
	this.bgDiv = js.create("div");
	this.percentage = 0;
	this.viewPercentage = (P.viewPercentage !== false);
	this.blinkOnReady = (P.blinkOnReady !== false);
	this.percentageOut = P.percentageOut || false;
		
	this.rootDiv.className = "js-loadBar-rootDiv";
	this.bgDiv.className = this.bgNormalStyle;

	this.rootDiv.appendChild(this.bgDiv);
	
	/*
		Interfaces
	*/
	this.appendTo = interfaces.appendTo;
	this.destroyNodes = interfaces.destroyNodes;
	
	this.use3D = function(use)
		{
		if(use)
			{
			this.bgNormalStyle = "js-loadBar-bg js-loadBar-bg-3D";
			this.bgReadyStyle = "js-loadBar-bg-ready js-loadBar-bg-ready-3D";
			}
		else
			{
			this.bgNormalStyle = "js-loadBar-bg js-loadBar-bg-plain";
			this.bgReadyStyle = "js-loadBar-bg-ready js-loadBar-bg-ready-plain";
			}
		}
	
	this.nodes = function()
		{
		return [this.bgDiv,this.rootDiv];
		}
	
	this.isComplete = function()
		{
		return (this.percentage >= 100);
		}
	
	this.setWidth = function(width)
		{
		this.width = width;
		this.rootDiv.style.width = width+"px";
		}
		
	this.setPercent = function(percentage)
		{
		if(this.percentage == percentage)return;
		this.percentage = percentage;
		var rw = ((this.rootDiv.clientWidth - 2) / 100) * percentage;		
		if(rw < 0)rw = 0;
		if(rw > this.width)rw = (this.rootDiv.clientWidth - 2);
		this.bgDiv.style.width = rw+"px";
		this.viewPercent();
		this.setReadyStyle();
		}
		
	this.viewPercent = function()
		{
		removeChilds(this.bgDiv);
		if(!this.viewPercentage)return;
		var span = js.create("span");
		if(this.percentageOut)
			{
			span.style.background = "#FFF";
			span.style.color = (this.isComplete() && this.blinkOnReady) ? "#093" : "#06C";
			}
		var perText = js.create(this.percentage+"%",true);
		span.appendChild(perText);
		this.bgDiv.appendChild(span);
		}
		
	this.setReadyStyle = function()
		{
		if(this.isComplete() && this.blinkOnReady)
			{
			this.rootDiv.className = "js-loadBar-rootDiv-ready";
			this.bgDiv.className = this.bgReadyStyle;
			}
		else
			{
			this.rootDiv.className = "js-loadBar-rootDiv";
			this.bgDiv.className = this.bgNormalStyle;
			}
		}
	
	this.use3D((P.use3D !== false));
	this.setWidth(P.width || 300);
	this.viewPercent();
	this.setReadyStyle();
	if(P.appendTo)this.appendTo(P.appendTo);
	}
	
function jsSwitch(P)
	{
	this.img = js.create("img");
	this.onImage = P.onImage;
	this.offImage = P.offImage;
	this.status = P.status || "off";
	this.img.src = (this.status == "on") ? P.onImage : this.offImage;
	this.img.className = P.className || "js-pointer";
	/*
		Interfaces
	*/
	this.respondsToEvent = interfaces.respondsToEvent;
	this.appendTo = interfaces.appendTo;
	this.Switch = function()
	{
		if(this.status == "on")
		{
			this.img.src = P.offImage;
			this.status = "off";
		}
		else
		{
			this.img.src = P.onImage;
			this.status = "on";
		}
	}
	var sw = this;
	this.respondsToEvent({
		type : "click",
		func : function(){sw.Switch();}
		});
	if(P.appendTo)this.appendTo(P.appendTo);
	}

function jsResizer(P)
{
	if(!P)P={};
	/*
		Publicas
	*/
	this.applyTo = false;
	this.endSize = null;
	this.jumps		= P.jumps		|| 20;
	this.timer		= P.timer		|| 15;
	/*
		Privadas
	*/
	this.tempSize = 0;
	this.interval = null;
	this.jsObjectIndex = js.intervalFunc(this);
	this.working = false;

	
	this.resize = function(P)
	{
		if(this.working)return;
		this.applyTo = js$(P.applyTo);
		this.endSize = P.endSize;
		
		switch(P.resizeMode)
		{
			case 'H':
				break;
			default:
				if(this.applyTo.offsetHeight > this.endSize)
				{
					this.jumpSize = (this.applyTo.offsetHeight - this.endSize) / this.jumps;
					this.tempSize = this.applyTo.offsetHeight;
					this.working = true;
					this.interval = setInterval("js.intervalFunctions["+this.jsObjectIndex+"].VCont()",this.timer);
				}
				else
				{
					this.jumpSize = (this.endSize - this.applyTo.offsetHeight) / this.jumps;
					this.tempSize = this.applyTo.offsetHeight;
					this.working = true;
					this.interval = setInterval("js.intervalFunctions["+this.jsObjectIndex+"].VExpa()",this.timer);
				}
				break;
		}
	}
	
	this.Stop = function()
	{
		clearInterval(this.interval);
		this.working = false;
	}
	
	this.VCont = function()
	{
		this.tempSize -= this.jumpSize;
		if(this.tempSize <= this.endSize)
		{
			this.Stop();
			this.applyTo.style.height = this.endSize+"px";
			return;
		}
		this.applyTo.style.height = this.tempSize+"px";
	}
	
	this.VExpa = function()
	{
		this.tempSize += this.jumpSize;
		if(this.tempSize >= this.endSize)
		{
			this.Stop();
			this.applyTo.style.height = this.endSize+"px";
			return;
		}
		this.applyTo.style.height = this.tempSize+"px";
	}
}

/*
	Muestra u oculta un elemento prograsivamente.
	
	Metodos
	Show('elemento a mostrar');
	Hide('elemento a ocultar');
*/
function jsAppear(P)
{
	if(!P)P={};
	/*
		Obtenemos el identificador js
	*/
	this.jsObjectIndex = js.intervalFunc(this);
	this.working = false;
	
	this.timer = P.timer || 25;
	this.opacityJump = P.opacityJump || 0.1;
	this.changeDisplay = (P.changeDisplay) ? P.changeDisplay : false;
	
	this.Show = function(E)
	{
		if(this.working)return;
		if($(E).getOpacity() == 1)return;
		this.workingOn = $(E);
		if(this.changeDisplay)this.workingOn.show();
		this.working = true;
		this.interval = setInterval("js.intervalFunctions["+this.jsObjectIndex+"].ShowObject()",this.timer);
	}
	
	this.Hide = function(E)
	{
		if(this.working)return;
		if($(E).getOpacity() == 0)return;
		this.workingOn = $(E);
		this.working = true;
		this.interval = setInterval("js.intervalFunctions["+this.jsObjectIndex+"].HideObject()",this.timer);
	}
	
	this.Stop = function()
	{
		clearInterval(this.interval);
		this.working = false;
		if(this.changeDisplay && this.workingOn.getOpacity() == 0)this.workingOn.hide();
	}
	
	this.ShowObject = function()
	{
		this.tempOp = this.workingOn.getOpacity() + this.opacityJump;
		if(this.tempOp >= 1)
		{
			this.workingOn.setOpacity(1);
			this.Stop();
		}
		this.workingOn.setOpacity(this.tempOp);
	}
	
	this.HideObject = function()
	{
		this.tempOp = this.workingOn.getOpacity() - this.opacityJump;
		if(this.tempOp <= 0)
		{
			this.workingOn.setOpacity(0);
			this.Stop();
		}
		this.workingOn.setOpacity(this.tempOp);
	}
}

/*
	jsMouseTag

	crea una capa que sigue al raton.	
	
	Parametros:
		smoothAppear	: (bool) Indica si la capa aparecera progresibamente o de golpe
		tagClass		: (string) Clase CSS que se le aplicara a la capa
		keepIndideWindow: (bool) Si es true, la capa nunca saldra del area visible de la ventana
		
	Propiedades:
		tagDiv			: Almacena una referencia a la capa
		isVisible		: (bool) Indica si la capa es visible
		
	Metodos:
		Show(Evento)	: Muestra la capa. Recive el evento que a disparado el metodo como parametro que posiciona la capa antes de mostrarla.
		Hide()			: Oculta la capa. No recibe parametros
		
*/
function jsMouseTag(P)
{
	if(!P)P={};
	/*
		Obtenemos un jsAppear para conseguir que el tag aparezca difuninado
	*/
	
	this.jsObjectIndex = js.intervalFunc(this);
	this.isVisible = false;
	
	this.tagDiv = js.create("div");
	this.smoothAppear = (P.smoothAppear) ? true : false;
	this.keepIndideWindow = (P.keepIndideWindow) ? true : false;
	
	if(this.smoothAppear)
	{
		this.appear = new jsAppear({
			changeDisplay : true,
			opacityJump : 0.2
		});
	}
	
	if(P.tagClass)
		this.tagDiv.className = P.tagClass;
	
	this.tagDiv.style.position = "absolute";
	
	var jsObjectIndex = this.jsObjectIndex;
	js.respondsToEvent({
		element : document,
		type : "mousemove",
		func : function(Ev){
			js.intervalFunctions[jsObjectIndex].followMouse(Ev);
		}
	});
	
	this.followMouse = function(Ev)
	{
		if(!this.isVisible)
			return;
		
		var posX = (Ev.pageX + 20);
		var posY = (Ev.pageY + 3);
		
		if(this.keepIndideWindow)
		{
			if((posX + this.tagDiv.offsetWidth) > window.innerWidth)
				posX -= (this.tagDiv.offsetWidth + 25);
				
			if((posY + this.tagDiv.offsetHeight) > window.innerHeight)
				posY -= (this.tagDiv.offsetHeight + 5);
		}
		
		this.tagDiv.style.left = posX + "px";
		this.tagDiv.style.top = posY + "px";
	}
	
	this.Show = function(Ev)
	{
		this.isVisible = true;
		if(Ev)
			this.followMouse(Ev);
		
		if(this.appear)
			this.appear.Show(this.tagDiv);
		else
			this.tagDiv.show();
	}
	
	this.Hide = function()
	{
		if(this.appear)
			this.appear.Hide(this.tagDiv);
		else
			this.tagDiv.hide();
		
		this.isVisible = false;
	}

	this.Hide();
	document.body.appendChild(this.tagDiv);
}
