//#16.0.1.0 WDUtil.js
//VersionVI: 30A160057k
// 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

// Detection du navigateur

var bIE = navigator.appName.indexOf("Microsoft") != -1;
var nIE = 0;
var bIEQuirks = false;
var bOpr = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
// On fait un cas particulier pour IE7
if (bIE)
{
	// Cas particulier de Opera qui s'annonce par defaut comme IE
	if (!bOpr)
	{
		var oExpr = new RegExp("MSIE (\\d)+[\\.\\d]*");
		var oRes = oExpr.exec(navigator.userAgent);
		if (oRes && oRes[1])
		{
			nIE = parseInt(oRes[1], 10);
		}
		oRes = null;
		oExpr = null;
		// Detecte le "quirks mode"
		bIEQuirks = (document.compatMode == "BackCompat");
	}
	else
	{
		bIE = false;
	}
}
// Detection de gecko pour avoir les autres browser ?
var bFF = (navigator.userAgent.toLowerCase().indexOf("firefox/") != -1);
if (bFF)
{
	var oExpr = new RegExp("Fire[Ff]ox/\\s*(\\d+)\\.*(\\d+)");
	var oRes = oExpr.exec(navigator.userAgent);
	var bFF35 = (oRes && oRes[1] && (((parseInt(oRes[1], 10) >= 3) && oRes[2] && (parseInt(oRes[2], 10) >= 5)) || (parseInt(oRes[1], 10) >= 4)));
	oRes = null;
	oExpr = null;
}
// Il faut chercher "chrome/" car sinon on trougve des faux positif (par exemple "chromeframe/")
var bCrm = (navigator.userAgent.toLowerCase().indexOf("chrome/") != -1);
var bSfr = (navigator.userAgent.toLowerCase().indexOf("safari") != -1) && (!bCrm);
var bMac = (navigator.platform.indexOf("Mac") != -1);
var bWK = bCrm || bSfr;

// Manipulation des Cookies : utilisation d'un objet comme espace de nommage
var clWDCookie = {
	ms_sSeparateurCookie: ";",
	ms_sSeparateurValeur: "="
};

// Recupere le cookie
clWDCookie.GetCookie = function GetCookie(sNom)
{
	var tabCookies = document.cookie.split(this.ms_sSeparateurCookie);
	var i = 0;
	var nLimiteI = tabCookies.length;
	for (i = 0; i < nLimiteI; i++)
	{
		var tabCookie = tabCookies[i].split(this.ms_sSeparateurValeur);
		if ((tabCookie[0] == sNom || tabCookie[0] == " " + sNom) && tabCookie[1])
		{
			return unescape(tabCookie[1]);
		}
	}
	return "";
};

// Ecrit un cookie
clWDCookie.SetCookie = function SetCookie(sNom, sValeur)
{
	var sExp = "Mon, 31 Dec 2010 23:59:59 UTC";
	// Si on est dans le futur (Apres 2009) : On met une autre date
	if (parseInt((new Date()).getFullYear(), 10) >= 2009)
	{
		sExp = new Date((new Date()).getTime() + 30 * 24 * 3600 * 1000).toGMTString();
	}
	this._SetCookie(sNom, sValeur, sExp);
};

// Supprime un cookie
clWDCookie.ClearCookie = function ClearCookie(sNom)
{
	this._SetCookie(sNom, "", "Fri, 02 Jan 1970 00:00:00 UTC");
};

// Ecrit un cookie, version interne
clWDCookie._SetCookie = function _SetCookie(sNom, sValeur, sExp)
{
	document.cookie = sNom + this.ms_sSeparateurValeur + escape(sValeur) + "; expires=" + sExp + "; path=/;";
};

// Utilisation d'un objet comme espace de nommage
var clWDUtil = {};

// Manipule les tag en forme normalise (normalement inutile sur les navigateurs recents)
clWDUtil.sGetTagName = function sGetTagName(oBalise)
{
	return oBalise.tagName ? oBalise.tagName.toLowerCase() : "";
};
// Indique si la balise est du bon type
clWDUtil.bBaliseEstTag = function bBaliseEstTag(oBalise, sTag)
{
	return (this.sGetTagName(oBalise) == sTag);
};

