// 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="img/fleche.gif" alt="oui" height="32" width="32" style="margin:0 5px"/>';
							non = '<img src="img/fleche.gif" alt="non" 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] = "ce champ ne peut pas être vide";
		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] = "";
			return true;
		}		
		
		return false;
		
	}
