//#12.00Aa WDAJAX.JS
//VersionVI: 30F120055n
// Le seul support technique disponible pour cette librairie est
// accessible a travers le service "Assistance Directe".

// Attention a ne pas mettre d'accent dans ce fichier COMMENTAIRES inclus

// Classe representant une requete

function WDAJAXRequete(nId, clRequete, bPost, bSynchrone)
{
	// On initialise nos membres
	this.m_nId = nId;
	this.m_clRequete = clRequete;
	this.m_bPost = bPost;
	this.m_bSynchrone = bSynchrone;
	this.m_bValide = true;
}

var _sAJAXNouvellePage = "";

WDAJAXRequete.prototype =
{
	m_sCallback:			"",				// Pas de callback par defaut
	readyStateUninitialized:0,				// Les valeurs d'etat de requetes
	readyStateLoading:		1,
	readyStateLoaded:		2,
	readyStateInteractive:	3,
	readyStateComplete:		4,
	sHeaderErreur:			"WebDevError",		// Header d'erreur
	sHeaderRedirPHP:		"WebDevRedirPHP",	// Header de redirection
	sHeaderXML:				"WebDevXMLDoc",

	// La callback en cas d'evenement asynchrone
	OnReadyState:function()
	{	// si c'est la notification de resultat pret
		if( this.m_clRequete.readyState == this.readyStateComplete )
		{	// on valide le resultat
			if( this.bValideResultat() )
			{	// si la requete n'a pas ete annulee
				if (this.m_sCallback != "")
				{	// on valide le resultat de la requete
					this.m_bValide = true;
					// on appelle la callback
					var sTmp = this.sGetResultat();
					eval(this.m_sCallback + "(sTmp," + this.m_nId + ")");
				}
			}
			// on libere la requete
			this.Libere();
		}
	},

	// La callback en cas d'evenement asynchrone dans le cas de la gestion des tables
	OnReadyStateTable:function (oObjetRequeteTable)
	{
		// Parfois on recoit deux readyStateComplete donc on n'a plus de requete
		// Test du cas
		if (!this.m_clRequete)
			return;

		// Si c'est la notification de resultat pret
		if (this.m_clRequete.readyState == this.readyStateComplete)
		{
			var bRes = false;

			// On valide le resultat
			if (this.bValideResultat())
			{
//				// Si la requete n'a pas ete annulee
//				this.m_bValide = true;

				// Si le resulat est valide on le renvoi
				bRes = clWDAJAXMain.bReponseGenerique(this, _PAGE_, oObjetRequeteTable);
			}

			// Si pas un resultat valide : reinti la table pour plus de securite
			if (!bRes)
			{
				// Libere la requete cote table pour eviter de bloquer le champs en demandant le reinit de la table
				oObjetRequeteTable.SupprimeRequete(true);
			}
			// Libere la requete
			this.Libere();
		}
	},

	// Regarde si il y a une redirection vers une page d'erreur en PHP
	bRedirectionPHP:function()
	{
		// Blinde par une exception car certains navigateurs renvoient une exception si le header n'existe pas
		try
		{	// on recupere la partie erreur de la requete
			var sErreur = this.m_clRequete.getResponseHeader(this.sHeaderRedirPHP);
			// Renvoie true si il y a eu une erreur qui declenche une redirection
			return (sErreur && sErreur.length>0 );
		}
		catch(e)
		{	// Pas de header, pas d'erreur
			return false;
		}
	},

	// Regarde si il y a une erreur serveur
	bErreurServeur:function()
	{	// on blinde par une exception car certains navigateurs renvoient une exception si le header n'existe pas
		try
		{	// on recupere la partie erreur de la requete
			var sErreur = this.m_clRequete.getResponseHeader(this.sHeaderErreur);
			// on renvoie true si il y a eu une erreur
			return ( sErreur && sErreur.length>0 );
		}
		catch(e)
		{	// pas de header, pas d'erreur
			return false;
		}
	},

	// La methode d'invocation : appel en interne
	Envoi:function(sRequete,sURL)
	{
		// Calcul de l'URL si on est en mode GET
		if (!this.m_bPost)
		{
			// On ajoute un ? ou un &
			sURL = sURL + ((sURL.indexOf("?") == -1) ? "?" : "&") + sRequete;
		}

		// On passe en mode invalide => Notre reponse n'a pas de sens
		this.m_bValide = false;

		// On actualise le compteur de requete synchrone en cours si besoin
		if (this.m_bSynchrone)
		{
			clWDAJAXMain.m_nRequeteSynchrone++;
		}
		// Et on affiche le temoin d'activite AJAX (Dans tous les cas : synchrone et asynchrone)
		clWDAJAXMain.ReactualiseActivite(false);

		// Ouverture de la requete
		this.m_clRequete.open(this.m_bPost ? "POST" : "GET", sURL, !(this.m_bSynchrone));

		// Ajoute l'encodage du POST
		this.m_clRequete.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		// Puis envoie de la requete
		this.m_clRequete.send(this.m_bPost ? sRequete : "");

		// On actualise le compteur de requete synchrone en cours si besoin
		if (this.m_bSynchrone)
		{
			clWDAJAXMain.m_nRequeteSynchrone--;
			// Et on affiche le temoin d'activite AJAX (Uniquement dans le cas synchrone)
			clWDAJAXMain.ReactualiseActivite(false);
		}
	},

	// Renvoi l'alphabet de la reponse si trouve
	// Sinon renvoi l'alphabet du document
	// Ne renvoie rien si le navigateur n'est pas IE
	sGetDocRequeteAlphabet:function ()
	{
		// Par defaut on prend la valeur stocke dans le document
		var sAlphabet = document.charset;

		// Si pas IE => FIni
		if (!sAlphabet)
		{
			return undefined;
		}

		// On regarde si on a un type mine dans la requete
		try
		{
			var sHeader = this.m_clRequete.getResponseHeader("Content-type");

			// Si on trouve la marque du charset : on renvoie la suite
			if (sHeader.indexOf("charset=") > 0)
			{
				return sHeader.substring(sHeader.indexOf("charset=") + "charset=".length);
			}
			// Sinon on renvoie la valeur par defaut
		}
		catch(e)
		{	// Pas de header, charset du document
		}
		return sAlphabet;
	},

	// verifie la validite du resultat d'une requete
	// affiche l'erreur dans le navigateur
	bValideResultat:function()
	{
		this.m_bValide = false;
		// le resultat n'est valide que si la requete a abouti
		if( this.m_clRequete.readyState == this.readyStateComplete )
		{	// si on a eu une erreur HTTP, inutile d'aller plus loin
			if( this.m_clRequete.status < 400 )
			{
				// Si il y a une redirection (Affichage d'une erreur PHP)
				if (this.bRedirectionPHP())
				{
					// On recupere la redirection
					var sRedirection = this.m_clRequete.responseText;
					// Execute la redirection
					document.location.replace(unescape(sRedirection));
				}
				else if(this.bErreurServeur())
				{	// Si il y a une erreur WL du serveur

					// Se libere soit meme
					_sAJAXNouvellePage = this.m_clRequete.responseText;

					// Si on est en internet exploreur il faut aussi injecter le charset sinon cela ne marche pas
					var sAlphabet = this.sGetDocRequeteAlphabet();
					this.Libere();
					// Marque l'AJAX comme plus disponible
					clWDAJAXMain.BloqueAJAX();

					// Si on est pas dans un gadget
					if (typeof System != "object")
					{
						// Methode qui ne marche pas en asynchrone : l'appel de open() arrete l'execution du script
						// Jamais de .open : cela ne marche pas dans certains navigateur
						if (bIE)
						{
							// On fait un cas particulier pour IE7
							if (bIE7)
							{
								var oDoc = document.open("text/html", "replace");
								if (sAlphabet) oDoc.charset = sAlphabet;
								oDoc.write(_sAJAXNouvellePage);
								oDoc.close();
							}
							else
							{
								document.oDoc = document.open("text/html", "_self", "", true);
								document.oDoc = document.oDoc.document;
								if (sAlphabet) document.oDoc.charset = sAlphabet;
								setTimeout("document.oDoc.write(_sAJAXNouvellePage);", 1);
							}
						}
						else
						{
							if (sAlphabet)
							{
								setTimeout("document.write(_sAJAXNouvellePage);document.charset='" + sAlphabet + "';document.close();", 1);
							}
							else
							{
								setTimeout("document.write(_sAJAXNouvellePage);document.close();", 1);
							}
						}
					}
					else
					{
						// On est dans un gadget => affiche dans un format spécifique fonctionnel
						// Supprime les RC de présentation
						_sAJAXNouvellePage = _sAJAXNouvellePage.replace(/\r/g, "");
						_sAJAXNouvellePage = _sAJAXNouvellePage.replace(/\n/g, "");
						// Remplace les paragraphes par des RC
						_sAJAXNouvellePage = _sAJAXNouvellePage.replace(/\<BR\>/ig, "\r\n");
						_sAJAXNouvellePage = _sAJAXNouvellePage.replace(/\<P\>/ig, "\r\n");
						// Supprime les balise
						_sAJAXNouvellePage = _sAJAXNouvellePage.replace(/\<[^\>]+\>/ig, "");
						// Remet des paragraphes
						_sAJAXNouvellePage = _sAJAXNouvellePage.replace(/\r\n/g, "<BR>");
						document.body.innerHTML = _sAJAXNouvellePage;
					}
//					document.write(sPageErreur);
//					document.close();
					// On ne doit pas remplacer le document immediatement car sinon le reste du script en cours risque
					// de ne pas bien marcher (Erreur JS) dans certains navigateur (IE)
				}
				else
				{	// on valide le resultat
					this.m_bValide = true;
					return true;
				}
			}
		}
		// resultat non valide
		return false;
	},

	// Recuperation du resultat en texte
	sGetResultat:function()
	{
		// Selon notre etat de validite
		if (this.m_bValide)
		{
			// On blinde par une exception car certains navigateurs renvoient une exception si le header n'existe pas
			try
			{
				// On recupere l'entete d'information sur le nom XML de la requete
				var sNomXML = this.m_clRequete.getResponseHeader(this.sHeaderXML);
				// Si on a un nom alors on declare le document XML et on renvoi son nom
				if (sNomXML && sNomXML.length > 0)
				{
					// Ici declaration du document XML
					XMLAjoutDoc(sNomXML, this.m_clRequete.responseXML);
					return sNomXML;
				}
			}
			catch(e)
			{
				// Pas de header, pas de reponse XML
			}

			// On renvoie la reponse bien encode pour le navigateur
			return clWDEncode.sEncodeCharset(this.m_clRequete.responseText, false);
		}
		else
		{
			return "";
		}
	},

	// La fonction d'initialisation : definie les callbacks
	Init:function()
	{
		// On definie la fonction de changement d'etat uniquement si on est en mode asynchrone
		if (!this.m_bSynchrone)
		{
			// Une reference sur nous meme
			var clWDAJAXRequete = this;
			this.m_clRequete.onreadystatechange = function() { clWDAJAXRequete.OnReadyState.call(clWDAJAXRequete); };
		}
	},

	// La fonction d'initialisation pour les tables ; definie la callback
	InitTable:function (oObjetRequeteTable)
	{
		// On definie la fonction de changement d'etat uniquement si on est en mode asynchrone
		if (!this.m_bSynchrone)
		{
			// Une reference sur nous meme
			var clWDAJAXRequete = this;
			this.m_clRequete.onreadystatechange = function() { clWDAJAXRequete.OnReadyStateTable.call(clWDAJAXRequete, oObjetRequeteTable); };
		}
	},

	// Renvoie Vrai si la requete est en cours
	bEnCours:function()
	{	// on renvoie true si une callback est active
		return (this.m_sCallback != "");
	},

	// Annule une requete asynchrone
	Annule:function()
	{
		// On annule la callback
		delete this.m_sCallback;

		// IE 6 : Bloque le onreadystatechange (delete ne suffit pas) + Un = null ne fonctionne pas donc on met une fonction vide
		this.m_clRequete.onreadystatechange = function () { };

		// Et on se libere
		this.Libere();
	},

	// Fermeture de la requete : se libere du tableau global des requetes
	Libere:function()
	{
		var i;
		var nLimiteI = clWDAJAXMain.m_tabConnection.length;
		for (i = 0; i < nLimiteI; i++)
		{
			// Si c'est nous meme
			if (clWDAJAXMain.m_tabConnection[i].m_nId == this.m_nId)
			{
				// On se supprime du tableau
				clWDAJAXMain.m_tabConnection[i] = null;
				// Et on enleve l'element du tableau
				clWDAJAXMain.m_tabConnection.splice(i, 1);
				// Et on sort direct
				break;
			}
		}
		// On libere nos membres par securite
		if (this && this.m_clRequete)
		{
			delete this.m_clRequete.onreadystatechange;	// Obligatoire ?
			delete this.m_clRequete;					// Pas obligatoire
		}

		// Actualise le temoin d'activite AJAX
		clWDAJAXMain.ReactualiseActivite(false);
	}
};

// Classe de creation des requetes

function WDAJAXMain()
{
	this.m_tabConnection = new Array();	// Tableau des connections
	this.m_nIdPos = 1;					// Id de connection

	this.m_tabRequetes = new Array();	// Tableau des evenements AJAX a traiter

	this.m_nRequeteSynchrone = 0;

	// Memorise si on est en mode AWP
	this.m_bPageAWP = document.location.pathname.substr(document.location.pathname.length - 4, 4).toUpperCase() == ".AWP";
};

