/*************************************************************************
 * verification_formulaire.js
 * Copyright (c) François Pirsch 2007
 * http://aspirine.org/contact/
 * Distribué sous licence BSD.
 *
 *	30 Mars 2007
 *
 * Vérifie automatiquement la validité d'un formulaire avant envoi.
 * Installation :
 * 1. Copier ce fichier sur le site
 * 2. Le lier au fichier HTML contenant le formulaire :
 *   <script type="text/javascript" src="verification_formulaire.js"></script>
 * 3. Mettre onsubmit="return valideForm(this)" au formulaire à vérifier.
 *
 * Dans le formulaire :
 * - L'élément contenant l'adresse email doit s'appeler "email"
 * - S'il y a un champ de confirmation d'adresse email,
 *   il doit s'appeler "email2"
 * - Les champs obligatoires doivent être précédés par le caractère "*".
 *************************************************************************/

function valideForm(f) {
	var champsObligatoires = [];
	var erreurs = [];
	var adresse1;

	/*
	 * Cette fonction renvoie le texte écrit juste avant un élément donné.
	 * Elle parcourt l'arbre du document vers l'arrière jusqu'à trouver
	 * un textNode contenant autre chose que des espaces.
	 */
	function textePrecedent(element) {
		var ELEMENTNODE = 1;
		var TEXTNODE = 3;

		// Ce navigateur connaît-il le DOM ?
		if(!element.nodeType) return "no nodetype";

		// Tant qu'on n'a pas trouvé un textNode contenant autre chose que des espaces...
		while((element.nodeType != TEXTNODE) || (element.nodeValue.search(/^\s*$/) == 0)) {
			// On prend l'élément précédent.
			if(element.previousSibling)
				element = element.previousSibling;
			// S'il n'y a pas d'élément précédent on prend le précédent du parent.
			else if(element.parentNode && element.parentNode.previousSibling)
				element = element.parentNode.previousSibling;
			// On ne peut plus remonter, c'est qu'on n'a rien trouvé, on quitte.
			else return;

			// Si on arrive sur un élément qui a des descendants, on descend pour
			// trouver le texte le plus à droite.
			while((element.nodeType == ELEMENTNODE) && element.lastChild)
				element = element.lastChild;
		}
		return element.nodeValue;
	}

	/*
	 * Fonctions vérifiant la validité et la confirmation d'une adresse email.
	 */
	function valideEmail(adr1) {
		adresse1 = adr1;
		if(adresse1 && !estVide(adresse1)) {
			if(adresse1.length > 100)
				erreurs.push('Cette adresse est trop longue');

			var atom = "[!#-'*+\\-\\/-9=?A-Z^-~]+";
			var regex_adresse =
				new RegExp("^"+atom+"(\\."+atom+")*@"+atom+"(\\."+atom+")*\\.[a-zA-Z]{2,4}$");
			if(adresse1.search(regex_adresse) != 0)
				erreurs.push("Adresse invalide.");

		}
		else if(champsObligatoires["email"])
			erreurs.push("L'adresse email est obligatoire.");
	}

	function confirmeEmail(adresse2) {
		if(adresse2) {
			if(adresse1 && (adresse2 != adresse1))
				erreurs.push("Il y a une faute de frappe entre les deux adresses entrées.");
		}
		else if(champsObligatoires["email2"])
			erreurs.push("La confirmation d'adresse email est obligatoire.");
	}


	/*
	 * Fonction vérifiant qu'un champ est rempli.
	 * On vérifie que la valeur n'est ni vide ni constituée d'un seul caractère répété.
	 */
	function estVide(valeur) {
		return (!valeur || (valeur.search(/^[\n\r]*(.)\1*[\n\r]*$/) >= 0));
	}

	/*
	 * Cette fonction vérifie le formulaire : syntaxe et confirmation de
	 * l'adresse email, présence des champs obligatoires.
	 */
	if(!f) f = document.forms[0];
	erreurs = [];
	adresse1 = '';
	var erreursFatales = [];

	// Vérification des champs obligatoires.
	var nom, node, texte;
	var radios = [];
	var multiples = [];
	for(var i = 0; i < f.elements.length; i++) {
		node = f.elements[i];
		nom = node.name;

		// Ils doivent être précédés d'une étoile.
		texte = textePrecedent(node);
		if(texte && texte.search(/\*\s*$/) >= 0)
			champsObligatoires[nom] = 1;

		// Aide pour le webmaster : vérifications pour un transfert correct.
		if((node.type == 'checkbox') || (node.type == 'select-multiple')) {
			// Attention : substr(-2) renvoie la chaîne entière dans Internet Explorer !
			if(nom.substr(nom.length-2) != '[]') {
				if(!multiples[nom]) multiples[nom] = {t:node.type, n:0};
				multiples[nom].n++;
			}
		} else
			if(nom.substr(nom.length-2) == '[]')
				erreurs.push("Le champ "+nom+" n'est ni de type checkbox ni de "+
				"type select-multiple, son nom ne doit pas se terminer par []");
		if(nom == "email") valideEmail(node.value);
		else if(nom == "email2") confirmeEmail(node.value);
		else if(champsObligatoires[nom]) {
			if((node.type == 'radio') ||
			   (node.type == 'checkbox')) {
				if(radios[nom] == undefined) radios[nom] = false;
				radios[nom] |= node.checked;
			}
			
		}
	}

	for(var r in radios)
		if(!radios[r]) erreurs.push("Le champ "+r+" est obligatoire.")
		;

	// Vérification d'une mauvaise conception du formulaire.
	for(var m in multiples)
		if(multiples[m].n > 1)
			erreursFatales.push("Le champ "+m+" est de type "+multiples[m].t+
				" et peut prendre plusieurs valeurs, son nom doit se terminer par []");
	// Affichage des erreurs et retour.
	if(erreursFatales.length) {
		alert("ATTENTION :\n"+erreursFatales.join("\n"));
		return false;
	}
	if(erreurs.length) {
		alert(erreurs.join("\n"));
		return false;
	}
	return true;
}