// Sens de lecture
clWDUtil.bRTL = (bIE ? (document.dir == "rtl") : (document.documentElement.dir == "rtl"));
clWDUtil.GetStyleLeft = function GetStyleLeft(oStyle)
{
	return this.bRTL ? oStyle.right : oStyle.left;
};
clWDUtil.SetStyleLeft = function SetStyleLeft(oStyle, nVal, nOffset)
{
	if (this.bRTL)
	{
		oStyle.right = (nVal - nOffset) + "px";
	}
	else
	{
		oStyle.left = (nVal + nOffset) + "px";
	}
};

// Fonction
if (bIE)
{
	clWDUtil.oGetOriginalTarget = function oGetOriginalTarget(oEvent) { return oEvent.srcElement; };
}
else if (bFF && !bWK)
{
	clWDUtil.oGetOriginalTarget = function oGetOriginalTarget(oEvent) { return oEvent.explicitOriginalTarget; };
}
else
{
	clWDUtil.oGetOriginalTarget = function oGetOriginalTarget(oEvent) { return oEvent.target; };
}

// .style.display des TR/TD
clWDUtil._sGetDisplayBlockIE = function _sGetDisplayBlockIE(oBalise)
{
	return "block";
};
clWDUtil._sGetDisplayBlock = function sGetDisplayBlock(oBalise)
{
	switch (this.sGetTagName(oBalise))
	{
		case "table": return "table";
		case "tr": return "table-row";
		case "td": return "table-cell";
		default: return "block";
	}
};
clWDUtil.sGetDisplayBlock = ((bIE && ((nIE < 8) || bIEQuirks)) ? clWDUtil._sGetDisplayBlockIE : clWDUtil._sGetDisplayBlock);

clWDUtil.sGetDisplayPourAffiche = function sGetDisplayPourAffiche(oBalise, bAffiche)
{
	return bAffiche ? this.sGetDisplayBlock(oBalise) : "none";
};

clWDUtil.SetDisplay = function SetDisplay(oBalise, bAffiche)
{
	if (oBalise && oBalise.style)
	{
		oBalise.style.display = this.sGetDisplayPourAffiche(oBalise, bAffiche);
	}
};

clWDUtil.bEstDisplay = function bEstDisplay(oElement, oDocument)
{
	var oBody = oDocument.body;
	while (oElement && (oElement != oBody))
	{
		if (_JGCS(oElement).display == "none")
		{
			return false;
		}
		oElement = oElement.parentNode;
	}
	return true;
};

if (bOpr)
{
	// Contournement pour createContextualFragment avec opera (perd les attributs de la racine dans certains cas)
	// Ne marche que s'il n'y a qu'un fils
	clWDUtil.oCreateContextualFragment = function oCreateContextualFragment(oRange, sFragment)
	{
		var oDiv = document.createElement('div');
		oDiv.innerHTML = sFragment;
		var oFils = oDiv.firstChild;
		while (oFils && (oFils.nodeName == "#text"))
		{
			oFils = oFils.nextSibling;
		}
		return oFils;
	};
}
else if (!bIE)
{
	clWDUtil.oCreateContextualFragment = function oCreateContextualFragment(oRange, sFragment) { return oRange.createContextualFragment(sFragment); };
}

// Emulation de getElementById (IE4 et IE pocket)
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; };
}

// Stop la propagation des evenements
var bStopPropagation = null;
if (bIE)
{
	bStopPropagation = function (oEvent) { oEvent.returnValue = false; return false; };
}
else
{
	bStopPropagation = function (oEvent) { if (oEvent.preventDefault) { oEvent.preventDefault(); } return false; };
}

// Stoppe conditionnelement la propagation
function bStopPropagationCond (oEvent, bStop)
{
	if (bStop)
	{
		return bStopPropagation(oEvent);
	}
	else
	{
		return true;
	}
}

