//#11.00Aa WDAJAX.JS
//VersionVI: 30A110054b
// 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

var bIE = navigator.appName.indexOf("Microsoft") != -1;
var bIE7 = false;
// On fait un cas particulier pour IE7
if (bIE)
{
	var oExpr = new RegExp("MSIE ([0-9])+[\.0-9]*");
	bIE7 = ((oExpr.exec(navigator.userAgent) != null) && (parseInt(oExpr.$1) >= 7));
}

// 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();

					// 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);
						}
					}
//					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 clWDAJAXMain.m_bReencodeLatin1 ? clWDAJAXMain.sReencodeCP1252(this.m_clRequete.responseText, false) : this.m_clRequete.responseText;
		}
		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);
	}
};

//
var oGetId = null;
if (document.getElementById)
{
	oGetId = function(sNomChamp) { return document.getElementById(sNomChamp); };
}
else if (document.all)
{
	oGetId = function(sNomChamp) { return document.all(sNomChamp); };
}
else
{
	oGetId = function(sNomChamp) { return null; };
}

// Classe de creation des requetes

function WDAJAXMain(bUTF8)
{
	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;

	// On aura besoin de transforme les chaines recus pour gerer les caratere interdit en ISO-8859-1 si besoin
	// Pas besoin de le faire en UTF-8 car il on deja ete encode pour avoir au final la bonne valeur unicode
	if (bUTF8 === undefined)
		bUTF8 = ((document.charset ? document.charset : (document.characterSet ? document.characterSet : "iso-8859-1")).toLowerCase() != "iso-8859-1");

	if (!bUTF8)
	{
		// On defini notre fonction d'encodage des parametres
		this.sEncode = function (sValeur)
		{
			// QW42602 : Traite le caratere euro
			sValeur = sValeur.replace(/\u20AC/g, String.fromCharCode(0x80));
			// Traite les carateres unicodes
			sValeur = sValeur.replace(/[\u0100-\uFFFF]/g, function(sCar) { var n = sCar.charCodeAt(0); var i; var nLimiteI = clWDAJAXMain.sConvCP1252.length; for(i = 0; i < nLimiteI; i++){ if(clWDAJAXMain.sConvCP1252[i]==n) return String.fromCharCode(i + 130);} return sCar; } );
			// Escape le tout
			sValeur = escape(sValeur);
			// Et remplace le + car il represente l'encodage de l'espace
			return sValeur.replace(/\+/g, "%2B");
		};
	}
	else
	{
		this.m_bReencodeLatin1 = false;
		// On defini notre fonction d'encodage des parametres
		this.sEncode = function (sValeur) { return encodeURIComponent(sValeur); };
	}

	// 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_bReencodeLatin1:		true,
	m_oActiviteChamp:		null,
	m_bActiviteVisible:		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_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_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_VIGNETTE:		26,
	XML_CHAMP_TYPE_GRAPHE:			33,
	XML_CHAMP_TYPE_CELLULE:			39,
	XML_CHAMP_TYPE_COLONNE:			56,
	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_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_WBTRACE_ID:					"WB_TRACE",

	// Le tableau pour la conversion depuis CP1252
	//											130		131		132		133		134		135		136		137		138		139		140		141?	142		143?	144?	145		146		147		148		149		150		151		152		153		154		155		156		157?	158?	159
	//											0x82	0x83	0x84	0x85	0x86	0x87	0x88	0x89	0x8A	0x8B	0x8C	0x8D	0x8E	0x8F	0x90	0x91	0x92	0x93	0x94	0x95	0x96	0x97	0x98	0x99	0x9A	0x9B	0x9C	0x9D	0x9E	0x9F
	sConvCP1252:					new Array(	8218,	402,	8222,	8230,	8224,	8225,	710,	8240,	352,	8249,	338,	141,	381,	143,	144,	8216,	8217,	8220,	8221,	8226,	8211,	8212,	732,	8482,	353,	8250,	339,	157,	158,	376),

	// 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()
	{
		// 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();

				// 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();
				}
				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 this.sEncode(oChamp.name) + "=" + this.sEncode(sValeur);
		// Champ qui ne retournent rien
		case "button":
			return "";
		// Check active
		case "checkbox":
		case "radio":
			if (oChamp.checked){return this.sEncode(oChamp.name) + "=" + this.sEncode(oChamp.value);}else{return "";}
		case "select-one":
			if (oChamp.selectedIndex != -1){return this.sEncode(oChamp.name) + "=" + this.sEncode(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 += this.sEncode(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 this.sEncode(oChamp.name) + "=" + this.sEncode(sValeur);
			}
		}
		return "";
	},

	// construit les valeurs de tous les champs de la page
	sConstruitValeurPage:function(oPage)
	{	// on parcours les champs de la page pour construire la requete
		var tabResultat = new Array(oPage.elements.length);
		var i;
		var nLimiteI = oPage.elements.length;
		for (i = 0; i < nLimiteI; i++)
		{
			var oElem = oPage.elements[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
			if ((this.sCommandeWDAction == oElem.name) || (!oElem.type))
			{
				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 = this.sEncode(this.m_sZRChamp) + "=" + this.sEncode(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);
				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);
				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);
				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;

			// 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 = this.sEncode(this.m_sZRChamp) + "=" + this.sEncode(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;
		// on 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 : "";
	},

	// Fonction de reencodage en HTML
	sReencodeInnerHTML:function(sValeur, bRemplaceBR, bPasEncodeBalise)
	{
		// Remplace le minimum de caracteres
		if (!bPasEncodeBalise)
		{
			sValeur = sValeur.replace(/&/g, "&amp;");
			sValeur = sValeur.replace(/</g, "&lt;");
			sValeur = sValeur.replace(/>/g, "&gt;");
//			sValeur = sValeur.replace(/\'/g, "&apos;");
//			sValeur = sValeur.replace(/\"/g, "&quot;");
		}

		// 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
		if (this.m_bReencodeLatin1)
		{
			// Si le charset de la page est Latin1
			// On transforme les caractere de CP1252 en leur equivalent unicode qui va fonctionner
			sValeur = this.sReencodeCP1252(sValeur, false);

			// Les caracteres restant (0xA0-0xFF) sont encode normalement en HTML
			sValeur = sValeur.replace(/[\xA0-\xFF]/g, function(sCar) { return "&#" + sCar.charCodeAt(0) + ";"; } );
		}

		if (bRemplaceBR)
		{
			// Met des balises BR pour les marques de lignes
			sValeur = sValeur.replace(/\r\n/g, "<BR>");
			sValeur = sValeur.replace(/\n/g, "<BR>");
		}

		// Renvoi de la valeur
		return sValeur;
	},

	// 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;
	},

	// Le jeu de caratere de windows est CP1252. Qui est un surensemble de ISO-8859-1
	// Il faut convertir tous les carateres entre 0x82 et 0x9F en leur version unicode
	// On converti en plus le caractere euro
	// Quid du caratere 0x81 ????
	sReencodeCP1252:function(sValeur, bHTML)
	{
		// Traite le caratere euro
		sValeur = sValeur.replace(/\x80/g, "\u20AC");

		// Puis les caractere de la plage
		// 130 = 0x82
		if (bHTML)
			sValeur = sValeur.replace(/[\x82-\x9F]/g, function(sCar) { return "&#" + clWDAJAXMain.sConvCP1252[sCar.charCodeAt(0) - 130] + ";"; } );
		else
			sValeur = sValeur.replace(/[\x82-\x9F]/g, function(sCar) { return String.fromCharCode(clWDAJAXMain.sConvCP1252[sCar.charCodeAt(0) - 130]); } );

		// Renvoi de la valeur convertie
		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:
				oElement = _JGE(sNomChamp, document, false);
				break;
			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 supplémentaire ce qui gène la manipulation de ..Valeur et ..Libellé
	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, 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)
		{
		// On traite le champ bouton specialement : Si c'est un champ image on fait comme les images
		case this.XML_CHAMP_TYPE_BOUTON:
			// Si on a le champ c'est que c'est un champ de type input => bouton "normal"
			if (oChamp)
			{
				oChamp.value = sValeur;
				break;
			}
			// Sinon c'est que l'on a un bouton image => On doit prendre l'image
			// Mais pas le droit de changer l'image d'un bouton image => donc ne fait rien
			break;
//			oChamp = _JGE("_" + sAliasChamp + "_IMG", document, false);
//			// 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:
			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 ajouté 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 = this.sReencodeInnerHTML(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
				// Pas besoin de le faire en UTF-8 car il on deja ete encode pour avoir au final la bonne valeur unicode
				oChamp.value = this.m_bReencodeLatin1 ? this.sReencodeCP1252(sValeur, false) : sValeur;
			}
			break;
		case this.XML_CHAMP_TYPE_LIBELLEHTML:
		case this.XML_CHAMP_TYPE_REGLETTE:
		case this.XML_CHAMP_TYPE_CHEMINNAV:
			// Dans certains cas une table est ajouté 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 = this.sReencodeInnerHTML(sValeur, false, true);
			break;
		default:								// Autres cas
			if (oChamp) oChamp.value = sValeur;
			break;
		case this.XML_CHAMP_TYPE_CELLULE:
			//assert(false);
			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 on a le champ c'est que c'est un champ de type input => bouton "normal"
			if (oChamp)
			{
				oChamp.value = sValeur;
				break;
			}
			// Sinon c'est que l'on a un bouton image => On doit prendre l'image
			break;
		case this.XML_CHAMP_TYPE_LIBELLE:
			// Dans certains cas une table est ajouté 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 = this.sReencodeInnerHTML(sValeur, true);
			break;
		case this.XML_CHAMP_TYPE_LIBELLEHTML:
			// Dans certains cas une table est ajouté 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 = this.sReencodeInnerHTML(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 TB autour
				if (oChamp.tagName.toUpperCase() == "TD") 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 = this.sReencodeInnerHTML(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 = this.sReencodeInnerHTML(sValeur, true);
			break;
		default:								// Autres cas
			// Ne fait rien
			break;
		}
	},

	// Hauteur
	ActionProprieteHauteur:function(oChamp, nTypeChamp, XMLAction)
	{
		var nHauteur = parseInt(this.sXMLGetValeur(XMLAction));
		if (nHauteur >= 0)
		{
			switch(nTypeChamp)
			{
			default:
				if (oChamp.height) oChamp.height = nHauteur;
				break;
			}
		}
	},

	// Largeur
	ActionProprieteLargueur:function(oChamp, nTypeChamp, XMLAction)
	{
		var nLargueur = parseInt(this.sXMLGetValeur(XMLAction));
		if (nLargueur >= 0)
		{
			switch(nTypeChamp)
			{
			default:
				if (oChamp.width) oChamp.width = nLargueur;
				break;
			}
		}
	},

	// X
	ActionProprieteX:function (oChamp, nTypeChamp, XMLAction)
	{
		//assert(oChamp.tagName == "DIV");
		// On ne filtre pas les positions , les positions negatives sont valides
		switch(nTypeChamp)
		{
		default:
			// oChamp est normalement le conteneur externe du champ
			if (oChamp && oChamp.style) oChamp.style.left = this.sXMLGetValeur(XMLAction) + "px";
			break;
		}
	},

	// Y
	ActionProprieteY:function (oChamp, nTypeChamp, XMLAction)
	{
		//assert(oChamp.tagName == "DIV");
		// On ne filtre pas les positions , les positions negatives sont valides
		switch(nTypeChamp)
		{
		default:
			// oChamp est normalement le conteneur externe du champ
			if (oChamp && oChamp.style) oChamp.style.top = this.sXMLGetValeur(XMLAction) + "px";
			break;
		}
	},

	// 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:
			// On modifie le style a la racine
			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=="#" + sAliasChamp) || (oFeuilleStyle.rules[j].selectorText=="#tz" + sAliasChamp))
						{
							oFeuilleStyle.rules[j].style.color = sCouleur;
						}
					}
				}
				// 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]=="#" + sAliasChamp) || (tabStylesNom[k]=="#tz" + sAliasChamp))
							{
								oFeuilleStyle.cssRules[j].style.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.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:
			// On modifie le style a la racine
			var tabStyles = document.getElementsByTagName("STYLE");
			//assert(tabStyles.length==1);
			var i;
			var nLimiteI = tabStyles.length;
			for (i = 0; i < nLimiteI; i++)
			{
				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=="#" + sAliasChamp) || (oFeuilleStyle.rules[j].selectorText=="#tz" + sAliasChamp))
						{	// Il vaudrait mieux style.backgroundColor mais comme la generation JS utilise style.background
							// et qu'il est difficile de changer
							oFeuilleStyle.rules[j].style.background = sCouleur;
						}
					}
				}
				// 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 < tabStylesNom.length; k++)
						{
							// Enleve les espaces abusif
							tabStylesNom[k] = tabStylesNom[k].replace(/ /g, "");
							if ((tabStylesNom[k]=="#" + sAliasChamp) || (tabStylesNom[k]=="#tz" + sAliasChamp))
							{	// Il vaudrait mieux style.backgroundColor mais comme la generation JS utilise style.background
								// et qu'il est difficile de changer
								oFeuilleStyle.cssRules[j].style.background = sCouleur;
							}
						}
					}
				}
			}
			break;
		case this.XML_CHAMP_TYPE_CELLULE:
			// On cherche le champ cellule
			oChamp = _JGE(sAliasChamp, document, true);
			// Et on lui applique le style
			if (oChamp && oChamp.style) oChamp.style.background = 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.background = sCouleur;

			// On ne cherche pas le champ lui meme mais le champ autour pour avoir la balise A
			// La balise A est le chamlp lui meme