WDAJAXMain.prototype =
{
	m_bWDAJAXMainValide:	true,		// Drapeau qui indique si on peu encore utiliser les fonctions AJAX
	m_bTestAJAXDisponible:	false,		// Pas teste
	m_bAJAXDisponible:		true,		// Mais disponible par defaut
	m_oActiviteChamp:		null,
	m_bActivite:			false,
	m_nActiviteOption:		0,

	eActivite_Fixe:			0,
	eActivite_HautGauche:	1,
	eActivite_HautDroite:	2,
	eActivite_BasGauche:	3,
	eActivite_BasDroite:	4,
	eActivite_Centrer:		5,
	m_fWinOnScroll:			null,
	m_fWinOnResize:			null,

	sCommandeAjax_Execute:			"WD_ACTION_=AJAXEXECUTE",		// Les commandes disponibles
	sCommandeAjax_Champ:			"WD_ACTION_=AJAXCHAMP",
	sCommandeAjax_Page:				"WD_ACTION_=AJAXPAGE",
	sCommandeAjax_InitGadget:		"WD_ACTION_=AJAXINITGADGET",
	sCommandeAjax_Erreur:			"WD_ACTION_=AJAXERREUR",
	sCommandeWDAction:				"WD_ACTION_",
	sCommandeAjax_ExecuteProc:		"EXECUTEPROC",
	sCommandeAjax_Evenement:		"EXECUTE",
	sCommandeAjax_Reglette:			"SCROLLTABLE",
	sCommandeAjax_ClicTable:		"CLICTABLE",
	sCommandeAjax_Contexte:			"WD_CONTEXTE_",

	XML_RACINE:						"WAJAX",
	XML_RACINERegExp:				new RegExp("<WAJAX>"),
	XML_JS:							"JS",
	XML_REDIR:						"REDIR",
	XML_CHAMP:						"CHAMP",
	XML_LISTE:						"LISTE",
	XML_TRACE:						"TRACE",
	XML_TRACE_ID:					"WDAJAX_TRACE",
	XML_CHAMP_ATT_ALIAS:			"ALIAS",
	XML_CHAMP_ATT_TYPE:				"TYPE",
	XML_CHAMP_TYPE_PAGEPRINCIPALE:	1,
	XML_CHAMP_TYPE_SAISIE:			2,
	XML_CHAMP_TYPE_LIBELLE:			3,
	XML_CHAMP_TYPE_BOUTON:			4,
	XML_CHAMP_TYPE_INTERRUPTEUR:	5,
	XML_CHAMP_TYPE_SELECTEUR:		6,
	XML_CHAMP_TYPE_LISTE:			7,
	XML_CHAMP_TYPE_IMAGE:			8,
	XML_CHAMP_TYPE_TABLE:			9,
	XML_CHAMP_TYPE_CHAMPFORMATE:	10,
	XML_CHAMP_TYPE_ZONEREPETEE:		11,
	XML_CHAMP_TYPE_HTML:			12,
	XML_CHAMP_TYPE_COMBO:			14,
	XML_CHAMP_TYPE_LIEN:			16,
	XML_CHAMP_TYPE_LIBELLEHTML:		17,
	XML_CHAMP_TYPE_REGLETTE:		21,
	XML_CHAMP_TYPE_MAPAREA:			22,
	XML_CHAMP_TYPE_CHEMINNAV:		23,
	XML_CHAMP_TYPE_TREEVIEW:		25,
	XML_CHAMP_TYPE_VIGNETTE:		26,
	XML_CHAMP_TYPE_IFRAME:			27,
	XML_CHAMP_TYPE_IFRAME_DEST:		31,
	XML_CHAMP_TYPE_IFRAME_SOURCE:	32,
	XML_CHAMP_TYPE_GRAPHE:			33,
	XML_CHAMP_TYPE_CELLULE:			39,
	XML_CHAMP_TYPE_SUPERCHAMP:		40,
	XML_CHAMP_TYPE_MODELEDECHAMP_SOURCE:42,
	XML_CHAMP_TYPE_MODELEDECHAMP_DEST:43,
	XML_CHAMP_TYPE_ONGLET:			44,
	XML_CHAMP_TYPE_PLANSITE:		45,
	XML_CHAMP_TYPE_VOLETONGLET:		49,
	XML_CHAMP_TYPE_SOUSMENU:		55,
	XML_CHAMP_TYPE_COLONNE:			56,
	XML_CHAMP_TYPE_OPTIONMENU:		57,
	XML_CHAMP_PROP:					"PROP",
	XML_CHAMP_PROP_ATT_NUM:			"NUM",
	XML_CHAMP_PROP_NUM_VALEUR:		1,	// Chaine
	XML_CHAMP_PROP_NUM_LIBELLE:		3,	// Chaine
	XML_CHAMP_PROP_NUM_LIBELLE_TABLE_AJAX: "TABLE_AJAX",
	XML_CHAMP_PROP_NUM_HAUTEUR:		5,	// Entier
	XML_CHAMP_PROP_NUM_LARGEUR:		6,	// Entier
	XML_CHAMP_PROP_NUM_COULEUR:		10,	// Formate en chaine
	XML_CHAMP_PROP_NUM_COULEURFOND:	11,	// Formate en chaine
	XML_CHAMP_PROP_NUM_ETAT:		12,	// Balise XML
	XML_CHAMP_PROP_NUM_VISIBLE:		18,	// Valeur formate en chaine
	XML_CHAMP_PROP_NUM_VALEURAFFICHEE:21,	// Chaine
	XML_CHAMP_PROP_NUM_IMAGE:		34,	// Chaine
	XML_CHAMP_PROP_NUM_URL:			38,	// Chaine
	XML_CHAMP_PROP_NUM_BULLE:		39,	// Chaine
	XML_CHAMP_PROP_NUM_X:			41,	// Chaine
	XML_CHAMP_PROP_NUM_Y:			42,	// Chaine
	XML_CHAMP_PROP_NUM_CURSEURSOURIS:43,// Chaine
	XML_CHAMP_PROP_NUM_POLICEGRAS:	47,	// Entier
	XML_CHAMP_PROP_NUM_POLICEITALIQUE:48,// Booleen formate en chaine
	XML_CHAMP_PROP_NUM_POLICENOM:	49,	// Chaine
	XML_CHAMP_PROP_NUM_POLICESOULIGNE:50,// Booleen formate en chaine
	XML_CHAMP_PROP_NUM_POLICETAILLE:51,	// Chaine
	XML_CHAMP_PROP_NUM_OPACITE:		52,	// Entier
	XML_CHAMP_PROP_NUM_CADRAGEH:	53,	// Chaine
	XML_CHAMP_PROP_NUM_CADRAGEV:	54,	// Chaine
	XML_CHAMP_PROP_NUM_INDICATION:	58,	// Chaine
	XML_CHAMP_JS:					"JS",
	XML_CHAMP_ETAT_ETAT:			"ETAT",
	XML_CHAMP_OPTIONS:				"OPTIONS",
	XML_CHAMP_OPTIONS_OPTION:		"OPTION",
	XML_CHAMP_SATURATION:			"SATURATION",
	XML_CHAMP_RECHARGE:				"RECHARGE",
	XML_CHAMP_REFRESH:				"REFRESH",
	XML_CHAMP_REFRESH_RESETTABLE:	"RESETTABLE",
	XML_CHAMP_REFRESH_DEBUT:		"DEBUT",
	XML_CHAMP_LIGNES:				"LIGNES",
	XML_CHAMP_LIGNES_DEBUT:			"DEBUT",
	XML_CHAMP_LIGNES_NOMBRE:		"NOMBRE",
	XML_CHAMP_LIGNES_SELECTION:		"SELECTION",
	XML_CHAMP_LIGNES_RUPTURES:		"RUPTURES",
	XML_CHAMP_LIGNES_COLONNES:		"COLONNES",
	XML_CHAMP_LIGNES_STYLE:			"STYLE",
	XML_CHAMP_LIGNES_LIGNE:			"LIGNE",
	XML_CHAMP_LIGNES_LIGNE_INDICE:	"INDICE",
	XML_CHAMP_LIGNES_LIGNE_DEBUT:	"DEBUT",
	XML_CHAMP_LIGNES_LIGNE_CORPS:	"CORPS",
	XML_CHAMP_LIGNES_LIGNE_FIN:		"FIN",
	XML_CHAMP_LIGNES_LIGNE_STYLE:	"STYLE",
	XML_CHAMP_TREEVIEW:				"TREEVIEW",
	XML_CHAMP_TREEVIEW_SELECT:		"SELECT",
	XML_CHAMP_TREEVIEW_DEROULE:		"DEROULE",
	XML_CHAMP_TREEVIEW_DEROULETAB:	"DEROULETAB",
	XML_CHAMP_TREEVIEW_NOEUDS:		"NOEUDS",

	XML_WBTRACE_ID:					"WB_TRACE",

	// Indique si le mode AJAX est temporairement bloque
	bWDAJAXMainValide:function()
	{
		// Bloque si le document n'est pas completement charge
		// Ca tombe bien on n'a le probleme que sous IE et document.readyState n'existe que sous IE
		if (document.readyState && (document.readyState != "interactive") && (document.readyState != "complete"))
			return false;

		// Renvoie la variable globale
		return this.m_bWDAJAXMainValide;
	},

	// Bloque le mode AJAX : remplacement de la page courante
	BloqueAJAX:function()
	{
		// Supprime le témoin d'activité
		this.m_oActiviteChamp = null;
		this.m_bActivite = false;

		// Met le flag a faux
		this.m_bWDAJAXMainValide = false;

		// Et supprime toutes les requetes asynchrones en cours
		while (this.m_tabConnection.length > 0)
		{
			this.m_tabConnection[0].Libere();
		}
	},

	// Recupere un nouvel ID de requete
	nGetNouvelId:function()
	{
		return this.m_nIdPos++;
	},

	// CRee un objet XMLHttpRequest
	clCreeXMLHttpRequest:function()
	{
		var clRequete = false;
		// On teste l'objet natif
		if(window.XMLHttpRequest)
		{
			try
			{
				clRequete = new XMLHttpRequest();
			}
			catch(e)
			{
				clRequete = false;
			}
		}
		// On teste l'objet ActiveX pour IE/Windows
		if ((!clRequete) && (window.ActiveXObject))
		{
			try
			{
				clRequete = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch(e)
			{
				try
				{
					clRequete = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch(e)
				{
					clRequete = false;
				}
			}
		}
		// On retourne notre objet
		return (clRequete === false) ? null : clRequete;
	},

	// Creation d'un objet WDAJAXRequete
	// Mettre bSansInit pour faire une initialisation personnalise
	clCreeWDAJAXRequete:function(bPost, bSynchrone, bSansInit)
	{
		// Pseudo parametres par defaut
		if (bPost == null) bPost = true;
		if (bSynchrone == null) bSynchrone = false;

		// On commence par cree la requete
		var clRequete = this.clCreeXMLHttpRequest();
		// Si pas de requete (AJAX pas disponible => Fin)
		if (!clRequete)
		{
			return null;
		}
		// Puis on cree l'objet
		var nId = this.nGetNouvelId();
		// var nId = this.nGetNouvelId.call(this); ??
		var clWDAJAXRequete = new WDAJAXRequete(nId, clRequete, bPost, bSynchrone);
		// Et on l'init
		if (!bSansInit)
		{
			clWDAJAXRequete.Init();
		}

		// On l'enregistre dans le tableau des connections si c'est une connexion asynchrone
		if (!bSynchrone)
		{
			this.m_tabConnection.push(clWDAJAXRequete);
		}

		// Puis on retourne l'objet
		return clWDAJAXRequete;
	},

	// Recherche un objet WDAJAXRequete
	GetWDAJAXRequete:function(nId)
	{	// On parcourt le tableau a la recherche de la requete
		var i;
		var nLimiteI = this.m_tabConnection.length;
		for (i = 0; i < nLimiteI; i++)
		{	// si c'est la requete recherchee, on la renvoie
			if(this.m_tabConnection[i].m_nId==nId)
				return this.m_tabConnection[i];
		}
		// si on arrive ici, on n'a pas trouve
		return null;
	},

	// Traite un requete
	bReponseGenerique:function (clRequete, oPage, oTable)
	{
		// Si le resulat est valide
		if(clRequete.bValideResultat())
		{
			// Si on n'a pas en reponse XML a nous (Par exemple avec l'utilisation de PageAffiche)
			if (
				(clRequete.m_clRequete.responseText.substring(0, "<?xml".length) != "<?xml")
				|| !clRequete.m_clRequete.responseText.match(this.XML_RACINERegExp))
			{
				var sNouvellePage = clRequete.m_clRequete.responseText;
				
				// En IE on doit redefinir le charset sinon on a un probleme
				var sAlphabet = clRequete.sGetDocRequeteAlphabet();
				// Se libere soit meme
				clRequete.Libere();
				clRequete = null;
				// Marque l'AJAX comme plus disponible
				this.BloqueAJAX();
				
				// Si on est pas dans un gadget
				if (typeof System != "object")
				{
					// Et ecrit le document
					// Jamais de .open : cela ne marche pas dans certains navigateur
					if (bIE)
					{
						var oDoc = document.open("text/html", "replace");
						if (sAlphabet) oDoc.charset = sAlphabet;
						oDoc.write(sNouvellePage);
						if (bIE7)
						{
							oDoc.close();
						}
					}
					else
					{
						document.write(sNouvellePage);
						if (sAlphabet) document.charset = sAlphabet;
						document.close();
					}
				}
				else
				{
					// On est dans un gadget => affiche dans un format spécifique fonctionnel
					// Supprime les RC de présentation
					sNouvellePage = sNouvellePage.replace(/\r/g, "");
					sNouvellePage = sNouvellePage.replace(/\n/g, "");
					// Remplace les paragraphes par des RC
					sNouvellePage = sNouvellePage.replace(/\<BR\>/ig, "\r\n");
					sNouvellePage = sNouvellePage.replace(/\<P\>/ig, "\r\n");
					// Supprime les balise
					sNouvellePage = sNouvellePage.replace(/\<[^\>]+\>/ig, "");
					// Remet des paragraphes
					sNouvellePage = sNouvellePage.replace(/\r\n/g, "<BR>");
					document.body.innerHTML = sNouvellePage;
				}
				return true;
			}
			else
			{
				// On traite le resultat de la requete
				return this.bActionXML(oPage, oTable, clRequete.m_clRequete.responseXML);
			}
		}
		else
		{
			return false;
		}
	},

	// construit la valeur du champ
	sConstruitValeurChampNom:function(oPage,sChamp)
	{	// on cherche le champ
		var oChamp = this.oChercheChamp(oPage,sChamp);
		// on construit la valeur du champ
		return( oChamp ? this.sConstruitValeurChamp(oChamp) : "" );
	},

	// construit la valeur du champ
	sConstruitValeurChamp:function(oChamp)
	{
		// selon le type du champ
		switch(oChamp.type.toLowerCase())
		{
		// Champs qui retournent leur valeur
		case "text":
		case "hidden":
		case "textarea":
		case "password":
			// On encode si possible les caractere UNICODEs
			var sValeur = oChamp.value;
			return clWDEncode.sEncodePOST(oChamp.name) + "=" + clWDEncode.sEncodePOST(sValeur);
		// Champ qui ne retournent rien
		case "button":
			return "";
		// Check active
		case "checkbox":
		case "radio":
			if (oChamp.checked){return clWDEncode.sEncodePOST(oChamp.name) + "=" + clWDEncode.sEncodePOST(oChamp.value);}else{return "";}
		case "select-one":
			if (oChamp.selectedIndex != -1){return clWDEncode.sEncodePOST(oChamp.name) + "=" + clWDEncode.sEncodePOST(oChamp.options[oChamp.selectedIndex].value);}else{return "";}
		case "select-multiple":
			var sOptions = "";
			var i = 0;
			var nLimiteI = oChamp.options.length;
			for (i = 0; i < nLimiteI; i++)
			{
				if (oChamp.options[i].selected)
				{
					if (sOptions.length > 0)
					{
						sOptions += "&";
					}
					sOptions += clWDEncode.sEncodePOST(oChamp.name) + "=" + oChamp.options[i].value;
				}
			}
			return sOptions;
		// Autres champs mais moins frequents qui ne retournent rien
		case "file":
		case "reset":
		case "submit":
			return "";
		default:
			// On encode si possible les caractere UNICODEs
			var sValeur = oChamp.value;
			if (sValeur === undefined)
			{
				return "";
			}
			else
			{
				return clWDEncode.sEncodePOST(oChamp.name) + "=" + clWDEncode.sEncodePOST(sValeur);
			}
		}
		return "";
	},

	// construit les valeurs de tous les champs de la page
	sConstruitValeurPage:function(tabElements)
	{	// on parcours les champs de la page pour construire la requete
		var tabResultat = new Array(tabElements.length);
		var i;
		var nLimiteI = tabElements.length;
		for (i = 0; i < nLimiteI; i++)
		{
			var oElem = tabElements[i];
			// Toutes le requetes AJAX incluent WD_ACTION_ qui est deja specifie
			// On doit donc le filtrer, sinon cette valeur est deux fois dans la requete et le PHP renvoie uniquement la seconde valeur
			// On evite aussi les balises EMBED et autres qui n'ont pas de type et pas de valeur
			// On vire aussi les elements inutiles des treeview (les champs PTH_xxx)
			var sNomElem = oElem.name;
			if ((sNomElem == this.sCommandeWDAction) || (!oElem.type) || (sNomElem.substr(0, 4) == "PTH_"))
			{
				tabResultat[i] = "";
			}
			else
			{
				// On rajoute le separateur si le dernier caratere n'en est pas deja un &
				// Et on contruit la valeur du champ avec
				tabResultat[i] = (((i>0) && (tabResultat[i - 1].charAt(tabResultat[i - 1].length - 1) != "&")) ? "&" : "") + this.sConstruitValeurChamp(oElem);

				// Vire les eventuelles paires vide
				if (tabResultat[i] == "&")
					tabResultat[i] = "";
			}
		}
		return tabResultat.join("");
	},

	// construit l'URL pour appeler une procedure AJAX
	sConstruitURL:function(sURL)
	{	// on renvoie l'URL
		return sURL;
	},

	// construit la requete pour appeler une procedure AJAX
	sConstuitRequeteProcedure:function(sProcedure,sContexte)
	{	// construction de la requete AJAX
		//	- action AJAX (non specifique)
		var sRequete = this.sCommandeAjax_Execute;
		//	- commande AJAX (non specifique)
		sRequete += "&" + this.sCommandeAjax_ExecuteProc + "=" + escape(sProcedure);
		//	- contexte d'execution (specifique)
		sRequete += "&" + this.sCommandeAjax_Contexte + "=" + escape(sContexte);
		// on renvoie la requete creee
		return sRequete;
	},

	// Construit la requete pour la recherche dans une table
	sConstuitRequeteTable:function (sRequeteTable)
	{	// Construction de la requete AJAX
		//	- Action AJAX (non specifique)
		var sRequete = this.sCommandeAjax_Execute;
		//	- Commande AJAX (non specifique)
		if (sRequete.length > 0)
		{
			sRequete += "&" + sRequeteTable;
		}
		// On renvoie la requete creee
		return sRequete;
	},

	// Defini le nom du champ du formulaire dont on doit transmettre la valeur en plus lors d'un envoi sans submit
	SetZRChamp:function (sZRChamp, sValeur)
	{
		this.m_sZRChamp = sZRChamp;
		this.m_sZRChampValeur = sValeur;
	},

	// construit la requete pour appeler un evenement AJAX
	sConstuitRequeteEvenement:function(oPage,sChamp,nEvenement,nOption)
	{	// construction de la requete AJAX selon les options
		var sRequete = "";
		switch(nOption)
		{	// on envoie la valeur du champ courant
		case 1 :
			// action AJAX
			sRequete += this.sCommandeAjax_Champ;
			// evenement
			sRequete += "&" + this.sCommandeAjax_Evenement + "=" + nEvenement;
			// champ
			sRequete += "&" + this.sCommandeAjax_Contexte + "=" + sChamp;
			// Valeur du champ
			var sValeur = this.sConstruitValeurChampNom(oPage,sChamp);
			if (sValeur!="")
				sRequete += "&" + sValeur;

			// Si on a indique (via _JAZR) de transmettre en plus l'occurrence courante de la ZR du champ : on la transmet
			if (this.m_sZRChamp)
			{
				sValeur = clWDEncode.sEncodePOST(this.m_sZRChamp) + "=" + clWDEncode.sEncodePOST(this.m_sZRChampValeur);
				if (sValeur != "")
					sRequete += "&" + sValeur;
			}
			break;

		// on envoie la valeur de tous les champs de la page
		case 2 :
			// action AJAX
			sRequete += this.sCommandeAjax_Page;
			// evenement
			sRequete += "&" + this.sCommandeAjax_Evenement + "=" + nEvenement;
			// champ
			sRequete += "&" + this.sCommandeAjax_Contexte + "=" + sChamp;
			// valeurs des champs de la page
			var sValeur = this.sConstruitValeurPage(oPage.elements);
			if(sValeur!="")
				sRequete += "&" + sValeur;
			break;

		// Clic sur une reglette mais sans submit
		case 3 :
			// Action AJAX
			sRequete += this.sCommandeAjax_Execute;
			// Evenement
			sRequete += "&" + this.sCommandeAjax_Reglette + "=" + sChamp;
			// Champ reglette
			sRequete += "&" + sChamp + "=" + nEvenement;
			break;

		// Clic sur une reglette avec submit
		case 4 :
			// Action AJAX
			sRequete += this.sCommandeAjax_Page;
			// Evenement
			sRequete += "&" + this.sCommandeAjax_Reglette + "=" + sChamp;
			// Champ reglette. A priori cette valeur est en double car deja dans le submit de la page donc on ne la me pas
			var oChampReglette = eval("oPage."+sChamp);
			if (oChampReglette) oChampReglette.value = nEvenement;
			// valeurs des champs de la page
			var sValeur = this.sConstruitValeurPage(oPage.elements);
			if(sValeur!="")
				sRequete += "&" + sValeur;
			break;

		// Selection d'une ligne de table
		case 5 :
			// Action AJAX
			sRequete += this.sCommandeAjax_Page;
			// Evenement
			sRequete += "&" + this.sCommandeAjax_ClicTable + "=" + sChamp;
			// Valeurs des champs de la page
			var sValeur = this.sConstruitValeurPage(oPage.elements);
			if(sValeur!="")
				sRequete += "&" + sValeur;
			break;

		// Selection d'une ligne de table sans submit
		case 6 :
			// Action AJAX
			sRequete += this.sCommandeAjax_Champ;
			// Evenement
			sRequete += "&" + this.sCommandeAjax_ClicTable + "=" + sChamp;
			// valeur du champ
			var sValeur = this.sConstruitValeurChampNom(oPage,sChamp);
			if (sValeur!="")
				sRequete += "&" + sValeur;
			break;

		// Initialisation d'un gadget vista
		case 7:
			// Action AJAX
			sRequete += this.sCommandeAjax_InitGadget;
			break;

		// on ne renvoie aucune valeur
		default :
			{
				// Si on a indique (via _JAZR) de transmettre en plus l'occurrence courante de la ZR du champ : on la transmet
				var sValeur = "";
				if (this.m_sZRChamp)
					sValeur = clWDEncode.sEncodePOST(this.m_sZRChamp) + "=" + clWDEncode.sEncodePOST(this.m_sZRChampValeur);
				// Action AJAX
				sRequete += (sValeur != "") ? this.sCommandeAjax_Champ : this.sCommandeAjax_Execute;
				// evenement
				sRequete += "&" + this.sCommandeAjax_Evenement + "=" + nEvenement;
				// champ
				sRequete += "&" + this.sCommandeAjax_Contexte + "=" + sChamp;
				// Valeur de la ZR
				if (sValeur != "")
					sRequete += "&" + sValeur;
				break;
			}
		}

		// Dans tous les cas (Que la valeur soit traite ou non) on supprime la reference a la ZR a transmettre en plus
		delete this.m_sZRChamp;
		delete this.m_sZRChampValeur;

		// Si la fonction existe dans la page : effectue les operations apres submit AJAX
		if (window.FinSubmitAJAX && (typeof FinSubmitAJAX == "function"))
		{
			FinSubmitAJAX();
		}

		// Renvoie la requete
		return sRequete;
	},

	// AJAXDisponible
	// renvoie TRUE si AJAX est disponible sur ce navigateur
	AJAXDisponible:function()
	{
		// Si deja teste
		if (this.m_bTestAJAXDisponible)
			return this.m_bAJAXDisponible;		// Renvoie la disponibilite calcule

		// On essaie de creer une requete
		var clRequete = this.clCreeXMLHttpRequest();
		// AJAX est disponible si on a pu creer la requete
		this.m_bAJAXDisponible = (clRequete != null);
		clRequete = null;
		this.m_bTestAJAXDisponible = true;

		// On renvoie la valeur calcule
		return this.m_bAJAXDisponible;
	},

	// renvoie la valeur d'un noeud XML
	sXMLGetValeur:function(XMLNoeud)
	{	// Renvoie la valeur du noeud
		// Sauf que s'il y a trop de texte, FireFox (et IE ?) decoupent en plusieurs fils de type texte

		if (!XMLNoeud) return "";

		// On recupere les nodes
		var tabNodes = XMLNoeud.childNodes;
		var nLimiteI = tabNodes.length;
		if (nLimiteI == 0) return "";

		// Donc on concatene les fils via un tableau que l'on join
		var tabValeur = new Array(nLimiteI);

		// On parcours les fils
		var i;
		for (i = 0; i < nLimiteI; i++)
		{
			//assert(tabNodes[i].nodeType == 3);

			// Met la valeur de la node dans le tableau
			tabValeur[i] = tabNodes[i].nodeValue;
		}

		// Renvoie la valeur calcule
		return tabValeur.join("");
	},

	// Indique si un attribut existe
	bXMLAttributExiste:function(XMLNoeud, sAttribut)
	{	// Renvoie vrai si l'attribut existe
		return (XMLNoeud.attributes.getNamedItem(sAttribut) ? true : false);
	},

	// renvoie la valeur d'un attribut de noeud XML
	sXMLGetAttribut:function(XMLNoeud, sAttribut)
	{
		//assert(bXMLAttributExiste(XMLNoeud, sAttribut);
		// Renvoie la valeur du noeud
		return XMLNoeud.attributes.getNamedItem(sAttribut).nodeValue;
	},

	// Renvoie la valeur d'un attribut de noeud XML ou "" si le neoud n'existe pas
	sXMLGetAttributSafe:function(XMLNoeud, sAttribut)
	{
		var oAtt = XMLNoeud.attributes.getNamedItem(sAttribut);
		// Renvoie la valeur de l'attribut si possible
		return oAtt ? oAtt.nodeValue : "";
	},

	// Renvoie la valeur d'un attribut de noeud XML ou "" si le neoud n'existe pas
	sXMLGetAttributSafeNull:function(XMLNoeud, sAttribut)
	{
		var oAtt = XMLNoeud.attributes.getNamedItem(sAttribut);
		// Renvoie la valeur de l'attribut si possible
		return oAtt ? oAtt.nodeValue : null;
	},

	// Enleve a la demande les espaces, RC, tabulations d'une chaine donne
	sTrim:function (sValeur, bEspaces, bTabulations, bRCs)
	{
		var szValeur = new String(sValeur);

		// Element du debut
		var nDebutChaine = 0;
		while (nDebutChaine < szValeur.length)
		{
			var cChar = szValeur.charAt(nDebutChaine);

			// Un espace ?
			if (bEspaces && (cChar == " "))
			{	// Oui on le saute
				nDebutChaine++;
				// Traite le caratere suivant
				continue;
			}
			// Une tabulation ?
			if (bTabulations && (cChar == "\b"))
			{	// Oui on le saute
				nDebutChaine++;
				// Traite le caratere suivant
				continue;
			}
			// Un rc?
			if (bEspaces && ((cChar == "\r") || (cChar == "\n")))
			{	// Oui on le saute
				nDebutChaine++;
				// Traite le caratere suivant
				continue;
			}
			// Pas un caratere interdit : fin du parcours
			break;
		}

		// Element de la fin
		var nFinChaine = szValeur.length;
		while (nFinChaine > nDebutChaine)
		{
			var cChar = szValeur.charAt(nFinChaine - 1);
			// Un espace ?
			if (bEspaces && (cChar == " "))
			{	// Oui on le saute
				nFinChaine--;
				// Traite le caratere suivant
				continue;
			}
			// Une tabulation ?
			if (bTabulations && (cChar == "\b"))
			{	// Oui on le saute
				nFinChaine++;
				// Traite le caratere suivant
				continue;
			}
			// Un rc?
			if (bEspaces && ((cChar == "\r") || (cChar == "\n")))
			{	// Oui on le saute
				nFinChaine++;
				// Traite le caratere suivant
				continue;
			}
			// Pas un caratere interdit : fin du parcours
			break;
		}
		// on renvoie la chaine resultat
		return szValeur.substring(nDebutChaine, nFinChaine);
	},

	// Enleve a la demande TOUS les RC, tabulations et doubles espaces d'une chaine donne
	sSansEspace:function (sValeur, bEspaces, bTabulations, bRCs)
	{
		// Les RC et les tabulations
		if (bRCs && bTabulations)
		{
			sValeur = sValeur.replace(/[\r\n\b]/g, "");
		}
		else if (bRCs)	// Les RC seuls
		{
			sValeur = sValeur.replace(/[\r\n]/g, "");
		}
		else if (bTabulations)	// Les tabulations seules
		{
			sValeur = sValeur.replace(/\b/g, "");
		}

		// Les espaces
		var nOldLength = 0;
		do
		{
			nOldLength = sValeur.length;
			sValeur = bEspaces ? sValeur.replace(/  /g, " ") : sValeur;
		} while(sValeur.length < nOldLength);

		// Renvoie la chaine resultat
		return sValeur;
	},

	// Recherche un champ par son alias
	oChercheChamp:function(oPage, sNomChamp, nTypeChamp, bExterieur)
	{
		var oElement;
		// Recherche pour la visibilite
		if (bExterieur)
		{
			if ((nTypeChamp == this.XML_CHAMP_TYPE_TABLE) || (nTypeChamp == this.XML_CHAMP_TYPE_ZONEREPETEE))
			{
				oElement = this.oGetConteneurParent(sNomChamp);
			}
			if (!oElement) oElement = _JGE(sNomChamp, document, bExterieur);
		}
		else
		{
			// Recherche normale
			switch (nTypeChamp)
			{
			// Pour les libelle il faut utiliser getElementById
			case this.XML_CHAMP_TYPE_LIBELLE:
			case this.XML_CHAMP_TYPE_CHAMPFORMATE:
			case this.XML_CHAMP_TYPE_LIBELLEHTML:
			case this.XML_CHAMP_TYPE_REGLETTE:
			case this.XML_CHAMP_TYPE_CHEMINNAV:
			case this.XML_CHAMP_TYPE_PLANSITE:
			// De meme pour les options de menu
			case this.XML_CHAMP_TYPE_SOUSMENU:
			case this.XML_CHAMP_TYPE_OPTIONMENU:
				oElement = _JGE(sNomChamp, document, false);
				break;
			// Pour les arbres il faut rechercher en priorite le champ avec un suffixe
			case this.XML_CHAMP_TYPE_TREEVIEW:
				oElement = _JGE(sNomChamp + "_", document, false);
			default:
				// Que la methode commune
				break;
			}
		}

		// Methodes commune en cas d'echec
		if (!oElement) oElement = eval("oPage." + sNomChamp);
		// Derniere chance pour les champ hors du formulaire
		if (!oElement)
		{
			oElement = document.getElementsByName(sNomChamp);
			// Sauf pour les interrupteur : on prend le premier champ
			if (oElement && nTypeChamp != this.XML_CHAMP_TYPE_SELECTEUR)
				oElement = oElement[0];
		}
		return oElement;
	},

	// Recupere le champ conteneur d'une ZR/Table
	oGetConteneurParent:function (sNomChamp)
	{
		var oConteneurParent = oGetId("con-" + sNomChamp);
		return oConteneurParent ? oConteneurParent : oGetId("ctz" + sNomChamp);
	},

	// Recupere la balise TBODY d'une balise TABLE
	oGetConteneurTBODY:function (oConteneurParent)
	{
		var oConteneurTBody = oConteneurParent;
		// Si le parent de la table/ZR est une balise de type table : on risque d'avoir un probleme avec la pseudo balise TBODY
		if ((oConteneurTBody) && (oConteneurTBody.tagName.toUpperCase() == "TABLE"))
		{
			// Recherche le TBODY
			var i;
			var nLimiteI = oConteneurTBody.childNodes.length;
			for (i = 0; i < nLimiteI; i++)
			{
				if (oConteneurTBody.childNodes[i].tagName && (oConteneurTBody.childNodes[i].tagName.toUpperCase() == "TBODY"))
				{
					oConteneurTBody = oConteneurTBody.childNodes[i];
					break;
				}
			}
		}
		return oConteneurTBody;
	},

	// Recupere une ligne d'un champ d'une ZR/Table
	oGetConteneurLigne:function (sNomChamp, nIndiceActuel)
	{
		return oGetId(sNomChamp + "_" + nIndiceActuel);
	},

	// Supprime la ligne donnee
	bSupprimeLigne: function (sNomChamp, nTypeChamp, nIndiceLigne, nNbRuptures, oConteneurParent, oConteneurTBody)
	{
		// On commence par recuperer la ligne
		var oLigneSuppr = this.oGetConteneurLigne(sNomChamp, nIndiceLigne);

		// Si pas de ligne => Fini
		if (!oLigneSuppr) return false;

		// On supprime les ruptures de la ligne si besoin
		if (nTypeChamp != this.XML_CHAMP_TYPE_TABLE)
		{
			this.SupprimeRuptures(sNomChamp, nIndiceLigne, nNbRuptures);
		}

		// Si on est dans une vrai table
		if (oConteneurTBody)
		{
			// On remonte les noeuds tant que l'on est le seul fils
			var oFils = null;
			var oElement = oLigneSuppr;
			while (oElement.parentNode != oConteneurTBody)
			{
				// Si on n'est pas le seul fils de notre parent => S'arrete ici
				if (oElement.parentNode.childNodes.length > 1)
				{
					oFils = oElement;
				}

				oElement = oElement.parentNode;
				// Si on est pas le seul fils => Multicolonne => On sort
				if (oFils)
				{
					break;
				}
			}

			// On supprime la ligne
			if (oFils)
			{
				oElement.removeChild(oFils);
			}
			else
			{
				oConteneurTBody.removeChild(oElement);
			}
		}
		else
		{
			// On supprime le noeud
			oConteneurParent.removeChild(oLigneSuppr);
		}

		// On ne supprime pas les styles car on n'a pas leurs noms
		// Mais de toutes facons comme il n'y a pas de ligne pour les appliquer pas de problemes
		// Et si un jour on rajoute de nouveau une ligne, elle sera avec son style donc celui-ci remplacera le style non detruit

		return true;
	},

	// Supprime les ruptures d'une ligne donne
	SupprimeRuptures: function (sNomChamp, nIndiceLigne, nNbRuptures)
	{
		// On parcours les niveaux de ruptures
		var i;
		for (i = 0; i < nNbRuptures; i++)
		{
			// D'abord le haut de la rupture
			var sRuptureHaut = oGetId(sNomChamp + "-H-" + i + "-" + nIndiceLigne);
			if ((sRuptureHaut) && (sRuptureHaut.parentNode))
			{
				sRuptureHaut.parentNode.removeChild(sRuptureHaut);
			}

			// Puis le bas
			var sRuptureBas = oGetId(sNomChamp + "-B-" + i + "-" + nIndiceLigne);
			if ((sRuptureBas) && (sRuptureBas.parentNode))
			{
				sRuptureBas.parentNode.removeChild(sRuptureBas);
			}
		}
	},

	// Certains champ on a un niveau de table tr td supplementaire ce qui gene la manipulation de ..Valeur et ..Libelle
	oSauteTableCadrage:function (oChamp)
	{
		if (oChamp && (oChamp.tagName.toUpperCase() == "TABLE"))
		{
			while (oChamp && (oChamp.tagName.toUpperCase() != "TD"))
			{
				oChamp = oChamp.firstChild;
			}
		}
		return oChamp;
	},

	// execute les actions pour une propriete
	ActionProprieteValeur:function(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		var sValeur = this.sXMLGetValeur(XMLAction);

		// Il n'y a pas encore eu de validation de l'existance de oChamp, donc on le fait ici si besoin

		// selon le type du champ
		switch(nTypeChamp)
		{
		// Le cas n'existe plus la propriete ..Valeur est transforme en ..Libelle sur le serveur
//		// On traite le champ bouton specialement : Si c'est un champ image on fait comme les images
//		case this.XML_CHAMP_TYPE_BOUTON:
//			// Si c'est un bouton image => On doit prendre le div interne
//			var oChampImg = _JGE("_" + sAliasChamp + "_IMG", document, false);
//			if (oChampImg)
//			{
//				oChampImg.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
//			}
//			else if (oChamp)
//			{
//				// Si on a le champ c'est que c'est un champ de type input => bouton "normal"
//				oChamp.value = sValeur;
//
//			}
//			break;
//			// Pas de break : on fait comme les images : on change le champ
		case this.XML_CHAMP_TYPE_IMAGE:
		case this.XML_CHAMP_TYPE_MAPAREA:
		case this.XML_CHAMP_TYPE_VIGNETTE:
		case this.XML_CHAMP_TYPE_GRAPHE:
		case this.XML_CHAMP_TYPE_IFRAME:		// On change la source des IFrames par un ..src
			if (oChamp) oChamp.src = sValeur;
			break;
		case this.XML_CHAMP_TYPE_LISTE:
			if (oChamp) oChamp.selectedIndex = parseInt(sValeur);
			break;
		case this.XML_CHAMP_TYPE_SELECTEUR:
			// Pour les selecteur : le code serveur a deja fait l'enventuelle transposition et le -1 requis
			var nOptionSel = parseInt(sValeur);

			// Si on a une valeur negative => Ne selectionne rien
			if (nOptionSel < 0)
			{
				// Si on n'a plus d'une option
				if (oChamp && oChamp.length)
				{	// Les deselectionnes toutes
					var i;
					var nLimiteI = oChamp.length;
					for (i = 0; i < nLimiteI; i++)
					{
						oChamp[i].checked = false;
					}
				}
				else if (oChamp)
				{
					// Une seule option
					//assert(nOptionSel==0);
					oChamp.checked = false;
				}
			}
			else
			{
				if (oChamp && oChamp.length)
				{	// Si on n'a plus d'une option
					if (oChamp && (nOptionSel <= oChamp.length)) oChamp[nOptionSel].checked = true;
				}
				else if (oChamp)
				{
					// Une seule option
					//assert(nOptionSel==0);
					oChamp.checked = true;
				}
			}
			break;
		case this.XML_CHAMP_TYPE_INTERRUPTEUR:
			if (oChamp) oChamp.checked = parseInt(sValeur);
			break;
		case this.XML_CHAMP_TYPE_LIBELLE:
		case this.XML_CHAMP_TYPE_CHAMPFORMATE:
			// Dans certains cas une table est ajoute et l'ID est sur la table au lieu de la cellule : retrouve la cellule
			oChamp = this.oSauteTableCadrage(oChamp);

			// Affectation de la valeur avec rajout des balises HTML
			if (oChamp) oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
			break;
		case this.XML_CHAMP_TYPE_SAISIE:		// Champ de saisie
			if (oChamp)
			{
				// On transforme pour gerer les caratere interdit en ISO-8859-1 si besoin
				oChamp.value = clWDEncode.sEncodeCharset(sValeur, false);
			}
			break;
		case this.XML_CHAMP_TYPE_HTML:
		case this.XML_CHAMP_TYPE_LIBELLEHTML:
			// Pour les champs HTML superposable : on prend le champ extérieur si on n'a pas le champ interieur
			if (!oChamp && oChampExt) oChamp = oChampExt;
		case this.XML_CHAMP_TYPE_REGLETTE:
		case this.XML_CHAMP_TYPE_CHEMINNAV:
		case this.XML_CHAMP_TYPE_PLANSITE:
			// Dans certains cas une table est ajoute et l'ID est sur la table au lieu de la cellule : retrouve la cellule
			oChamp = this.oSauteTableCadrage(oChamp);

			// Affectation de la valeur sans rajout des balises HTML
			if (oChamp) oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, false, true);
			break;
		default:								// Autres cas
			if (oChamp) oChamp.value = sValeur;
			break;
		case this.XML_CHAMP_TYPE_IFRAME_DEST:
		case this.XML_CHAMP_TYPE_IFRAME_SOURCE:
		case this.XML_CHAMP_TYPE_CELLULE:
		case this.XML_CHAMP_TYPE_SUPERCHAMP:
		case this.XML_CHAMP_TYPE_MODELEDECHAMP_SOURCE:
		case this.XML_CHAMP_TYPE_MODELEDECHAMP_DEST:
			//assert(false);
			break;

		case this.XML_CHAMP_TYPE_ONGLET:
			// Changement du volet selectionne
			// On force la selection car la valeur renvoie par le serveur est forcement valide et
			// Que la commande sur el ..Etat des volets peut ne pas encore etre execute
			var oVarChamp = eval("cl" + sAliasChamp);
			if ((typeof oVarChamp == "object") && (oVarChamp.AfficheVolet))
			{
				var nValeur = parseInt(sValeur);
				if (!isNaN(nValeur) && (nValeur >= 1));
				{
					// -1 car la valeur est la valeur WL
					oVarChamp.AfficheVolet(nValeur - 1);
				}
			}
			break;
		}
	},

	// Libelle
	ActionProprieteLibelle:function(oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		var sValeur = this.sXMLGetValeur(XMLAction);
		// Selon le type du champ
		switch(nTypeChamp)
		{
		// On traite le champ bouton specialement : Si c'est un champ image on fait comme les images
		case this.XML_CHAMP_TYPE_BOUTON:
			// Si c'est un bouton image => On doit prendre le div interne
			var oChampImg = _JGE("_" + sAliasChamp + "_IMG", document, false);
			if (oChampImg && (oChampImg.tagName.toUpperCase() != "IMG"))
			{
				oChampImg.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
			}
			else if (oChamp)
			{
				// Si on a le champ c'est que c'est un champ de type input => bouton "normal"
				oChamp.value = sValeur;

			}
			break;
		case this.XML_CHAMP_TYPE_LIBELLE:
			// Dans certains cas une table est ajoute et l'ID est sur la table au lieu de la cellule : retrouve la cellule
			oChamp = this.oSauteTableCadrage(oChamp);

			// Affectation de la valeur avec rajout des balises HTML
			if (oChamp) oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
			break;
		case this.XML_CHAMP_TYPE_LIBELLEHTML:
			// Dans certains cas une table est ajoute et l'ID est sur la table au lieu de la cellule : retrouve la cellule
			oChamp = this.oSauteTableCadrage(oChamp);

			// Affectation de la valeur sans rajout des balises HTML
			if (oChamp) oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, false, true);
			break;
		case this.XML_CHAMP_TYPE_LIEN:
			// On ne cherche pas le champ lui meme mais le champ autour pour avoir la balise a
			oChamp = _JGE(sAliasChamp, document, false, true);
			if (oChamp)
			{
				// Soit on est directement sur le a ou sur le TD autour
				while (oChamp && (oChamp.tagName.toUpperCase() != "A")) oChamp = oChamp.firstChild;
				if (oChamp)
				{
					oChamp.innerHTML = sValeur;
				}
			}
			break;
		case this.XML_CHAMP_TYPE_TABLE:
			// On cherche un id special pour les tables et colonne de table
			oChamp = oGetId("lz" + sAliasChamp);
			if (!oChamp) oChamp = _JGE(sAliasChamp, document, false, true);
			oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
			break;

		case this.XML_CHAMP_TYPE_COLONNE:
			// Si c'est une table AJAX : on doit rechercher la cellule interne
			var sTableAjax = new String(this.sXMLGetAttributSafe(XMLAction, this.XML_CHAMP_PROP_NUM_LIBELLE_TABLE_AJAX));
			if (sTableAjax.length > 0)
			{
				var nSeparateur = sTableAjax.indexOf(";");
				var clTable = eval("cl" + sTableAjax.substring(0, nSeparateur));
				oChamp = clTable.oGetTableId(clTable.ID_TITRE, parseInt(sTableAjax.substring(nSeparateur + 1)));
			}
			// On cherche un id special pour les tables et colonne de table
			if (!oChamp) oChamp = oGetId((nTypeChamp == this.XML_CHAMP_TYPE_TABLE ? "lz" : "tt") + sAliasChamp);
			if (!oChamp) oChamp = _JGE(sAliasChamp, document, false, true);
			oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
			break;

		case this.XML_CHAMP_TYPE_SOUSMENU:
		case this.XML_CHAMP_TYPE_OPTIONMENU:
			// Cas des elements de menu
			if (oChamp) oChamp.innerHTML = clWDEncode.sEncodeInnerHTML(sValeur, true);
			break;

		default:								// Autres cas
			// Ne fait rien
			break;
		}
	},

	// Hauteur
	ActionProprieteHauteur:function(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		var nHauteur = parseInt(this.sXMLGetValeur(XMLAction));
		if (nHauteur >= 0)
		{
			switch (nTypeChamp)
			{
			// Cas particulier pour les conteneurs (Cellules, Superchamps, modeles de champs)
			case this.XML_CHAMP_TYPE_CELLULE:
			case this.XML_CHAMP_TYPE_SUPERCHAMP:
//			case this.XML_CHAMP_TYPE_MODELEDECHAMP_SOURCE
			case this.XML_CHAMP_TYPE_MODELEDECHAMP_DEST:
				// Il faut modifier la cellule interne
				oChamp.getElementsByTagName("TD")[0].height = nHauteur;
				// La cellule
				this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "height", nHauteur + "px", false);
				// Et la cellule externe
				oChamp = oChamp.parentNode;
				while (oChamp && (oChamp != document.body))
				{
					switch (oChamp.tagName.toUpperCase())
					{
					case "TABLE":
						oChamp.height = nHauteur;
						// Pas de break
					default:
						oChamp = oChamp.parentNode;
						break;
					case "DIV":
						this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "height", nHauteur + "px", false);
						oChamp = null;
					}
				}
				break;
			// Cas particuliers des interrupteurs et des sélecteurs => Il faut manipuler chaque instance de l'intérrupteur
			case this.XML_CHAMP_TYPE_INTERRUPTEUR:
			case this.XML_CHAMP_TYPE_SELECTEUR:
				// Modifie la taille globale
				this.ActionProprieteStyleGenerique(oChampExt, nTypeChamp, "height", nHauteur + "px", false);

				// Puis modifier la hauteur de chaque interrupteurs => Ce n'est pas ce que fait le code serveur traditionnel
				break;
				
			// Cas des onglets : on manipule les conteneur des onglets
			case this.XML_CHAMP_TYPE_ONGLET:
//				this.ActionProprieteStyleGenerique(oChampExt, nTypeChamp, "height", nHauteur + "px", false);
//				this.ActionProprieteStyleGenerique(oGetId("con-" + sAliasChamp), nTypeChamp, "height", nHauteur + "px", false);
				// Appele la méthode de la classe
				var oVarChamp = eval("cl" + sAliasChamp);
				if ((typeof oVarChamp == "object") && (oVarChamp.AfficheVolet))
				{
					if (!isNaN(nHauteur) && (nHauteur >= 0));
					{
						// -1 car la valeur est la valeur WL
						oVarChamp.HauteurVolet(nHauteur);
					}
				}
				break;
			
			default:
				this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "height", nHauteur + "px", false);
				break;
			}
		}
	},

	// Largeur
	ActionProprieteLargueur:function(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		var nLargueur = parseInt(this.sXMLGetValeur(XMLAction));
		if (nLargueur >= 0)
		{
			switch (nTypeChamp)
			{
			// Cas particulier pour les conteneurs (Cellules, Superchamps, modeles de champs)
			case this.XML_CHAMP_TYPE_CELLULE:
			case this.XML_CHAMP_TYPE_SUPERCHAMP:
//			case this.XML_CHAMP_TYPE_MODELEDECHAMP_SOURCE
			case this.XML_CHAMP_TYPE_MODELEDECHAMP_DEST:
				// Il faut modifier la cellule interne
				oChamp.getElementsByTagName("TD")[0].width = nLargueur;
				// La cellule
				this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "width", nLargueur + "px", false);
				// Et la cellule externe
				oChamp = oChamp.parentNode;
				while (oChamp && (oChamp != document.body))
				{
					switch (oChamp.tagName.toUpperCase())
					{
					case "TABLE":
						oChamp.width = nLargueur;
						// Pas de break
					default:
						oChamp = oChamp.parentNode;
						break;
					case "DIV":
						this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "width", nLargueur + "px", false);
						oChamp = null;
					}
				}
				break;
			// Cas particuliers des interrupteurs et des sélecteurs => Il faut manipuler chaque instance de l'intérrupteur
			case this.XML_CHAMP_TYPE_INTERRUPTEUR:
			case this.XML_CHAMP_TYPE_SELECTEUR:
				// Modifie la taille globale
				this.ActionProprieteStyleGenerique(oChampExt, nTypeChamp, "width", nLargueur + "px", false);

				// Puis modifier la hauteur de chaque interrupteurs => Ce n'est pas ce que fait le code serveur traditionnel
				break;
			
			// Cas des onglets : on manipule le conteneur externe et le contenuer interne
			case this.XML_CHAMP_TYPE_ONGLET:
				this.ActionProprieteStyleGenerique(oChampExt, nTypeChamp, "width", nLargueur + "px", false);
				this.ActionProprieteStyleGenerique(oGetId("con-" + sAliasChamp), nTypeChamp, "width", nLargueur + "px", false);

			default:
				this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "width", nLargueur + "px", false);
				break;
			}
		}
	},

	// X
	ActionProprieteX:function (oChamp, nTypeChamp, XMLAction)
	{
		//assert(oChamp.tagName == "DIV");
		// On ne filtre pas les positions , les positions negatives sont valides
		this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, bRTL ? "right" : "left", this.sXMLGetValeur(XMLAction) + "px", false);
	},

	// Y
	ActionProprieteY:function (oChamp, nTypeChamp, XMLAction)
	{
		//assert(oChamp.tagName == "DIV");
		// On ne filtre pas les positions , les positions negatives sont valides
		this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "top", this.sXMLGetValeur(XMLAction) + "px", false);
	},

	// Couleur
	ActionProprieteCouleur:function(oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		// On ne recupere la couleur qu'une fois
		var sCouleur = this.sXMLGetValeur(XMLAction);
		// Puis selon le type de champ on fait des actions differentes
		switch(nTypeChamp)
		{
		// Les interrupteurs et les selecteurs sont particulier
		case this.XML_CHAMP_TYPE_INTERRUPTEUR:
		case this.XML_CHAMP_TYPE_SELECTEUR:
			oChamp = _JGE(sAliasChamp, document, false, true);
			if (oChamp && oChamp.style) oChamp.style.color = sCouleur;
//			this.ActionProprieteCouleurFeuilleStyle(sAliasChamp, false, false, sCouleur);
			break;

		case this.XML_CHAMP_TYPE_CHEMINNAV:
		case this.XML_CHAMP_TYPE_PLANSITE:
		case this.XML_CHAMP_TYPE_REGLETTE:
		case this.XML_CHAMP_TYPE_TREEVIEW:
			// Pour les champs de type reglette, le style est sur le conteneur de la reglette (Pas de problemes)
			// mais il y a une surcharge du style pour toutes les balises A dans la ligne (car sinon les balises n'heritent pas du style)
			this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "color", sCouleur, true);
			break;

		case this.XML_CHAMP_TYPE_COLONNE:
			// Va modifier le style dans l'entete de la page
			this.ActionProprieteCouleurFeuilleStyle("#c-" + sAliasChamp, "color", sCouleur);
			break;

		case this.XML_CHAMP_TYPE_LIEN:
			oChamp = _JGE(sAliasChamp, document, false, false);
			// Pas de break : fait comme pour les autres champs pour le reste

		// Mais pas de problemes avec les autres champs
		default:
			if (oChamp && oChamp.style) oChamp.style.color = sCouleur;
			break;
		}
	},

	// Couleur de fond
	ActionProprieteCouleurFond:function(oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		// On ne recupere la couleur qu'une fois
		var sCouleur = this.sXMLGetValeur(XMLAction);
		// Puis selon le type de champ on fait des actions differentes
		switch(nTypeChamp)
		{
		case this.XML_CHAMP_TYPE_PAGEPRINCIPALE:
			document.bgColor = sCouleur;
			break;

		// Les interrupteurs et les selecteurs sont particulier
		case this.XML_CHAMP_TYPE_INTERRUPTEUR:
		case this.XML_CHAMP_TYPE_SELECTEUR:
			oChamp = _JGE(sAliasChamp, document, false, true);
			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
//			this.ActionProprieteCouleurFeuilleStyle(sAliasChamp, false, true, sCouleur);
			break;

//		// Les champs tables
//		case this.XML_CHAMP_TYPE_TABLE:
//			// Il faut modifier les elements commencant par les prefixe suivant : ctz, lz, tt
//			var oChamp = document.getElementById("ctz" + sAliasChamp);
//			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
//			oChamp = document.getElementById("lz" + sAliasChamp);
//			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
//			oChamp = document.getElementById("tt" + sAliasChamp);
//			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
//			break;

		case this.XML_CHAMP_TYPE_IFRAME_DEST:
		case this.XML_CHAMP_TYPE_IFRAME_SOURCE:
		case this.XML_CHAMP_TYPE_CELLULE:
		case this.XML_CHAMP_TYPE_SUPERCHAMP:
		case this.XML_CHAMP_TYPE_MODELEDECHAMP_SOURCE:
		case this.XML_CHAMP_TYPE_MODELEDECHAMP_DEST:
			// On cherche le champ cellule
			oChamp = _JGE(sAliasChamp, document, false);
			// Et on lui applique le style
			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
			break;

		case this.XML_CHAMP_TYPE_LIEN:
			// Pour QW46375 : Les champs liens on le style sur la balise tz (Sur la cellule conteneur) et sur le champ lien
			// On cherche la cellule de table
			var oChamp2 = _JGE(sAliasChamp, document, true);
			// Et on lui applique le style
			if (oChamp2 && oChamp2.style) oChamp2.style.backgroundColor = sCouleur;
			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
			break;

		case this.XML_CHAMP_TYPE_REGLETTE:
			// Pour les champs de type reglette, le style est sur le conteneur de la reglette (Pas de problemes)
			// mais il y a une surcharge du style pour toutes les balises A dans la ligne (car sinon les balises n'heritent pas du style)
			this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "backgroundColor", sCouleur, true);
			break;

		// Mais pas de problemes avec les autres champs
		default:
			//assert(oChamp)
			if (oChamp && oChamp.style) oChamp.style.backgroundColor = sCouleur;
			break;
		}
	},

	// Etat d'un champ
	ActionProprieteEtat:function (oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		// Essai de trouver la collection des attributs de la balise A
		var oBaliseA = null;
		if (oChamp.tagName == "A")
		{
			oBaliseA = oChamp;
		}
		else if (oChamp.parentNode.tagName == "A")
		{
			oBaliseA = oChamp.parentNode;
		}
		else
		{
			return;
		}

		// Recupere l'etat final
		var nEtat = parseInt(this.sXMLGetAttribut(XMLAction, this.XML_CHAMP_ETAT_ETAT));
		// Et la balise avec les attributs
		var oBalise = XMLAction.firstChild;

		// Selon le type de champ
		switch (nTypeChamp)
		{
		// Champ qui genere des liens
		case this.XML_CHAMP_TYPE_BOUTON:
		case this.XML_CHAMP_TYPE_LIEN:
		case this.XML_CHAMP_TYPE_MAPAREA:
		// Et aussi sur les options de menu
		case this.XML_CHAMP_TYPE_SOUSMENU:
		case this.XML_CHAMP_TYPE_OPTIONMENU:
		// Gestion de ..Etat sur les volets d'onglets
		case this.XML_CHAMP_TYPE_VOLETONGLET:
			// Parcours les attributs de oBalise pour les ajouter ou les supprimer du champ
			var tabAttributs = oBalise.attributes;
			var i;
			var nLimiteI = tabAttributs.length;
			for (i = 0; i < nLimiteI; i++)
			{
				var oAttribut = tabAttributs.item(i);

				if (nEtat != 0)
				{
					// Si on desactive => Supprime l'attribut
					switch (oAttribut.nodeName.toLowerCase())
					{
					case "onmouseout":
						oBaliseA.onmouseout = null;
						break;
					case "onmouseover":
						oBaliseA.onmouseover = null;
						break;
					default:
						oBaliseA.removeAttribute(oAttribut.nodeName, 0);
						break;
					}
				}
				else
				{
					// Ajoute/modifie l'attribut
					switch (oAttribut.nodeName.toLowerCase())
					{
					case "onmouseout":
						oBaliseA.onmouseout = new Function("", "document." + oAttribut.nodeValue);
						break;
					case "onmouseover":
						oBaliseA.onmouseover = new Function("", "document." + oAttribut.nodeValue);
						break;
					default:
						oBaliseA.setAttribute(oAttribut.nodeName, oAttribut.nodeValue, 0);
						break;
					}
				}
			}
			break;
		default:
			break;
		}
	},

	// Couleur de fond
	ActionProprieteVisible:function(oChamp, nTypeChamp, XMLAction)
	{
		// Selon le type du champ
		switch(nTypeChamp)
		{
		case this.XML_CHAMP_TYPE_VOLETONGLET:
		case this.XML_CHAMP_TYPE_SOUSMENU:
		case this.XML_CHAMP_TYPE_OPTIONMENU:
			// Cas des elements de menu : on fait un display:none/block
			if (oChamp && oChamp.style) oChamp.style.display = (this.sXMLGetValeur(XMLAction) == "0") ? "none" : "block";
			break;

		default:
			var sVisibility = "";
			switch(this.sXMLGetValeur(XMLAction))
			{
			case "0":
				sVisibility = "hidden";		// Cache
				break;
			case "1":
			default:
				sVisibility = "inherit";
				break;
			}
			// oChamp est normalement le conteneur externe du champ
			if (oChamp && oChamp.style) oChamp.style.visibility = sVisibility;
			break;
		}
	},

	// Image
	ActionProprieteImage:function(oChamp, nTypeChamp, XMLAction)
	{
		// Selon le type du champ
		switch(nTypeChamp)
		{
		default:
			oChamp.src = this.sXMLGetValeur(XMLAction);
			break;
		}
	},

	// URL
	ActionProprieteURL:function(oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		var oChampCpy = oChamp;
		// Selon le type du champ
		switch(nTypeChamp)
		{
		case this.XML_CHAMP_TYPE_MAPAREA:
			// Sur les champs image clicable simple l'id est sur le IMG et la A autour n'en a pas
			if (oChamp && (oChamp.tagName.toUpperCase() == "IMG") && (oChamp.parentNode.tagName.toUpperCase() == "A"))
				oChamp = oChamp.parentNode;
			break;
		default:
			// On ne cherche pas le champ lui meme mais le champ autour pour avoir la balise a
			oChamp = _JGE(sAliasChamp, document, false, true);
			// Sauf que on ne trouve rien dans le cas des lien simples
			if (!oChamp)
				oChamp = oChampCpy;
			break;
		}
		if (oChamp)
		{
			// Soit on est directement sur le a ou sur le TB autour
			if (oChamp.tagName.toUpperCase() == "TD") oChamp = oChamp.firstChild;
			if (oChamp)
			{
				var sURL = this.sXMLGetValeur(XMLAction);
				// Si le champ est un bouton, il faut faire autrement
				if (oChamp.tagName.toUpperCase() == "INPUT")
				{
					// Normalement son action commence par javascript:_JCL('xxx');
					// Remplacer le premier paramètre
					var rPremierParam = new RegExp("\\(\\'([^\\']*)\\'", "");
					var sOnClick = oChamp.getAttributeNode("onclick").value;
					if (rPremierParam.test(sOnClick))
					{
						sOnClick = sOnClick.replace(rPremierParam, function () { return "('" + sURL + "'"; })
						oChamp.onclick = new Function("", sOnClick);
					}
				}
				else
				{
					oChamp.href = sURL;
				}
			}
		}
	},

	// Bulle
	ActionProprieteBulle:function (oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		var sValeur = this.sXMLGetValeur(XMLAction);
		// selon le type du champ
		switch(nTypeChamp)
		{
		case this.XML_CHAMP_TYPE_INTERRUPTEUR:
		case this.XML_CHAMP_TYPE_SELECTEUR:
			// Pour les interrupteurs/selecteurs : on a un tableau d'elements
			var oElements = document.getElementsByName(sAliasChamp);
			if (oElements && oElements.length)
			{
				var i;
				var nLimiteI = oElements.length;
				for (i = 0; i < nLimiteI; i++)
				{
					if (oElements[i]) oElements[i].title = sValeur;
				}
			}
			// On ne fait pas le cas par defaut => sort direct
			return;

			// Cas special des table ou le champ trouve par defaut est le champ cache et pas la racine de la table
		case this.XML_CHAMP_TYPE_TABLE:
			oChamp = this.oGetConteneurParent(sAliasChamp);
			break;

			// On traite le champ bouton specialement : Si c'est un champ image on fait comme les images
		case this.XML_CHAMP_TYPE_BOUTON:
			// On doit aussi manipuler le champ fils si disponible
			if (oChamp.firstChild) oChamp.firstChild.title = sValeur;
			break;
		}

		if (oChamp) oChamp.title = sValeur;
	},

	// CurseurSouris
	ActionProprieteCurseurSouris:function (oChamp, nTypeChamp, XMLAction)
	{
		this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, "cursor", this.sXMLGetValeur(XMLAction), true);
	},

	// PoliceGras
	ActionProprietePoliceGras:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "fontWeight", parseInt(this.sXMLGetValeur(XMLAction)), true);
	},

	// PoliceItalique
	ActionProprietePoliceItalique:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "fontStyle", parseInt(this.sXMLGetValeur(XMLAction)) ? "italic" : "normal", true);
	},

	// PoliceNom
	ActionProprietePoliceNom:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "fontFamily", this.sXMLGetValeur(XMLAction), true);
	},

	// PoliceSoulignee
	ActionProprietePoliceSoulignee:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "textDecoration", parseInt(this.sXMLGetValeur(XMLAction)) ? "underline" : "none", true);
	},

	// PoliceTaille
	ActionProprietePoliceTaille:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "fontSize", this.sXMLGetValeur(XMLAction), true);
	},

	// CurseurSouris
	ActionProprieteOpacite:function (oChamp, nTypeChamp, XMLAction)
	{
		var nOpacite = parseInt(this.sXMLGetValeur(XMLAction));
		if (isNaN(nOpacite)) nOpacite = 100;
		if (nOpacite < 0) nOpacite = 0;
		if (nOpacite > 100) nOpacite = 100;

		// Selon le navigateur
		if (bIE)
		{	// Manipule les filtres
			if (oChamp)
			{
				var tabFilters = oChamp.filters;
				if (tabFilters.exists("alpha"))
				{
					tabFilters.item("alpha").opacity = nOpacite;
				}
				else if (tabFilters.exists("DXImageTransform.Microsoft.Alpha"))
				{
					tabFilters.item("DXImageTransform.Microsoft.Alpha").opacity = nOpacite;
				}
				else if (oChamp.style)
				{
					oChamp.style.filter += "alpha(opacity=" + nOpacite + ")"
				}
			}
		}
		else
		{	// Autre : manipule opacity sous forme de double

			// oChamp est normalement le conteneur externe du champ
			if (oChamp && oChamp.style) oChamp.style.opacity = (nOpacite / 100) + "";
		}
	},

	// Cadrage horizontal
	ActionProprieteCadrageH:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "textAlign", this.sXMLGetValeur(XMLAction), true);
	},

	// Cadrage vertical
	ActionProprieteCadrageV:function (oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp)
	{
		this.ActionProprieteStylePolice(oChamp, oChampExt, nTypeChamp, sAliasChamp, "verticalAlign", this.sXMLGetValeur(XMLAction), true);
	},

	// Indication
	ActionProprieteIndication:function (oChamp, nTypeChamp, XMLAction, sAliasChamp)
	{
		// L'indication ne concerne que le champ de saisie
		// Celui-ci n'a pas de PCode serveur AJAX. Il n'a donc pas le focus actuellement (puisqu'un autre champ a declenche l'evenement)

		// Trouve l'objet
		var oVarChamp = eval("cl" + sAliasChamp);
		if ((typeof oVarChamp == "object") && (oVarChamp.SetIndication))
		{
			oVarChamp.SetIndication(this.sXMLGetValeur(XMLAction));
		}
	},

	// Aplique une propriete (liee a la police) du style sur un champ
	ActionProprieteStylePolice:function (oChamp, oChampExt, nTypeChamp, sAliasChamp, sNomStyle, sValeurProp, bElementsReglette)
	{
		// selon le type du champ
		switch(nTypeChamp)
		{
		// Certains elements du formulaire son impermeable a la police de l'element du dessus (La police est dans le style)
		// Il faut donc appliquer la propriete au champ
		case this.XML_CHAMP_TYPE_SAISIE:
		case this.XML_CHAMP_TYPE_BOUTON:
		case this.XML_CHAMP_TYPE_LISTE:
		case this.XML_CHAMP_TYPE_CHAMPFORMATE:
		case this.XML_CHAMP_TYPE_COMBO:
		case this.XML_CHAMP_TYPE_LIEN:
		// D'autres comme le treeview : il ne faut manipuler un id tres speficique (nom avec un _)
		case this.XML_CHAMP_TYPE_TREEVIEW:
		case this.XML_CHAMP_TYPE_LIBELLE:
			this.ActionProprieteStyleGenerique(oChamp, nTypeChamp, sNomStyle, sValeurProp, bElementsReglette);
			break;
			
		case this.XML_CHAMP_TYPE_COLONNE:
			// Va modifier le style dans l'entete de la page
			this.ActionProprieteCouleurFeuilleStyle("#c-" + sAliasChamp, sNomStyle, sValeurProp);
			break;

		// Les interrupteurs et les selecteurs sont particulier
		case this.XML_CHAMP_TYPE_INTERRUPTEUR:
		case this.XML_CHAMP_TYPE_SELECTEUR:
			oChampExt = _JGE(oChamp[0].name, document, false, true);
			// Pas de break

		default:
			this.ActionProprieteStyleGenerique(oChampExt, nTypeChamp, sNomStyle, sValeurProp, bElementsReglette);
			break;
		}
	},

	// Aplique une propriete du style sur un champ
	ActionProprieteStyleGenerique:function (oChamp, nTypeChamp, sNomStyle, sValeurProp, bElementsReglette)
	{
		// Si on a pas de champ : fini
		if (!oChamp)
			return;

		// selon le type du champ
		switch(nTypeChamp)
		{
		// Il faut faire de meme pour les liens du chemin de navigation
		case this.XML_CHAMP_TYPE_CHEMINNAV:
		case this.XML_CHAMP_TYPE_PLANSITE:
		case this.XML_CHAMP_TYPE_REGLETTE:
		case this.XML_CHAMP_TYPE_TREEVIEW:
			// Si on demande de traiter les elements de la reglette
			if (bElementsReglette)
			{
				this.ActionProprieteStyleGeneriqueReglette(oChamp, sNomStyle, sValeurProp);
			}
			// Pas de break

		default:
			oChamp.style[sNomStyle] = sValeurProp;
		}
	},

	// Applique une propriete du style sur les liens d'une reglette
	ActionProprieteStyleGeneriqueReglette:function (oReglette, sNomStyle, sValeurProp)
	{
		// Si on a pas de reglette : fini
		if (!oReglette)
			return;

		var tabLiens = oReglette.getElementsByTagName("a");
		var i;
		var nLimiteI = tabLiens.length;
		for (i = 0; i < nLimiteI; i++)
		{
			tabLiens[i].style[sNomStyle] = sValeurProp;
		}
	},

	// Modifie la couleur ou la couleur de fond dans les styles present dans les feuilles de style