// Attache une fonction a un evenement
function HookOnXXX (oCible, sEventIE, sEventFF, fFonction, bCapture)
{
	if (oCible.addEventListener)
	{
		oCible.addEventListener(sEventFF, fFonction, bCapture ? true : false);
	}
	else if (oCible.attachEvent)
	{
		oCible.attachEvent(sEventIE, fFonction);
	}
	else
	{
		// Cas d'un objet sorti du DOM dans opera : ne fait rien
	}
}

// Detache une fonction d'un evenement
function UnhookOnXXX(oCible, sEventIE, sEventFF, fFonction, bCapture)
{
	if (oCible.removeEventListener)
	{
		oCible.removeEventListener(sEventFF, fFonction, bCapture ? true : false);
	}
	else if (oCible.detachEvent)
	{
		oCible.detachEvent(sEventIE, fFonction);
	}
	else
	{
		// Cas d'un objet sorti du DOM dans opera : ne fait rien
	}
}

// Indique si un element est fils d'un autre
function bEstFils (oElement, oParent, oDocument)
{
	var oBody = oDocument.body;
	while (oElement && (oElement != oBody))
	{
		if (oElement == oParent)
		{
			return true;
		}
		oElement = oElement.parentNode;
	}
	return false;
}

// Supprime tous les fils d'un elements
function SupprimeFils (oElement)
{
	var tabChildNodes = oElement.childNodes;
	while (tabChildNodes.length > 0)
	{
		oElement.removeChild(tabChildNodes[0]);
	}
}

// Supprime une variable du HTML si elle existe
// Retourne si la variable existait
function bHTMLVideDepuisVariable(oObjet, sNomVariable)
{
	if (oObjet[sNomVariable])
	{
		// Si la variable existe, la supprime du HTML et de l'objet
		var oElement = oObjet[sNomVariable];
		if (oElement.parentNode)
		{
			oElement.parentNode.removeChild(oElement);
		}
		oObjet[sNomVariable] = null;
		delete oObjet[sNomVariable];
		return true;
	}
	else
	{
		// Supprime par securite (variable existante mais vide)
		delete oObjet[sNomVariable];
		return false;
	}
}

// Construit les parametres d'une fonction serveur appelee
// nNbParamIgnore contient le nombre de parametres a ignorer dans tabParamOriginaux
function sConstuitProcedureParams (nNbParamIgnore, tabParamsOriginaux)
{
	var i;
	var nLimiteI = tabParamsOriginaux.length;
	// + Car on laisse le premier indice vide donc comme ca on a automatiquement le "&" initial
	var tabParams = new Array(nLimiteI - nNbParamIgnore + 1);
	tabParams[0] = "";
	for (i = nNbParamIgnore; i < nLimiteI; i++)
	{
		var nIndiceReel = i - nNbParamIgnore + 1;
		// 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
		var oParam = tabParamsOriginaux[i];
		tabParams[nIndiceReel] = "PA" + (i - nNbParamIgnore + 1) + "=" + ((oParam === true) ? "1" : ((oParam === false) ? "0" : clWDEncode.sEncodePOST(oParam + "")));
	}
	return tabParams.join("&");
}

// Recupere l'action depuis le location
function _sGetPageActionDepuisLocation (sAction)
{
	// On prend l'URL si on n'a pas d'action
	sAction = location.href + sAction;
	// On vire l'ancre
	var nAncreTaille = location.hash.length;
	if (nAncreTaille > 0)
	{
		var nAncrePos = sAction.indexOf(location.hash);
		sAction = sAction.substr(0, nAncrePos) + sAction.substr(nAncrePos + nAncreTaille);
	}
	return sAction;
}