//			oChamp = _JGE(sAliasChamp, document, false, true);
//			// Pas de break : fait comme pour les autres champs pour le reste

		// Mais pas de problemes avec les autres champs
		default:
			//assert(oChamp)
			// Il vaudrait mieux style.backgroundColor mais comme la generation JS utilise style.background
			// et qu'il est difficile de changer
			if (oChamp && oChamp.style) oChamp.style.background = 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:
			// 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
					oBaliseA.removeAttribute(oAttribut.nodeName, 0);
				}
				else
				{
					// Ajoute/modifie l'attribut
					oBaliseA.setAttribute(oAttribut.nodeName, oAttribut.nodeValue, 0);
				}
			}
			break;
		default:
			break;
		}
	},

	// Couleur de fond
	ActionProprieteVisible:function(oChamp, nTypeChamp, XMLAction)
	{
		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;
	},

	// 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)
	{
		// Selon le type du champ
		switch(nTypeChamp)
		{
		default:
			// 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 TB autour
				if (oChamp.tagName.toUpperCase() == "TD") oChamp = oChamp.firstChild;
				if (oChamp)
				{
					oChamp.href = this.sXMLGetValeur(XMLAction);
				}
			}
			break;
		}
	},

	// 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;
				}
			}
			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;
			// PAS DE BREAK
		default:
			// Pour les interrupteurs/selecteurs : on a un tableau d'elements
			if (oChamp) oChamp.title = sValeur;
			break;
		}
	},

	// CurseurSouris
	ActionProprieteCurseurSouris:function (oChamp, nTypeChamp, XMLAction)
	{
		// selon le type du champ
		switch(nTypeChamp)
		{
		default:
			if (oChamp && oChamp.style) oChamp.style.cursor = this.sXMLGetValeur(XMLAction);
			break;
		}
	},

	// 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 = this.sReencodeInnerHTML(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 ? "" : this.sReencodeInnerHTML(this.sXMLGetValeur(XMLLigne.childNodes[0]), false, true);
			//assert(XMLLigne.childNodes[1].nodeName==this.XML_CHAMP_LIGNES_LIGNE_CORPS);
			var sCorps = this.sReencodeInnerHTML(this.sXMLGetValeur(XMLLigne.childNodes[bCorpsSeul ? 0 : 1]), false, true);
			//assert(XMLLigne.childNodes[2].nodeName==this.XML_CHAMP_LIGNES_LIGNE_FIN);
			var sFin = bCorpsSeul ? "" : this.sReencodeInnerHTML(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;
					}
				}
				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>");
								sContenuActuelTable = sContenuActuelTable.substring(0, nPosTR) + sDebut + sCorps + sFin + "</TR>" + sContenuActuelTable.substring(nPosTR + "</TR>".length);
							}
							else
							{
								var nPosTBody = sContenuActuelTable.toUpperCase().lastIndexOf("</TBODY>");
								sContenuActuelTable = sContenuActuelTable.substring(0, nPosTBody) + sDebut + sCorps + sFin + "</TBODY>" + sContenuActuelTable.substring(nPosTBody + "</TBODY>".length);
							}
						}
						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);
		}
	},

	// Rechargement d'une image dynamique
	ActionChampRecharge:function (oChamp, XMLAction)
	{
		// Modification du parametre anticache du champ image
		var sUrlImage = oChamp.src;
		// Recherche du second =
		var nDebut = sUrlImage.indexOf("=") + 1;
		nDebut = sUrlImage.indexOf("=", nDebut) + 1;
		// Recherche d'un POSSIBLE second &
		var nEt = sUrlImage.indexOf("&") + 1;
		nEt = sUrlImage.indexOf("&", nEt);

		// Code anticache
		var sAntiCache = "";
		if (nEt == -1)
		{
			szAntiCache = sUrlImage.substr(nDebut);
		}
		else
		{
			szAntiCache = sUrlImage.substring(nDebut, nEt);
		}
		// Si trouve
		if (szAntiCache.length > 0)
		{
			var nAntiCache = parseInt(szAntiCache) + 1;
			if (nEt == -1)
			{
				oChamp.src = sUrlImage.substr(0, nDebut) + nAntiCache
			}
			else
			{
				oChamp.src = sUrlImage.substr(0, nDebut) + nAntiCache + sUrlImage.subStr(nEt);
			}
		}
//		else
//		{	// Modification de l'URL => Impossible cela casse alors dans le moteur
//			oChamp.src = sUrlImage + "&__V=0";
//		}
	},

	// 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 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, 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, nTypeChamp, XMLAction);		break;
						// Largeur
						case this.XML_CHAMP_PROP_NUM_LARGEUR:			if (oChamp)this.ActionProprieteLargueur(oChamp, nTypeChamp, XMLAction);		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(this.oChercheChamp(oPage, sAliasChamp, nTypeChamp, true), 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(this.oChercheChamp(oPage, sAliasChamp, nTypeChamp, true), nTypeChamp, XMLAction);		break;
						// Y
						case this.XML_CHAMP_PROP_NUM_Y:					this.ActionProprieteY(this.oChercheChamp(oPage, sAliasChamp, nTypeChamp, true), nTypeChamp, XMLAction);		break;
						// CurseurSouris
						case this.XML_CHAMP_PROP_NUM_CURSEURSOURIS:		this.ActionProprieteCurseurSouris(this.oChercheChamp(oPage, sAliasChamp, nTypeChamp, true), nTypeChamp, XMLAction);		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);		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(this.m_bReencodeLatin1 ? this.sReencodeCP1252(sCodeJS, false) : sCodeJS);
	},

	// 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)
	{
		// 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);

		// Supprime les traces du premier affichage
		var oOldTrace = _JGE(this.XML_WBTRACE_ID, document);
		while (oOldTrace)
		{
			oOldTrace.parentNode.removeChild(oOldTrace);
			oOldTrace = _JGE(this.XML_WBTRACE_ID, document)
		}

		// Si la trace est vide : on supprime la zone de trace si besoin
		if ((sTrace + "").length == 0)
		{
			// Si la zone existe
			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 = this.sReencodeInnerHTML(sTrace, true);
	},

	// execute les actions
	// oObjet : Selon la requete => objet formulaire, objet table (Ou objet cache de la table)
	bActionXML:function(oPage, oObjet, XML)
	{	// on recupere la racine
		var XMLListeRacine = XML.getElementsByTagName(this.XML_RACINE);
		if (!XMLListeRacine) return false;
		var XMLRacine = XMLListeRacine ? XMLListeRacine[0] : null;
		if (!XMLRacine) return false;
		// on lance le parcours des actions a effectuer
		var XMLAction = XMLRacine.firstChild;
		while(XMLAction!=null)
		{	// selon le type d'action
			switch(XMLAction.nodeName)
			{	// champ
				case this.XML_CHAMP:	this.ActionChamp(oPage, XMLAction);			break;
				// Code js pur
				case this.XML_JS:		this.ActionJS(oPage, XMLAction);			break;
				// Redirection
				case this.XML_REDIR:	this.ActionRedirection(oPage, XMLAction);	break;
				// Gestion du cache des tables
				case this.XML_LISTE:	oObjet.ActionListe(XMLAction);				break;
				// Affichage de traces
				case this.XML_TRACE:	this.ActionTrace(oPage, XMLAction);				break;
			}
			// on passe au fils suivant
			XMLAction = XMLAction.nextSibling;
		}
		return true;
	},

	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(); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
			window.onresize = function () { if (oTmp.m_fWinOnResize) { oTmp.m_fWinOnResize(); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
		}
		else
		{
			window.onscroll = function (event) { if (oTmp.m_fWinOnScroll) { oTmp.m_fWinOnScroll(event); } oTmp._ReactualiseActivite(oTmp.m_bActivite); };
			window.onresize = function (event) { if (oTmp.m_fWinOnResize) { oTmp.m_fWinOnResize(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;

		// Calcule le scrollLeft et scrollTop du navigateur selon le navigateur et le mode
		var oSource = bIE ? (document.documentElement.clientWidth ? document.documentElement : document.body) : document.body;
		var nScrollLeft = bIE ? oSource.scrollLeft : window.pageXOffset;
		var nScrollTop = bIE ? oSource.scrollTop : window.pageYOffset;

		// Place le temoin d'activite
		switch (this.m_nActiviteOption)
		{
		default:
		case this.eActivite_Fixe:
			// Rien
			break;
		case this.eActivite_HautGauche:
			this.m_oActiviteChamp.style.left = _JCCP(nScrollLeft, this.m_oActiviteChamp, true, false) + "px";
			this.m_oActiviteChamp.style.top = _JCCP(nScrollTop, this.m_oActiviteChamp, false, false) + "px";
			break;
		case this.eActivite_HautDroite:
			this.m_oActiviteChamp.style.left = (_JCCP(nScrollLeft, this.m_oActiviteChamp, true, false) + oSource.clientWidth - this.m_oActiviteChamp.clientWidth) + "px";
			this.m_oActiviteChamp.style.top = _JCCP(nScrollTop, this.m_oActiviteChamp, false, false) + "px";
			break;
		case this.eActivite_BasGauche:
			this.m_oActiviteChamp.style.left = _JCCP(nScrollLeft, this.m_oActiviteChamp, true, false) + "px";
			this.m_oActiviteChamp.style.top = (_JCCP(nScrollTop, this.m_oActiviteChamp, false, false) + oSource.clientHeight - this.m_oActiviteChamp.clientHeight) + "px";
			break;
		case this.eActivite_BasDroite:
			this.m_oActiviteChamp.style.left = (_JCCP(nScrollLeft, this.m_oActiviteChamp, true, false) + oSource.clientWidth - this.m_oActiviteChamp.clientWidth) + "px";
			this.m_oActiviteChamp.style.top = (_JCCP(nScrollTop, this.m_oActiviteChamp, false, false) + oSource.clientHeight - this.m_oActiviteChamp.clientHeight) + "px";
			break;
		case this.eActivite_Centrer:
			this.m_oActiviteChamp.style.left = (_JCCP(nScrollLeft, this.m_oActiviteChamp, true, false) + (oSource.clientWidth - this.m_oActiviteChamp.clientWidth) / 2) + "px";
			this.m_oActiviteChamp.style.top = (_JCCP(nScrollTop, this.m_oActiviteChamp, false, false) + (oSource.clientHeight - this.m_oActiviteChamp.clientHeight) / 2) + "px";
			break;
		}

		// Et l'affiche
		this.m_oActiviteChamp.style.visibility = bVisible ? "inherit" : "hidden";
	}
};

//// On instancie un objet principal
var clWDAJAXMain = new WDAJAXMain(_bUTF8_);

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 été bloqué par un l'appel de _JAZR qui précede 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 immédiatement
		bBloque = true;
	}
	else
	{
		clWDAJAXMain.SetZRChamp(sZRChamp, sValeur);
	}
}
