// JavaScript Document




/*----------------------------------------------------------------------------------------------------------------------*
 *                                                                                                                      *
 *                                                VALIDATION DE FORMULAIRES                                             *
 *                                                                                                                      *
 *----------------------------------------------------------------------------------------------------------------------*/






/*  Ce module valide les champs (input, textarea ou select) d'un ou de plusieurs formulaires d'une page html.
	Chaque champ Ã  valider doit Ãªtre dÃ©clarÃ© avec l'un des noms de classe suivants :
		"ident", "passe", "conf", "nom", "tel", "@", "cp"
	A chacune de ces classes correspond une ou plusieurs expressions rationnelles de filtrage, ainsi que le ou les messages de rejet correspondant.
	Il permet l'affichage, dans la page ou dans une boÃ®te d'alerte, d'un message global listant les raisons des rejets, ainsi que
	l'affichage pour chaque champ non valide du motif de rejet qui le concerne et/ou d'un symbole 'ok' ou 'rejet'
	
	Principes de validation :
		- Les champs dont le nom est dans la liste des champs obligatoires seront invalides si :
				. champ texte (text et textarea) : est Ã©gal Ã  une chaÃ®ne vide
				. cases Ã  cocher ou les boutons radio (checkbox et radio) : sont tous dÃ©cochÃ©s
				. listes dÃ©roulantes (select) : l'option sÃ©lectionnÃ©e est celle qui correspond Ã  la valeur 0, null ou chaÃ®ne vide
		- Les champs des classes listÃ©es ci-dessus doivent correspondre au Filtre imposÃ© par l'expression rationelle correspondante 
		- Le champ de classe 'conf' (confirmation de mot de passe) doit Ãªtre identique au champ de classe 'passe'.


	/*----------------------------------------------- MISE EN OEUVRE ---------------------------------------------------

	Dans la page html du formulaire :
	
	1- Dans l'entÃªte (head), faire rÃ©fÃ©rence Ã  ce script :
								<script type="text/javascript" src="valide_form.js"></script>
	
	2- Dans la balise 'body', appeler dans l'attribut 'onload' la fonction d'initialisation autant de fois qu'il y a de formulaires Ã  valider :
	   Un formulaire : 		<body onload="ini_form(idForm, surSaisie, surSoumis, listeChampsOblig)">
	   Plusieurs formulaires :	<body onload="ini_form(idForm1, surSaisie, surSoumis, listeChampsOblig); ini_form(idForm2, ..., ..., ...); ini_form(idForm3, ...);">
	   oÃ¹ :
	   		idForm : 	l'id du formulaire Ã  valider.				Exemple : 'monFormulaire'
			surSaisie :	chaÃ®ne composÃ©e de lettres indiquant les effets dÃ©sirÃ©s lors de la saisie de chaque champ :
							""  : aucun effet, 
							"s" : affichage d'un symbole 'ok' ou 'rejet' Ã  proximitÃ© du champ
							"t" : affichage du texte expliquant le rejet Ã  proximitÃ© du champ
						Exemple : "st" : affichage du symbole et du texte (dans cet ordre)
			surSoumis : chaine  composÃ©e de lettres indiquant les effets dÃ©sirÃ©s lors de la soumission du formulaire :
							""  : aucun effet
							"s" : affichage d'un symbole ok ou rejet Ã  proximitÃ© de chaque champ
							"t" : affichage du texte expliquant le rejet Ã  proximitÃ© de chaque champ
							"b" : affichage les messages de rejet en bloc
							"a" : affichage les messages de rejet dans une fenÃªtre d'alerte
						Exemple "sa" : affichage du symbole 'ok' ou 'rejet' en face de chaque champ, et boÃ®te d'alerte avec l'ensemble des messages.
			listeChampsOblig : liste des champs obligatoires.
						Exemple : 'nom', 'prenom', 'courriel', 'tel', 'adresse', 'cp', 'commune'
	   Exemple :	<body onload="ini_form('monFormulaire', 'st', 't', 'nom', 'prenom', 'courriel', 'tel', 'adresse', 'cp', 'commune')">

	3- Affecter Ã  chaque champ de saisie Ã  valider 
			- une classe (attribut 'class') parmi celles ci-dessus, qui conditionne le Filtre de saisie.
			- un nom (attribut 'name') si sa saisie est obligatoire
						Exemple :  <input type="text" name="pseudo" class=""ident" />
	
	4- S'il y a un effet 's' ou 't' Ã  la saisie ou Ã  la soumission, crÃ©er des zones de messages (par exemple span, p, td, ..) Ã  proximitÃ© de
			chacun des champs de saisie. Ces zones doivent avoir comme id : "msg_[nom du formulaire]_[nom du champ]".
						Exemple :  <span id="msg_form1_ident></span>
	   S'il y a un effet 'b' Ã  la soumission, crÃ©er une zone de message global (par exemple div, td) Ã  l'endroit voulu. 
	   		Elle doit avoir comme id : 'msg_[nom du formulaire]'
						Exemple :  <td id="msg_form1"></span>
					
	5- Modifier si besoin est les expressions rationnelles et les messages correspondant Ã  chacune des classes de validation. Voir ci-dessous.
	
	/*------------------------------------------------------------------------------------------------------------------------------------------*/
	
	

	// Quelques Filtres usuels (Na = non accentuÃ©)
	//PasLettre = /[\x00-\x40\x5B-\x60\x7B-\xBF]/;
	//LettresNa = /^[\x41-\x5A\x61-\x7A]+$/;
	//LettresNaChiffres = /^[\x30-\x39\x41-\x5A\x61-\x7A]+$/;
	//Lettres = /^[\x41-\x5A\x61-\x7A\xC0-\xD6\xD8-\xF6\xF8-\xFF]+$/;
	//LettresChiffres = /^[\x30-\x39\x41-\x5A\x61-\x7A\xC0-\xD6\xD8-\xF6\xF8-\xFF]+$/;
	//LettrePuisLettresChiffres = /^[\x41-\x5A\x61-\x7A\xC0-\xFF]([\x30-\x39\x41-\x5A\x61-\x7A\xC0-\xFF]|\d)*$/;        



	//Initialisation des Filtres et des textes de messages
	var Textes;	
	var Filtres;
	function ini_filtres()
	{
		Textes = new Array();
		Filtres = new Array();
		Textes['ident'] 	= new Array();		Filtres['ident'] 	= new Array();
		Textes['passe'] 	= new Array();		Filtres['passe'] 	= new Array();
		Textes['nom'] 		= new Array();		Filtres['nom'] 		= new Array();
		Textes['tel'] 		= new Array();		Filtres['tel']  	= new Array();
		Textes['@'] 		= new Array();		Filtres['@'] 		= new Array();
		Textes['cp'] 		= new Array();		Filtres['cp'] 		= new Array();
		
		
		
	/*------------------------------------------- MODIFIER CI-DESSOUS LES FILTRES ET LES MESSAGES ---------------------------------------------------*/
		
		// Identifiant
		Textes['ident'][0] 	= "Seuls sont acceptÃ©s les lettres et chiffres. Le premier caractÃ¨re doit Ãªtre une lettre.";
		Filtres['ident'][0] = /^[\x41-\x5A\x61-\x7A\xC0-\xFF]([\x30-\x39\x41-\x5A\x61-\x7A\xC0-\xFF]|\d)*$/;
		
		// Mot de passe
		Textes['passe'][0] 	= "Seuls sont acceptÃ©s les lettres non accentuÃ©es et les chiffres.";
		Filtres['passe'][0] = /^[a-zA-Z0-9]*$/;
		Textes['passe'][1] 	= "Le mot de passe doit comporter entre 4 et 12 caractÃ¨res.";
		Filtres['passe'][1] = /^.{4,12}$/;
		
		// Nom, prÃ©nom
		Textes['nom'][0] 	= "Les seuls symboles autorisÃ©s sont : espace, apostrophe, trait d'union et point.";
		Filtres['nom'][0] 	= /^[\x30-\x39\x41-\x5A\x61-\x7A\xC0-\xD6\xD8-\xF6\xF8-\xFF '\-\.]+$/;
		Textes['nom'][1] 	= "Ce champ doit commencer par une lettre.";
		Filtres['nom'][1] 	= /^[\x41-\x5A\x61-\x7A\xC0-\xD6\xD8-\xF6\xF8-\xFF]/;	
		
		// NumÃ©ro de tÃ©lÃ©phone
		Textes['tel'][0] 	= "Seuls sont acceptÃ©s le signe + (en tÃªte), les parenthÃ¨ses et l'espace simple (hors parenthÃ¨ses).";
		Filtres['tel'][0] 	= /^\+?( ?(\(\d+\)|\d+))+$/;
		Textes['tel'][1] 	= "Les numÃ©ros nationaux ont 10 chiffres, les internationaux commencent par +.";
		Filtres['tel'][1] 	= /^\+|^.{10}$/;

		// Adresse Ã©lectronique
		Textes['@'][0]		= "Champ non valide";
		Filtres['@'][0]		= /^[\w][\w\.-]*@[\w\.-]+\.[\w]+$/;
		
		//Code postal
		Textes['cp'][0]		= "Le code postal doit comporter 5 chiffres sans espace.";
		Filtres['cp'][0]		= /^\d{5}$/;

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

}



		var ListesOblig;
		var OnChanges;
		var OnSubmits;
		var Passe;

	function ini_form()
	{
		var args, IdForm, TypeAlerte, ListeOblig, Formulaire, Champs, i;
		args = ini_form.arguments;
		IdForm = args[0];
		OnChange = args[1];
		OnSubmit = args[2];
		ListeOblig = new Array();
		for(i=0; i<args.length-3;i++)
			ListeOblig[i]=args[3+i];

		if(typeof(ListesOblig)=="undefined")
		{
			ListesOblig = new Array();
			OnChanges = new Array();
			OnSubmits = new Array();
		}
		ListesOblig[IdForm] = ListeOblig;
		OnChanges[IdForm] = OnChange;
		OnSubmits[IdForm] = OnSubmit;
		
		Formulaire = document.getElementById(IdForm);
		
		if(OnChange)
		{
			Champs = Formulaire.elements;
			if(navigator.appName=="Netscape")	
				for(i=0; i<Champs.length; i++)
					Champs[i].setAttribute("onchange", "javascript: return valide_champ(this, '" + IdForm + "')");
			else
				for(i=0; i<Champs.length; i++)
					Champs[i].onchange = function(){return valide_champ(this, IdForm);}
		}
		
		if(OnSubmit)
		{
			if(navigator.appName=="Netscape")	
				Formulaire.setAttribute("onsubmit", "javascript: return valide_form(this.id)");
			else
				Formulaire.onsubmit = function(){return valide_form(this.id);};
		}
	}




	function valide_champ(Champ, IdForm, Message, Valide, groupes_cases)
	{
		var NomChamp, Texte, Oblig, SurEven, ChampMsg, j;
		
		NomChamp = Champ.name;
		Classe = Champ.className;
		
		// Si valide_champ est appelÃ© directement, Message n'est pas dÃ©fini.
		// Si il est appelÃ© dans la boucle de valide_form, Message est dÃ©fini.
		if(typeof(Message)=="undefined")
		{
			Message = new Array();
			Change = true;
		}
		else
			Change = false;
			
		if(typeof(Filtres)=="undefined")
			ini_filtres();

		switch(Champ.type)
		{
			case "text":
			case "textarea":
			case "password":
				Oblig = false;
				// Ce champ est-il dans la liste des champs obligatoires ?
				for (j=0; j<ListesOblig[IdForm].length; j++){
					if (ListesOblig[IdForm][j]==NomChamp)
					{
						Oblig = true;
						break;
					}
				}
				// Faire la validation correspondant au type de champ
				switch (Classe)
				{
					case "passe" :
						Passe = Champ.value;
						if(typeof(Passe)=="undefined")
							Passe = "";
					case "ident" :
					case "nom" :
					case "tel" : 
					case "@" :
					case "cp" :
						Valide = validateur(Champ, Message, Oblig) && Valide;
						break;
					case "conf":
						if(Champ.value != Passe){
							Message[Champ.name] = "La confirmation ne correspond pas au mot de passe.";
							Valide = false;
						}
						break;
					default:
						Message[NomChamp] = "";
						Valide = !ChampManquant(Champ, Message, Oblig) && Valide;
						break;
				}
				break;
				
			case "checkbox":
			case "radio":
				groupes_cases[NomChamp] = groupes_cases[NomChamp] || Champ.checked;
				break;
			
			case "textarea":
				break;
				
			case "select-one":
				Message[NomChamp] = "";
				if(!Champ.selectedIndex){
					Message[NomChamp] = "Veuillez faire un choix";
					Valide = false;
				}
				break;
		}
		
		if(Change)
		{
			SurChange = OnChanges[IdForm];
			Texte = "";
			for (i=0; i<SurChange.length; i++)
			{
				lettre = SurChange.substr(i, 1);
				ChampMsg = document.getElementById("msg_" + IdForm + "_" + NomChamp);;
				switch(lettre)
				{
					// Texte
					case "t":
						Texte += Message[NomChamp];
						break;
					// Symbole
					case "s":
						oui = '<img src="img/oui.gif" alt="oui" height="12"  width="12" style="margin:0 10px"/>';
						non = '<img src="img/non.gif" alt="non" height="12"  width="12" style="margin:0 10px"/>';
						Texte += Message[NomChamp]? non : oui;
						break;
				}

			}
			ChampMsg.innerHTML = Texte;			
		}
		
		return Valide;
	}




	function valide_form(IdForm)
	{
		var Formulaire, NbrChamps, NbrOblig, Champ, NomChamp, NomGroupe, Texte, groupes_cases, i, j;
		var Valide = true;

		Formulaire = document.getElementById(IdForm);
		Champs = Formulaire.elements;
		//Champs = Formulaire.getElementsByTagName('input');
		NbrChamps = Champs.length;
		NbrOblig = ListesOblig[IdForm].length;
		groupes_cases = new Array();
		Message = new Array();
		SurSoumis = OnSubmits[IdForm];
		
		// Pour chacun des champs du formulaire
		for (i=0; i<NbrChamps; i++){
			Champ = Champs[i];
			Valide = valide_champ(Champ, IdForm, Message, Valide, groupes_cases);
		}
		
		for(NomGroupe in groupes_cases){
			// Ce groupe est-il dans la liste des champs obligatoires ?
			Message[NomGroupe] = "";
			Oblig = false;
			for (j=0; j<NbrOblig; j++){
				if (ListesOblig[IdForm][j]==NomGroupe)
				{
					Oblig = true; 
					break;
				}
			}
			Val = groupes_cases[NomGroupe];
			if (Oblig && !Val){
				Message[NomGroupe] = "Veuillez cocher une case.";
				Valide = false;
			}
		}				
		
		// Affichage des messages individuels
		for(nom in Message)
		{
			champ = document.getElementById("msg_" + IdForm + "_" + nom);
			champ.innerHTML = Message[nom];
		}
		
		// Affichage des messages
		if(SurSoumis)
		{
			// Messages individuels
			for(nom in Message)
			{
				ChampMsg = document.getElementById("msg_" + IdForm + "_" + nom);
				Texte = "";
				for (i=0; i<SurSoumis.length; i++)
				{
					lettre = SurSoumis.substr(i, 1);
					switch(lettre)
					{
						// Texte
						case "t":
							Texte += Message[nom];
							break;
						// Symbole
						case "s":
							oui = '<img src="oui.gif" alt="ok" height="32" width="32" style="margin:0 5px"/>';
							non = '<img src="non.gif" alt="" height="32" width="32" style="margin:0 5px"/>';
							Texte += Message[nom]? non : oui;
							break;
					}
					ChampMsg.innerHTML = Texte;
				}
			}
			
			// Message global
			for (i=0; i<SurSoumis.length; i++)
			{
				lettre = SurSoumis.substr(i, 1);
				switch(lettre)
				{
					case "a":
						Texte = "";
						for(nom in Message)
							if(Message[nom])
								Texte += nom + " :\t\t" + Message[nom] + "\n";
						alert(Texte);
						break;
					case "b":
						Texte = "<table style='border-collapse:collapse'>";
						for(nom in Message)
						{
							if(Message[nom])
							{
								Texte += "<tr>";
								Texte += "<td style='padding-right:5px'>" + nom + "</td>";
								Texte += "<td>" + Message[nom] + "</td>";
								Texte += "</tr>";
							}
						}
						Texte += "</table>";
						ChampMsg = document.getElementById('msg_'+ IdForm + '_soumis');
						ChampMsg.innerHTML = Texte;
						break;
				}
			}
			
		}

	return Valide;
		                  
	}



	/* Validation d'un champ
		Retourne vrai si valide.
		Si invalide ou manquant, ajoute une ligne de message et retourne faux.
			Champ :		L'objet champ concernÃ©
			Message : 	Liste des messages retournÃ©s
			Oblig :		BoolÃ©en indiquant si le champ doit Ãªtre rempli.
	*/
	function validateur(Champ, Message, Oblig){
		var Classe, Filtre, i, n, res;
		Message[Champ.name] = "";
		if (ChampManquant(Champ, Message, Oblig)) {return false;}
		
		Classe = Champ.className;
		
		n = Filtres[Classe].length;
		for (i=0; i<n; i++)
		{
			Filtre = Filtres[Classe][i];
			res = Filtre.test(Champ.value);
			if (!res){
				Message[Champ.name] = Textes[Classe][i];
				return false;
			}
		}
		return true;
	}
	
	
	


	/* Indique si le champ n'a pas Ã©tÃ© rempli alors qu'il est obligatoire.
		Si c'est le cas, ajoute une ligne de message et retourne vrai. 
		Sinon retourne faux.
	*/
	function ChampManquant(Champ, Message, Oblig){
		if (Oblig && Champ.value ==""){
			Message[Champ.name] = "Veuillez remplir ce champ.";
			return true;
		}		
		
		return false;
		
	}