// Recupere l'action d'une page
// oPage : formulaire a utiliser (null possible)
// bParamSuppr : indique s'il faut supprimer les parametres de l'URL
// bIDSession : Indique s'il faut ajouter l'ID de session
// bPourRepRes : Indique que la reference est avec le repertoire res et qu'il faut eviter les chemin relatifs
function sGetPageAction (oPage, bParamSuppr, bIDSession, bPourRepRes)
{
	// Trouve la page si besoin
	if (!oPage)
	{
		oPage = _PAGE_;
	}

	// Calcule l'URL
	var sAction = (oPage.action.length > 0) ? oPage.action : "";
	if ((sAction.length == 0) || (sAction.charAt(0) == "?"))
	{
		// Si l'action se retourve deja dans l'URL de la page, on ne la double pas
		if (-1 != location.href.indexOf(sAction))
		{
			sAction = _sGetPageActionDepuisLocation("");
		}
		else
		{
			sAction = _sGetPageActionDepuisLocation(sAction);
		}
	}
	// Implicitement on a sAction > 0 (teste dans le premier if)
	else if ((nIE >= 8) && !bIEQuirks)
	{
		// En mode non quirks, IE retourne une addresse absolue pour FORM.action
		// Sauf que dans une page AWP l'action est vide. IE complete quand meme et retourne donc le chemin de la page
		// Evidement ce n'est pas une action valide au final
		var sActionAttribut = _PAGE_.getAttributeNode("action").value;
		if ((0 == sActionAttribut.length) || ("?" == sActionAttribut.charAt(0)))
		{
			sAction = _sGetPageActionDepuisLocation(sActionAttribut);
		}
	}

	if (bPourRepRes && (sAction.indexOf("/") == -1) && (sAction.length > 0))
	{
		sAction = "../" + sAction;
	}

	// Vire les parametres
	if (bParamSuppr && (sAction.indexOf("?") != -1))
	{
		sAction = sAction.substr(0, sAction.indexOf("?"));
	}

	// Ajoute l'ID de session si besoin
	if (bIDSession)
	{
		if ((sAction.indexOf("AWPID=") == -1) && (window["_AWPID_A_"] !== undefined))
		{
			// Ajoute le separateur et la session
			var sID = (sAction.indexOf("?") != -1) ? _AWPID_A_ : _AWPID_P_;
			// Et s'il est vide prend le cookie de session s'il existe :
			// Firefox et chrome qui en donnent pas leurs cookies au plugins (= Flash)
			if ((bFF || bWK) && (sID.length == 0))
			{
				sID = clWDCookie.GetCookie("AWP_CSESSION");
				if (sID.length > 0)
				{
					sID = ((sAction.indexOf("?") != -1) ? "&" : "?") + "AWPID=" + sID;
				}
			}
			sAction += sID;
		}
		else if (window["_PHPID_"] !== undefined)
		{
			var sNomPHPID = _PHPID_.split("=");
			if ((sNomPHPID.length > 0) && (sAction.indexOf(sNomPHPID + "=") == -1))
			{
				// Ajoute le separateur et la session
				sAction += ((sAction.indexOf("?") != -1) ? "&" : "?") + _PHPID_;
			}
		}
	}
	// Renvoie la valeur
	return sAction;
}

// Ajoute une regle CSS
function CreeStyle(oFeuilleStyle, sNomStyle, sTexteStyle)
{
	// Ne cree pas un style vide
	if (sTexteStyle.length)
	{
		// Ajoute un style dans la feuille de style donnee
		if (oFeuilleStyle.addRule)
		{
			oFeuilleStyle.addRule(sNomStyle, sTexteStyle);
		}
		else
		{
			oFeuilleStyle.insertRule(sNomStyle + " {" + sTexteStyle + "}", oFeuilleStyle.cssRules.length);
		}
	}
}

// Encodage des valeurs

function WDEncode (bUTF8)
{
	// 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.sEncodePOST = WDEncode.prototype.sEncodePOST_CP1252;

		// Et d'ecriture de valeur dans le HTML
		this.sEncodeCharset = WDEncode.prototype.sEncodeCharset_CP1252;
	}
	else
	{
		// Le fonctionnement par defaut des fonctions est OK
	}
}