//	ActionProprieteCouleurFeuilleStyle:function (sAliasChamp, bTreeView, bCouleurFond, sCouleur)
	ActionProprieteCouleurFeuilleStyle:function (sRuleName, sNomStyle, sValeurProp)
	{
//		// Construit les nom de regles acceptees
//		var tabRulesName = new Array("#" + sAliasChamp, "#tz" + sAliasChamp);
//		if (bTreeView)
//			tabRulesName.push("#s-" + sAliasChamp);
//		// Et son iterateur
//		var nRuleName;
//		var nRuleNameLimite = tabRulesName.length;

		// On modifie le style a la racine
		var tabStyles = document.getElementsByTagName("STYLE");
		var i;
		var nLimiteI = tabStyles.length;
		for (i = 0; i < nLimiteI; i++)
		{
			// Pour internet explorer
			if (tabStyles[i].styleSheet)
			{
				var oFeuilleStyle = tabStyles[i].styleSheet;

				// On parcours les sous styles
				var j;
				var nLimiteJ = oFeuilleStyle.rules.length;
				for (j = 0; j < nLimiteJ; j++)
				{
//					var sSelectorText = oFeuilleStyle.rules[j].selectorText;
//					// Recherche le nom courant dans le tableau des regles acceptees
//					for (nRuleName = 0; nRuleName < nRuleNameLimite; nRuleName++)
//					{
//						if (sSelectorText == tabRulesName[nRuleName])
//						{
//							if (bCouleurFond)
//								oFeuilleStyle.rules[j].style.backgroundColor = sCouleur;
//							else
//								oFeuilleStyle.rules[j].style.color = sCouleur;
//						}
//					}
					if (oFeuilleStyle.rules[j].selectorText == sRuleName)
					{
						oFeuilleStyle.rules[j].style[sNomStyle] = sValeurProp;
					}
				}
			}
			// Pour FireFox et autres
			else if (tabStyles[i].sheet)
			{
				var oFeuilleStyle = tabStyles[i].sheet;

				// On parcours les sous styles
				var j;
				var nLimiteJ = oFeuilleStyle.cssRules.length;
				for (j = 0; j < nLimiteJ; j++)
				{
					// On recupere la liste des styles pour voir si notre style y est
					// Comme les styles sont groupes par le moteur selon des styles qui doivent reste identique il sufit de trouver notre style une fois
					// Ici les styles sont groupe donc il faut faire un parsing
					var tabStylesNom = oFeuilleStyle.cssRules[j].selectorText.split(",");
					var k;
					var nLimiteK = tabStylesNom.length;
					for (k = 0; k < nLimiteK; k++)
					{
//						// Enleve les espaces abusif
//						var sSelectorText = tabStylesNom[k].replace(/ /g, "");
//						// Recherche le nom courant dans le tableau des regles acceptees
//						for (nRuleName = 0; nRuleName < nRuleNameLimite; nRuleName++)
//						{
//							if (sSelectorText == tabRulesName[nRuleName])
//							{
//								if (bCouleurFond)
//									oFeuilleStyle.cssRules[j].style.backgroundColor = sCouleur;
//								else
//									oFeuilleStyle.cssRules[j].style.color = sCouleur;
//							}
//						}
						if (tabStylesNom[k].replace(/ /g, "") == sRuleName)
						{
							oFeuilleStyle.cssRules[j].style[sNomStyle] = sValeurProp;
						}
					}
				}
			}
		}
	},

	// Execute un code JS sur l'objet
	ActionChampJS:function (oChamp, sAliasChamp, XMLAction)
	{
		if (!oChamp)
		{
			// Essai avec un getElementById
			oChamp = _JGE(sAliasChamp, document);
		}

		if (oChamp)
		{
			eval("oChamp" + this.sXMLGetValeur(XMLAction));
		}
	},

	// Ajoute des options au champ
	ActionChampOptions:function (oChamp, XMLAction)
	{
		// On parcourt les options du champ
		var XMLOption = XMLAction.firstChild;
		while(XMLOption)
		{
			// Selon l'option transmise
			switch (XMLOption.nodeName)
			{
			// Option simple
			default:
			case this.XML_CHAMP_OPTIONS_OPTION:
				// On ajoute l'option
				oChamp.options[oChamp.options.length] = new Option(this.sXMLGetValeur(XMLOption), oChamp.options.length + 1);
				// Il y a un problemes avec les carteres > 127
				oChamp.options[oChamp.options.length-1].innerHTML = clWDEncode.sEncodeInnerHTML(oChamp.options[oChamp.options.length-1].innerHTML, false, true);
				break;
			// Liste sature
			case this.XML_CHAMP_SATURATION:
				//assert(oChamp.options.length == 0);
				//assert(!XMLOption.nextSibling);
				// On ajoute l'option
				oChamp.options[oChamp.options.length] = new Option(this.sXMLGetValeur(XMLOption), -1);
				break;
			}
			// Option suivante
			XMLOption = XMLOption.nextSibling;
		}
	},

	// Modifie les lignes d'une table/d'un zone repetee
	ActionChampLignes:function (oChamp, nTypeChamp, XMLAction, sNomChamp)
	{
		// On utilise outerHTML avec IE et les autres methodes avec les autres navigateurs
		var bUtiliseOuterHTML = bIE;

		// On recupere les attributs de la ZR/Table
		// Indice du premier element
		var nDebut = parseInt(this.sXMLGetAttribut(XMLAction,this.XML_CHAMP_LIGNES_DEBUT));
		// Nombre d'element
		var nNombre = parseInt(this.sXMLGetAttribut(XMLAction,this.XML_CHAMP_LIGNES_NOMBRE));
		// Ligne selectionne
		var nSelection = parseInt(this.sXMLGetAttribut(XMLAction,this.XML_CHAMP_LIGNES_SELECTION));
		//asert(nNombre<=nLimite);
		var nNbRuptures = 0;
		if (this.bXMLAttributExiste(XMLAction, this.XML_CHAMP_LIGNES_RUPTURES))
		{
			nNbRuptures = parseInt(this.sXMLGetAttribut(XMLAction,this.XML_CHAMP_LIGNES_RUPTURES));
		}
		// Multicolonnes ?
		var bMultiColonnes = this.bXMLAttributExiste(XMLAction, this.XML_CHAMP_LIGNES_COLONNES);
		var nMultiColonnes = bMultiColonnes ? parseInt(this.sXMLGetAttribut(XMLAction,this.XML_CHAMP_LIGNES_COLONNES)) : 1;

		// Regarde si on doit aussi gerer les styles de la ligne
		var bStyle = this.bXMLAttributExiste(XMLAction, this.XML_CHAMP_LIGNES_STYLE);

		// On recupere le debut actuel
		var nDebutActuel = parseInt(eval("_PAGE_." + sNomChamp + "_DEB").value);
		var nIndiceActuel;

		// On trouve le conteneur des lignes de la table
		// On a deux conteneur : le conteneur parent logique (Souvent une balise TABLE) et le conteneur physique reel
		// qui dans le cas d'une table est une balise TBODY ajoute (+/- automatiquement par le navigateur)
		var oConteneurParent = this.oGetConteneurParent(sNomChamp);
		var oConteneurTBody = this.oGetConteneurTBODY(oConteneurParent);

		// Pour les lignes existantes
		// On a trois cas :
		// - IE + Champ table : on remplace le contenu de la ligne de table par celui renvoye par le moteur
		// - IE + ZR : on remplace l'interieur de la ligne (Exterieur du DIV) de table par celle renvoye par le moteur
		// - Autres : on fait un remplace avec les methodes du DOM

		// Supprime les lignes en trop au debut
		while ((nDebutActuel < nDebut) && this.bSupprimeLigne(sNomChamp, nTypeChamp, nDebutActuel, nNbRuptures, oConteneurParent, oConteneurTBody))
		{
			nDebutActuel++;
		}

		// Ou les lignes en trop apres la fin
		if (nDebutActuel >= nDebut + nNombre)
		{
			while (this.bSupprimeLigne(sNomChamp, nTypeChamp, nDebutActuel, nNbRuptures, oConteneurParent, oConteneurTBody))
			{
				nDebutActuel++;
			}
		}

		// Pour le premier cas on lit d'une fois le outerHTML de la table pour que le traitement soit plus rapide
		// Recupere le contenu du conteneur actuel (Sans espaces ni RC superflus)
		if ((bUtiliseOuterHTML) && (nTypeChamp == this.XML_CHAMP_TYPE_TABLE))
		{	// Pas de scope en JS donc sContenuActuelTable existe meme a la sortie du block
			var sContenuActuelTable = oConteneurParent.outerHTML;
			sContenuActuelTable = this.sSansEspace(sContenuActuelTable, true, true, true);
		}

		// On parcourt les lignes du champ
		var XMLLigne = XMLAction.firstChild;
		while(XMLLigne)
		{
			//assert(XMLLigne.nodeName == this.XML_CHAMP_LIGNES_LIGNE);

			// Recupere le numero de la ligne modifiee
			nIndiceActuel = parseInt(this.sXMLGetAttribut(XMLLigne, this.XML_CHAMP_LIGNES_LIGNE_INDICE));

			// Recupere les trois partie de la ligne
			// Optimisation : dans certains cas, si debut et fin sont vide, seule la balise corps est transmise
			var bCorpsSeul = XMLLigne.childNodes.length == 1;
			//assert(XMLLigne.childNodes[0].nodeName==this.XML_CHAMP_LIGNES_LIGNE_DEBUT);
			var sDebut = bCorpsSeul ? "" : clWDEncode.sEncodeInnerHTML(this.sXMLGetValeur(XMLLigne.childNodes[0]), false, true);
			//assert(XMLLigne.childNodes[1].nodeName==this.XML_CHAMP_LIGNES_LIGNE_CORPS);
			var sCorps = clWDEncode.sEncodeInnerHTML(this.sXMLGetValeur(XMLLigne.childNodes[bCorpsSeul ? 0 : 1]), false, true);
			//assert(XMLLigne.childNodes[2].nodeName==this.XML_CHAMP_LIGNES_LIGNE_FIN);
			var sFin = bCorpsSeul ? "" : clWDEncode.sEncodeInnerHTML(this.sXMLGetValeur(XMLLigne.childNodes[2]), false, true);

			// On trouve la ligne actuelle avec l'ID actuel
			var oLigne = this.oGetConteneurLigne(sNomChamp, nIndiceActuel);

			// Si on trouve la ligne : on change uniquement son HTML
			if (oLigne)
			{
				// Si on peux utiliser outerHTML
				if (bUtiliseOuterHTML)
				{	// Pour IE
					// Dans les tables on remplace toute la ligne car les tr et td on des informations
					if (nTypeChamp == this.XML_CHAMP_TYPE_TABLE)
					{
						// Et de la ligne actuelle (Sans espaces ni RC superflus)
						var sContenuActuelLigne = oLigne.outerHTML;
						sContenuActuelLigne = this.sSansEspace(sContenuActuelLigne, true, true, true);

						// Et la position de la ligne actuelle dans cette table
						// Cela fonctionne car on a vire les espaces et RC que les navigateur ajoutes
						var nPositionActuelleLigne = sContenuActuelTable.indexOf(sContenuActuelLigne);
						// Et remplace cette ligne

						sContenuActuelTable = sContenuActuelTable.substring(0, nPositionActuelleLigne) + sDebut + sCorps + sFin + sContenuActuelTable.substring(nPositionActuelleLigne + sContenuActuelLigne.length);
					}
					else
					{
						// On supprime les ruptures de la ligne car sCorps les contient et cree plusieurs balises paralleles
						this.SupprimeRuptures(sNomChamp, nIndiceActuel, nNbRuptures);

						//assert(nTypeChamp==this.XML_CHAMP_TYPE_ZONEREPETEE);
						// On ne teste pas si la ligne a change car comme IE reorganise le HTML, les chances sont que les chaines
						// soient differentes meme si logiquement identique
						oLigne.outerHTML = sCorps;

						// On retrouve la ligne actuelle apres modification
						oLigne = this.oGetConteneurLigne(sNomChamp, nIndiceActuel);

						// Si la couleur de fond a change et que l'on est dans des colonnes monolignes, il faut modifier le parent si besoin
						var sCouleurFond = oLigne.style.backgroundColor;
						if (_JGCS(oLigne.parentNode).backgroundColor != sCouleurFond)
						{
							oLigne.parentNode.style.backgroundColor = sCouleurFond;
						}
					}
				}
				else
				{	// Pour les autres navigateur

					// On supprime les ruptures de la ligne car sCorps les contient et cree plusieurs balises paralleles
					if (nTypeChamp != this.XML_CHAMP_TYPE_TABLE)
					{
						this.SupprimeRuptures(sNomChamp, nIndiceActuel, nNbRuptures);
					}

					// Optim ?
					if (oLigne.parentNode.childNodes.length == 1)
					{
						oLigne.parentNode.innerHTML = sCorps;
					}
					else
					{
						// Pour les autres navigateur
						var oRange = document.createRange();	// Pas disponible pour IE donc pas d'unification possible
						oRange.setStartBefore(oLigne);
						oLigne.parentNode.replaceChild(oRange.createContextualFragment(sCorps), oLigne);
					}
					// Recupere le TBODY nouvellement cree si besoin
					if (oConteneurParent == oConteneurTBody)
					{
						oConteneurParent = this.oGetConteneurParent(sNomChamp);
						oConteneurTBody = this.oGetConteneurTBODY(oConteneurParent);
					}
				}
			}
			else
			{
				// On ne trouve pas la ligne : on doit donc la creer
				// On ajoute un voisin a la derniere ligne
				if (oConteneurParent.insertAdjacentHTML)
				{	// Pour IE

					// insertAdjacentHTML ne marche pas sur les balises <TABLE> et <TBODY>
					if ((oConteneurTBody != oConteneurParent) && (oConteneurTBody))
					{
						// Si on n'a pas encore sContenuActuelTable on le recupere
						// Possible car on passe aussi ici pour les ZRs
						if (!sContenuActuelTable)
						{
							sContenuActuelTable = oConteneurParent.outerHTML;
							sContenuActuelTable = this.sSansEspace(sContenuActuelTable, true, true, true);
						}

						//assert(oConteneurParent.tagName.toUpperCase() == "TABLE");
						//assert(oConteneurTBody.tagName.toUpperCase() == "TBODY"))
						// Normalement la zone ce fini par </TABLE>
						//assert(sContenuTable.substr(sContenuTable.length - oConteneurParent.tagName.toUpperCase().length) == "</TABLE>")
						if (sContenuActuelTable.substr(sContenuActuelTable.length - "</TABLE>".length).toUpperCase() == "</TABLE>")
						{
							// Si on est multicolonne => Utile <TD>
							if (bMultiColonnes)
							{
								var nPosTR = sContenuActuelTable.toUpperCase().lastIndexOf("</TR>");
								// Si on ne trouve pas de TR : il n'y a pas de ligne dans la ZR
								if (nPosTR == -1)
								{
									var nPosTBody = sContenuActuelTable.toUpperCase().lastIndexOf("</TBODY>");
									// Supprime le </TD> en trop au debut de la ligne
									if (sDebut.toUpperCase().indexOf("</TR>") == 0)
									{
										sDebut = sDebut.substring("</TR>".length);
									}
									else if (sCorps.toUpperCase().indexOf("</TR>") == 0)
									{
										sCorps = sCorps.substring("</TR>".length);
									}
									if ((sFin.toUpperCase().lastIndexOf("</TR>") != (sFin.length - "</TR>".length)) && (sCorps.toUpperCase().lastIndexOf("</TR>") != (sCorps.length - "</TR>".length)))
									{
										sFin += "</TR>";
									}
									sContenuActuelTable = sContenuActuelTable.substring(0, nPosTBody) + sDebut + sCorps + sFin + sContenuActuelTable.substring(nPosTBody);
								}
								else
								{
									sContenuActuelTable = sContenuActuelTable.substring(0, nPosTR) + sDebut + sCorps + sFin + sContenuActuelTable.substring(nPosTR);
								}
							}
							else
							{
								var nPosTBody = sContenuActuelTable.toUpperCase().lastIndexOf("</TBODY>");
								sContenuActuelTable = sContenuActuelTable.substring(0, nPosTBody) + sDebut + sCorps + sFin + sContenuActuelTable.substring(nPosTBody);
							}
						}
						else
						{
							sContenuActuelTable += sDebut + sCorps + sFin + oConteneurParent.tagName;
						}
					}
					else
					{
						oConteneurTBody.insertAdjacentHTML("beforeEnd", sDebut + sCorps + sFin);
						// Met a jour le conteneur parent
						oConteneurParent = this.oGetConteneurParent(sNomChamp);
						oConteneurTBody = this.oGetConteneurTBODY(oConteneurParent);
					}
				}
				else
				{	// Pour les autres navigateur
					var oRange = document.createRange();
					if (bMultiColonnes && ((nIndiceActuel % nMultiColonnes) != 1))
					{
						oRange.setStart(oConteneurTBody.lastChild, 0);
						oConteneurTBody.lastChild.appendChild(oRange.createContextualFragment(sDebut + sCorps + sFin));
					}
					else
					{
						oRange.setStart(oConteneurTBody, 0);
						oConteneurTBody.appendChild(oRange.createContextualFragment(sDebut + sCorps + sFin));
					}

					// Recupere le TBODY nouvellement cree si besoin
					if (oConteneurParent == oConteneurTBody)
					{
						oConteneurParent = this.oGetConteneurParent(sNomChamp);
						oConteneurTBody = this.oGetConteneurTBODY(oConteneurParent);
					}
				}
			}

			// Change le(s) style(s) de la ligne si besoin

			// Si on a une quatrieme node fille c'est que l'on a un style a modifie pour la ligne
			//assert((!bStyle) || (XMLLigne.childNodes.length >= 4));
			//assert((!bStyle) || (XMLLigne.childNodes[3].nodeName==this.XML_CHAMP_LIGNES_LIGNE_STYLE));
			if (bStyle)
			{
				this.ActionLigneStyle(this.sXMLGetValeur(XMLLigne.childNodes[3]));
			}

			// Ligne suivante
			XMLLigne = XMLLigne.nextSibling;
		}

		// Met a jour le conteneur parent si besoin
		if (sContenuActuelTable)
		{
			oConteneurParent.outerHTML = sContenuActuelTable;
			oConteneurParent = this.oGetConteneurParent(sNomChamp);
			oConteneurTBody = this.oGetConteneurTBODY(oConteneurParent);
		}

		// Supprime les lignes en trop a la fin pour le cas ou les deux plages d'incides se recoupaient
		nIndiceActuel = nDebut + nNombre;
		while (this.bSupprimeLigne(sNomChamp, nTypeChamp, nIndiceActuel, nNbRuptures, oConteneurParent, oConteneurTBody))
		{
			nIndiceActuel++;
		}

		// Il y a des problemes si on vide tout dans firefox et co et que l'on vide la table
		if ((!bUtiliseOuterHTML) && (nNombre == 0) && (oConteneurTBody != oConteneurParent) && (oConteneurTBody.childNodes.length == 0))
		{
			while (oConteneurParent.childNodes.length)
			{
				oConteneurParent.removeChild(oConteneurParent.childNodes[0]);
			}
		}

		// Met les valeurs dans les champs cache
		eval("_PAGE_." + sNomChamp + "_DEB").value = nDebut;
		eval("_PAGE_._" + sNomChamp + "_OCC").value = nNombre;
		if (nSelection >= 0) oChamp.value = nSelection;
	},

	// Recoit un bout de CSS et l'ajoute dans la page
	// Pour optimiser les choses : si un style est vide on le degage
	ActionLigneStyle:function (sStyle)
	{
		// sTyle est un bout de CSS de la forme
		// #ID1, #ID2, ...	{ style1 }
		// #ID3, ...		{ style2 }
		// etc
		// Il peut y avoir des {} vide au milieu

		// Donc pour le parsing on decoupe d'abord selon les }
		var tabNouveauxStyles = sStyle.split("}");
		// tabNouveauxStyles contient un tableau de lignes de la forme
		// #ID1, #ID2, ...	{ style1			<= split a fait partir le } final

		// On va maintenant traiter les lignes individuelles
		var i;
		var nLimiteI = tabNouveauxStyles.length;
		for (i = 0; i < nLimiteI; i++)
		{
			this._ActionLigneStyleLigne(tabNouveauxStyles[i]);
		}
	},

	// Recoit une ligne de CSS et l'ajoute dans la page
	// Pour optimiser les choses : si un style est vide on le degage
	_ActionLigneStyleLigne:function (sLigneStyle)
	{
		var nDebutTexteStyle = sLigneStyle.indexOf("{");
		//assert(nDebutTexteStyle <= 0);
		// Par securite si pas de style (-1) ou pas de nom de style (0) on boucle
		if (nDebutTexteStyle <= 0)
			return;

		// On decoupe le nom des styles et le contenu du style
		var sNomsStyle = sLigneStyle.substring(0, nDebutTexteStyle);
		var sTexteStyle = sLigneStyle.substring(nDebutTexteStyle + 1);

		// On vire les espaces/tabulations/RC du debut et de la fin du style comme ca si on decouvre que le style est vide on va
		// optimiser en n'en creant pas un autres
		sTexteStyle = this.sTrim(sTexteStyle, true, true, true);

		// La feuille de style par defaut pour l'ajout
		var oStyle = document.getElementsByTagName("STYLE");
		var oStyleSheetDefaut = oStyle[0].styleSheet ? oStyle[0].styleSheet : oStyle[0].sheet;

		// Puis on decoupe les noms de styles selon le separateur ","
		var tabNomsStyle = sNomsStyle.split(",");

		// Et on les traites
		var i;
		var nLimiteI = tabNomsStyle.length;
		for (i = 0; i < nLimiteI; i++)
		{
			var sNomStyle = this.sTrim(tabNomsStyle[i]);
			// Si le nom du style est vide ou sans nom : on ignore ce nom de style
			if ((sNomStyle.legnth == 0) || (sNomStyle == "#"))
			{
				//assert(false);
				continue;
			}

			// Puis on modifie le style
			// Supprime l'ancien style
			var oStyleSheet = this._oActionSupprimeStyle(sNomStyle);
			// Et recree le nouveau si le texte du style est non vide
			if (sTexteStyle.length > 0)
			{	// On recre si possible le style dans la feuille de style ou on l'a supprimer
				this._ActionCreerStyle(sNomStyle, sTexteStyle, oStyleSheet ? oStyleSheet : oStyleSheetDefaut);
			}
		}
	},

	// Supprime l'ancien style portant le nom et le recree si besoin
	_oActionSupprimeStyle:function(sNomStyle)
	{
		// Recherche et supprime le style existant si besoin
		var tabStyles = document.getElementsByTagName("STYLE");
		//assert(tabStyles.length==1);
		var i;
		var nLimiteI = tabStyles.length;
		for (i = 0; i < nLimiteI; i++)
		{
			// Pour internet explorer
			if (tabStyles[i].styleSheet)
			{
				var oFeuilleStyle = tabStyles[i].styleSheet;

				// On parcours les sous styles
				var j;
				var nLimiteJ = oFeuilleStyle.rules.length;
				for (j = 0; j < nLimiteJ; j++)
				{
					if (oFeuilleStyle.rules[j].selectorText == sNomStyle)
					{
						oFeuilleStyle.removeRule(j);
						// Comme on a supprimer une regle : on recule d'un cran sinon j+1 qui est devenu j n'est pas teste
						j--;
						nLimiteJ--;
					}
				}
			}
			// Pour FireFox et autres
			else if (tabStyles[i].sheet)
			{
				var oFeuilleStyle = tabStyles[i].sheet;

				// On parcours les sous styles
				var j;
				var nLimiteJ = oFeuilleStyle.cssRules.length;
				for (j = 0; j < nLimiteJ; j++)
				{
					// On recupere la liste des styles pour voir si notre style y est
					// Comme les styles sont groupes par le moteur selon des styles qui doivent reste identique il sufit de trouver notre style une fois
					// Ici les styles sont groupe donc il faut faire un parsing
					var tabStylesNom = oFeuilleStyle.cssRules[j].selectorText.split(",");
					var k;
					var nLimiteK = tabStylesNom.length;
					for (k = 0; k < nLimiteK; k++)
					{
						// Enleve les espaces abusif
						tabStylesNom[k] = tabStylesNom[k].replace(/ /g, "");
						if (tabStylesNom[k] == sNomStyle)
						{
							// Les regles ne sont pas factorisee par le moteur donc si on en supprime une on peu supprime aussi toutes ses
							// voisines
							oFeuilleStyle.deleteRule(j);
							// Comme on a supprimer une regle : on recule d'un cran sinon j+1 qui est devenu j n'est pas teste
							j--;
							nLimiteJ--;
							break;
						}
					}
				}
			}
		}
	},

	// Cree un style dans le feuille de style donnee
	_ActionCreerStyle:function(sNomStyle, sTexteStyle, oStyleSheet)
	{
		// Ajoute un style dans la feuille de style donnee
		if (oStyleSheet.addRule)
		{	// Pour internet explorer
			oStyleSheet.addRule(sNomStyle, sTexteStyle);
		}
		else
		{
			//assert(oStyleSheet.insertRule)
			oStyleSheet.insertRule(sNomStyle + " {" + sTexteStyle + "}", oStyleSheet.length);
		}
	},

	// Contenu d'un TV
	ActionChampTreeview:function (oChamp, XMLAction, sAliasChamp)
	{
		// Recupere les sous parties

		// Selection en cours
		//assert(XMLAction.childNodes[0].nodeName == this.XML_CHAMP_TREEVIEW_SELECT);
		document.getElementsByName(sAliasChamp + "_AS")[0].value = this.sXMLGetValeur(XMLAction.childNodes[0]);

		// Noeuds deroules
		//assert(XMLAction.childNodes[1].nodeName == this.XML_CHAMP_TREEVIEW_DEROULE);
		document.getElementsByName(sAliasChamp)[0].value = this.sXMLGetValeur(XMLAction.childNodes[1]);
		//assert(XMLAction.childNodes[2].nodeName == this.XML_CHAMP_TREEVIEW_DEROULETAB);
		var sNex = this.sXMLGetValeur(XMLAction.childNodes[2]);
		document.getElementsByName("NEX_" + sAliasChamp)[0].value = sNex;
		// Il faut aussi mettre a jour la variable globale avec les elements deroules
		window["oItems_" + sAliasChamp] = sNex.split(',');

		// Contenu des noeuds
		//assert(XMLAction.childNodes[3].nodeName == this.XML_CHAMP_TREEVIEW_NOEUDS);
		var oContenu = oGetId(sAliasChamp + "_");
		oContenu.innerHTML = clWDEncode.sEncodeInnerHTML(this.sXMLGetValeur(XMLAction.childNodes[3]), false, true);
	},

	// Rechargement d'une image dynamique
	ActionChampRecharge:function (oChamp, XMLAction)
	{
		// Recherche le parametre anticache du champ image
		var rNoCache = new RegExp("(" + oChamp.name + "\\=)(\\d+)", "i");
		var sUrlImage = oChamp.src;
		if (rNoCache.test(sUrlImage))
		{
			oChamp.src = sUrlImage.replace(rNoCache, function (sExp, s1, s2) { return s1 + (parseInt(s2) + 1); });
		}
		else
		{
			// Recherche un paramètre sans option
			var rNoCacheVide = new RegExp("(" + oChamp.name + "\=)([^\d]|$)", "i");
			if (rNoCacheVide.test(sUrlImage))
			{
				oChamp.src = sUrlImage.replace(rNoCacheVide, function (sExp, s1, s2) { return s1 + (new Date()).getTime() + s2; });
			}
		}
	},

	// Rechargement d'une table AJAX
	ActionChampRefresh:function (sAliasChamp, XMLAction)
	{
		// Recherche du champ
		var oVarChamp = eval("cl" + sAliasChamp);
		if ((typeof oVarChamp == "object") && (oVarChamp.Refresh))
		{
			var nReset = 0;
			switch (this.sXMLGetAttributSafe(XMLAction, this.XML_CHAMP_REFRESH_RESETTABLE))
			{
			case "1":
				nReset = 1;
				break;
			case "2":
				nReset = 2;
				break;
			}
			var sNouveauDebut = this.sXMLGetAttributSafe(XMLAction, this.XML_CHAMP_REFRESH_DEBUT);
			var nNouveauDebut = -1;
			var sCleNouveauDebut;
			if ((sNouveauDebut != "") && (!isNaN(parseInt(sNouveauDebut))))
			{
				nNouveauDebut = parseInt(sNouveauDebut);
				if (sNouveauDebut.indexOf(";") > -1)
				{
					sCleNouveauDebut = sNouveauDebut.substring(sNouveauDebut.indexOf(";") + 1);
				}
			}
			oVarChamp.Refresh(nReset, nNouveauDebut, sCleNouveauDebut);
		}
	},

	// execute les actions sur les champs
	ActionChamp:function(oPage,XMLChamp)
	{
		// on recupere l'alias du champ
		var sAliasChamp = this.sXMLGetAttribut(XMLChamp,this.XML_CHAMP_ATT_ALIAS);
		// on recupere le type du champ
		var nTypeChamp = parseInt(this.sXMLGetAttribut(XMLChamp,this.XML_CHAMP_ATT_TYPE));
		// on cherche le champ
		var oChamp = this.oChercheChamp(oPage, sAliasChamp, nTypeChamp);
		var oChampExt = this.oChercheChamp(oPage, sAliasChamp, nTypeChamp, true);
		var XMLAction = XMLChamp.firstChild;
		while(XMLAction!=null)
		{	// selon le type d'action
			switch(XMLAction.nodeName)
			{	// propriete
				case this.XML_CHAMP_PROP :
				{	// selon la propriete
					switch(parseInt(this.sXMLGetAttribut(XMLAction,this.XML_CHAMP_PROP_ATT_NUM)))
					{
						// Valeur affiche => Valeur
						case this.XML_CHAMP_PROP_NUM_VALEURAFFICHEE:
						// Valeur
						case this.XML_CHAMP_PROP_NUM_VALEUR:			this.ActionProprieteValeur(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Libelle
						case this.XML_CHAMP_PROP_NUM_LIBELLE:			this.ActionProprieteLibelle(oChamp, nTypeChamp, XMLAction, sAliasChamp);	break;
						// Hauteur
						case this.XML_CHAMP_PROP_NUM_HAUTEUR:			if (oChamp)this.ActionProprieteHauteur(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Largeur
						case this.XML_CHAMP_PROP_NUM_LARGEUR:			if (oChamp)this.ActionProprieteLargueur(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Couleur
						case this.XML_CHAMP_PROP_NUM_COULEUR:			this.ActionProprieteCouleur(oChamp, nTypeChamp, XMLAction, sAliasChamp);	break;
						// Couleur de fond. Comme on peu manipuler la couleur de fond de la page
						// le test d'existantce de oChamp est deporte dans ActionProprieteCouleurFond
						case this.XML_CHAMP_PROP_NUM_COULEURFOND:		this.ActionProprieteCouleurFond(oChamp, nTypeChamp, XMLAction, sAliasChamp);break;
						// Etat d'un champ
						case this.XML_CHAMP_PROP_NUM_ETAT:				this.ActionProprieteEtat(oChamp, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Visibilite : manipule la partie externe du champ
						case this.XML_CHAMP_PROP_NUM_VISIBLE:			this.ActionProprieteVisible(oChampExt, nTypeChamp, XMLAction);				break;
						// Image
						case this.XML_CHAMP_PROP_NUM_IMAGE:				if (oChamp)this.ActionProprieteImage(oChamp, nTypeChamp, XMLAction);		break;
						// URL. pas de test de l'existence du champ car on va recherche la balise autour du champ
						case this.XML_CHAMP_PROP_NUM_URL:				this.ActionProprieteURL(oChamp, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Bulle
						case this.XML_CHAMP_PROP_NUM_BULLE:				this.ActionProprieteBulle(oChamp, nTypeChamp, XMLAction, sAliasChamp);		break;
						// X
						case this.XML_CHAMP_PROP_NUM_X:					this.ActionProprieteX(oChampExt, nTypeChamp, XMLAction);					break;
						// Y
						case this.XML_CHAMP_PROP_NUM_Y:					this.ActionProprieteY(oChampExt, nTypeChamp, XMLAction);					break;
						// CurseurSouris
						case this.XML_CHAMP_PROP_NUM_CURSEURSOURIS:		this.ActionProprieteCurseurSouris(oChampExt, nTypeChamp, XMLAction);		break;
						// PoliceGras
						case this.XML_CHAMP_PROP_NUM_POLICEGRAS:		this.ActionProprietePoliceGras(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// PoliceItalique
						case this.XML_CHAMP_PROP_NUM_POLICEITALIQUE:	this.ActionProprietePoliceItalique(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);	break;
						// PoliceNom
						case this.XML_CHAMP_PROP_NUM_POLICENOM:			this.ActionProprietePoliceNom(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// PoliceSoulignee
						case this.XML_CHAMP_PROP_NUM_POLICESOULIGNE:	this.ActionProprietePoliceSoulignee(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);	break;
						// PoliceTaille
						case this.XML_CHAMP_PROP_NUM_POLICETAILLE:		this.ActionProprietePoliceTaille(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);	break;
						// Opacite
						case this.XML_CHAMP_PROP_NUM_OPACITE:			this.ActionProprieteOpacite(oChampExt, nTypeChamp, XMLAction);				break;
						// Cadrage horizontal
						case this.XML_CHAMP_PROP_NUM_CADRAGEH:			this.ActionProprieteCadrageH(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Cadrage vertical
						case this.XML_CHAMP_PROP_NUM_CADRAGEV:			this.ActionProprieteCadrageV(oChamp, oChampExt, nTypeChamp, XMLAction, sAliasChamp);		break;
						// Indication
						case this.XML_CHAMP_PROP_NUM_INDICATION:		this.ActionProprieteIndication(oChamp, nTypeChamp, XMLAction, sAliasChamp);	break;
					}
					break;
				}
				// Code JS a executer sur l'objet
				case this.XML_CHAMP_JS:			this.ActionChampJS(oChamp, sAliasChamp, XMLAction);						break;
				// Options a ajouter a l'objet
				case this.XML_CHAMP_OPTIONS:	if (oChamp)this.ActionChampOptions(oChamp, XMLAction);					break;
				// Lignes d'une table/ZR
				case this.XML_CHAMP_LIGNES:		
					if (oChamp)
					{
						this.ActionChampLignes(oChamp, nTypeChamp, XMLAction, sAliasChamp);
						// Avec IE, on manipule la propriété outerHTML donc l'objet DOM change et oChamp et oChampExt deviennent invalides
						oChamp = this.oChercheChamp(oPage, sAliasChamp, nTypeChamp);
						oChampExt = this.oChercheChamp(oPage, sAliasChamp, nTypeChamp, true);
					}
					break;
				// Contenu d'un TV
				case this.XML_CHAMP_TREEVIEW:	this.ActionChampTreeview(oChamp, XMLAction, sAliasChamp);	break;
				// Rechargement d'une image dynamique
				case this.XML_CHAMP_RECHARGE:	if (oChamp)this.ActionChampRecharge(oChamp, XMLAction);					break;
				// Rafraichisement d'une table AJAX
				case this.XML_CHAMP_REFRESH:	this.ActionChampRefresh(sAliasChamp, XMLAction);						break;
			}
			// on passe a l'action suivante
			XMLAction = XMLAction.nextSibling;
		}
	},

	// execute les actions JS simple
	ActionJS:function(oPage,XMLAction)
	{	// On recupere le code JS a executer
		var sCodeJS = unescape(this.sXMLGetValeur(XMLAction));
		// Execute le code JS
		// Si on est en encodage latin-1 (Donc pas en UTF-8) : On encode les caracteres > 127
		// Pas besoin de le faire en UTF-8 car il on deja ete encode pour avoir au final la bonne valeur unicode
		eval(clWDEncode.sEncodeCharset(sCodeJS, false));
	},

	// Execute une redirection
	ActionRedirection:function(oPage,XMLAction)
	{
		// On recupere la redirection
		var sRedirection = this.sXMLGetValeur(XMLAction);
		// Execute la redirection
		document.location.replace(unescape(sRedirection));
	},

	// Affiche une trace
	ActionTrace:function (oPage, XMLAction, bAjout)
	{
		// Recherche la zone de trace dans la page
		var oDivTrace = _JGE(this.XML_TRACE_ID, document);

		// Recupere la valeur de la trace
		var sTrace = this.sXMLGetValeur(XMLAction);

		// Si besoin calcule la trace précédente pour faire une concaténation		
		var sTracePrecedente = "";
		
		// Supprime les traces du premier affichage
		var oOldTrace = _JGE(this.XML_WBTRACE_ID, document);
		while (oOldTrace)
		{
			// Ajoute le texte à la trace précédente si besoin
			if (bAjout)
			{
				sTracePrecedente += ((sTracePrecedente.length > 0) ? "\r\n" : "") + _JCIR(oOldTrace);
			}
			// Supprime la zone de trace
			oOldTrace.parentNode.removeChild(oOldTrace);
			oOldTrace = _JGE(this.XML_WBTRACE_ID, document)
		}

		// Si besoin ajoute aussi le contenu courante de la trace
		if (bAjout)
		{
			if (oDivTrace)
			{
				sTracePrecedente += ((sTracePrecedente.length > 0) ? "\r\n" : "") + _JCIR(oDivTrace);
			}
			sTrace = sTracePrecedente + ((sTracePrecedente.length > 0) && (sTrace.length > 0) ? "\r\n" : "") + sTrace;
		}

		// Si la trace est vide : on supprime la zone de trace si besoin
		if ((sTrace + "").length == 0)
		{
			// Si la zone existe => La supprime
			if (oDivTrace)
			{
				// La supprime
				oDivTrace.parentNode.removeChild(oDivTrace);
			}
			// Fin du traitement
			return;
		}

		// Si la zone n'existe pas : la cree
		if (!oDivTrace)
		{
			// Cree dynamiquement un formulaire dans la cellule
			var oDivTrace = document.createElement("DIV");
			oDivTrace.id = this.XML_TRACE_ID;
			oDivTrace.style.width = 1024;
//			oDivTrace.style.height = 20;
			oDivTrace.style.backgroundColor = "#FFFF00";
			oDivTrace.style.fontFamily = "Courier New,Courier,mono";
			oDivTrace.style.fontSize = "x-small";

			// Ajoute la zone a la page
			var oPremier = document.body.firstChild;
			if (oPremier)
			{
				oDivTrace = document.body.insertBefore(oDivTrace, oPremier);
			}
			else
			{
				oDivTrace = document.body.insertBefore(oDivTrace);
			}
		}
		// Affecte le texte dans la zone en effectuant la conversion
		oDivTrace.innerHTML = clWDEncode.sEncodeInnerHTML(sTrace, true);
	},

	// execute les actions
	// oObjet : Selon la requete => objet formulaire, objet table (Ou objet cache de la table)
	bActionXML:function(oPage, oObjet, oXML)
	{	// on recupere la racine
		var oXMLListeRacine = oXML.getElementsByTagName(this.XML_RACINE);
		if (oXMLListeRacine)
		{
			var oXMLRacine = oXMLListeRacine ? oXMLListeRacine[0] : null;
			if (oXMLRacine)
			{
				// Lance le parcours des actions a effectuer
				var oXMLAction = oXMLRacine.firstChild;
				// Si on est dans la MAJ d'une table => ajout à la trace précédente
				var bMAJTable = false;
				var oXMLTrace = null;
				while(oXMLAction)
				{
					// Selon le type d'action
					switch(oXMLAction.nodeName)
					{
					// Champ
					case this.XML_CHAMP:	this.ActionChamp(oPage, oXMLAction);			break;
					// Code js pur
					case this.XML_JS:		this.ActionJS(oPage, oXMLAction);			break;
					// Redirection
					case this.XML_REDIR:	this.ActionRedirection(oPage, oXMLAction);	break;
					// Gestion du cache des tables
					case this.XML_LISTE:
						oObjet.ActionListe(oXMLAction);
						bMAJTable = true;
						break;
					// Affichage de traces
					case this.XML_TRACE:
						oXMLTrace = oXMLAction;
						break;
					}
					// Passe au fils suivant
					oXMLAction = oXMLAction.nextSibling;
				}
				
				// Si on a une trace l'affiche
				if (oXMLTrace)
				{
					this.ActionTrace(oPage, oXMLTrace, bMAJTable);
				}
				return true;
			}
		}
		return false;
	},

	sGetPageAction:function(oPage, bParam)
	{
		// Trouve la page si besoin
		if (!oPage)
			oPage = _PAGE_;

		// Calcule l'URL
		var sAction = (_PAGE_.action.length > 0) ? _PAGE_.action : "";
		if (sAction.length == 0)
		{
			// On prend l'URL si on n'a pas d'action
			sAction = location.href;
			// On vire l'ancre
			if (location.hash.length > 0)
			{
				sAction = sAction.subStr(0, sAction.indexOf(location.hash) - 1);
			}
		}

		// Vire les parametres
		if (bParam && (sAction.indexOf("?") != -1))
			sAction = sAction.subStr(0, sAction.indexOf("?") - 1);

		// Renvoie la valeur
		return sAction;
	},

	ErreurAJAX:function()
	{
		// Ici requete au serveur qui indique que le navigateur ne supporte pas les appels AJAX

		// L'action sans les parametres
		var sAction = this.sGetPageAction(null, true);
		// Ajout de la commande d'erreur
		sAction += "?" + this.sCommandeAjax_Erreur;
		// Et remplacement de la page courante
		document.location = sAction;
	},

	// Execute le code serveur d'un champ
	AJAXExecuteEvenement:function(oPage, sChamp, nEvenement, nOption)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return;

		// Si l'AJAX n'est pas disponible
		if (!this.AJAXDisponible())
		{
			// On utilise la methode normale
			this.NormalExecuteEvenement(oPage, sChamp, nEvenement, nOption);
			return;
		}

		// Empile la requete
		// Assert(this.m_tabRequetes.length == 0);
		var stRequete	= new Object();
		stRequete.oPage		= oPage;
		stRequete.sChamp	= sChamp;
		stRequete.nEvenement= nEvenement;
		stRequete.nOption	= nOption;
		this.m_tabRequetes.push(stRequete);

		// Force le reaffichage de l'activite AJAX
		this.ReactualiseActivite(true);

		// Et demande le traitement de l'evenement
		// Permet de ne pas bloquer l'affichage (Fermeture des combos)
		setTimeout("clWDAJAXMain.TraiteAJAXExecuteEvenement();", 1);
	},

	// Traite les evenements AJAX en attente
	TraiteAJAXExecuteEvenement:function()
	{
		// Supprime le reaffichage de l'activite AJAX
		this.ReactualiseActivite(false);

		// Assert(this.m_tabRequetes.length == 1);
		// Tant que l'on a des requetes
		while(this.m_tabRequetes.length > 0)
		{
			// Recupere la requete
			var stRequete = this.m_tabRequetes[0];
			// Vire la requete de la liste
			this.m_tabRequetes.shift();
			// Traite la requete
			var bRes = this.bAJAXExecuteEvenementInterne(stRequete.oPage, stRequete.sChamp, stRequete.nEvenement, stRequete.nOption);

			// Et sort direct si on est en erreur
			if (!bRes) this.m_tabRequetes.length = 0;
		}
	},

	// Execute le code serveur d'un champ. Version interne : celle appele via un timer
	bAJAXExecuteEvenementInterne:function(oPage, sChamp, nEvenement, nOption)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return;

		// on prepare la requete
		var sRequete = this.sConstuitRequeteEvenement(oPage, sChamp, nEvenement, nOption);

		// on prepare l'URL
		var sURL = this.sConstruitURL(this.sGetPageAction(oPage));
		// on cree la requete
		var clRequete = this.clCreeWDAJAXRequete(true,true);

		// Si la creation n'a pas echoue (AJAX possible)
		if (clRequete)
		{
			// On execute la requete
			clRequete.Envoi(sRequete,sURL);
			// Si le resulat est valide on le renvoi
			return this.bReponseGenerique(clRequete, oPage, null);
		}
		else
		{
			// Cas AJAX impossible
			this.ErreurAJAX();
			return false;
		}
	},

	// Appel normal dans le cas ou AJAX n'est pas disponible
	NormalExecuteEvenement:function(oPage, sChamp, nEvenement, nOption)
	{
		switch(nOption)
		{	// Envoie la valeur du champ courant. Renvoie la valeur de tous les champs car on ne sait pas faire moins
		case 1 :
			// Donc pas de break ici
			// Envoie la valeur de tous les champs de la page
		case 2 :
			// Construction d'un _JSL
			_JSL(oPage, sChamp, "_self", "", "");
			break;

		case 3 :				// Clic sur une reglette mais sans submit
			// Resultat de la forme "/WD110AWP/WD110AWP.EXE?WD_ACTION=SCROLLTABLE&TABLE1=4"
			// Construction d'un _JCL ?
			break;

		case 4 :				// Clic sur une reglette avec submit
			// Appel de _RXXX
			eval("_R" + sChamp + "(" + nEvenement + ")");
			break;

		// Ne renvoie aucune valeur
		default :
			// Construction d'un _JCL
			_JCL(oPage.action + "?" + sChamp, "_self", "", "");
			break;
		}
	},

	// AJAXExecute
	// declenche l'execution synchrone d'une procedure AJAX sur le serveur
	// ATTENTION : le nombre de parametres est variable
	AJAXExecuteSynchrone:function(sProcedure,sAliasContexte)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return "";

		// on prepare la requete
		var sRequete = this.sConstuitRequeteProcedure(sProcedure,sAliasContexte);
		// on ajoute les parametres de la procedure
		var nNbParamIgnore = 2;
		var i;
		var nLimiteI = arguments.length;
		for (i = nNbParamIgnore; i < nLimiteI; i++ )
		{
			// Si l'arguement est un booleen alors on envoi 0/1 pour faux/vrai
			// Car le cast en chaine du false/true du JS donne "false"/"true", ce que le serveur ne sait pas bien convertir en boolen
			sRequete += "&PA" + ( i - nNbParamIgnore + 1 ) + "=" + ((arguments[i] === true) ? "1" : ((arguments[i] === false) ? "0" : escape(arguments[i])));
		}
		// on prepare l'URL
		var sURL = this.sConstruitURL(this.sGetPageAction());
		// on cree la requete
		var clRequete = this.clCreeWDAJAXRequete(true,true);
		// Si la creation n'a pas echoue (AJAX possible)
		if (clRequete)
		{
			// on execute la requete
			clRequete.Envoi(sRequete,sURL);
			// On verifie la validite du resultat et on le renvoie si il est valide
			var sRes = clRequete.bValideResultat() ? clRequete.sGetResultat() : "";
			// Libere la requete
			clRequete.Libere();
			clRequete = null;
			// Renvoi le resultat
			return sRes;
		}
		else
		{
			// Cas AJAX impossible
			this.ErreurAJAX();
			return "";
		}
	},

	// AJAXExecuteAsynchrone
	// declenche l'execution asynchrone d'une procedure AJAX sur le serveur
	// ATTENTION : Le nombres de parametres est variable
	AJAXExecuteAsynchrone:function(sProcedure, sNomCallback, sAliasContexte)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return "";

		// on prepare la requete
		var sRequete = this.sConstuitRequeteProcedure(sProcedure,sAliasContexte);
		// on ajoute les parametres de la procedure
		var nNbParamIgnore = 3;
		var i;
		var nLimiteI = arguments.length;
		for (i = nNbParamIgnore; i < nLimiteI; i++ )
		{
			// Si l'arguement est un booleen alors on envoi 0/1 pour faux/vrai
			// Car le cast en chaine du false/true du JS donne "false"/"true", ce que le serveur ne sait pas bien convertir en boolen
			sRequete += "&PA" + ( i - nNbParamIgnore + 1 ) + "=" + ((arguments[i] === true) ? "1" : ((arguments[i] === false) ? "0" : escape(arguments[i])));
		}
		// on prepare l'URL
		var sURL = this.sConstruitURL(this.sGetPageAction());
		// on cree la requete
		var clRequete = this.clCreeWDAJAXRequete(true, false);
		// Si la creation n'a pas echoue (AJAX possible)
		if (clRequete)
		{
			// on recupere son identifiant pour manipulations ulterieure (annulation, recuperation du resultat)
			var nIdRequete = clRequete.m_nId;
			// on renseigne la allback pour la validation du resultat
			clRequete.m_sCallback = sNomCallback;
			// on execute la requete
			clRequete.Envoi(sRequete,sURL);
			// on renvoie l'identifiant de la requete
			return nIdRequete;
		}
		else
		{
			// Cas AJAX impossible
			this.ErreurAJAX();
			return "";
		}
	},

	// AJAXAppelAsynchroneEnCours
	// renvoie l'etat d'une requete asynchrone
	AJAXAppelAsynchroneEnCours:function(nId)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return false;

		// on commence par rechercher la requete
		var clRequete = this.GetWDAJAXRequete(nId);
		// si on trouve la requete, c'est qu'elle est en cours
		return( clRequete!=null&&clRequete.bEnCours() );
	},

	// AJAXAnnuleAppelAsynchrone
	// annule une requete asynchrone
	AJAXAnnuleAppelAsynchrone:function(nId)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return false;

		// on commence par rechercher la requete
		var clRequete = this.GetWDAJAXRequete(nId);
		// si on trouve la requete, on l'annule
		if(clRequete!=null) clRequete.Annule();
	},

	// AJAXRecupereLignesTable
	// Demande les lignes donnees de la tabel donnee au serveur
	AJAXRecupereLignesTable:function (oObjetRequeteTable, sRequeteTable)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return "";

		// Prepare la requete
		var sRequete = this.sConstuitRequeteTable(sRequeteTable);
		// Prepare l'URL
		var sURL = this.sConstruitURL(this.sGetPageAction());
		// Cree la requete et demandant une initialisation speciale
		var clRequete = this.clCreeWDAJAXRequete(true, false, true);

		// Si la creation n'a pas echoue (AJAX possible)
		if (clRequete)
		{
			// Demande l'initialisation pour les tables
			clRequete.InitTable(oObjetRequeteTable);

			// Recupere son identifiant pour manipulations ulterieure (annulation, recuperation du resultat)
			var nIdRequete = clRequete.m_nId;
			// Execute la requete
			clRequete.Envoi(sRequete, sURL);
			// Renvoie l'identifiant de la requete
			return nIdRequete;
		}
		else
		{
			// Cas AJAX impossible
			this.ErreurAJAX();
			return false;
		}
	},

	// AJAXRecupereLignesTableSelection
	// Demande les lignes donnees de la table donnee au serveur
	AJAXRecupereLignesTableSelection:function (oObjetRequeteTable, sRequeteTable, bSubmit)
	{
		// Si plus d'AJAX on sort
		if (!this.bWDAJAXMainValide()) return "";

		// Prepare la requete
		var sRequete = this.sConstuitRequeteEvenement(eval("_PAGE_"), oObjetRequeteTable.m_oObjetTable.m_sAliasTable, 0, bSubmit ? 5 : 6) + "&" + sRequeteTable;
		// Prepare l'URL
		var sURL = this.sConstruitURL(this.sGetPageAction());
		// Cree la requete et demandant une initialisation speciale
		var clRequete = this.clCreeWDAJAXRequete(true, false, true);

		// Si la creation n'a pas echoue (AJAX possible)
		if (clRequete)
		{
			// Demande l'initialisation pour les tables
			clRequete.InitTable(oObjetRequeteTable);

			// Recupere son identifiant pour manipulations ulterieure (annulation, recuperation du resultat)
			var nIdRequete = clRequete.m_nId;
			// Execute la requete
			clRequete.Envoi(sRequete, sURL);
			// Renvoie l'identifiant de la requete
			return nIdRequete;
		}
		else
		{
			// Cas AJAX impossible
			this.ErreurAJAX();
			return false;
		}
	},

	// Sauve le temoin d'activite AJAX
	InitActivite:function (sActiviteChamp, nActiviteOption)
	{
		// Recupere directement le champ
		this.m_oActiviteChamp = _JGE(sActiviteChamp, document, true);
		// Et sauve l'option
		this.m_nActiviteOption = nActiviteOption;

		// Initialise les callback de redimensionnement/defilement du navigateur
		this.m_fWinOnScroll = window.onscroll;
		this.m_fWinOnResize = window.onresize;

		var oTmp = this;
		if (bIE)
		{
			window.onscroll = function () { if (oTmp.m_fWinOnScroll) { oTmp.m_fWinOnScroll.apply(windows); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
			window.onresize = function () { if (oTmp.m_fWinOnResize) { oTmp.m_fWinOnResize.apply(windows); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
		}
		else
		{
			window.onscroll = function (event) { if (oTmp.m_fWinOnScroll) { oTmp.m_fWinOnScroll.apply(windows, [event]); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
			window.onresize = function (event) { if (oTmp.m_fWinOnResize) { oTmp.m_fWinOnResize.apply(windows, [event]); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
		}

		// Et met a jour le temoin
		// S'il n'a pas encore ete defini le defini
		// S'il est deje defini : utilise sa valeur pour afficher le temoin
		this._ReactualiseActivite(this.m_bActivite ? this.m_bActivite : false);
	},

	// Met a jour le temoin d'activite AJAX si besoin
	ReactualiseActivite:function (bForce)
	{
		// Calcule le nouvel etat
		var bActivite = (this.m_tabConnection.length > 0) || (this.m_nRequeteSynchrone > 0) || bForce;
		// Si l'etat change : effectue les modifications
		if (this.m_bActivite != bActivite)
		{
			this._ReactualiseActivite(bActivite);
		}
	},

	// Met a jour le temoin d'activite AJAX
	_ReactualiseActivite:function (bVisible)
	{
		// Sauve le nouvel etat
		this.m_bActivite = bVisible;

		// Si pas de temoin => Fin
		if (!this.m_oActiviteChamp) return;

		// Appel de la fonction _JFDE poru le deplacement
		_JDE(this.m_oActiviteChamp, document, this.m_nActiviteOption);

		// Et l'affiche
		this.m_oActiviteChamp.style.visibility = bVisible ? "inherit" : "hidden";
	}
};

// On instancie un objet principal
var clWDAJAXMain = new WDAJAXMain();

// S'il y a deux clics 'rapides' dans un bouton AJAX d'une zone repetee. Comme _JAEE est non bloquant (utilise un setTimeout)
// Alors il peut y avoir deux appels ) _JAZR + _JAEE qui s'empilent
// Mais au lieu de s'executer dans l'ordre _JAZR, _JAEE, _JAEE_Interne, _JAZR, _JAEE, _JAEE_Interne
// l'ordre est _JAZR, _JAEE, _JAZR, _JAEE, _JAEE_Interne, _JAEE_Interne. Comme un appel supprime la valeur surcharge par _JAZR
// alors le second ne recoit rien et manipule la premiere ligne
var bBloque = false;

// Fonction d'appel
//function _JAES(sProcedure, sAliasContexte) { return clWDAJAXMain.AJAXExecuteSynchrone(sProcedure, sAliasContexte); }
//function _JAEA(sProcedure, sNomCallback, sAliasContexte) { return clWDAJAXMain.AJAXExecuteAsynchrone(sProcedure, sNomCallback, sAliasContexte); }
function _JAAAEC(nId) { return clWDAJAXMain.AJAXAppelAsynchroneEnCours(nId); }
function _JAAAA(nId) { return clWDAJAXMain.AJAXAnnuleAppelAsynchrone(nId); }
function _JAD() { return clWDAJAXMain.AJAXDisponible(); }
function _JAEE(oPage, sChamp, nEvenement, nOption)
{
	if (bBloque)
	{	// Si on a ete bloque par un l'appel de _JAZR qui precede immediatement
		bBloque = false;
	}
	else
	{
		clWDAJAXMain.AJAXExecuteEvenement(oPage, sChamp, nEvenement, nOption);
	}
}
function _JAZR(sZRChamp, sValeur)
{
	if (clWDAJAXMain.m_sZRChamp)
	{	// Bloque l'appel de _JAEE qui suit immediatement
		bBloque = true;
	}
	else
	{
		clWDAJAXMain.SetZRChamp(sZRChamp, sValeur);
	}
}