// Fonctionnement par defaut des fonctions d'encodage : pour les pages UTF8
// Encodage pour l'ecriture dans le POST : simple echapement
WDEncode.prototype.sEncodePOST = function sEncodePOST(sValeur)
{
	return encodeURIComponent(sValeur);
};

// Encodage pour l'ecriture dans la page : ne fait rien
WDEncode.prototype.sEncodeCharset = function sEncodeCharset(sValeur)
{
	return sValeur;
};

// Version pour les pages non UTF8 (CP1252) des fonctions d'encodage
// Encodage pour l'ecriture dans le POST : remplacement de tous les carateres unicodes par leur valeur CP1252 si possible
WDEncode.prototype.sEncodePOST_CP1252 = function sEncodePOST_CP1252(sValeur)
{
	// Traite les carateres unicodes
	sValeur = sValeur.replace(/[\u0100-\uFFFF]/g, function(sCar) { var n = sCar.charCodeAt(0); var i; var nLimiteI = WDEncode.prototype.tabConvCP1252.length; for(i = 0; i < nLimiteI; i++) { if(WDEncode.prototype.tabConvCP1252[i] == n) { return String.fromCharCode(i + 128); } } return sCar; } );
	// Escape le tout
	sValeur = escape(sValeur);
	// Et remplace le + car il represente l'encodage de l'espace
	return sValeur.replace(/\+/g, "%2B");
};

// Encodage pour l'ecriture dans la page : remplace les carateres qui ne sont pas dans l'alphabet par leur valeur UNICODE
WDEncode.prototype.sEncodeCharset_CP1252 = function sEncodeCharset_CP1252(sValeur, bHTML)
{
	// Le jeu de caratere de windows est CP1252. Qui est un surensemble de ISO-8859-1
	// Il faut convertir tous les carateres entre 0x80 et 0x9F en leur version unicode

	// Puis les caractere de la plage
	// 128 = 0x80
	sValeur = sValeur.replace(/[\x80-\x9F]/g, function(sCar) { return String.fromCharCode(WDEncode.prototype.tabConvCP1252[sCar.charCodeAt(0) - 128]); } );

	if (bHTML)
	{
		// Les caracteres restant (0xA0-0xFF) sont encode normalement en HTML
		sValeur = sValeur.replace(/[\xA0-\xFF]/g, function(sCar) { return "&#" + sCar.charCodeAt(0) + ";"; } );
	}

	// Renvoi de la valeur convertie
	return sValeur;
};

// Le tableau pour la conversion depuis CP1252
//										128		129?	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
//										0x80	0x81	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
WDEncode.prototype.tabConvCP1252 = [	8364,	129,	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,	382,	376	];

// Fonction de reencodage en HTML
WDEncode.prototype.sEncodeInnerHTML = function sEncodeInnerHTML(sValeur, bRemplaceBR, bPasEncodeBalise, bSansHTMLDansEncodeCharset)
{
	// 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 le charset de la page est Latin1 (Donc pas en UTF-8)
	// => On transforme les caractere de CP1252 en leur equivalent unicode qui va fonctionner
	// => On encode les autres caracteres > 127
	// Appele le pointeru qui pointe deja sur la bonne fonction
	sValeur = this.sEncodeCharset(sValeur, bSansHTMLDansEncodeCharset ? false : true);

	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;
};

// Instancie un objet principal
var clWDEncode = new WDEncode(_bUTF8_);

// Classe de base des types avances
function WDTypeAvance(bConstructeur)
{
	if (bConstructeur)
	{
	}
}

// Lire une propriete : a definir dans chaque type
WDTypeAvance.prototype.GetProp = function GetProp(nPropriete)
{
	return null;
};

// Gestion des elements popup de la page
function WDPopupAutomatique (oObjetParent)
{
	// Memorise les parametres
	this.m_oObjetParent = oObjetParent;

	var oThis = this;
	// Cree la methode de hook dans la classe
	this.m_fOnFocus = function(oEvent) { return oThis.OnFocus(oEvent ? oEvent : event); };
	this.m_fOnBlur = function(oEvent) { return oThis.OnBlur(oEvent ? oEvent : event); };

	// Cree une fonction qui appele la fonction de masquage
	this.m_fTimeout = function(oEvent) { oThis.Masque(oEvent, true); };
}

WDPopupAutomatique.prototype =
{
//	m_oElement:				null,
//	m_oObjetParent:			null,
//	m_nTimeoutFocus:		null,

	// Affiche le champ
	Affiche:function (oEvent, oElement, oParam)
	{
		// Si on a 'deja' un element, masque l'element precedent
		if (this.m_oElement)
		{
			this.Masque(oEvent, true);
		}
		// Memorise que l'on a un element
		this.m_oElement = oElement;

		// Efface le timeout existant si besoin
		this.__ClearTimeout();

		// Hook les onfocus/onblur des elements
		this.__HookOnFocusBlurRecursif(oElement);

		// Appel le champ hote
		this.m_oObjetParent.AfficheInterne(oEvent, oElement, oParam);

		// Affiche l'element
		clWDUtil.SetDisplay(this.m_oElement, true);

		// Donne le focus au premier champ APRES l'affichage
		try
		{
			this.m_oElement.getElementsByTagName("a")[0].focus();
		}
		catch (e)
		{
		}
	},

	// Notification de que champ doit etre masquer
	Masque:function (oEvent, bLostFocus)
	{
		// Efface le timeout existant si besoin
		this.__ClearTimeout();

		// Seulement si l'element existe (il peut ne pas existe si la popup n'a pas ete affichee
		if (this.m_oElement)
		{
			this.__UnhookOnFocusBlurRecursif(this.m_oElement);

			// Masque le champ
			clWDUtil.SetDisplay(this.m_oElement, false);
		}

		// Appel le champ hote
		this.m_oObjetParent.MasqueInterne(oEvent, bLostFocus);

		// Supprime l'element
		delete this.m_oElement;
	},

	// Hook les onfocus/onblur des liens
	__HookOnFocusBlurRecursif:function (oElement)
	{
		// Hook l'element uniquement s'il peut recevoir le focus
		if (oElement.focus)
		{
			HookOnXXX(oElement, "onfocus", "focus", this.m_fOnFocus);
			HookOnXXX(oElement, "onblur", "blur", this.m_fOnBlur);
		}

		// Et ses fils qui ne sont pas du texte simple
		var oFils = oElement.firstChild;
		while (oFils)
		{
			if (oFils.nodeName != "#text")
			{
				this.__HookOnFocusBlurRecursif(oFils);
			}
			oFils = oFils.nextSibling;
		}
	},

	// Supprime les hooks
	__UnhookOnFocusBlurRecursif:function (oElement)
	{
		// Unhook l'element uniquement s'il peut recevoir le focus
		if (oElement.focus)
		{
			UnhookOnXXX(oElement, "onfocus", "focus", this.m_fOnFocus);
			UnhookOnXXX(oElement, "onblur", "blur", this.m_fOnBlur);
		}

		// Et ses fils qui ne sont pas du texte simple
		var oFils = oElement.firstChild;
		while (oFils)
		{
			if (oFils.nodeName != "#text")
			{
				this.__UnhookOnFocusBlurRecursif(oFils);
			}
			oFils = oFils.nextSibling;
		}
	},

	// Evenement avant l'affectation en AJAX du contenu du calendrier
	PreAffecteHTML:function (bDepuisAJAX)
	{
		// Si le champ est affiche : supprime les hooks
		if (this.m_oElement && (this.m_oElement.style.display == clWDUtil.sGetDisplayBlock(this.m_oElement)))
		{
			this.__UnhookOnFocusBlurRecursif(this.m_oElement);
		}
	},

	// Evenement apres l'affectation en AJAX du contenu du calendrier
	PostAffecteHTML:function (bDepuisAJAX)
	{
		// Si le champ est affiche : restaure les hooks
		if (this.m_oElement && (this.m_oElement.style.display == clWDUtil.sGetDisplayBlock(this.m_oElement)))
		{
			this.__HookOnFocusBlurRecursif(this.m_oElement);
		}
		// Donne le focus au premier champ
		try
		{
			this.m_oElement.getElementsByTagName("a")[0].focus();
		}
		catch (e)
		{
		}
	},

	// Notification qu'un lien a pris le focus.
	OnFocus:function (oEvent)
	{
		// Efface le timeout existant si besoin
		this.__ClearTimeout();
	},

	// Notification que le champ a perdu le focus.
	// Il faut tester si le focus est parti dans un autre champ du calendrier ou a l'exterieur
	OnBlur:function (oEvent)
	{
		// On veut detecter les pertes de focus du calendrier
		// Sauf que la perte de focus d'un lien peut donner le focus a un autre lien du calendrier
		// => On fait un timeout de 1ms qui sera annule par le onfocus de l'autre lien si besoin
		if (!this.m_nTimeoutFocus)
		{
			// Un timeout de 1ms est trop faible pour Chrome
			// Il faut une valeur vraiment importante pour les versions recente de Chrome (il y a alors quand meme un leger lag visuel) et aussi pour safari
			var nDuree = (bWK) ? 200 : 1;
			this.m_nTimeoutFocus = setTimeout(this.m_fTimeout, nDuree);
		}
	},

	// Efface le timeout existant si besoin
	__ClearTimeout:function ()
	{
		// Supprime le timeout actif
		if (this.m_nTimeoutFocus)
		{
			// Invalide le timeout aupres du systeme
			clearTimeout(this.m_nTimeoutFocus);

			// Supprime le membre
			delete this.m_nTimeoutFocus;
		}
	}
};

// Gestion d'un champ de saisie temporaire
function WDPopupSaisie (oObjetParent, bValideSurBlur)
{
	// Si on est pas dans l'init d'un protoype
	if (oObjetParent)
	{
		// Memorise les parametres
		this.m_oObjetParent = oObjetParent;
		this.m_bValideSurBlur = bValideSurBlur;
	}
}

// Initialisation
WDPopupSaisie.prototype.Init = function Init()
{
	// Fonction de validation (attention on suppose que l'on a un formulaire)
	var oThis = this;
	this.m_fValide = function(oEvent) { oEvent = oEvent ? oEvent : event; oThis.Valide(oEvent, oThis.m_oSaisie.value); return bStopPropagation(oEvent); };
	this.m_fAnnule = function(oEvent) { oEvent = oEvent ? oEvent : event; oThis.Annule(); return bStopPropagation(oEvent); };
	this.m_fAnnuleSiEsc = function(oEvent)
	{
		oEvent = oEvent ? oEvent : event;
		if (27 == oEvent.keyCode)
		{
			return oThis.m_fAnnule();
		}
	};
};

// Debut de la saisie
// nReductionLargeur : pour la saisie dans le champ table : on ne prend pas toute la largeur
WDPopupSaisie.prototype.Debut = function Debut(oConteneurParent, nReductionLargeur)
{
	// Annulle l'ancienne saisie si besoin (arrive dans des combinaisons d'evenements bizarres)
	this.Annule();

	// Appel de la methode personnalisable
	this._vDebut.apply(this, arguments);

	// Et donne le focus au champ de saisie
	this.m_oSaisie.focus();
	var oThis = this;
	setTimeout(function() { oThis.__DonneFocusSaisie(); }, 1);
};

// Fixe le focus
WDPopupSaisie.prototype.__DonneFocusSaisie = function __DonneFocusSaisie()
{
	// Si le champ de saisie est directement supprime de la page, .focus ne fonctionne pas
	// Dans ce cas selon le navigateur, oSaisie.parentNode est null ou est le document, en tous cas ce n'est pas le formulaire
	if (this.m_oSaisie)
	{
		var oParent = this.m_oSaisie.parentNode;
		if (oParent && ("form" == clWDUtil.sGetTagName(oParent)))
		{
			this.m_oSaisie.focus();
		}
	}
};

// Debut de la saisie
// nReductionLargeur : pour la saisie dans le champ table : on ne prend pas toute la largeur
WDPopupSaisie.prototype._vDebut = function _vDebut(oConteneurParent, nReductionLargeur)
{
	// Cree dynamiquement la zone de recherche
	var oFormulaire = document.createElement("form");
	// Avec son action
	oFormulaire.method = "post";
	oFormulaire.action = "javascript:return false;";
	// Puis on place le formulaire au bon endroit
	oFormulaire.style.position = "absolute";
	oFormulaire.style.top = "0px";
	oFormulaire.style.left = "0px";
	oFormulaire.style.width = (oConteneurParent.offsetWidth - nReductionLargeur - 1) + "px";
	oFormulaire.style.height = "100%";

	// Ensuite on fait le champs de saisie
	var oSaisie = document.createElement("input");
	oSaisie.type = "text";
	// On l'attache a son parent
	oSaisie = oFormulaire.appendChild(oSaisie);
	// Et lui defini son style
	oSaisie.style.position = "absolute";
	oSaisie.style.top = "0px";
	oSaisie.style.left = "0px";
	oSaisie.style.width = "100%";
	oSaisie.style.height = "100%";
	oSaisie.style.borderWidth = "0";
	oSaisie.style.borderStyle = "solid";
	// Si la hauteur du parent est faible : reduit la taille de la police
	if ((oConteneurParent.offsetHeight <= 18) && (oConteneurParent.offsetHeight > 0))
	{
		oSaisie.style.fontSize = Math.max(oConteneurParent.offsetHeight - 4, 6) + "px";
	}

	// On met le tout dans la cellule de recherche
	this.m_oFormulaire = oConteneurParent.appendChild(oFormulaire);
	this.m_oSaisie = this.m_oFormulaire.elements[0];

	// Et la methode de validation qui renvoie toujours faux pour ne pas valider le formulaire
	HookOnXXX(this.m_oFormulaire, "onsubmit", "submit", this.m_fValide);
	// Gere la perte du focus et l'annulation
	HookOnXXX(this.m_oSaisie, "onblur", "blur", this.m_bValideSurBlur ? this.m_fValide : this.m_fAnnule);
	HookOnXXX(this.m_oSaisie, "onkeydown", "keydown", this.m_fAnnuleSiEsc);
};

// Valide la saisie
WDPopupSaisie.prototype.Valide = function Valide(oEvent, sValeur)
{
	// Seulement si on a une saisie
	if (this.m_oFormulaire)
	{
		// Appel de la methode personnalisable
		this._vValide.apply(this, arguments);
	}

	// Supprime le HTML de la saisie
	this.Annule();
};

// Valide la saisie
WDPopupSaisie.prototype._vValide = function _vValide(oEvent, sValeur)
{
	// Rien
};

// Annule la saisie
WDPopupSaisie.prototype.Annule = function Annule()
{
	// Seulement si on a deja une saisie en cours
	if (this.m_oFormulaire)
	{
		// Appel de la methode personnalisable
		this._vAnnule.apply(this, arguments);

		// Supprime les evenements
		UnhookOnXXX(this.m_oSaisie, "onkeypress", "keypress", this.m_fAnnuleSiEsc);
		UnhookOnXXX(this.m_oSaisie, "onblur", "blur", this.m_fAnnule);
		UnhookOnXXX(this.m_oFormulaire, "onsubmit", "submit", this.m_fValide);
	}

	// Supprime le onblur de l'element de saisie pour eviter que le navigateur (IE) ne s'emelle les pinceau si on creer un nouvel objet)
	bHTMLVideDepuisVariable(this, "m_oSaisie");
	bHTMLVideDepuisVariable(this, "m_oFormulaire");
};

// Annule la saisie
WDPopupSaisie.prototype._vAnnule = function _vAnnule()
{
	// Rien
};